Запись в энергонезависимую память без прерывания UART прерывает выполнение на STM32F4XX - PullRequest
0 голосов
/ 27 февраля 2019

У меня есть несколько ошибок OVERRUN на периферии UART, потому что я продолжаю получать данные UART, пока мой код останавливается, потому что я выполняю операцию записи на флэш-памяти .

Я использую прерываниядля UART и поясняется в Прикладной ноте AN3969 :

Прошивка эмуляции EEPROM запускается из внутренней Flash-памяти, поэтому доступ к Flash-памяти будет заблокирован во время операций, требующих удаления Flash илипрограммирование (инициализация EEPROM, обновление переменной или удаление страницы).Как следствие, код приложения не выполняется, и прерывание не может быть обработано.

Такое поведение может быть приемлемым для многих приложений, однако для приложений с ограничениями в реальном времени необходимо запуститькритические процессы из внутренней памяти.

В этом случае:

  1. Перемещение таблицы векторов во внутреннюю память.
  2. Выполнение всех критических процессов и процедур обработки прерыванийиз внутренней оперативной памяти.Компилятор предоставляет ключевое слово для объявления функций как функции RAM;функция копируется из флэш-памяти в ОЗУ при запуске системы, как и любая инициализированная переменная.Важно отметить, что для функции ОЗУ все используемые переменные и вызываемые функции должны быть в ОЗУ.

Так что я ищу в Интернете инайдено AN4808 , в котором приведены примеры того, как поддерживать прерывания во время операций флэш-памяти.

Я продолжил и изменил свой код:

Сценарий компоновщика : Добавлена ​​таблица векторов в SRAM и определена секция .ramfunc

/* stm32f417.dld */
ENTRY(Reset_Handler)

MEMORY
{
    ccmram(xrw)       : ORIGIN = 0x10000000, LENGTH = 64k
    sram              : ORIGIN = 0x20000000, LENGTH = 112k
    eeprom_default    : ORIGIN = 0x08004008, LENGTH = 16376
    eeprom_s1         : ORIGIN = 0x08008000, LENGTH = 16k
    eeprom_s2         : ORIGIN = 0x0800C000, LENGTH = 16k
    flash_unused      : ORIGIN = 0x08010000, LENGTH = 64k
    flash             : ORIGIN = 0x08020000, LENGTH = 896k
}

_end_stack = 0x2001BFF0;

SECTIONS 
{
  . = ORIGIN(eeprom_default);
  .eeprom_data :
  {
    *(.eeprom_data)
  } >eeprom_default

  . = ORIGIN(flash);

  .vectors :
    {
        _load_vector = LOADADDR(.vectors);
        _start_vector = .;
        *(.vectors)
        _end_vector = .;
    } >sram AT >flash

    .text :
    {
        *(.text)
        *(.rodata)
        *(.rodata*)
        _end_text = .;
    } >flash

    .data : 
    {
        _load_data = LOADADDR(.data);
        . = ALIGN(4);
        _start_data = .;
        *(.data)
    } >sram AT >flash


    .ramfunc :
    {
        . = ALIGN(4);
        *(.ramfunc)
        *(.ramfunc.*)
        . = ALIGN(4);
        _end_data = .;
    } >sram AT >flash

    .ccmram :
    {
        _load_ccmram = LOADADDR(.ccmram);
        . = ALIGN(4);
        _start_ccmram = .;
        *(.ccmram)
        *(.ccmram*)
        . = ALIGN(4);
        _end_ccmram = .;
    } > ccmram AT >flash

    .bss :
    {
        _start_bss = .;
        *(.bss)
        _end_bss = .;
    } >sram

    . = ALIGN(4);

    _start_stack = .;


}

_end = .;
PROVIDE(end = .);

Сброс обработчика : Добавлена ​​копия таблицы векторов SRAM и определена секция .ramfunc

