Skip to main content
Clemens Ehm
Associate II
October 23, 2017
Question

Write into flash while USART interrupt executed

  • October 23, 2017
  • 19 replies
  • 5258 views
Posted on October 23, 2017 at 12:33

Hello,

I have some trouble to write into the flash of my stm32f I can send via usart a lot of commands to the µC, interprete and execute them finally. One command is to write some data into the flash but if I write and the usart is still receiving data, the communication is totally dead - only mcu reset helps.

The only 'solution' which doesn't crash the communication is to deactivate the usart with USART1->CR1 &= ~USART_CR1_UE; before I write into flash and re-enable it after the flash operation - but that's not a real solution cause I will lose data/commands.

What I tried:

- Moving the vector table into SRAM

- Disable the usart interrupt (NVIC_DisableIRQ(USART1_IRQn);)

-

__disable_irq

(

)

;

before the flash operation

Without any effect. The linker script has the following settings:

MEMORY

{

FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K

UNUSED (rx) : ORIGIN = 0x8020000, LENGTH = 128K

RAM (xrw) : ORIGIN = 0x200000C0, LENGTH = 32K - 0xC0

}

I always write into the UNUSED section, not the FLASH where the running firmware is stored.

The best solution would be to disable the interrupt for the flash-write-time, the mcu buffering all incoming packages for the moment and after re-enabling the interrupt I receive the buffered data. Is that somehow possible or you have any other useful hints for me?

Thanks

Note: this post was migrated and contained many threaded conversations, some content may be missing.
    This topic has been closed for replies.

    19 replies

    Uwe Bonnes
    Chief
    October 23, 2017
    Posted on October 23, 2017 at 13:03

    Single bank devices have no read while write capability. So make sure everything related to uart reception is in RAM and not in flash, and chances are good that reception while flashing will not loose character.s

    Clemens Ehm
    Associate II
    October 23, 2017
    Posted on October 23, 2017 at 14:18

    Thx for the answer. I did the following now:

    #define RAMFUNC __attribute__ ((long_call, section ('.ramfunctions')))

    Added '*(.ramfunctions) ' inside the .data section

      .data :

      {

        . = ALIGN(4);

        _sdata = .;        /* create a global symbol at data start */

        *(.data)           /* .data sections */

        *(.data*)          /* .data* sections */

        . = ALIGN(4);

        *(.ramfunctions)

        _edata = .;        /* define a global symbol at data end */

      } >RAM AT> FLASH

    And added the define before my IRQ Handler:

    RAMFUNC void USART1_IRQHandler(void)

    {

        if( ( USART1->ISR & USART_ISR_RXNE ) == USART_ISR_RXNE )

        {

            t_u8 byte = (uint8_t)(USART1->RDR); /* Receive data, clear flag */

            BufferPut( &U1Rx, byte );

        }

    }

    And also before the BufferPut Function where the data is saved in a struct

    RAMFUNC t_bool BufferPut( volatile my_fifo *buffer, t_u8 ch)

    {

        buffer->buff[buffer->in++] = ch;

        if( buffer->in == USARTBUFFSIZE )

        {

            buffer->in = 0;//start from beginning

        }

        return true;

    }

    But I still have the same issue.

    Edit: I checked the output.map and it seems okay:

     *(.ramfunctions)

     .ramfunctions  0x20000848       0x48 utils/usart.o

                    0x20000848                BufferPut

                    0x2000086c                USART1_IRQHandler

                    0x20000890                _edata = .
    Uwe Bonnes
    Chief
    October 23, 2017
    Posted on October 23, 2017 at 14:26

    Is you interrupt table also in RAM?

    Clemens Ehm
    Associate II
    October 23, 2017
    Posted on October 23, 2017 at 14:33

    Should be.  Linker Script:

    RAM (xrw)      : ORIGIN = 0x200000C0, LENGTH = 32K - 0xC0

    First function I call from main():

    ♯ define APPLICATION_ADDRESS         (uint32_t)0x08000000

    ♯ define SYSCFG_MemoryRemap_SRAM     ((uint8_t)0x03)

    volatile uint32_t *VectorTable = (uint32_t *) 0x20000000;

    void Remap_Table(void)

    {

        for (uint32_t i = 0; i < 48; i++)

        {

            VectorTable[i] = *(__IO uint32_t*) (APPLICATION_ADDRESS + (i << 2));

        }

        SYSCFG_MemoryRemapConfig( SYSCFG_MemoryRemap_SRAM );

    }
    Clemens Ehm
    Associate II
    October 23, 2017
    Posted on October 23, 2017 at 16:14

    Disable the Receivepart of the USART with USART1->CR1 &= ~USART_CR1_RE; before writing into flash is also enough. The mcu will not stuck/freeze anymore. So it must be something with the receive part but I already removed my irq sub function and only call a 3 line IRQ Handler of USART 1. That's all.

    Tesla DeLorean
    Guru
    October 23, 2017
    Posted on October 23, 2017 at 16:23

    If the USART is jamming up check for error status and clear that. FLASH writing will stall the processor long enough to get overrun errors.

    Best to make sure all code and data runs from RAM, and nothing touches FLASH like SysTick or anything else. Using RX DMA instead of interrupts can be quite effective.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Clemens Ehm
    Associate II
    October 25, 2017
    Posted on October 25, 2017 at 11:35

    I just tried to use DMA for the RX Part of the USART and well... it's at least better than the interrupt implementation.

    I still lose data while writing into flash and I have an input on the usart but the mcu is not crashing anymore.

    Uwe Bonnes
    Chief
    October 25, 2017
    Posted on October 25, 2017 at 11:59

    Is the DMA buffer large enough to hold all the data you expect during flash write?