君正X2100 RTOS 固件升级

news2024/11/19 17:44:31

        使用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、文件内容
#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;
}

三、开发应用

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的内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1624516.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vivado Versal 串行 I/O 硬件调试流程、使用 Vivado Serial I/O Analyzer 来调试设计

Versal 串行 I/O 硬件调试流程 Versal ™ ACAP 无需再生成 IBERT IP &#xff0c; 因为使用系统内串行 I/O 调试所需的必要逻辑现已集成到 GTY 收发器架构内。使 用 GTY 收发器的任何设计均可用于串行 I/O 硬件调试。 Versal 串行 I/O 硬件调试流程具有 2 个不同阶…

10.JAVAEE之网络编程

1.网络编程 通过网络,让两个主机之间能够进行通信 >基于这样的通信来完成一定的功能进行网络编程的时候,需要操作系统给咱们提供一组 AP1, 通过这些 API才能完成编程&#xff08;API 可以认为是 应用层 和 传输层 之间交互的路径&#xff09;&#xff08;API:Socket API相当…

【Qt常用控件】—— QWidget 核心属性

目录 &#xff08;一&#xff09;控件概述 1.1 关于控件体系的发展 &#xff08;二&#xff09;QWidget 核心属性 2.1 核心属性概览 2.2 enabled 2.3 geometry 2.4 windowTitle 2.5 windowIcon 2.6 windowOpacity 2.7 cursor 2.8 font 2.9 toolTip 2.10 focus…

java的ArrayList LinkedList的操作

文章目录 ArrayList1. ArrayList集合的特点2. 操作 LinkedList1. LinkedList集合的特点2. 操作 参考链接 ArrayList 1. ArrayList集合的特点 2. 操作 add(Object element) 向列表的尾部添加指定的元素。size() 返回列表中的元素个数。get(int index) 返回列表中指定位置的元素…

Git ignore、exclude for TortoiseGit 小结

1.Ignore Type&#xff1a;忽略类型&#xff0c;也即忽略规则&#xff0c;如何去忽略文件? 1.1.Ignore item(s) only in containing folder(s)&#xff1a;仅忽略在包含在文件夹中项目。 仅忽略该文件夹下选定的patterns。the patterns其实就是文件类型&#xff0c;比如.txt后…

MATLAB循环语句

MATLAB 循环语句 在某些情况下&#xff0c;您需要多次执行一个代码块。通常&#xff0c;语句是按顺序执行的。首先执行函数中的第一条语句&#xff0c;然后执行第二条&#xff0c;依此类推。 编程语言提供了各种控制结构&#xff0c;允许更复杂的执行路径。 循环语句允许我们…

把 KubeBlocks 跑在 Kata 上,真的可行吗?

背景 容器的安全性一直是广受关注的话题。这个领域也产生了很多不错的开源项目。Kata就是其中之一。 Kata Containers&#xff08;简称 Kata&#xff09;是一种开源项目&#xff0c;它提供了一种安全而高性能的容器运行时环境。Kata Containers 利用虚拟化技术&#xff08;通常…

【深度学习实战(24)】如何实现“断点续训”?

一、什么是断点续训&#xff1a; 中断的地方&#xff0c;继续训练。与加载预训练权重有什么区别呢&#xff1f;区别在于优化器参数和学习率变了。 二、如何实现“断点续训” 我们需要使用checkpoint方法保存&#xff0c;模型权重&#xff0c;优化器权重&#xff0c;训练轮数…

TablePlus for Mac/Win:开启高效数据开发新纪元

在当今数字化时代&#xff0c;数据的重要性日益凸显。无论是企业还是个人&#xff0c;都需要一款强大而实用的本地原生数据开发软件来提升工作效率。而 TablePlus for Mac/Win 正是这样一款卓越的工具&#xff0c;它为用户带来了全新的体验&#xff0c;让数据开发变得更加轻松、…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(三)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 4 - 6节&#xff09; P5《04.快速入门》 本节来实现一个 HelloWorld 效果&#xff1a; 1、打开编辑器&#xff0c;选择新建项目&…