void Reset_Handler(void)
{
  unsigned int *src, *dst;

  /* Copy vector table from flash to RAM */
  src = &_load_vector;
  dst = &_start_vector;
  while (dst < &_end_vector)
    *dst++ = *src++;

  /* Copy data section from flash to RAM */
  src = &_load_data;
  dst = &_start_data;
  while (dst < &_end_data)
    *dst++ = *src++;

  /* Copy data section from flash to CCRAM */
  src = &_load_ccmram;
  dst = &_start_ccmram;
  while (dst < &_end_ccmram)
    *dst++ = *src++;

  /* Clear the bss section */
  dst = &_start_bss;
  while (dst < &_end_bss)
    *dst++ = 0;

  SystemInit();
  SystemCoreClockUpdate();

  RCC->AHB1ENR = 0xFFFFFFFF;
  RCC->AHB2ENR = 0xFFFFFFFF;
  RCC->AHB3ENR = 0xFFFFFFFF;
  RCC->APB1ENR = 0xFFFFFFFF;
  RCC->APB2ENR = 0xFFFFFFFF;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOFEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOGEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOIEN;
  RCC->AHB1ENR |= RCC_AHB1ENR_CCMDATARAMEN;

  main();

  while(1);
}

system_stm32f4xxx.c: Некомментированный VECT_TAB_SRAM define

/*!< Uncomment the following line if you need to relocate your vector Table in
     Internal SRAM. */
#define VECT_TAB_SRAM
#define VECT_TAB_OFFSET  0x00 /*!< Vector Table base offset field. 
                                   This value must be a multiple of 0x200. */

Добавлено определение RAMFUNC для установки атрибутов раздела:

#define RAMFUNC __attribute__ ((section (".ramfunc")))

Добавлен RAMFUNC перед функцией и прототипами, связанными с UART, чтобы запускаться из ОЗУ.

RAMFUNC void USART1_IRQHandler(void)
{
  uint32_t sr = USART1->SR;
  USART1->SR & USART_SR_ORE ? GPIO_SET(LED_ERROR_PORT, LED_ERROR_PIN_bp):GPIO_CLR(LED_ERROR_PORT, LED_ERROR_PIN_bp);
  if(sr & USART_SR_TXE)
  {

    if(uart_1_send_write_pos != uart_1_send_read_pos)
    {
      USART1->DR = uart_1_send_buffer[uart_1_send_read_pos];
      uart_1_send_read_pos = (uart_1_send_read_pos + 1) % USART_1_SEND_BUF_SIZE;
    }
    else
    {
      USART1->CR1 &= ~USART_CR1_TXEIE;
    }
  }

  if(sr & (USART_SR_RXNE | USART_SR_ORE)) 
  {
    USART1->SR &= ~(USART_SR_RXNE | USART_SR_ORE);
    uint8_t byte = USART1->DR;
    uart_1_recv_buffer[uart_1_recv_write_pos] = byte;
    uart_1_recv_write_pos = (uart_1_recv_write_pos + 1) % USART_1_RECV_BUF_SIZE;
  }
}

Моя цель работает правильно с таблицей векторов и функцией UART в ОЗУ, но я все еще получаюпревышение на USART.Я также не отключаю прерывания при выполнении операции флэш-записи.

Я также пытался запускать код из ОЗУ CCM вместо SRAM, но я видел на этот пост код не может бытьисполняется в оперативной памяти CCM на STMF32F4XX ...

Есть идеи?Спасибо.

1 Ответ

0 голосов
/ 27 февраля 2019

Любая попытка чтения с флэш-памяти во время операции записи приводит к остановке шины.

Чтобы не блокироваться флэш-записью, я думаю, что не только прерываниекод, но прерванная функция также должна запускаться из ОЗУ, иначе ядро ​​не сможет перейти в состояние, когда возможны прерывания.

Попробуйте переместить код обработки флэш-памяти в ОЗУ.

Если это возможноЯ бы посоветовал переключиться на MCU с двумя независимыми банками флэш-памяти, например, на серию 427/429/437/439, совместимую с выводами и программным обеспечением.Вы можете посвятить один банк программному коду, а другой - EEPROM-подобному хранилищу данных, тогда написание второго банка не помешает запуску кода из первого банка.

...