一、硬件基础要求
N32H47X系列MCU内置原厂自举BOOT程序,仅支持USART3串口、USB-FS全速USB两种下载通信接口,对应硬件引脚定义如下:
USART3通信引脚:PA9(TX)、PA10(RX)
USB-FS通信引脚:PA11(D-)、PA12(D+)
实际使用前需确认硬件电路引脚接线正常,保证通信链路连通。
二、整体操作流程说明
2.1工程文件路径说明
官方配套工程存放路径:
Nsing.N32H47x_48x_Library.1.2.0/projects/n32h47x_48x_EVAL/applications/JumpToBOOT
KEIL编译工程目录:MDK-ARM
业务逻辑源文件:src/xxx.c
宏定义、函数声明头文件:inc/xxx.h
2.2全局参数宏与变量定义
2.2.1函数指针类型声明
跳转BOOT依赖无参无返回值函数指针,需提前定义类型:
2.2.2芯片内存与BOOT基础参数
// 定义跳转函数指针类型 typedef void(*pFunction)(void);
2.2.2芯片内存与BOOT基础参数
// MCU内部SRAM基础配置
#define SRAM_BASE_ADDR (0x20000000U) // SRAM起始基地址
#define SRAM_SIZE (0x24000U) // SRAM总容量
#define SRAM_VECTOR_WORD_SIZE (128U) // SRAM中断向量表字数
// 在SRAM末尾预留0x200字节作为BOOT跳转专用向量区
#define SRAM_VECTOR_ADDR (SRAM_BASE_ADDR + SRAM_SIZE - 0x200U)
// BOOT程序固定地址参数(V1.0版本默认值,禁止随意修改)
uint32_t BootAddr = 0x1FFF01a1U; // BOOT程序入口地址
uint32_t SPAddr = 0x200024a8U; // BOOT默认栈指针地址
uint32_t _mainAddr = 0x1FFF0189U; // BOOT主函数地址
#define SRAM_BASE_ADDR (0x20000000U) // SRAM起始基地址
#define SRAM_SIZE (0x24000U) // SRAM总容量
#define SRAM_VECTOR_WORD_SIZE (128U) // SRAM中断向量表字数
// 在SRAM末尾预留0x200字节作为BOOT跳转专用向量区
#define SRAM_VECTOR_ADDR (SRAM_BASE_ADDR + SRAM_SIZE - 0x200U)
// BOOT程序固定地址参数(V1.0版本默认值,禁止随意修改)
uint32_t BootAddr = 0x1FFF01a1U; // BOOT程序入口地址
uint32_t SPAddr = 0x200024a8U; // BOOT默认栈指针地址
uint32_t _mainAddr = 0x1FFF0189U; // BOOT主函数地址
关键参数注意事项
SRAM_BASE_ADDR、SRAM_SIZE需根据实际使用芯片的片内SRAM容量修改;必须在SRAM尾部预留0x200字节,用于存放跳转临时中断向量表;
BootAddr、_mainAddr等BOOT固定地址参数禁止修改;
文档默认参数适配绝大多数应用场景,无特殊需求无需调整。
2.3功能函数实现与调用说明
2.3.1系统时钟切换函数(切换至HSI内部高速时钟)
跳转BOOT前必须将系统时钟切换为片内HSI时钟,建议直接调用官方封装函数,不建议自行重写时钟逻辑:
/**
* @brief 将系统时钟切换至HSI内部高速时钟
* @retval SUCCESS:时钟配置成功;ERROR:时钟启动超时失败
*/
ErrorStatus SetSysClockToHSI(void)
{
uint32_t timeout_value = 0xFFFFFFFFU;
ErrorStatus ClockStatus;
// 复位RCC外设
RCC_DeInit();
// 使能内部高速时钟HSI
RCC_EnableHsi(ENABLE);
// 等待HSI时钟稳定
ClockStatus = RCC_WaitHsiStable();
if (ClockStatus == SUCCESS)
{
// 开启Flash预取缓冲
FLASH_PrefetchBufSet(FLASH_PrefetchBuf_EN);
// Flash访问等待周期设为0
FLASH_SetLatency(FLASH_LATENCY_0);
// 配置AHB、APB分频,HCLK/PCLK1/PCLK2均等于系统时钟
RCC_ConfigHclk(RCC_SYSCLK_DIV1);
RCC_ConfigPclk2(RCC_HCLK_DIV1);
RCC_ConfigPclk1(RCC_HCLK_DIV1);
// 恢复PLL分频默认配置
RCC->PLLCTRL |= 0x00040000U;
// 选择HSI作为系统时钟源
RCC_ConfigSysclk(RCC_SYSCLK_SRC_HSI);
// 循环等待时钟源切换完成,超时直接返回错误
while (RCC_GetSysclkSrc() != RCC_CFG_SCLKSTS_HSI)
{
if ((timeout_value--) == 0U)
{
return ERROR;
}
}
} else
{
// HSI时钟启动失败
return ERROR;
}
return SUCCESS;
}
* @brief 将系统时钟切换至HSI内部高速时钟
* @retval SUCCESS:时钟配置成功;ERROR:时钟启动超时失败
*/
ErrorStatus SetSysClockToHSI(void)
{
uint32_t timeout_value = 0xFFFFFFFFU;
ErrorStatus ClockStatus;
// 复位RCC外设
RCC_DeInit();
// 使能内部高速时钟HSI
RCC_EnableHsi(ENABLE);
// 等待HSI时钟稳定
ClockStatus = RCC_WaitHsiStable();
if (ClockStatus == SUCCESS)
{
// 开启Flash预取缓冲
FLASH_PrefetchBufSet(FLASH_PrefetchBuf_EN);
// Flash访问等待周期设为0
FLASH_SetLatency(FLASH_LATENCY_0);
// 配置AHB、APB分频,HCLK/PCLK1/PCLK2均等于系统时钟
RCC_ConfigHclk(RCC_SYSCLK_DIV1);
RCC_ConfigPclk2(RCC_HCLK_DIV1);
RCC_ConfigPclk1(RCC_HCLK_DIV1);
// 恢复PLL分频默认配置
RCC->PLLCTRL |= 0x00040000U;
// 选择HSI作为系统时钟源
RCC_ConfigSysclk(RCC_SYSCLK_SRC_HSI);
// 循环等待时钟源切换完成,超时直接返回错误
while (RCC_GetSysclkSrc() != RCC_CFG_SCLKSTS_HSI)
{
if ((timeout_value--) == 0U)
{
return ERROR;
}
}
} else
{
// HSI时钟启动失败
return ERROR;
}
return SUCCESS;
}
2.3.2 BOOT跳转核心API函数Jump_To_BOOT
调用该函数即可直接跳转至芯片内置BOOT自举程序,完整实现如下:
/**
* @brief 应用程序跳转至内置BOOT引导程序
* @note 跳转前自动初始化临时向量表、关闭缓存、切换HSI时钟、关闭全局中断
*/
void Jump_To_BOOT(void)
{
uint8_t value1[8] = {0x00U};
uint8_t value2 = 8U;
uint32_t i;
uint32_t *pVec;
// 1. 初始化SRAM临时中断向量表,全部清零
pVec = (uint32_t *)SRAM_VECTOR_ADDR;
for (i = 0; i < SRAM_VECTOR_WORD_SIZE; i++)
{
pVec[i] = 0U; }
// 2. 关闭并复位Flash指令缓存
FLASH_iCacheCmd(DISABLE);
FLASH_iCacheRST();
// 3. 读取片内存储区BOOT版本号
Get_NVR(0x1FFF37A8U, value1, value2);
if ((value1[0] & 0xFFU) == 0x11U)
{
// BOOT V1.1版本适配
SPAddr = 0x200024C0U;
pVec[SysTick_IRQn + 16U] = 0x1FFF2F15U;
pVec[USART3_IRQn + 16U] = 0x1FFF2F95U;
pVec[USB_FS_LP_IRQn + 16U] = 0x1FFF3095U;
}
else
{
// BOOT V1.0版本默认适配
pVec[SysTick_IRQn + 16U] = 0x1FFF2d31U;
pVec[USART3_IRQn + 16U] = 0x1FFF2db1U;
pVec[USB_FS_LP_IRQn + 16U] = 0x1FFF2eb1U;
}
// 4. 关闭全局中断,避免跳转过程中断干扰
__disable_irq();
// 5. 独立看门狗配置重载与关闭写保护
IWDG_ReloadKey();
IWDG_WriteConfig(IWDG_WRITE_DISABLE);
IWDG_SetPrescalerDiv(IWDG_PRESCALER_DIV256);
// 6. 切换系统时钟至HSI
SetSysClockToHSI();
// 7. 绑定BOOT入口函数指针
pFunction JumpBoot = (pFunction)BootAddr;
// 初始化BOOT程序栈指针
__set_MSP(SPAddr);
// 8. 重新开启全局中断
__enable_irq();
// 设置内核向量表偏移至SRAM临时向量区
SCB->VTOR = SRAM_VECTOR_ADDR;
// 9. 执行跳转,进入BOOT引导程序
JumpBoot();
}
* @brief 应用程序跳转至内置BOOT引导程序
* @note 跳转前自动初始化临时向量表、关闭缓存、切换HSI时钟、关闭全局中断
*/
void Jump_To_BOOT(void)
{
uint8_t value1[8] = {0x00U};
uint8_t value2 = 8U;
uint32_t i;
uint32_t *pVec;
// 1. 初始化SRAM临时中断向量表,全部清零
pVec = (uint32_t *)SRAM_VECTOR_ADDR;
for (i = 0; i < SRAM_VECTOR_WORD_SIZE; i++)
{
pVec[i] = 0U; }
// 2. 关闭并复位Flash指令缓存
FLASH_iCacheCmd(DISABLE);
FLASH_iCacheRST();
// 3. 读取片内存储区BOOT版本号
Get_NVR(0x1FFF37A8U, value1, value2);
if ((value1[0] & 0xFFU) == 0x11U)
{
// BOOT V1.1版本适配
SPAddr = 0x200024C0U;
pVec[SysTick_IRQn + 16U] = 0x1FFF2F15U;
pVec[USART3_IRQn + 16U] = 0x1FFF2F95U;
pVec[USB_FS_LP_IRQn + 16U] = 0x1FFF3095U;
}
else
{
// BOOT V1.0版本默认适配
pVec[SysTick_IRQn + 16U] = 0x1FFF2d31U;
pVec[USART3_IRQn + 16U] = 0x1FFF2db1U;
pVec[USB_FS_LP_IRQn + 16U] = 0x1FFF2eb1U;
}
// 4. 关闭全局中断,避免跳转过程中断干扰
__disable_irq();
// 5. 独立看门狗配置重载与关闭写保护
IWDG_ReloadKey();
IWDG_WriteConfig(IWDG_WRITE_DISABLE);
IWDG_SetPrescalerDiv(IWDG_PRESCALER_DIV256);
// 6. 切换系统时钟至HSI
SetSysClockToHSI();
// 7. 绑定BOOT入口函数指针
pFunction JumpBoot = (pFunction)BootAddr;
// 初始化BOOT程序栈指针
__set_MSP(SPAddr);
// 8. 重新开启全局中断
__enable_irq();
// 设置内核向量表偏移至SRAM临时向量区
SCB->VTOR = SRAM_VECTOR_ADDR;
// 9. 执行跳转,进入BOOT引导程序
JumpBoot();
}
三、N32H47X系列使用要点总结
硬件层面:仅支持USART3、USB-FS两种BOOT下载接口,接线需完整;
内存配置:SRAM尾部必须预留0x200字节空间用于临时中断向量表;
时钟要求:跳转前强制切换HSI,不可使用外部HSE/PLL时钟;
版本兼容:函数内部自动读取BOOT版本,区分V1.0/V1.1配置栈地址与中断向量;
调用方式:业务代码中直接调用Jump_To_BOOT()即可完成跳转,无需额外操作。