【matlab】reshape函数介绍及应用

【matlab】reshape函数介绍及应用 【先赞后看养成习惯】求点赞关注收藏&#x1f600; 在MATLAB中&#xff0c;reshape函数是一种非常重要的数组操作函数&#xff0c;它可以改变数组的形状而不改变其数据。本文将详细介绍reshape函数的使用方法和应用。 1. reshape函数的基本语…

Redisson分布式锁 --- 源码分析

1.获取一把锁 RLock lock redissonClient.getLock("订单lock"); 2.业务代码加锁 lock.lock(); 2.1 lock.tryAcquire Long ttl tryAcquire(leaseTime, unit, threadId); 2.2 lua脚本: tryLockInnerAsync方法 如果获取锁失败&#xff0c;返回的结果是这个key的剩…

ssm项目搭建,springboot项目搭建

一、springboot项目搭建 1.新建一个文件夹用idea打开 2.配置maven工作目录、jdk路径、编码方式 3.pom.xml依赖管理&#xff1a;不同的项目&#xff0c;只需要修改下面的三行就可以 <groupId>com.qcby</groupId> <artifactId>HXQ0419</artifactId> &l…

如何安装、升级英伟达显卡驱动

目录 方式一&#xff1a;GeForce Experience 方式二&#xff1a;英伟达官网手动下载驱动 在做深度学习的过程中&#xff0c;难免会使用到cudatoolkit&#xff0c;而cudatoolkit又需要跟英伟达显卡驱动适配。比如笔者使用的电脑目前安装的英伟达显卡驱动 Driver Version: 516.…

git的安装与配置教程--超详细版

一、git的安装 1. 官网下载git git官网地址&#xff1a;https://git-scm.com/download/win/ 选择需要的版本进行下载 2、下载完成之后&#xff0c;双击下载好的exe文件进行安装。 3、默认是C盘&#xff0c;推荐修改一下路径&#xff0c;然后点击下一步 4、Git配置&#xff…

Java虚拟机(jvm)常见问题总结

1.电脑怎样认识我们编写的Java代码 首先先了解电脑是二进制的系统&#xff0c;他只认识 01010101比如我们经常要编写 HelloWord.java 电脑是怎么认识运行的HelloWord.java是我们程序员编写的&#xff0c;我们人可以认识&#xff0c;但是电脑不认识 Java文件编译的过程 1. 程…

4.25日学习记录

[HZNUCTF 2023 preliminary]ppppop 对于php反序列化&#xff0c;在之前的学习中有过了解&#xff0c;但是对于序列化字符串的格式不是很了解&#xff0c;刚好接触这题&#xff0c;可以了解一下 序列化字符串的格式&#xff1a; 布尔型&#xff08;bool&#xff09;b&#xf…

bugfix: com.alibaba.druid.sql.parser.EOFParserException: EOF

前言 在日常的开发工作中&#xff0c;我们经常会遇到各种各样的问题&#xff0c;其中涉及数据库操作的接口联调尤其容易出现意想不到的状况。今天我就遇到了一个关于Druid SQL解析异常的问题&#xff0c;具体表现为com.alibaba.druid.sql.parser.EOFParserException: EOF。通过…

盲人使用公共设施:科技助力无障碍出行与智能识别

在我们的日常生活中&#xff0c;公共设施扮演着不可或缺的角色&#xff0c;它们为人们提供了便利的服务&#xff0c;构建起和谐、高效的社会环境。然而&#xff0c;对于视障人士而言&#xff0c;尽管公共设施设计之初便考虑到通用性和包容性&#xff0c;实际使用过程中仍难免遭…

云原生Kubernetes: K8S 1.29版本 部署Nexus

目录 一、实验 1.环境 2.搭建NFS 3. K8S 1.29版本 部署Nexus 二、问题 1.volumeMode有哪几种模式 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构版本IP备注masterK8S master节点1.29.0192.168.204.8 node1K8S node节点1.29.0192.168.204.9node2K…