实验平台使用的是STM32F103RCT6核心板。
使用的是HAL库,keil开发环境。
实验效果:上电先运行 bootloader ,LED D4(pc2) 闪烁 10 次后进入 APP,仅供学习参考。
一、bootloader 部分
1、打开CUBEMX,选择F103RCT6,配置外部时钟,如图
2、配置串口如图
3、配置io口如图(PC2 为LED D4的io口)
4、时钟配置,如图
5、工程保存位置选择、生成代码
然后点击生成代码
6、在 main.c 中编写代码
如图
(还不会用printf的朋友可以看上一篇文章,很简单 直接复制过来即可)
typedef void (*jump_func)(void); //函数指针
jump_func myAppEntry;
uint32_t appxaddr = 0x8008000;
//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
void sys_msr_msp(uint32_t addr)
{
__set_MSP(addr); /* 设置栈顶地址 */
}
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("ST bootloader\n");
//应用程序地址
myAppEntry = (jump_func)*(volatile uint32_t *)(appxaddr + 4);
uint8_t i = 0;
while (1)
{
printf("ST bootloader\n");
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_SET);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_Delay(300);
if(i++ >= 10)
{
//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
sys_msr_msp(*(volatile uint32_t *)appxaddr);
myAppEntry();
}
}
}
这里说明一下,我们一共烧录两个程序,第一个程序是 bootloader ,烧录的地址和大小设置如图:
第二个程序是APP的程序,烧录的地址和大小设置如图:
这里其实可以看出来 appxaddr 为什么是0x8008000这个值了,0x8000000+0x8000表示APP的起始地址。
由于要烧录两个程序,所以烧录的时候不能全片擦除,设置如下:
点击
这样我们的 bootloader 就制作完成了。
二、APP 的制作
我们直接做一个 LED D4(PC2) 、LED D5(PC3) 一起闪烁的效果区分 bootloader 。
只配置两个io口和串口即可
外部时钟选择和时钟的配置和bootloader一样即可,这里就不再赘述了,直接生成代码。
生成代码后
1、为了确保中断功能的正常使用,需要修改中断向量表,如图
2、修改代码下载地址,避免将bootloader 的程序擦掉
3、同样选择部分擦除,避免烧录时全片擦除,将bootloader 擦掉了
到这里就可以下载测试了。
总结:
1、烧录两个程序 :一个bootloader 一个 APP
2、两个程序的烧录位置要区分开
3、烧录时不能全片擦除 避免擦掉 bootloader
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_56420043/article/details/141818027
|