cancel
Showing results for 
Search instead for 
Did you mean: 

Issue with running from SRAM

SBurc
Associate II

This is a new issue involved in running from SRAM. I recently posted an issue:

https://community.st.com/s/question/0D50X0000BDnc5pSQB/stm32f7-uart5-issue

and this is a second, possibly related issue.

The software I am writing is a Built-in-Test and bootloader, which does the following:

Tests all of the testable hardware on the board, saving the results to a RAM region. Depending on external events (IOs and communication), either runs an application or stays present to receive new application and application data files, and burns them to one of three different flashes on the board (the internal flash, an external SPI serial flash, and an external QSPI serial flash). Because it burns the internal flash, it was decided the easiest route would be to run the entire application from SRAM, eliminating the need to burn via DMA or copy bits and pieces of code to RAM and run them there.

The process nearly works completely. The only two problems that appeared during testing were failures in the built-in test which did not appear when the built-in test was run from flash. The first was the one in the previous issue in the link about - one UART, UART5, has a strange noise issue which does not appear when running from flash, but does when running from SRAM. I worked around this for now, and although I cannot explain why it happens, I am able to patch it.

The other issue is the Digital Temperature sensor. The built in test is testing that there is communication with two digitial temperature sensors (from another manufacturer, at different places on the board), and then it tests that they are able to generate interrupts. The sensors have a feature that allows setting them low and high temerature alarms, and to receive an interrupt when they are out of range. The interrupt is cleared by reading the configuration register, and set whenever an out-of-range temperature conversion is done. The built in test first reads the sensors's device ID register (which returns a specific value) and thus ensures there is I2C communication with the devices. It then puts both of them into shutdown mode, and sets the limits to -80C and -70C. It then, one sensor at a time, requests a one-shot conversion from each sensor with the same limits in place, and checks that an interrupt occurred (via variables set in the interrupt). It then clears the interrupt by reading the configuration register, verifies the interrupt output has gone back to steady state, and then sets both of them for continuous conversions with limits at -60 C to +100 C (hopefully never interrupting again, unless the box overheats or freezes).

This code runs perfectly from the flash. From SRAM, under the debugger, if I stop and do it in bits and pieces, it also does, but running straight through - it does not. I place a scope on the interrupt line, and see no interrupt is ever generated, let alone cleared. I will post a bit of the code here and explain more:

[The actual problem code will be included in a comment, as this is too long to post with the code itself.  ]

A few explanations about the code : ThisWasCausedOnPurpose is a boolean value which is used in the interrupt to avoid taking corrective action (in the case of a real overtemperature interrupt, I shut down a lot of power consumers). OverTempFaultStatus returns a variable which is reset in the interrupt (Interrupt occurred means the value will be false), or set by reading the status of the interrupt pin in RecheckOvertempFault.

If I place a breakpoint after having read the DevIDs (BP1), I see that they have been read correctly.

If I place a breakpoint after having done a one-shot conversion on the device (BP2), it will work, and I will see the interrupt line fall. However, if I run directly to break at BP3, where should have been cleared, I still see it fallen. If I stop at BP2 and step through (F10, for the IAR users), I then see it clear on the scope. And again, running without breakpoints causes the test to fail, with no interrupts occurring.

This means: (A) the code is there, in place, and correct (some of the responses I have gotten from tech support were asking if I was sure the code in flash and SRAM were really the same), it seems IMHO to be some timing issue.

The main difference between running in flash and SRAM is that in SRAM I have turned off all caching (I and D) because (a) I don't need it, for the purposes of running a slow bootloader it's plenty fast without, and (b) I was afraid that caches on RAM which is being used for both instructions and data might confuse things.

1 REPLY 1
SBurc
Associate II

Here is the code:

bool InitTemperatureSensor(uint8_t which, uint16_t Configuration, float llimit, float hlimit)

{

  HAL_StatusTypeDef status = HAL_OK;

  uint16_t addr = DT_SLAVE_ADDR_0;

  int16_t Lowlimit;

  int16_t Highlimit;

  bool result = true;

  bool WriteConfigRegTwice = false;

  

  if (which != 0)

   addr = DT_SLAVE_ADDR_1;

  if (Configuration == OUR_CONFIG_FOR_BIT_START)

  WriteConfigRegTwice = true;

  Highlimit = (int16_t)(hlimit/COUNTS_TO_DEGREES);

  Lowlimit = (int16_t)(llimit/COUNTS_TO_DEGREES);

  Configuration = SWAP_BYTES_IN_WORD(Configuration);

  Highlimit = SWAP_BYTES_IN_WORD(Highlimit);

  Lowlimit = SWAP_BYTES_IN_WORD(Lowlimit);

  if (WriteConfigRegTwice) // when starting up, to avoid extra interrupts, put into shutdown mode before writing limits. Other times, we will be in shutdown mode.

  {

   status = HAL_I2C_Mem_Write(&hi2c2, addr, (uint16_t)CONFIGURATION_REG, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&Configuration), 2, 100); 

   if (status != HAL_OK)

    result = false;

  }

  status = HAL_I2C_Mem_Write(&hi2c2, addr, (uint16_t)HIGH_LIMIT_REG, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&Highlimit), 2, 100);  

  if (status != HAL_OK)

   result = false;

  status = HAL_I2C_Mem_Write(&hi2c2, addr, (uint16_t)LOW_LIMIT_REG, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&Lowlimit), 2, 100);  

  if (status != HAL_OK)

   result = false;

  status = HAL_I2C_Mem_Write(&hi2c2, addr, (uint16_t)CONFIGURATION_REG, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&Configuration), 2, 100); 

  if (status != HAL_OK)

   result = false;

  return result;

}

