当前位置:   article > 正文

单片机中实现bootloader功能_单片机bootloader

单片机bootloader

1.bootloader简介

Bootloader是指系统启动的第一段代码,位于计算机或嵌入式设备的非易失性存储器(如闪存、EPROM等)中。它负责初始化硬件设备、加载操作系统内核,并将控制权传递给内核的入口点,开始系统的正常运行。

Bootloader的主要功能包括以下几个方面:

  1. 硬件初始化:Bootloader负责初始化计算机或设备的硬件设备,包括处理器、内存、外设等。这些初始化操作确保系统硬件处于正确的状态,并为后续的操作做好准备。

  2. 引导加载:Bootloader从存储介质(如闪存)中读取操作系统内核的镜像,并将其加载到内存中。这涉及到文件系统的解析和解压缩,确保内核映像正确加载到内存中。

  3. 参数传递:Bootloader还负责将一些参数传递给操作系统内核,例如启动参数、设备参数等。这些参数可以影响内核的运行方式和配置。

  4. 可选功能:某些Bootloader还提供额外的功能,例如启动菜单、系统恢复、固件升级等。这些附加功能可以根据需要进行扩展和定制。

Bootloader在计算机和嵌入式系统中起到了非常重要的作用,它是系统启动的关键环节。Bootloader的设计和实现需要考虑硬件平台的特点和要求,以及操作系统的需求。不同平台和设备可能使用不同类型的Bootloader,例如基于BIOS的x86系统(相关技术可以查看BIOS专栏)、基于U-Boot的嵌入式系统等。

总之,Bootloader是系统启动过程中的第一步,它负责初始化硬件、加载内核,并将控制权传递给内核,使系统正常运行。

2.在单片机中实现一个有OTA功能的bootloader

  1. 地址映射:单片机的存储器中需要划分出一部分空间用于存放Bootloader代码。这个空间通常位于存储器的固定地址处,并设置为可写入和可执行。

  2. 启动向量设置:将单片机的启动向量设置为Bootloader的起始地址,以便在上电或复位时跳转到Bootloader代码处执行。

  3. 初始化硬件:Bootloader需要初始化所使用的硬件,包括外设、时钟、中断等。

  4. 检查更新:Bootloader需要检查是否存在新的固件更新。这可以通过读取特定的存储区域、接收网络数据或其他方式来实现。如果有更新,Bootloader会下载并存储到适当的位置。

  5. 启动应用程序或内核:如果没有新的固件更新,Bootloader可以直接跳转到应用程序或操作系统内核的入口点。否则,Bootloader将加载新的固件并跳转到它的入口点。

针对OTA更新,可以设计一个分区用于存储固件更新的数据。这个分区可以是单片机存储器中的一个区域,专门用于存放OTA更新的固件数据。当检测到有固件更新时,Bootloader会通过网络或其他外设接收更新数据,并将其存储到OTA分区中。然后,Bootloader会根据OTA分区中的固件数据进行更新操作,最后跳转到新固件的入口点执行。

3.内存划分的示例

  1. /*
  2. 使用布局如下:
  3. 0x08000000 -|--------------------- 给定一个起始地址
  4. ~ | 64k bootloard的程序
  5. 0x08010000 -|--------------------- ApplicationAddress
  6. ~ | 256k 应用程序1 确保应用程序的大小不会覆盖到下面的数据
  7. ~ | 确保应用程序的大小不会覆盖到下面的数据
  8. 0x08050000 -|--------------------- UpgradeFileAddress
  9. ~ | 256k 应用程序2 (也可作为OTA程序区)
  10. ~ |
  11. 0x08090000 -|-------------------------
  12. ~ | 数据区
  13. end -|
  14. */

4.bootloader示例1

每次在bootloader启动时都去检查OTA程序区是否存在程序

如果存在则将OTA程序拷贝到应用程序的内存中,运行。然后清空OTA空间中的代码。

