[英]Writing to non-volatile memory without disrupting UART interrupts execution on STM32F4XX
我在 UART 外圍設備上有幾個 OVERRUN 錯誤,因為我在代碼停止時一直接收 UART 數據,因為我正在 flash 上執行寫操作。
我正在為 UART 使用中斷,並在應用筆記AN3969中有說明:
EEPROM 仿真固件從內部 Flash 運行,因此在需要 Flash 擦除或編程(EEPROM 初始化、變量更新或頁面擦除)的操作期間,對 Flash 的訪問將停止。 結果,應用程序代碼不被執行,中斷不能被服務。
對於許多應用程序來說,這種行為可能是可以接受的,但是對於具有實時限制的應用程序,您需要從內部 RAM 運行關鍵進程。
在這種情況下:
- 重新定位內部 RAM 中的向量表。
- 從內部 RAM 執行所有關鍵進程和中斷服務程序。 編譯器提供了一個關鍵字來將函數聲明為 RAM function; function 在系統啟動時從 Flash 復制到 RAM,就像任何初始化變量一樣。 重要的是要注意,對於 RAM function,所有使用的變量和調用的函數都應該在 RAM 中。
所以我在互聯網上搜索並找到了 AN4808 ,它提供了有關如何在 flash 操作時保持中斷運行的示例。
我繼續修改我的代碼:
Linker 腳本:將向量表添加到 SRAM 並定義 a.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 並定義 a.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 定義
/*!< 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")))
在 UART 相關的 function 和原型之前添加了 RAMFUNC,因此它可以從 RAM 運行。
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;
}
}
我的目標在 RAM 中使用矢量表和 UART function 正常運行,但我仍然在 USART 上出現溢出。 在執行 flash 寫操作時,我也沒有禁用中斷。
我還嘗試從 CCM RAM 而不是 SRAM 運行代碼,但是我在這篇文章中看到代碼不能在 STMF32F4XX 上的 CCM RAM 上執行...
任何想法? 謝謝。
正在進行寫操作時, 任何嘗試從閃存讀取的操作都會導致總線停頓。
為了不被閃存寫入所阻止,我認為不僅中斷代碼,而且中斷功能也必須從RAM運行,否則內核將無法進入可能發生中斷的狀態。
嘗試將閃存處理代碼重新定位到RAM。
如果可能的話,我建議您切換到具有兩個獨立的閃存組的MCU,例如與引腳和軟件兼容的427/429/437/439系列。 您可以將一個存儲區專用於編程代碼,將另一個存儲區專用於類似EEPROM的數據存儲,然后寫入第二個存儲區將不會干擾從第一個存儲區運行的代碼。
正如建議的那樣,可能需要從 RAM 執行代碼,或者更確切地說,確保在寫入過程中不執行任何 flash 讀取操作。
要進行測試,您可能需要為 ram 而不是 flash 編譯整個可執行文件。 IE 將所有內容放入 ram 中,根本不使用 flash。
然后,您可以使用 gdb 加載二進制文件並開始執行...測試您的 uart 並確保它按預期工作。 至少通過這種方式,您可以確定 flash 未被使用。
一些微控制器具有 READ WILE WRITE 部分,它們同時執行多個操作沒有問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.