void ClearAlert(uint8_t which)

{

 uint16_t Configuration;

 uint16_t addr = DT_SLAVE_ADDR_0;

 HAL_StatusTypeDef status = HAL_ERROR;

  

  if (which != 0)

   addr = DT_SLAVE_ADDR_1;

 while (status != HAL_OK)

  status = HAL_I2C_Mem_Read(&hi2c2, addr, CONFIGURATION_REG, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&Configuration), 2, 10);  

  

}

void TemperatureSensorBIT(bool *resultTS0, bool *resultTS1)

{

  HAL_StatusTypeDef status = HAL_OK;

  uint16_t Devid;

   

  *resultTS0 = true; // assume success

  *resultTS1 = true;

  status = HAL_I2C_Mem_Read( &hi2c2, DT_SLAVE_ADDR_0, DEVICE_ID, I2C_MEMADD_SIZE_8BIT, (uint8_t *)(&Devid), 2, 10);  

  if (status != HAL_OK)

  {

   *resultTS0 = false;

  }

  Devid = SWAP_BYTES_IN_WORD(Devid);

  Devid &= 0x0FFF;

  if (Devid != EXPECTED_ID)

  {

   *resultTS0 = false;

  }

  status = HAL_I2C_Mem_Read(&hi2c2, DT_SLAVE_ADDR_1, DEVICE_ID, I2C_MEMADD_SIZE_8BIT, (uint8_t *)(&Devid), 2, 10);  

  if (status != HAL_OK)

  {

   *resultTS1 = false;

  }

  Devid = SWAP_BYTES_IN_WORD(Devid);

  Devid &= 0x0FFF;

  if (Devid != EXPECTED_ID)

  {

   *resultTS1 = false;

  }

   

// BP1

  ThisWasCausedOnPurpose = true; // just in case we set off an interrupt when in initialization

  InitTemperatureSensor(0, OUR_CONFIG_FOR_BIT_START, -80.0, -70.0); 

  ThisWasCausedOnPurpose = true; // just in case we set off an interrupt when in initialization

  InitTemperatureSensor(1, OUR_CONFIG_FOR_BIT_START, -80.0, -70.0); 

  ClearAlert(0); // Probably does nothing, but doesn't hurt

  ClearAlert(1);

  

  // Now ready to make the test

  ThisWasCausedOnPurpose = true;

  InitTemperatureSensor(0, OUR_CONFIG_FOR_BIT_CONVERT, -80.0, -70.0); // One shot conversion

// BP2

  OS_Time_Delay_Ms(2);

  ClearAlert(0);

  *resultTS0 = (Overtemp_Fault_Status() == false);  

// BP3

  uint8_t retry = 0;

  do

  {

   ClearAlert(0);

   RecheckOvertempFault(); // Also resets value returned in Overtemp_Fault_Status if pin is back in place.

   if (++retry == 0)

   {

    *resultTS0 = false; // if pin didn't go back to normal, fault.

    break;

   }

  } while (Overtemp_Fault_Status() == false);

  ThisWasCausedOnPurpose = true;

  InitTemperatureSensor(1, OUR_CONFIG_FOR_BIT_CONVERT, -80.0, -70.0);

  OS_Time_Delay_Ms(2);

  ClearAlert(1);

  *resultTS1 = (Overtemp_Fault_Status() == false);  

  retry = 0;

  do

  {

   ClearAlert(1);

   RecheckOvertempFault();

   if (++retry == 0)

   {

    *resultTS1 = false; // if pin didn't go back to normal, fault.

    break;

   }

  } while (Overtemp_Fault_Status() == false);

  

  InitTemperatureSensor(0, OUR_CONFIG_NORMAL, LOW_TEMPERATURE, HIGH_TEMPERATURE); // ready to continue.

  InitTemperatureSensor(1, OUR_CONFIG_NORMAL, LOW_TEMPERATURE, HIGH_TEMPERATURE); 

  if (*resultTS0)

   PUBR.TemperatureSenseBIT |= (1 << 0);

  if (*resultTS1)

   PUBR.TemperatureSenseBIT |= (1 << 1);

  

  PUBR.MPUTemperature = ReadTemperatureSensor(0);

  PUBR.MPUTemperature2 = ReadTemperatureSensor(1);

  ThisWasCausedOnPurpose = false;

}