使用cloner工具烧写固件需要在上电之前让boot_sel[2:0]处于boot from USB模式,但是电路板装在机壳内部后不方便改变boot_sel[2:0]的状态,如果要升级固件,需要通过机壳留出的USB口、网口、或者无线网络进行固件更新。
X2100的固件由两部分组成,bootloader和rtos app,spl bin文件就是bootloader,启动时由处理器内部固化的代码将bootloader拷贝到DDR,然后执行bootloader,bootloader再将rtos app拷贝到DDR,再执行rtos app。rtos app拷贝到DDR的地址由config文件指定,可通过配置界面->通用选项查看或修改。
再增加一个二级bootloader,启动流程改为spl--->2ndboot--->RTOS App。
创建一个应用,配置文件只保留一些基本功能。
设置固件使用的内存大小为3MB,剩余的留给RTOS App,所以这个够用就行。
开启USB CDC功能 :
参考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、将镜像的内容从拷贝到镜像头部内容指定的地址,然后运行。
- #include <stdio.h>
- #include <cpu/irqflags.h>
- #include <driver/irq.h>
- #include <cpu/cpu.h>
- #include <common.h>
- #include <usb/gadget_serial.h>
- #include <os.h>
- #include "filesystem/include/mtd_driver_nor.h"
-
- #define PARTITON_NAME "app"
-
- struct rtos_header {
- unsigned int code[2];
- unsigned int tag;
- unsigned int version;
- unsigned long img_start;
- unsigned long img_end;
- unsigned long heap_start;
- unsigned long heap_end;
- unsigned long mapped_rtosdata_size;
- };
-
- static const struct gadget_id serial_id = {
- .vendor_id = 0x0525,
- .product_id = 0xa4a7
- };
-
- static const struct usb_cdc_serial_param serial_parameters ={
- .dwDTERate = 115200,
- .bCharFormat = USB_CDC_1_STOP_BITS,
- .bParityType = USB_CDC_NO_PARITY,
- .bDataBits = 8
- };
-
- static void serial_param_callback(struct usb_cdc_serial_param *p)
- {
- printf("usb serial: dwDTERate %d, bCharFormat %d, bParityType %d, bDataBits %d\n",
- p->dwDTERate, p->bCharFormat, p->bParityType, p->bDataBits);
- }
-
- static void serial_connect_callback(int connect)
- {
- printf("serial_connect_callback %d\n", connect);
- }
-
- static inline int rtos_check_header(struct rtos_header *rtos)
- {
- if (rtos->tag != 0x534f5452) {
- printf("rtos bad tag: %x\n", rtos->tag);
- return -1;
- }
- if (rtos->img_start >= rtos->img_end) {
- printf("rtos bad off: %lx %lx\n", rtos->img_start, rtos->img_end);
- return -1;
- }
-
- return 0;
- }
-
- static inline int rtos_check_intersection(unsigned int start0, unsigned int end0, unsigned int start1, unsigned int end1)
- {
- if (start1 < start0 && end1 < start0)
- return 0;
- if (start1 >= end0 && end1 >= end0)
- return 0;
- return 1;
- }
-
- static inline void rtos_start(struct rtos_header *rtos, void *arg)
- {
- void (*func)(void *arg) = (void *)rtos->img_start;
- flush_cache_all();
- func(arg);
- }
-
- static void release_all_resources(void)
- {
- usb_core_exit();
-
- local_irq_disable();
- arch_deinit_cpu();
- // lcd
- // disable_irq(IRQ_LCD);
- // release_irq(IRQ_LCD);
-
- // intc
- disable_irq(IRQ_V_IP2);
- release_irq(IRQ_V_IP2);
-
- // ost
- disable_irq(IRQ_V_IP4);
- release_irq(IRQ_V_IP4);
- local_irq_enable();
- }
-
- int read_rtos_start_addr_by_name(struct rtos_header *rtos, int *offset, const char *find_node_name)
- {
- struct mtd_nor_partition *mtd_part;
-
- struct mtd_nor_partition *parts = sfc_nor_flash_partition_information();
-
- if (parts == NULL) {
- return -EIO;
- }
-
- for (mtd_part = parts; mtd_part->name != NULL; mtd_part++) {
- if ( !strcmp(find_node_name, mtd_part->name) ) {
- *offset = mtd_part->offset;
- sfc_nor_flash_read( mtd_part->offset, sizeof(struct rtos_header), (void *)rtos);
- break;
- }
- }
-
- return 0;
- }
-
- static void boot_app(void)
- {
- int ret = 0;
- int offset = 0;
-
- struct rtos_header *rtos = malloc(sizeof(struct rtos_header));
- assert(rtos != NULL);
- memset(rtos, 0, sizeof(struct rtos_header));
-
- // 根据烧录工具中设置的分区名字获取镜像信息
- ret = read_rtos_start_addr_by_name(rtos, &offset, PARTITON_NAME);
-
- if (ret != 0) {
- printf("get partition_information fail!\n");
- goto error;
- }
-
- if (rtos_check_header(rtos)) {
- goto error;
- }
-
- // 检查加载是否会覆盖到旧系统地址上
- if (rtos_check_intersection(CONFIG_OS_MEM_ADDR, (CONFIG_OS_MEM_ADDR + CONFIG_OS_MEM_SIZE), rtos->img_start, rtos->img_end)) {
- printf("address overlap\n");
- goto error;
- }
-
- sfc_nor_flash_read(offset, rtos->img_end -rtos->img_start, (void *)rtos->img_start);
-
- release_all_resources();
-
- rtos_start(rtos, NULL);
-
- error:
- free(rtos);
- return ;
- }
-
- static unsigned char usb_test_buf[1024];
-
- static void usb_gadget_serial_thread(void *data)
- {
- int len, i;
-
- while (1) {
- msleep(1000);
- len = gadget_serial_read(usb_test_buf, sizeof(usb_test_buf), 0, 0);
-
- if (len > 0) {
- for (i = 0; i < len; i++){
- printf("usb read %c\n", usb_test_buf[i]);
- }
- if ( !strncmp(usb_test_buf, "boot-app", strlen("boot-app"))) {
- boot_app();
- }
- }
- }
- }
-
- int application_2nd_boot_app(void)
- {
- gadget_serial_init(&serial_id, &serial_parameters, serial_connect_callback, serial_param_callback);
- thread_create("usb gadget serial thread", 8192, usb_gadget_serial_thread, NULL);
- return 0;
- }
修改配置,不选spl文件,固件加载的地址需要≥二级bootloader的固件加载的地址+固件使用的内存大小,固件使用的内存大小为总的DDR大小 - 二级bootloader固件使用的内存大小 - 其余部分。如X2100的DDR大小是64MB,二级bootloader固件使用的内存大小是3MB,其余部分是1MB,那么应用的固件使用的内存大小是62914560(60MB)。
修改配置文件之后先make 配置文件,然后执行make,在freertos目录下会生成一个zero.bin,可将其改为其它名字。
启动cloner->配置->SFC->分区信息->添加一个app分区:
烧录之后,设备运行的是二级bootloader的程序,用上位机给设备的CDC串口发送"boot-app"消息,二级bootloader会将app.bin拷贝到指定的内部地址,然后运行。
可在二级bootloader程序程序中加入Y-mode文件接收程序,上位机发送新的app.bin文件给设备,覆盖当前app.bin所在flash的内容。