概述

本教程主要根据官方推荐的教程进行改编,详细信息请参考
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   欢迎大家一起来撩。

RT-Thread—STM32—在线升级(Ymodem_OTA、HTTP_OTA)的更多相关文章

  1. STM32 IAP 在线升级详解(转)

    源:http://blog.csdn.net/yx_l128125/article/details/12992773 (扩展-IAP主要用于产品出厂后应用程序的更新作用,考虑到出厂时要先烧写IAP   ...

  2. 【转载】STM32 IAP 在线升级详解

      (扩展-IAP主要用于产品出厂后应用程序的更新作用,考虑到出厂时要先烧写IAP  再烧写APP应用程序要烧写2次增加工人劳动力基础上写了“STM32 IAP+APP ==>双剑合一”链接稍后 ...

  3. android 在线升级借助开源中国App源码

    android 在线升级借助开源中国App源码 http://www.cnblogs.com/luomingui/p/3949429.html android 在线升级借助开源中国App源码分析如下: ...

  4. STM32 IAP升级

    STM32 IAP在线升级,用Jlink设置读保护后前5K字节是默认加了写保护的,导致IAP升级时擦除和写入FLASH不成功,可以做两个boot,前5k为第一个boot程序,上电时负责跳转到APP还是 ...

  5. C#做的在线升级小程序

    转自原文C#做的在线升级小程序 日前收到一个小任务,要做一个通用的在线升级程序.更新的内容包括一些dll或exe或.配置文件.升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的 ...

  6. 【WCF】基于WCF的在线升级

    一.前言       前不久因公司产品需要完成了在线升级功能,因为编程技术不精,不敢冒然采用Socket方法实现在线升级,所以使用比较方便稳妥的WCF方式 如果考虑并发能力的话还是Socket> ...

  7. dsp 28377在线升级 实例总结

    使用dsp品台28377d来实现在线升级的功能. 方案 : 升级程序  +  应用程序 升级程序 : 主要的目的是将上位机发送过来的应用程序数据(ccs编译生成的.bin文件)烧写到指定位置,之后在跳 ...

  8. 关于DSP的boot mode / boot loader /上电顺序 /在线升级等问题的总结

    使用器件 ti dsp c2000 2837x 1.dsp的上电过程和boot mode以及boot loader 1)dsp的上电顺序, 对于双核系统而言 , 他的上电启动顺序如下所示: 系统复位或 ...

  9. Encrypting bootloader (程序BIN文件加密及在线升级)

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 在上一个博客随笔,我介 ...

随机推荐

  1. Typora+markdown 最常用语法教程

    Typora+markdown 最常用语法教程(by 程序员宝藏) Typora+markdown 最常用语法教程(by 程序员宝藏) 请先配置推荐配置(文件->偏好设置): 文章目录 Typo ...

  2. React Hooks Typescript 开发的一款 H5 移动端 组件库

    CP design 使用 React hooks Typescript 开发的一个 H5 移动端 组件库 English | 简体中文 badge button icon CP Design Mobi ...

  3. setAttribute 方法

    IE8及以下不支持 setAttribute用来修改dom标签上的属性比如(onclick); getAttribute用来获取dom标签上的属性

  4. Eclipse无法查看第三方jar包源代码解决

    我在csdn写了过了:https://blog.csdn.net/weixin_40404606/article/details/105174820

  5. 9.Maven的生命周期

    Clean Lifecycle: 在进行真正的构建之前进行一些清理工作. Default Lifecycle :构建的核心部分,编译,测试,打包,部署等等. Site Lifecycle : 生成项目 ...

  6. 线程间交换数据的Exchanger

    作者:Steven1997 链接:https://www.jianshu.com/p/9b59829fb191 来源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处. Exc ...

  7. 马哥教育PYTHON相关基础 笔记

    1 python 推荐书籍 <python Cookbook> <learn python the hard way> <google's python class> ...

  8. D - Super Jumping! Jumping! Jumping!

    Nowadays, a kind of chess game called "Super Jumping! Jumping! Jumping!" is very popular i ...

  9. 1008 Elevator (20 分)

    The highest building in our city has only one elevator. A request list is made up with N positive nu ...

  10. PTA | 1020. 月饼 (25)

    月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼.现给定所有种类月饼的库存量.总售价.以及市场的最大需求量,请你计算可以获得的最大收益是多少. 注意:销售时允许取出一部分库存.样 ...