解决STM32F0/F1内部FLASH写操作导致中断程序无法响应的问题

必看链接:试图搞懂MDK程序下载到flash(二)–分散加载文件scatter
参考链接:STM32F10x单片机Flash写操作导致中断不响应问题

最近本人在写STM32F0系列的FLASH写操作的代码时突然发现一个问题,MCU往内部FLASH写入数据的过程中,中断程序是无法响应的,若此时发生中断,MCU是不能跳转到相应的中断程序上去的。

官方手册《STM32F10xxx闪存编程手册.en》Page11描述如下:
在这里插入图片描述
MCU在执行内部flash写操作时,又必须响应中断,这要怎么办?
其实MCU执行的代码一般是放在FLASH地址上,MCU运行代码又必须向FLASH读取代码,但是向内部FLASH写数据的过程中,就不能继续读取FLASH中的程序,所以我们可以把中断程序(里面中断调用的所有)函数都放在RAM中,并把中断向量表(FLASH:0x08000000)映射到RAM(0x02000000),若在FLASH写数据期间发生中断,MCU会从RAM运行中断程序,从而保证中断程序正常执行。现在以STM32F0系列的例程讲解:

相关链接:STM32中断向量表的位置,重定向

一、映射中断向量表至RAM地址0x02000000

注:F0和F1系列MCU,映射中断向量表到RAM地址0x0200000方法不同,但是F1的方法好像不适用于F0

void IAP_Set()
{
    
    
  u32 i=0;
	/* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/  
  /* Copy the vector table from the Flash (mapped at the base of the application
     load address 0x08000000) to the base address of the SRAM at 0x20000000. */
  for(i = 0; i < 48; i++)//先将"应用程序"的中断向量表拷贝到sram中
  {
    
    
    *((uint32_t*)(0x20000000 + (i << 2)))=*(__IO uint32_t*)(0x08000000 + (i<<2));
  }
  /* Enable the SYSCFG peripheral clock*/ 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 
	/* Remap SRAM at 0x00000000 */
	/*然后再配置SYSCFG寄存器的最低两位,将sram映射到地址0,这样,在发生中断后,cpu从地址0取
	中断向量,这样实际上就是从SRAM中取的中断向量,而SRAM中的中断向量表又是之前从"应用程序"
	的中断向量表拷贝过来的,所以,最终其实是取的“应用程序”的中断向量表*/
  SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
}

二、将RAM的起始地址偏移0xC0个字节,KEIL工程设置如下:

在这里插入图片描述

三、将中断程序用到的所有相关代码、包括用到的库函数全部编译进RAM区域

参考链接:STM32 进阶教程 11 - RAM中运行程序
这里我采用上述链接方法四方案,按照如下步骤配置KEIL工程(里面的文件是我新建文件所写,也可以改原本工程的文件)
在这里插入图片描述

按照如下灵活编辑:

