• 君正X2100 RTOS 固件升级


            使用cloner工具烧写固件需要在上电之前让boot_sel[2:0]处于boot from USB模式,但是电路板装在机壳内部后不方便改变boot_sel[2:0]的状态,如果要升级固件,需要通过机壳留出的USB口、网口、或者无线网络进行固件更新。

    一、升级方案

    1、固件分析

            X2100的固件由两部分组成,bootloader和rtos app,spl bin文件就是bootloader,启动时由处理器内部固化的代码将bootloader拷贝到DDR,然后执行bootloader,bootloader再将rtos app拷贝到DDR,再执行rtos app。rtos app拷贝到DDR的地址由config文件指定,可通过配置界面->通用选项查看或修改。

    2、启动流程

     再增加一个二级bootloader,启动流程改为spl--->2ndboot--->RTOS App。

    二、开发二级bootloader

    1、修改配置文件

    创建一个应用,配置文件只保留一些基本功能。

    设置固件使用的内存大小为3MB,剩余的留给RTOS App,所以这个够用就行。

    开启USB CDC功能 :

    2、程序

    参考sdk /freertos/example/usb/device/gadget_cdc_serial_boot_app.c文件。代码运行逻辑:

    1、创建cdc_serial接收线程;

    2、接收到上位机发送的boot-app消息后执行boot-app()函数;

    3、boot-app()先查找指定的镜像分区,需要和cloner烧录工具中指定的名字一样;

            #define PARTITON_NAME "app"

    4、查找到分区后检查镜像的头部内容,如果头部内容的tag是0x534f5452(“RTOS”)再判断头部内容中指定的内存加载地址是否和当前运行的程序冲突,没有冲突就继续执行,有冲突就立即退出。

     5、将镜像的内容从拷贝到镜像头部内容指定的地址,然后运行。

    3、文件内容
    1. #include <stdio.h>
    2. #include <cpu/irqflags.h>
    3. #include <driver/irq.h>
    4. #include <cpu/cpu.h>
    5. #include <common.h>
    6. #include <usb/gadget_serial.h>
    7. #include <os.h>
    8. #include "filesystem/include/mtd_driver_nor.h"
    9. #define PARTITON_NAME "app"
    10. struct rtos_header {
    11. unsigned int code[2];
    12. unsigned int tag;
    13. unsigned int version;
    14. unsigned long img_start;
    15. unsigned long img_end;
    16. unsigned long heap_start;
    17. unsigned long heap_end;
    18. unsigned long mapped_rtosdata_size;
    19. };
    20. static const struct gadget_id serial_id = {
    21. .vendor_id = 0x0525,
    22. .product_id = 0xa4a7
    23. };
    24. static const struct usb_cdc_serial_param serial_parameters ={
    25. .dwDTERate = 115200,
    26. .bCharFormat = USB_CDC_1_STOP_BITS,
    27. .bParityType = USB_CDC_NO_PARITY,
    28. .bDataBits = 8
    29. };
    30. static void serial_param_callback(struct usb_cdc_serial_param *p)
    31. {
    32. printf("usb serial: dwDTERate %d, bCharFormat %d, bParityType %d, bDataBits %d\n",
    33. p->dwDTERate, p->bCharFormat, p->bParityType, p->bDataBits);
    34. }
    35. static void serial_connect_callback(int connect)
    36. {
    37. printf("serial_connect_callback %d\n", connect);
    38. }
    39. static inline int rtos_check_header(struct rtos_header *rtos)
    40. {
    41. if (rtos->tag != 0x534f5452) {
    42. printf("rtos bad tag: %x\n", rtos->tag);
    43. return -1;
    44. }
    45. if (rtos->img_start >= rtos->img_end) {
    46. printf("rtos bad off: %lx %lx\n", rtos->img_start, rtos->img_end);
    47. return -1;
    48. }
    49. return 0;
    50. }
    51. static inline int rtos_check_intersection(unsigned int start0, unsigned int end0, unsigned int start1, unsigned int end1)
    52. {
    53. if (start1 < start0 && end1 < start0)
    54. return 0;
    55. if (start1 >= end0 && end1 >= end0)
    56. return 0;
    57. return 1;
    58. }
    59. static inline void rtos_start(struct rtos_header *rtos, void *arg)
    60. {
    61. void (*func)(void *arg) = (void *)rtos->img_start;
    62. flush_cache_all();
    63. func(arg);
    64. }
    65. static void release_all_resources(void)
    66. {
    67. usb_core_exit();
    68. local_irq_disable();
    69. arch_deinit_cpu();
    70. // lcd
    71. // disable_irq(IRQ_LCD);
    72. // release_irq(IRQ_LCD);
    73. // intc
    74. disable_irq(IRQ_V_IP2);
    75. release_irq(IRQ_V_IP2);
    76. // ost
    77. disable_irq(IRQ_V_IP4);
    78. release_irq(IRQ_V_IP4);
    79. local_irq_enable();
    80. }
    81. int read_rtos_start_addr_by_name(struct rtos_header *rtos, int *offset, const char *find_node_name)
    82. {
    83. struct mtd_nor_partition *mtd_part;
    84. struct mtd_nor_partition *parts = sfc_nor_flash_partition_information();
    85. if (parts == NULL) {
    86. return -EIO;
    87. }
    88. for (mtd_part = parts; mtd_part->name != NULL; mtd_part++) {
    89. if ( !strcmp(find_node_name, mtd_part->name) ) {
    90. *offset = mtd_part->offset;
    91. sfc_nor_flash_read( mtd_part->offset, sizeof(struct rtos_header), (void *)rtos);
    92. break;
    93. }
    94. }
    95. return 0;
    96. }
    97. static void boot_app(void)
    98. {
    99. int ret = 0;
    100. int offset = 0;
    101. struct rtos_header *rtos = malloc(sizeof(struct rtos_header));
    102. assert(rtos != NULL);
    103. memset(rtos, 0, sizeof(struct rtos_header));
    104. // 根据烧录工具中设置的分区名字获取镜像信息
    105. ret = read_rtos_start_addr_by_name(rtos, &offset, PARTITON_NAME);
    106. if (ret != 0) {
    107. printf("get partition_information fail!\n");
    108. goto error;
    109. }
    110. if (rtos_check_header(rtos)) {
    111. goto error;
    112. }
    113. // 检查加载是否会覆盖到旧系统地址上
    114. if (rtos_check_intersection(CONFIG_OS_MEM_ADDR, (CONFIG_OS_MEM_ADDR + CONFIG_OS_MEM_SIZE), rtos->img_start, rtos->img_end)) {
    115. printf("address overlap\n");
    116. goto error;
    117. }
    118. sfc_nor_flash_read(offset, rtos->img_end -rtos->img_start, (void *)rtos->img_start);
    119. release_all_resources();
    120. rtos_start(rtos, NULL);
    121. error:
    122. free(rtos);
    123. return ;
    124. }
    125. static unsigned char usb_test_buf[1024];
    126. static void usb_gadget_serial_thread(void *data)
    127. {
    128. int len, i;
    129. while (1) {
    130. msleep(1000);
    131. len = gadget_serial_read(usb_test_buf, sizeof(usb_test_buf), 0, 0);
    132. if (len > 0) {
    133. for (i = 0; i < len; i++){
    134. printf("usb read %c\n", usb_test_buf[i]);
    135. }
    136. if ( !strncmp(usb_test_buf, "boot-app", strlen("boot-app"))) {
    137. boot_app();
    138. }
    139. }
    140. }
    141. }
    142. int application_2nd_boot_app(void)
    143. {
    144. gadget_serial_init(&serial_id, &serial_parameters, serial_connect_callback, serial_param_callback);
    145. thread_create("usb gadget serial thread", 8192, usb_gadget_serial_thread, NULL);
    146. return 0;
    147. }

    三、开发应用

    1、修改配置文件

            修改配置,不选spl文件,固件加载的地址需要≥二级bootloader的固件加载的地址+固件使用的内存大小,固件使用的内存大小为总的DDR大小 - 二级bootloader固件使用的内存大小 - 其余部分。如X2100的DDR大小是64MB,二级bootloader固件使用的内存大小是3MB,其余部分是1MB,那么应用的固件使用的内存大小是62914560(60MB)。

    2、编译生成固件

            修改配置文件之后先make 配置文件,然后执行make,在freertos目录下会生成一个zero.bin,可将其改为其它名字。

    四、烧录和测试

     1、SFC添加分区

    启动cloner->配置->SFC->分区信息->添加一个app分区:

    2、添加app烧录

    3、 测试

            烧录之后,设备运行的是二级bootloader的程序,用上位机给设备的CDC串口发送"boot-app"消息,二级bootloader会将app.bin拷贝到指定的内部地址,然后运行。

    五、更新app

            可在二级bootloader程序程序中加入Y-mode文件接收程序,上位机发送新的app.bin文件给设备,覆盖当前app.bin所在flash的内容。

  • 相关阅读:
    杰理之SPP 连接和断开事件处理【篇】
    mysql-DBA(1)-数据库备份恢复-导入导出-日志解释
    ESP8266-Arduino编程实例-ADS1015(ADC)驱动
    猪齿鱼实践之持续交付中的分支管理与版本控制
    webpack和vite的区别
    Vscode远程调试
    基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(排它条件网关)
    MySQL--视图、存储过程、触发器
    Linux环境下使用Docker搭建Jenkins容器
    菜鸡的秋招升级打怪之旅
  • 原文地址:https://blog.csdn.net/professionalmcu/article/details/138162939