这种方法需要在bootloader程序中进行OTA的校验和擦除,但是管控集中,更加安全,不会因为应用程序的出错而造成当前应用程序的出错。

  1. #define ApplicationAddress 0x08010000
  2. #define UpgradeFileAddress 0x08050000
  3. #define FlashEndAddress 0x08090000
  4. #define UpgradeFileMaxLen (FlashEndAddress - UpgradeFileAddress)
  5. typedef void (*pFunction)(void);
  6. /* 升级程序消息摘要 */
  7. typedef struct __UpgradeDigest
  8. {
  9. char MagicNumber[4]; //用与分辨是否是自己人
  10. uint32_t FileSize;
  11. uint32_t CRCValue;
  12. } UpgradeDigest;
  13. void runApplication()
  14. {
  15. printf("应用程序启动中...\r\n");
  16. if (检查ApplicationAddress地址是否有效 - todo)
  17. {
  18. pFunction Jump_To_Application;
  19. uint32_t JumpAddress;
  20. JumpAddress = *(volatile uint32_t*) (ApplicationAddress + 4);
  21. Jump_To_Application = (pFunction) JumpAddress;
  22. //设置主堆栈指针的起始地址(ApplicationAddress) todo;
  23. Jump_To_Application();
  24. }
  25. }
  26. int main(void)
  27. {
  28. /* 一些硬件的初始化 */
  29. ...
  30. UpgradeDigest *digest = NULL;
  31. uint32_t appAddress = 0;
  32. uint32_t gradeAddress = 0;
  33. uint32_t crc32 = 0;
  34. uint8_t upgradeFileFound = 0;
  35. /* 1.检查指定区域是否存在'升级程序消息摘要' */
  36. digest = (UpgradeDigest *)UpgradeFileAddress;
  37. if( (memcmp(digest->MagicNumber, "xxxx", 4) == 0) &&
  38. (digest->FileSize <= UpgradeFileMaxLen) )
  39. {
  40. /* 存在'升级程序消息摘要',准备校验升级文件 */
  41. appAddress = ApplicationAddress;
  42. gradeAddress = UpgradeFileAddress + sizeof(UpgradeDigest);
  43. crc32 = getCRC32((uint8_t *)gradeAddress, digest->FileSize);
  44. if(crc32 == digest->CRCValue)
  45. {
  46. /* 检验成功 */
  47. upgradeFileFound = 1;
  48. }
  49. else
  50. {
  51. /* 校验失败,清空程序升级区 - todo */
  52. printf("校验升级文件失败: CRC校验失败! \r\n");
  53. }
  54. }
  55. if(upgradeFileFound)
  56. {
  57. /* 2.升级文件校验成功,开始复制数据至程序启动位置 */
  58. printf("开始升级");
  59. Flash_WriteData(appAddress, (uint32_t *)gradeAddress, digest->FileSize);
  60. /* 3.复制结束,校验程序CRC */
  61. crc32 = getCRC32((uint8_t *)ApplicationAddress, digest->FileSize);
  62. if(crc32 == digest->CRCValue)
  63. {
  64. /* 复制成功, 清空升级数据 - todo */
  65. /* 4. 现在可以启动程序 */
  66. printf("升级成功! \r\r\n");
  67. runApplication();
  68. }
  69. else
  70. {
  71. /* 复制失败,清空应用程序区 - todo*/
  72. printf("升级失败: CRC校验失败,复制过程出错! \r\n");
  73. }
  74. }
  75. else
  76. {
  77. runApplication(); //不存在ota程序直接运行
  78. }
  79. }

5.bootloader示例2

这种方法下2个应用程序区都将保留,当应用程序2区被激活时则执行应用程序2,反之则执行应用程序1。

这种方法需要在应用程序中管控更多的变量,但是在程序启动来说会更快。因为2个OTA区都可以在应用程序中修改,造成了一定的风险。

  1. #define ApplicationAddress_1 0x08010000
  2. #define ApplicationAddress_2 0x08050000
  3. typedef void (*pFunction)(void);
  4. /* OTA消息摘要 */
  5. typedef struct __OTADigest
  6. {
  7. uint32_t active; //是否启用
  8. uint32_t FileSize;
  9. uint32_t CRCValue;
  10. } OTADigest;
  11. void runApplication(uint32_t JumpAddress)
  12. {
  13. printf("应用程序启动中...\r\n");
  14. if (检查JumpAddress地址是否有效 - todo)
  15. {
  16. pFunction Jump_To_Application;
  17. Jump_To_Application = (pFunction) *(volatile uint32_t*) (JumpAddress + 4);
  18. //设置主堆栈指针的起始地址(JumpAddress) todo;
  19. Jump_To_Application();
  20. }
  21. }
  22. int main(void)
  23. {
  24. /* 一些硬件的初始化 */
  25. ...
  26. OTADigest *ota = NULL;
  27. uint32_t gradeAddress = 0;
  28. uint32_t crc32 = 0;
  29. uint8_t OTA_2_FileFound = 0;
  30. /* 1.检查指ota 2区是否存在程序 */
  31. ota = (OTADigest *)ApplicationAddress_2;
  32. if(ota->active == 1))
  33. {
  34. /* ota 1 区 启用,准备校验升级文件 */
  35. gradeAddress = ApplicationAddress_2 + sizeof(OTADigest);
  36. crc32 = getCRC32((uint8_t *)gradeAddress, digest->FileSize);
  37. if(crc32 == digest->CRCValue)
  38. {
  39. /* 检验成功 */
  40. OTA_2_FileFound = 1;
  41. }
  42. }
  43. if(OTA_2_FileFound)
  44. {
  45. runApplication(ApplicationAddress_2);
  46. }
  47. else
  48. {
  49. runApplication(ApplicationAddress_1); //不存在ota 2 程序直接运行ota 1程序
  50. }
  51. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/613895
推荐阅读
  • 相关标签
      

    闽ICP备14008679号