LR_IROM1 0x08000000 0x00010000  {
    
        ; load region size_region
  ER_IROM1 0x08000000 0x00010000  {
    
      ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x200000C0 0x00002000  {
    
      ; RW data
	*.o (RESET_ram, +First)
	*.o (RAMCODE)
	startup_stm32f030_inram.o(+RO)
	SMG.o(+RO +RW)
	stm32f0xx_it.o(+RO +RW)
	stm32f0xx_flash.o(+RO +RW)
	stmflash.o(+RO +RW)
	system_stm32f0xx.o(.data, +ZI +RW)	
   .ANY (+RW +ZI)
  }
}

注:因为由用到了FLASH,所以要把响应的固件库也要包含进去,以及存放中断函数的it.c文件和所有调用到的函数

四、新建并修改启动文件,并添加到工程内


                PRESERVE8
                THUMB


; Vector Table Mapped to Address 0 at Reset
                AREA    RESET_ram, DATA, READONLY
                EXPORT  __Vectors_ram
                EXPORT  __Vectors_End_ram
                EXPORT  __Vectors_Size_ram

__Vectors_ram   DCD     0                   ; Top of Stack
                DCD     0                  ; Reset Handler
                DCD     NMI_Handler                    ; NMI Handler
                DCD     HardFault_Handler              ; Hard Fault Handler
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     SVC_Handler                    ; SVCall Handler
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     PendSV_Handler                 ; PendSV Handler
                DCD     SysTick_Handler                ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler                ; Window Watchdog
                DCD     0                              ; Reserved
                DCD     RTC_IRQHandler                 ; RTC through EXTI Line
                DCD     FLASH_IRQHandler               ; FLASH
                DCD     RCC_IRQHandler                 ; RCC
                DCD     EXTI0_1_IRQHandler             ; EXTI Line 0 and 1
                DCD     EXTI2_3_IRQHandler             ; EXTI Line 2 and 3
                DCD     EXTI4_15_IRQHandler            ; EXTI Line 4 to 15
                DCD     0                              ; Reserved
                DCD     DMA1_Channel1_IRQHandler       ; DMA1 Channel 1
                DCD     DMA1_Channel2_3_IRQHandler     ; DMA1 Channel 2 and Channel 3
                DCD     DMA1_Channel4_5_IRQHandler     ; DMA1 Channel 4 and Channel 5
                DCD     ADC1_IRQHandler                ; ADC1 
                DCD     TIM1_BRK_UP_TRG_COM_IRQHandler ; TIM1 Break, Update, Trigger and Commutation
                DCD     TIM1_CC_IRQHandler             ; TIM1 Capture Compare
                DCD     0                              ; Reserved
                DCD     TIM3_IRQHandler                ; TIM3
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     TIM14_IRQHandler               ; TIM14
                DCD     TIM15_IRQHandler               ; TIM15
                DCD     TIM16_IRQHandler               ; TIM16
                DCD     TIM17_IRQHandler               ; TIM17
                DCD     I2C1_IRQHandler                ; I2C1
                DCD     I2C2_IRQHandler                ; I2C2
                DCD     SPI1_IRQHandler                ; SPI1
                DCD     SPI2_IRQHandler                ; SPI2
                DCD     USART1_IRQHandler              ; USART1
                DCD     USART2_IRQHandler              ; USART2
                
__Vectors_End_ram

__Vectors_Size_ram  EQU  __Vectors_End_ram - __Vectors_ram

                AREA    |.text|, CODE, READONLY

                IMPORT  NMI_Handler                    ;NMI Handler
                IMPORT  HardFault_Handler              ;Hard Fault Handler
                IMPORT  SVC_Handler                    ;SVCall Handler
                IMPORT  PendSV_Handler                 ;PendSV Handler
                IMPORT  SysTick_Handler                ;SysTick Handler
					                                   
                IMPORT  WWDG_IRQHandler                [WEAK]
                IMPORT  RTC_IRQHandler                 [WEAK]
                IMPORT  FLASH_IRQHandler               [WEAK]
                IMPORT  RCC_IRQHandler                 [WEAK]
                IMPORT  EXTI0_1_IRQHandler             [WEAK]
                IMPORT  EXTI2_3_IRQHandler             [WEAK]
                IMPORT  EXTI4_15_IRQHandler            [WEAK]
                IMPORT  DMA1_Channel1_IRQHandler       [WEAK]
                IMPORT  DMA1_Channel2_3_IRQHandler     [WEAK]
                IMPORT  DMA1_Channel4_5_IRQHandler     [WEAK]
                IMPORT  ADC1_IRQHandler                [WEAK]
                IMPORT  TIM1_BRK_UP_TRG_COM_IRQHandler [WEAK]
                IMPORT  TIM1_CC_IRQHandler             [WEAK]
                IMPORT  TIM3_IRQHandler                [WEAK]
                IMPORT  TIM14_IRQHandler               [WEAK]
                IMPORT  TIM15_IRQHandler               [WEAK]
                IMPORT  TIM16_IRQHandler               [WEAK]
                IMPORT  TIM17_IRQHandler               [WEAK]
                IMPORT  I2C1_IRQHandler                [WEAK]
                IMPORT  I2C2_IRQHandler                [WEAK]
                IMPORT  SPI1_IRQHandler                [WEAK]
                IMPORT  SPI2_IRQHandler                [WEAK]
                IMPORT  USART1_IRQHandler              [WEAK]
                IMPORT  USART2_IRQHandler              [WEAK]
                
	END         

编译成功后,查看“工程名.map文件”(文件夹内搜索就行),可以看到相关的函数都已经编译到RAM地址中了
在这里插入图片描述

一下scatter文件是我个人写的,放出来提供给大家参考参考:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

; ";"为注释
LR_IROM1 0x08002000 0x00010000  {
    
        ; 代码加载区,表示从此处开始执行
  ER_IROM1 0x08002000 0x00010000  {
    
      ; 代码执行区要与代码加载区地址一致
   *.o (RESET, +First)               ; 将中断向量表放在开头
   *(InRoot$$Sections)               ; 根据各种地址生成启动代码,实现对映像(程序)的加载
   .ANY (+RO)                        ; 只读变量、代码本身放在ROM区域
  }
  RW_IRAM1 0x200000C0 0x00000600  {
    
      ; 可读可写区域,空间大小为0x00000600
	.ANY (+RW)                       ; 可读可写变量存放在0x200000C0开头处,0x20000000-0x200000C0存放的是拷贝至RAM里面的中断向量表
  }
  RAM_CODE 0x20000600 0x00002000 {
    
       ; 需要运行在RAM的程序、初始化为0(.ZI)变量的区域
	SMG.o                            ; SMG.c文件编译成SMG.o文件,里面的函数防止在该段区域
	timer.o                          ; 同上
	stm32f0xx_it.o
	stm32f0xx_flash.o
	stmflash.o
	system_stm32f0xx.o(.data, +ZI)	
   .ANY (+ZI)
  }
}
; 上面分区域只是为了更好的观察.map文件

以下为生成的.map文件的局部截图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42518229/article/details/108131700