2024-10-15 07:32 AM - last edited on 2024-10-16 08:06 AM by SofLit
We're running into a really weird situation with a bootloader that copies some code into ITCM. The bootloader initializes various peripherals and clocks and then copies data from the QSPI flash to both the SRAM and to the ITCM memory. Then we use the NVIC_SystemReset() call to fully reset everything (apparently there's an Errata that some things don't get properly de-initialized unless a full reset is called). But we are running into a very strange situation whereby it looks like the last byte that was written into ITCM gets corrupted by the SystemReset call! We've tried a few things like settng the ITCM to not be cacheable and calling SCB_CleanDCache before doing the reset. It always seems to be the last byte written. As a test, I used memset to zero-out an additional 35 bytes, and the problem happened at the last byte of the memset. The value seems to be possibly related to some other ITCM contents (e.g. if I zero out the entire ITCM before copying the the code, then the 'bad' value is 0, otherwise it's some other value e.g. 0x1b. How does it even know what the last-written address is? The same copy function is then used to copy to SRAM, so it doesn't seem likely that it's some register value. I'm Shook!
Solved! Go to Solution.
2024-10-16 08:02 AM - edited 2024-10-16 08:04 AM
For all internal SRAM having ECC, all write operations followed by a system reset is affected by the same behavior. So you need to add a dummy write to the same memory to avoid the behavior.
2024-10-15 07:46 AM
Hello @TallMike ,
You need to provide the exact MCU part number. Please check Tips on posting.
If I understand well, the issue is not related to the bootloader but to a behavior to ITCM memory?
So if someone writes a 10 length bytes buffer to ITCM RAM , do you mean that after reset the last byte i.e. 10th byte will be wrong?
2024-10-15 12:41 PM
Right, sorry, here's the part number:;STM32H750IB
And correct, it's not a per-se bootloader issue, it's a System Reset issue,
And yes your understanding is correct: the last byte (e.g. the 10th) will get modified.
2024-10-15 01:15 PM
*((unsigned long *)TOP_OF_RAM) = 0xDEADCAFE;
__DSB(); // Fence
...
NVIC_SystemReset();
2024-10-15 07:51 PM
Is this an actual valid solid solution? I would be worried that it does other unexpected things too unless this is a known issue?
2024-10-16 03:02 AM
Hello @TallMike ,
I reproduced the behavior with this sample code:
#define ITCM_BASE_ADDRESS 0x0
#define PATTERN 0x55
uint8_t *Buffer = NULL;
uint8_t Button_pressed = 0;
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
Buffer = (uint8_t*)ITCM_BASE_ADDRESS;
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(Button_pressed == 1)
{
for(uint32_t i = 0; i<16; i++)
{
*(Buffer+i) = PATTERN;
}
NVIC_SystemReset();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == USER_BUTTON_Pin)
{
/* Toggle LED1 */
Button_pressed = 1;
}
}
And it's a behavior caused by the ECC controller. In fact all write access go through ECC controller before to be written in the RAM. In your case, when you write the last byte and you reset the MCU, that byte still in the ECC controller and didn't reach the memory. As a workaround, after writing the last byte, do a dummy byte write to the memory. Please, refer to the AN5342 "How to use error correction code (ECC) management for internal memories
protection on STM32 MCUs" / Page 17:
This is how I worked around the behavior:
#define ITCM_BASE_ADDRESS 0x0
#define PATTERN 0x55
#define ITCM_LAST_BYTE_ADDRESS 0xFFFF
uint8_t *Buffer = NULL;
uint8_t Button_pressed = 0;
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
Buffer = (uint8_t*)ITCM_BASE_ADDRESS;
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(Button_pressed == 1)
{
for(uint32_t i = 0; i<16; i++)
{
*(Buffer+i) = PATTERN;
}
*(uint8_t*)ITCM_LAST_BYTE_ADDRESS = 0; // Dummy write after an effective last byte write
NVIC_SystemReset();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == USER_BUTTON_Pin)
{
/* Toggle LED1 */
Button_pressed = 1;
}
}
Hope it does answer your question.
2024-10-16 07:54 AM
Thanks for the info! And wow!
One other question: does this also happen when writing to SRAM? We are also copying to SRAM. Does it have the same issue as well? I didn't get a chance to do a test for that.
2024-10-16 08:02 AM - edited 2024-10-16 08:04 AM
For all internal SRAM having ECC, all write operations followed by a system reset is affected by the same behavior. So you need to add a dummy write to the same memory to avoid the behavior.