cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L0: Writing to flash blocks interrupts despite moving vector table & ISRs to RAM

Alexandre Courtemanche
Associate II

Writing bytes to internal flash memory blocks all interrupts on the STM32L0 despite moving the vector table and ISR functions to RAM

 

The Context

I have a embedded system running on an STM32L053 processor that needs to process STM32 hardware timer interrupts regularly and cannot be disabled. These top-priority interrupts cannot be prevented because it could cause a failure in the whole system. I also need to process user inputs that can cause writes to NVM (non-volatile memory) at random times to save settings while processing timer interrupts concurrently. I am using IAR compiler.

 

The problem

During the flash writes that can occur randomly, it blocks CPU execution as well as all interrupts for about 6ms. This is a problem because the processing of hardware timer interrupts cannot be prevented or it can cause a failure of the entire system.

 

The potential solution

After some research, I found this document on ST's website that explains exactly how to manage this problem. From what I understand in this document, the list of things to do to prevent the blocking of interrupts are the following:

  • Initiating the flash writes from RAM.
  • Interrupt handler code must be placed in RAM
  • Abstain from using constants that are placed in program Flash memory
  • Data EEPROM cannot be read while being written
  • Vector table relocated in RAM
  • Vector table address must be written in the System Control Block register VTOR.
  • Check that the vectors in the table needed during data EEPROM write access period are pointing to RAM

 

Vector table relocation

void SystemInit (void)
{    
  // (...)
  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  /* Vector Table Relocation in Internal SRAM */
  #pragma section = ".intvec_RAM"
  SCB->VTOR = (uint32_t)__section_begin(".intvec_RAM");
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}

Linker Script:

Linker Script
 
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000 ;
define symbol __ICFEDIT_region_ROM_end__   = 0x0800FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x200000EC;
define symbol __ICFEDIT_region_RAM_end__   = 0x20001FFF;
 
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_heap__   = 0x200;
/**** End of ICF editor section. ###ICF###*/
 
define symbol __RAM_intvec_start = 0x20000000;
define memory mem with size = 4G;
define region ROM_region      = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
define region RAM_region      = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];
 
 
define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };
 
initialize by copy { readwrite };
initialize by copy { section .intvec_RAM };
 
do not initialize  { section .noinit };
 
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place at address mem: __RAM_intvec_start { section .intvec_RAM };
 
place in ROM_region   { readonly };
place in RAM_region   { readwrite,
                        block CSTACK, block HEAP };

Startup Script:

I have two startup scripts added to my project, one with the original vector table (in flash) that has all the handlers except forReset_Handler replaced with Empty_Handler and the other that has the handlers placed in RAM.

The ISR Code:

__ramfunc void TIM22_IRQHandler(void)
{
    if(LL_TIM_IsActiveFlag_TRIG(TIM22) == 1)
    {
        LL_TIM_ClearFlag_TRIG(TIM22);
    }
    if(LL_TIM_IsActiveFlag_CC2(TIM22) == 1)
    {
        LL_TIM_ClearFlag_CC2(TIM22);
        LL_TIM_ClearFlag_CC2OVR(TIM22);
    }
}

The Flash write blocking code

This is the piece of code that blocks all interrupts from happening for about about 6ms (the time it takes for a write to flash). It called periodically.

 

typedef struct 
{
    uint8_t uniqueNumber; // 1 byte
} Eeprom_t;
 
__ramfunc static void SaveStuffToFlash(void)
{
    static uint8_t _numberToStore = 1;
    _eepromData.uniqueNumber = _numberToStore;
    while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == 1) 
    {
        // wait for flag to go to zero.
    };
    _numberToStore++;
}

The persistent problem

I don't know why, but the interruptions are still getting blocked when the SaveStuffToFlash() function is called. I don't have all the code in RAM, only the code that does the save to the internal flash. I followed all the directions in the application note and it seems to still block interrupts. I have run out of ideas and means to debug this.

 

This discussion is locked. Please start a new topic to ask your question.
3 REPLIES 3
Uwe Bonnes
Principal III

I expect e.g. LL_TIM_IsActiveFlag_TRIG() to reside in flash and so block.Use only register access are function you have explicit checked for residing in RAM.

Alexandre Courtemanche
Associate II

If I look at the disassembly of the ISR, there is absolutely no access to flash at all. Everything is in RAM (0x2000000) or timer peripherals (0x4000000).

0693W00000Hqv9bQAB.png