RT-Thread—STM32—在线升级(Ymodem_OTA、HTTP_OTA)

概述

本教程主要根据官方推荐的教程进行改编,详细信息请参考
OTA Downloader软件包
STM32 通用 Bootloader

本例程通过自己实际搭建环境,测试总结。

bootloader的制作

文末有我已经做好的Bootloader文件,可供参考

 

 

 

烧录Bootloader

  • 选择合适的工具烧录BootLoader
  • 这里我选择的是J-Flash ARM V4.34(使用的是ST-Link/V2)
  • 连接之后下载刚刚生成的Bootloader文件(xxxx.bin)

 

 

 

  • 连接串口,测试打印信息
  • 能看到我们之前制作Bootloader时,相关的参数以及logo,说明Bootloader烧录成功,如下图所示
  • 博主使用的是Xshell软件(建议使用Xshell软件)
  • Xhell官网

 

 

 

制作APP程序

使用RT-Thread Studio 添加这些软件包。

 

 

 

 

代码修改

    • 打开fal_cfg.h文件(此过程一定要和Bootloader制作是保持地址对应,否者没法升级)
    • 更改app的开始地址
      #define RT_APP_PART_ADDR 0x08010000 // app区的开始地址
    • 更改分区表
#include <rtconfig.h>
#include <board.h>

/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev onchip_flash_manager;// 片内 flash 分区管理对象

/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &onchip_flash_manager,                                           \
}

/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG

#define FAL_PART_TABLE                                                               \
{                                                                                    \
    {FAL_PART_MAGIC_WROD,        "bl",   "onchip_flash_manager",                0, 64 * 1024, 0}, \
    {FAL_PART_MAGIC_WROD,        "app",   "onchip_flash_manager",   64*1024, 320 * 1024, 0}, \
    {FAL_PART_MAGIC_WORD,   "download",   "onchip_flash_manager",   384*1024, 128 * 1024, 0}, \
}

  

#include <fal.h>

/**
 * fal 读操作
 * @param offset    基于分区首地址的偏移量
 * @param buf       数据读取后的缓存区
 * @param size      要读取的数据个数
 * @return
 */
static int my_read(long offset, uint8_t *buf, size_t size)
{
    uint32_t startAddr; // 起始地址
    uint32_t endAddr;   // 结束地址

    // 首先,要读取数据的首地址的计算公式:
    // 起始地址 = flash device 起始地址 + flash 分区的偏移地址 + 相对分区偏移地址
    // 然后此处传入的 offset,在 fal_partition_read() 中完成了 flash 分区的偏移地址 + 相对分区偏移地址的求和.
    // 所以此处的 offset = flash 分区的偏移地址 + 相对分区偏移地址
    startAddr = onchip_flash_manager.addr + offset;

    // 结束地址 = startAddr + 要读取的字节长度
    endAddr = startAddr + size;

    if (endAddr > STM32_FLASH_END_ADDRESS)
    {
        rt_kprintf("read outrange flash size! addr is (0x%p)\n", endAddr);
        return -RT_EINVAL;
    }

    for (uint32_t i = 0; i < size; i++, buf++, startAddr++)
    {
        *buf = *(rt_uint8_t *) startAddr;
    }

    return size;
}

/**
 * fal 写操作
 * @param offset    基于分区首地址的偏移
 * @param buf       要写入的数据的缓存
 * @param size      要写入的数据长度
 * @return
 */
static int my_write(long offset, const uint8_t *buf, size_t size)
{
    rt_err_t result = RT_EOK;   // 返回值
    uint32_t startAddr;         // 操作起始地址
    uint32_t endAddr;           // 操作结束地址

    startAddr = onchip_flash_manager.addr + offset;
    endAddr = startAddr + size;

    // 因为写入时按字节存放,所以起始地址需要 4 的倍数
    if (startAddr % 4 != 0)
    {
        rt_kprintf("write addr must be 4-byte alignment\n");
        return -RT_EINVAL;
    }

    if (endAddr > STM32_FLASH_END_ADDRESS)
    {
        rt_kprintf("write outrange flash size! addr is (0x%p)\n", endAddr);
        return -RT_EINVAL;
    }

    HAL_FLASH_Unlock();

    while (startAddr < endAddr)
    {
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, startAddr, *((rt_uint32_t *)buf)) == HAL_OK)
        {
            if (*(rt_uint32_t *)startAddr != *(rt_uint32_t *)buf)
            {
                result = -RT_ERROR;
                break;
            }
            startAddr += 4;
            buf  += 4;
        }
        else
        {
            result = -RT_ERROR;
            break;
        }
    }

    HAL_FLASH_Lock();

    if (result != RT_EOK)
    {
        return result;
    }

    return size;
}

