嵌入式MCU BootLoader开发配置详细笔记教程

您所在的位置:网站首页 三星bootloader不支持cmdline 嵌入式MCU BootLoader开发配置详细笔记教程

嵌入式MCU BootLoader开发配置详细笔记教程

2024-07-07 05:44:04| 来源: 网络整理| 查看: 265

目录

一、BootLoader基础

二、BootLoader原理及配置

三、BootLoader程序

bootloader.h

bootloader.c

四、Application1 用户程序

application1.h

application1.c

五、Application2 用户程序

application2.h

六、程序运行效果

七、工程文件Demo

一、BootLoader基础

        对于接触过嵌入式Linux系统开发的开发者们,想必对BootLoader是不陌生的,因为定制化移植Linux系统,最先接触的就是BootLoader程序。但如果是从单片机MCU起步的开发者,可能对BootLoader就不是那么熟悉了,因为单片机开发最先接触的往往是GPIO外设的驱动开发。但不管是嵌入式Linux的MPU开发,还是嵌入式单片机的MCU开发,BootLoader的功能都是一样的。它是嵌入式系统中一种特殊的软件程序,它在系统加电或复位后最先执行,负责初始化硬件设备、设置系统环境,并最终引导加载操作系统内核或用户指定的应用程序。BootLoader 起到了桥梁的作用,连接了硬件启动与高级软件运行之间的环节,确保系统能够从一个初始、裸机的状态过渡到一个完整的、可操作的运行环境。

        当然,除了嵌入式开发者们,对于喜欢DIY装机的极客们,对于BootLoader应该也是不陌生的,并且经常接触到它,如电脑在安装或开启Windows时的BIOS界面,本质上也是一个BootLoader引导程序。如下图为常见的BootLoader显示的GUI界面图。

如下例举的是一些BootLoader 的主要功能和作用:

①、硬件初始化:

开启和配置基本的硬件模块,如CPU、时钟、内存控制器、中断控制器、串口、GPIO等,使它们进入工作状态。设置堆栈、中断向量表等关键数据结构,为后续软件执行做好准备。

②、内存管理:

建立内存空间映射图,识别可用的RAM区域及其大小,为操作系统内核分配合适的运行空间。对于使用MMU(Memory Management Unit)的系统,可能还需要设置内存分页和映射规则。

③、引导加载操作系统:

从非易失性存储器(如Flash、EEPROM、NAND/NOR Flash等)中读取并验证操作系统的内核映像。将内核映像加载到RAM中指定的位置,并按照内核所需的特定格式设置启动参数和环境变量。

④、固件升级:

提供一种安全机制,允许在运行时通过网络、串口、USB等接口接收新的固件映像,并将其写入非易失性存储器,实现设备的远程或本地固件更新。

⑤、系统诊断与恢复:

可能包含简单的故障检测和恢复机制,如硬件自检、低级别固件修复、安全模式启动等功能,帮助在系统启动失败时进行故障排查和恢复。

⑥、多重引导支持:

在某些系统中,BootLoader 可能支持选择加载不同的操作系统版本或应用程序,提供多启动选项,增强系统的灵活性和可定制性。

        目前BootLoader 的应用广泛存在于各种嵌入式系统中,如消费电子领域中,随处可见的智能手机,智能电脑,智能手表、路由器等。在汽车电子领域的车载系统ADAS(Advanced Driver Assistance Systems)模块、ECU(Electronic Control Units)等,及医疗设备领域的便携式医疗仪器、监护设备、植入式医疗器械等。基本上有电子产品的地方,都能看到BootLoader的身影,因此掌握BootLoader是从事嵌入式开发的一项非常基本的技能。

二、BootLoader原理及配置

        本文主要是针对单片机MCU设备进行BootLoader的配置讲解,目标设备为STM32G431,开发平台是MDK KEIL V5以上。

        如下图所示是FLASH中的数据分布图,可见FLASH的用户代码区域的起始程序为BootLoader引导程序,然后紧接着的是应用程序APP1和应用程序APP2。

        其中,BootLoader和APP1及APP2都是完整的用户代码程序,但因BootLoader只起一个引导跳转APP启动操作,所以占用的FLASH内存空间较小。

        提醒:App的个数可以根据实际需求进行设置,只要不超过FLASH的内存空间大小限制即可,为了效果展示,在本文中设置了一个BootLoader程序,两个APP应用程序进行切换。

        如下图所示的是,Bootloader、App1、App2在FLASH中的内存地址映射图。在BootLoader的程序配置好后,根据触发条件的不同,会自动跳转到不同的APP应用程序。

        BootLoader和APP应用程序的启动跳转切换,原理上就是内存地址的切换,当BootLoader程序接收到对应的操作触发条件时,会进行相应的地址跳转切换,及一些其它的附加操作,然后执行该地址空间上的用户程序。但一般来说,BootLoader中会进行CPU工作模式、配置内存控制器、初始化外设等工作,为后续程序运行创建一个稳定的硬件环境。所以在APP中可以节省掉BootLoader中已经进行过的硬件环境配置。

        如下图所示为《STM32G4系列微控制器参考手册》官方文件中截图下来的,STM32的FLASH中是按页(扇区)进行读写操作的,每页大小为2KB,所以内存空间配置时,必须以页为最小单元分配。

如何配置BootLoader及APP应用程序的下载烧录?

①、单击魔术棒

②、选择Target

③、修改IROM1中的Start地址数据及Size数据

        修改Size空间的大小时,需要先确定程序编译后的内存大小是多少,如果内存空间配置不够,会导致编译及下载报错。如下图所示为查看程序编译后需要的内存空间大小的方式。     

三、BootLoader程序 bootloader.h #ifndef __BOOTLOADER_H #define __BOOTLOADER_H #include "main.h" #define FLASH_BASE_ADDR (uint32_t)(0x08000000) //BootLoader 预留10KB的FLASH空间 --- (0x0800 0000 --> 0x0800 27FF) //Application1 预留20KB的FLASH空间 --- (0x0800 2800 --> 0x0800 77FF) //Application2 预留20KB的FLASH空间 --- (0x0800 7800 --> 0x0800 C7FF) #define BOOT_BASE_ADDR FLASH_BASE_ADDR #define APP1_BASE_ADDR (uint32_t)(0x08002800) #define APP2_BASE_ADDR (uint32_t)(0x08007800) #define KEY_DOWN GPIO_PIN_RESET #define KEY_UP GPIO_PIN_SET #define LED1 LED1_LCD8_Pin #define LED2 LED2_LCD9_Pin #define LED3 LED3_LCD10_Pin #define LED4 LED4_LCD11_Pin #define LED5 LED5_LCD12_Pin #define LED6 LED6_LCD13_Pin #define LED7 LED7_LCD14_Pin #define LED8 LED8_LCD15_Pin #define LED_ON GPIO_PIN_RESET #define LED_OFF GPIO_PIN_SET extern volatile uint8_t key1_flag; extern volatile uint8_t key2_flag; void BootLoader_Code(void); void Key_San(void); void LED_Control(int led, int state); void LED_Close_All(void); #endif bootloader.c #include "bootloader.h" typedef void (*pFunction)(void); pFunction Boot_Jump_to_App; uint32_t jump_addr; #if 0 //初始化用户栈指针汇编程序 __ASM void __set_MSP(uint32_t mainStackPointer) { msr msp, r0 bx lr } #endif /** * @brief BootLoader程序 * @param None * @retval None */ void BootLoader_Code(void) { LED_Close_All(); printf("------------Hello BootLoader V 1.0---------\r\n"); printf("------------Editor:牛马大师兄--------------\r\n\r\n"); printf("------------Press KEY1 Boot APP1-----------\r\n"); printf("------------Press KEY2 Boot APP2-----------\r\n"); //扫描按键状态,根据按键跳转到相应的APP程序 while(1) { Key_San(); if(key1_flag==1||key2_flag==1) { break; } } if(key1_flag == 1) { //检查用户代码1的栈顶地址,是否位于0x20000000~0x2001ffff内。 if (((*(volatile uint32_t*)APP1_BASE_ADDR) & 0x2FFE0000 ) == 0x20000000) { printf("\r\n-------------- APP1 Starting --------------\r\n"); //屏蔽所有中断,防止跳转过程中,中断干扰 __disable_irq(); //用户代码的第二个字,为程序开始地址(复位地址) jump_addr = *(volatile uint32_t*)(APP1_BASE_ADDR+4); Boot_Jump_to_App = (pFunction)jump_addr; //初始化用户栈指针 __set_MSP(*(volatile uint32_t*) APP1_BASE_ADDR); //用户程序跳转 Boot_Jump_to_App(); } }else if(key2_flag == 1) { //检查用户代码2的栈顶地址,是否位于0x20000000~0x2001ffff内。 if (((*(volatile uint32_t*)APP2_BASE_ADDR) & 0x2FFE0000 ) == 0x20000000) { printf("\r\n-------------- APP2 Starting --------------\r\n"); //屏蔽所有中断,防止跳转过程中,中断干扰 __disable_irq(); //用户代码的第二个字,为程序开始地址(复位地址) jump_addr = *(volatile uint32_t*)(APP2_BASE_ADDR+4); Boot_Jump_to_App = (pFunction)jump_addr; //初始化用户栈指针 __set_MSP(*(volatile uint32_t*) APP2_BASE_ADDR); //用户程序跳转 Boot_Jump_to_App(); } } } volatile uint8_t key1_flag = 0; volatile uint8_t key2_flag = 0; /** * @brief 按键扫描程序 * @param None * @retval None */ void Key_San(void) { if(HAL_GPIO_ReadPin(GPIOB, KEY1_Pin) == KEY_DOWN) { HAL_Delay(10); if(HAL_GPIO_ReadPin(GPIOC, KEY1_Pin) == KEY_DOWN) { key1_flag = 1; printf("\r\n--------------- KEY 1 PRESS ---------------\r\n"); LED_Control(LED1, LED_ON); } } if(HAL_GPIO_ReadPin(GPIOB, KEY2_Pin) == KEY_DOWN) { HAL_Delay(10); if(HAL_GPIO_ReadPin(GPIOC, KEY1_Pin) == KEY_DOWN) { key2_flag = 1; printf("\r\n--------------- KEY 2 PRESS ---------------\r\n"); LED_Control(LED2, LED_ON); } } } /** * @brief LED控制程序 * @param led:操作的LED灯 * @param state:LED的状态 * @retval None */ void LED_Control(int led, int state) { HAL_GPIO_WritePin(GPIOC, led, state); HAL_GPIO_WritePin(LED_LOCK_GPIO_Port, LED_LOCK_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(LED_LOCK_GPIO_Port, LED_LOCK_Pin, GPIO_PIN_RESET); } /** * @brief 关闭全部的LED指示灯 * @param None * @retval None */ void LED_Close_All(void) { HAL_GPIO_WritePin(GPIOC, LED6_LCD13_Pin|LED7_LCD14_Pin|LED8_LCD15_Pin|LED1_LCD8_Pin |LED2_LCD9_Pin|LED3_LCD10_Pin|LED4_LCD11_Pin|LED5_LCD12_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(LED_LOCK_GPIO_Port, LED_LOCK_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(LED_LOCK_GPIO_Port, LED_LOCK_Pin, GPIO_PIN_RESET); }

        主函数中对BootLoader程序进行调用

        修改BootLoader程序烧录地址及内存空间大小

四、Application1 用户程序 application1.h #ifndef __APPLICATION_H #define __APPLICATION_H #include "main.h" #define APP1_VECT_ADDR_OFFSET 0x2800 void App1_Code(void); #endif application1.c #include "application1.h" /** * @brief App1应用程序 * @param None * @retval None */ void App1_Code(void) { //设置中断向量偏移表 SCB->VTOR = FLASH_BASE | APP1_VECT_ADDR_OFFSET; //使能全局中断--不使能会出现异常 __enable_irq(); //APP1中的业务代码程序 printf("--------- Welcome to Application 1 --------\r\n"); LCD_Init(); LCD_SetBackColor(Black); LCD_SetTextColor(White); LCD_Clear(Black); HAL_Delay(200); LCD_DisplayStringLine(Line4, (unsigned char *)" Application 1 "); }

         主函数中对App1程序进行调用

        修改App1程序烧录地址及内存空间大小

五、Application2 用户程序 application2.h #ifndef __APPLICATION_H #define __APPLICATION_H #include "main.h" #define APP2_VECT_ADDR_OFFSET 0x7800 void App2_Code(void); #endif

application2.c

#include "application2.h" /** * @brief App2应用程序 * @param None * @retval None */ void App2_Code(void) { //设置中断向量偏移表 SCB->VTOR = FLASH_BASE | APP2_VECT_ADDR_OFFSET; //使能全局中断--不使能会出现异常 __enable_irq(); //APP2中的业务代码程序 printf("--------- Welcome to Application 2 --------\r\n"); LCD_Init(); LCD_SetBackColor(Black); LCD_SetTextColor(White); LCD_Clear(Black); HAL_Delay(200); LCD_DisplayStringLine(Line4, (unsigned char *)" Application 2 "); }

         主函数中对App2程序进行调用

        修改App2程序烧录地址及内存空间大小

六、程序运行效果

开发板实物演示图,按下KEY1按键,启动APP1;按下KEY2按键,启动APP2。

        

上位机串口输出数据演示图

七、工程文件Demo

        本文关于BootLoader讲解演示的3个工程文件可查阅下面的链接访问,文件已上传至CSDN平台的文件资源仓库。

【免费】嵌入式MCUBootLoader开发配置工程Demo资源-CSDN文库



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