STM32F0xx IAP实现之中断向量表重定义

本文介绍如何在STM32F0xx系列单片机上实现中断向量表的重定义。由于STM32F0xx没有提供直接用于此目的的寄存器,因此通过在RAM中放置中断向量表并利用特定寄存器配置来实现。文中提供了具体的实现步骤及代码示例。
在STM32F103等cortex-m3/m4内核的单片机上可以通过设置SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;该寄存器的值来实现中断向量表的重定义。但在STM32F0xx系列以cortex-m0为内核的单片机中却怎么也找不到这个设置中断向量表的寄存器,可以通过以下方法来实现中断向量表重定义。

基本思想:
1、将中断向量表放入到RAM的起始地址(只需要在应用程序中保留RAM其实地址的0x100大小不使用即可)。
2、在bootload中将应用程序的中断向量表从Flash中拷贝到RAM中。
3、设置STM32F0xx中断向量表位于RAM中,主要用到的寄存器如下:




具体实现代码如下:
/*
*  Function: void JumpToApp(void)
* Parameter: none
*    Return: none
*/
static void JumpToApp(void)
{
  ApplicationAddress = APP_FLASHADDR;
  if (((*(uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
  {
    /* Jump to user application */
    m_JumpAddress = *(uint32_t*) (ApplicationAddress + 4);  /*最开头4个字节存放MSP的初始值,从这之后的4个字节存放                                                                                       ResetHandler中断向量*/
    JumpToApplication = (FunVoidType) m_JumpAddress;

    /* Initialize user application's Stack Pointer */
    __set_MSP(*(uint32_t*) ApplicationAddress);
    JumpToApplication();
  }
}
/*
*  Function: void clock_init(void)
* Parameter: none
*    Return: none
*/
int main(void)
{
  memcpy((void*)0x20000000, (void*)APP_FLASHADDR, 0x100);
  SYSCFG->CFGR1 |= 0x03;
 
  JumpToApp();
  while (1);
}
#include "stm32f0xx_hal.h" #include "fatfs.h" #include "IAP.h" #include "main.h" #include "stm32f0xx_hal.h" #include "fatfs.h" #include "main.h" // 硬件配置 #define BOOT_START_ADDR 0x08000000 // BootLoader起始地址 #define APP_START_ADDR 0x08003000 // APP起始地址(预留前12KB给BootLoader) #define FIRMWARE_SIZE 0x0000C000 // 最大固件大小12KB #define SCB_VTOR (*(volatile uint32_t*)0xE000ED08) // 中断向量表寄存器地址 // SD卡文件系统相关 FATFS fs; FIL fil; UINT bytesRead; uint8_t buffer[512]; // SD卡读取缓冲区 // 中断向量表重定位 void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset) { SCB_VTOR = NVIC_VectTab | (Offset & 0x1FFFFF80); } // 跳转到APP函数 void JumpToApp(void) { typedef void (*pFunction)(void); pFunction JumpToApplication; // 检查APP栈顶地址合法性 if((*(volatile uint32_t*)APP_START_ADDR) < 0x20000000) { Error_Handler(); // 地址非法 } // 设置中断向量表 NVIC_SetVectorTable(APP_START_ADDR, 0x0); // 获取复位向量地址 JumpToApplication = (pFunction)(*(volatile uint32_t*)(APP_START_ADDR + 4)); // 初始化主堆栈指针 __set_MSP(*(volatile uint32_t*)APP_START_ADDR); // 禁用所有中断 __disable_irq(); // 跳转执行 JumpToApplication(); } // 固件更新主函数 void iap_update(void) { uint32_t pageError = 0; FRESULT res; // 挂载SD卡文件系统 res = f_mount(&fs, "", 1); if(res != FR_OK) { Error_Handler(); // SD卡挂载失败 } // 打开固件文件 res = f_open(&fil, "wx.bin", FA_READ); if(res == FR_OK) { // 解锁FLASH HAL_FLASH_Unlock(); // 配置擦除参数 FLASH_EraseInitTypeDef eraseInit = {0}; eraseInit.TypeErase = FLASH_TYPEERASE_PAGES; eraseInit.PageAddress = APP_START_ADDR; eraseInit.NbPages = (FIRMWARE_SIZE + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE; // 擦除APP区域 if(HAL_FLASHEx_Erase(&eraseInit, &pageError) != HAL_OK) { Error_Handler(); // 擦除失败 } // 读取并写入固件 uint32_t writeAddr = APP_START_ADDR; f_read(&fil, buffer, sizeof(buffer), &bytesRead); while(bytesRead > 0) { // 处理完整16位数据 uint32_t alignedSize = (bytesRead / 2) * 2; for(uint32_t i = 0; i < alignedSize; i += 2) { uint16_t data = (uint16_t)(buffer[i] | (buffer[i+1] << 8)); if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, writeAddr, data) != HAL_OK) { Error_Handler(); // 写入失败 } writeAddr += 2; } // 处理奇数长度最后一个字节 if(bytesRead % 2 != 0) { uint16_t lastByte = (uint16_t)buffer[bytesRead - 1]; if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, writeAddr, lastByte) != HAL_OK) { Error_Handler(); // 写入失败 } writeAddr += 2; } // 读取下一块数据 f_read(&fil, buffer, sizeof(buffer), &bytesRead); } // 关闭文件和卸载文件系统 f_close(&fil); // f_unmount(""); // 锁定FLASH HAL_FLASH_Lock(); // 跳转到APP JumpToApp(); } else { // 未找到固件文件,直接跳转APP // f_unmount(""); JumpToApp(); } } // 错误处理函数 //void Error_Handler(void) { // while(1) { // HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_10); // HAL_Delay(500); // } //} 怎么判断SD卡升级的状态
最新发布
11-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值