/**
 * fal 擦操作
 * @param offset    基于分区首地址的偏移
 * @param size      要擦除的区域大小
 * @return
 */
static int my_erase(long offset, size_t size)
{
   rt_err_t result = RT_EOK;                // 返回值
   uint32_t startAddr;                      // 操作起始地址
   uint32_t endAddr;                        // 操作结束地址
   FLASH_EraseInitTypeDef EraseInitStruct;  // flash 擦除结构体
   uint32_t PAGEError = 0;                  // 错误页

   startAddr = onchip_flash_manager.addr + offset;
   endAddr = startAddr + size;

   if ((endAddr) > STM32_FLASH_END_ADDRESS)
   {
       rt_kprintf("ERROR: erase outrange flash size! addr is (0x%p)\n", endAddr);
       return -RT_EINVAL;
   }

   HAL_FLASH_Unlock();

   EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
   EraseInitStruct.PageAddress = (uint32_t)RT_ALIGN_DOWN(startAddr, FLASH_PAGE_SIZE);
   EraseInitStruct.NbPages     = (size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;

   if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
   {
       result = -RT_ERROR;
       goto __exit;
   }

__exit:
   HAL_FLASH_Lock();

   if (result != RT_EOK)
   {
       return result;
   }

   rt_kprintf("erase done: addr (0x%p), size %d\n", startAddr, size);
   return size;
}

/**
 *  片内 flash 分区管理对象
 */
const struct fal_flash_dev onchip_flash_manager =
{
    .name = "onchip_flash_manager",   // 名称
    .addr = 0x08000000,                             // 首地址
    .len = 512 * 1024,                              // 管理 flash 片区大小
    .blk_size = 1 * 1024,                           // 用于擦除最小粒度的闪存块大小
    .ops = {RT_NULL, my_read, my_write, my_erase}
};

static void init_fal(void)
{
    fal_init();
}

//INIT_APP_EXPORT(init_fal);

static void fal_test(void)
{
    // 查找分区
    const struct fal_partition* fal_partition_data = fal_partition_find("data");
    if(fal_partition_data == NULL)
    {
        rt_kprintf("未找到 data 分区");
        return;
    }

    // 分区擦除
    int erase_result = fal_partition_erase(fal_partition_data, 0, 1024);
    if(erase_result < 0)
    {
        rt_kprintf("data 分区擦除失败");
        return;
    }

    // 分区写入
    char data_in[] = {0x01, 0x02, 0x03, 0x04, 0x05};
    int write_result = fal_partition_write(fal_partition_data, 0, data_in, 5);
    if(write_result < 0)
    {
        rt_kprintf("data 分区写入失败");
        return;
    }

    // 分区读出
    char data_out[5] = {0};
    int read_result = fal_partition_read(fal_partition_data, 0, data_out, 5);
    if(read_result < 0)
    {
        rt_kprintf("data 分区读取失败");
        return;
    }
    rt_kprintf("0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x\r\n",
            data_out[0], data_out[1], data_out[2], data_out[3], data_out[4]);

}

MSH_CMD_EXPORT(fal_test, fal_test);

  

#include "fal.h"
#define APP_VERSION "V1.1.1"
#define RT_APP_PART_ADDR 0x08010000     //程序启动运行地址
static int ota_app_vtor_reconfig(void)
{
    #define NVIC_VTOR_MASK   0x3FFFFF80
    /* Set the Vector Table base location by user application firmware definition */
    SCB->VTOR = RT_APP_PART_ADDR & NVIC_VTOR_MASK;

    return 0;
}
INIT_BOARD_EXPORT(ota_app_vtor_reconfig);

/* PLEASE DEFINE the LED0 pin for your board, such as: PA5 */
#define LED0_PIN    GET_PIN(A, 5)
#define key         GET_PIN(C, 13)

int main(void)
{
    int count = 1;
    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(key, PIN_MODE_OUTPUT);
    rt_pin_write(key, 0);
    rt_thread_mdelay(1000);
    rt_pin_write(key, 1);

    fal_init();
    LOG_D("version:%s\r\n",APP_VERSION);

    while (count++)
    {
        /* set LED0 pin level to high or low */
        rt_pin_write(LED0_PIN, count % 2);
        //LOG_D("Hello RT-Thread!");
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}

  烧录APP程序的时候一定要注意下载起始地址:0x8010000

 

查看串口打印数据:

 

 

查看网络是MC20是否正常联网:

 

 

 打包升级程序:

  • 打开目录packagesota_downloader-latesttoolsota_packager
  • 找到如下所示的生成软件包生成工具,并且打开

 

 

  • 点击选择固件找到主目录下的rtthread.bin文件
  • 添加固件区名固件版本然后打包
  • 成功后会在rtthread.bin文件的同一目录下生成rtthread.rbl文件

 

 

  • 打开串口输入help会打印帮助信息
  • 输入ymodem_ota执行升级命令

 

 

 

  • 在黑窗口点击鼠标右键–>传输–>YMODEM(Y)
  • 选择刚刚生成的rtthread.rbl文件,打开进行升级,如下图所示

 

 

 

  • 成功之后,会看到版本变化了,说明升级成功,如下图所示
  •  

     

 然后串口输入http_ota

需要NGINX搭建个web服务器  访问url地址可以自动下载打包好的文件

 

 由于flash 太小没有通过http升级成功。

 

小结

在线升级很多地方都能够用到,能够对产品的缺陷及时进行修复,当然这需要更大的Flash硬件资源,需要测试demo的可以QQ联系我 

我的QQ:319438908   欢迎大家一起来撩。

 

原文地址:https://www.cnblogs.com/wt88/p/12779442.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


  译序:JWMediaPlayer是开源的网页使用的Flash播放器。本文采摘于JWPlayer的官方文档,讲解了JWPlayer对于RTMP的使用方法,我们可以从JWPlayer客户端的角度来了解RTMP协议。以下是官方原文:      简介    RTMP(RealTimeMessagingProtocol
    Flash编程原理都是只能将1写为0,而不能将0写成1.所以在Flash编程之前,必须将对应的块擦除,而擦除的过程就是将所有位都写为1的过程,块内的所有字节变为0xFF.因此可以说,编程是将相应位写0的过程,而擦除是将相应位写1的过程,两者的执行过程完全相反.一、Nor和NandFlash
 上传setenvgatewayip192.168.1.1;setenvserverip192.168.1.7;setenvipaddr192.168.1.156;mw.b0x820000000xff0x1000000sfprobe0sfread0x8200000000x1000000tftp0x82000000test.bin0x1000000 下载mw.b82000000ff1000000tftp82000000test.bi
Error:FlashDownloadFailed-"Cortex-M3"出现一般有两种情况:1.SWD模式下,Debug菜单中,Reset菜单选项(Autodetect/HWreset/sysresetReq/Vectreset)默认是AutoDetect,改成SysResetReq即可。2.Jtag模式下,主要是芯片大小选错。Flash->ConfigureFalshTools配置窗口,切换到“Utilities"
jPlayer是一个用于控制和播放mp3文件的jQuery插件。它在后台使用Flash来播放mp3文件,前台播放器外观完全可以使用XHML/CSS自定义。支持:有一点比较好的是,在支持html5的浏览器上会使用html5的标签audio或者video,而不支持的浏览器上使用swf来播放选择需要播放的Mp3文件。播放、暂停
#ifndef__FONTUPD_H__#define__FONTUPD_H__#include"sys.h" //字库信息结构体定义33字节__packedtypedefstruct{u8fontok;//字库存在标志,0XAA,字库正常;其他,字库不存在u32ugbkaddr;//unigbk的地址u32ugbksize;//unigbk的大小u32f12addr;//gbk12地址u32g
ROM(ReadOnlyMemory)和RAM(RandomAccessMemory)指的都是半导体存储器。ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是在掉电之后就丢失数据,但是访问速度快。典型的RAM就是计算机的内存。RAM有两大类,一种称为静态RAM(StaticRAM/SRAM),SRAM速度非常快,是目前读写最快的存储
JSpc端和移动端实现复制到剪贴板功能实现在网页上复制文本到剪切板,一般是使用JS+Flash结合的方法,网上有很多相关文章介绍。随着HTML5技术的发展,Flash已经在很多场合不适用了,甚至被屏蔽。本文介绍的一款JS插件,实现了纯JS方法复制文本到剪切板。插件名是Clipboard.js,该插件不依
例子:R0=1R1=1R2=10R3=e000ed10R12=0LR=fffffff9(中断返回值)PC=0PSR=60000013或60000016或60000036(Z、C、EXCEPT_NUM:RTC_WKUP_IRQn、EXTI0_IRQn、USART2_IRQn)BFAR=e000ed38(不关心)CFSR=20000(INVSTATE:Invalidstateusagefault thePCvaluestackedf
 内存接口概念首先来分析下操作GPIO控制器和操作UART控制器两者的区别如图是S3C2440是个片上系统,有GPIO控制器(接有GPIO管脚),有串口控制器(接有TXDRXD引脚)配置GPIO控制器相应的寄存器,即可让引脚输出高低电平;配置UART控制器相应的寄存器,即可让引脚输出波形。前者相对简单,类
小编导语:    近几年来,网页游戏成为了游戏界关注的焦点,由于其制作简单,成本低并且收益率较高,因此成为了众多游戏厂商追逐的对象,但是除了商家夸张的炒作宣传外,很少有页游佳作出现。然而,随着Unity3D游戏引擎的出现,网页游戏的3D化成了页游冲出重围的杀手锏,那么在flash网页游戏称
1.指定数组到特定的Flash单元#pragmalocation=0x000FFF00 __rootconstcharFlash_config[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0
继续研究发现,计算机的固件真的很有趣。参考了一些重要的资料,比如http://donovan6000.blogspot.com/2013/06/insyde-bios-modding-advanced-and-power-tabs.html等,对于IDA的使用也了解了一些。最后,总结一下目前看来可行性的方案:0.基础知识储备,包括UEFIBIOS的概念,InsydeBIOS的
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>navigator对象<itle></head><body><buttononclick="checkFlash()">检测</button>
修改网上流传的flash-marker.js(function(global,factory){typeofexports==='object'&&typeofmodule!=='undefined'?module.exports=factory():typeofdefine==='function'&&define.amd?define(factory
shareObject本地缓存存储位置:win7系统用户到C:\Users\[你的用户名]\AppData\Roaming\Macromedia\FlashPlayer\#SharedObjects\XP或2003用户到:C:\DocumentsandSettings\用户名\ApplicationData\Macromedia\FlashPlayer\#SharedObjects\ ---------------------作者:iteye_
安装谷歌浏览器之后经常遇到Flash崩溃或者浏览器在浏览Flash内容时卡死的情况。在网上查找资料大多都认为应该是浏览器自带的Flash插件工作模式引起的问题,解决方法如下:首先在地址栏输入chrome://plugins/显示浏览器使用的插件。点击右上角的详细信息,可以看到Flash插件为进程外
之前一直使用的W25Q16spiflash都没问题,换了一款W25Q80后发现工作不正常,经过测试,初步定位到问题在于初始化SPI后是否将CS拉高。于是又去查看了一下原厂代码:发现原厂的代码初始化SPI接口时是专门拉高CS的。结论:网上很多代码初始化SPI接口时没有专门拉高CS,对某些型号可能确实
======================================================NANDFlash最小存储单元:写数据操作:通过对控制闸(ControlGate)施加高电压,然后允许源极(SOURCE)和汲极(RRAIN)间的N信道(N-Channel)流入电子,等到电流够强,电子获得足够能量时,便会越过浮置闸(FloatingGate)底下的二氧化硅层(S
安装CnarioPlayer3.8.1.156或其他版本时,有时会出现如下提示:Warning4154.AdobeFlashPlayer13...notcorrectlyinstalled:请前往AdobeFlash网站,并选择下图示的版本下载安装: