Skip to content

简单来说,Bootloader就是单片机上电或复位后,在你的主应用程序APP运行之前,先跑起来的一小段特殊程序。

你可以把它想象成电脑开机时的BIOS/UEFI。电脑按下电源键,不是直接就进Windows或MacOS了对吧?得先有个东西检查下硬件,做点初始化,然后再去加载操作系统。

1. 什么是IAP?什么是OTA?

IAP(In-Application Programming),“应用程序内编程”或“在应用中自编程”。本质含义:MCU 在运行用户代码(App或Bootloader)时,通过自身的代码(而不是用外部编程器/仿真器)来擦写和更新片上 Flash 内容。典型的应用场景:在系统上线后,通过串口、CAN、USB、以太网等接口下载新固件,并写入指定Flash区,完成固件升级。

OTA(Over-The-Air),直译就是“空中下载”或者“远程升级”,也就是使用无线的IAP,例如蓝牙或者wifi,它也是IAP。

2. 代码讲解

炸鸡派IAP_F411的代码详见仓库连接:https://gitee.com/kingham/FryPi/tree/master/2.software/2.Advanced/7.IAP_F411

我们直接打开工程进行学习,外设的初始化我们就不再讲了,LCD、串口、PWM背光这些都是基础的部分内容。

c
//开机启动时如果按下KEY1, 进入boot中IAP升级模式
if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == 0)
{
    // 延时判断是否真的按下
    delay_ms(500);
    if(HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) == 0)
    {
        LCD_ShowString(72, LCD_H/2, (uint8_t*)"Bootload", WHITE, BLACK, 24, 0);//12*6,16*8,24*12,32*16
        LCD_ShowString(32, LCD_H/2+48, (uint8_t*)"OV-Watch V2.4.1", WHITE, BLACK, 24, 0);
        boot_in_menu_flag = 1;
        //go in boot menu
        FLASH_If_Init();
        Main_Menu();
    }
}

//如果没按下KEY1, 且有APP程序, 则运行APP, 没有APP则
else
{
    uint32_t data1, data2;
    char *str_flag;
    uint32_t address = 0x08008000; // Flash 中数据的起始地址

    // 读取地址为 0x08008000 的数据
    data1 = *(uint32_t *)address;

    // 读取地址为 0x08008004 的数据
    data2 = *(uint32_t *)(address + sizeof(uint32_t));

    // 将数据转换为字符数组
    char str1[5], str2[5];
    memcpy(str1, &data1, sizeof(data1));
    memcpy(str2, &data2, sizeof(data2));
    str1[4] = '\0';
    str2[4] = '\0';

    // 拼接两个字符数组
    char combined_str[9];
    strcpy(combined_str, str1);
    strcat(combined_str, str2);

    // 检查是否与 "APP FLAG" 相同
    if (strcmp(combined_str, "APP FLAG") == 0)
    {
        // 如果相同则跳转
        printf("APP FLAG OK, jump to app\r\n");
        //user code here
        SysTick->CTRL = 0X00;//禁止SysTick
        SysTick->LOAD = 0;
        SysTick->VAL = 0;
        __disable_irq();

        //set JumpAddress
        JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
        /* Jump to user application */
        Jump_To_Application = (pFunction) JumpAddress;
        /* Initialize user application's Stack Pointer */
        __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
        Jump_To_Application();
    }
    // no legal APP
    else
    {
        LCD_ShowString(74, LCD_H/2, (uint8_t*)"No App!", WHITE, BLACK, 24, 0);//12*6,16*8,24*12,32*16
        LCD_ShowString(32, LCD_H/2+48, (uint8_t*)"Please Download", WHITE, BLACK, 24, 0);
        HAL_Delay(1000);
    }
}

0X0800 0000是MCU的启动地址,0X0800 8000存放了一个字符串,为自己设定的一个字符"APP FLAG",有则代表APP已经正常通过boot烧录了,0X0800 C000之后,就是存放的APP的代码内容了。

上面代码在启动时候的代码的大致意思,用一个流程图来表示更加直观:即上电后检测是否按键按下,按下进入boot升级,可以下载外部的.bin文件,然后再启动APP。如果上电时不按KEY按键,则正常进入APP(如果有的话)。具体的API内部内容,大家可以在源码中查看。

3. 上机实测

3.1. 准备待烧录的APP

接下来我们烧录BootLoader程序,然后使用SecureCRT烧录我们准备好的xxx.bin文件,注意,这个xxx.bin的工程的起始地址需要设置为:0x0000C000U

我们直接以LVGL手表例程为例,更改起始地址为0x0000C000

c
SCB->VTOR = 0x0000C000U;

然后更改设置,更改偏移地址,打开microlib

设置编译完生成.bin文件,稍等用Ymodem协议下载进去。

sh
fromelf.exe --bin -o "$L@L.bin" "#L

3.2. 烧录BootLoader并进入升级模式

烧录IAP程序,然后连接串口,按住按键上电,打开SecureCRT连接串口可以看到这个界面:

然后按照菜单输入数字,进入下载模式,此时会一直输出ccccc...等待你发送Ymodem

发送完bin后,显示成功,正常重启或者直接输入3就能进入APP了