stm32f407单片机rt thread 片外spi flash OTA升级配置示例

参考地址https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/

第一步,生成BootLoader。

Bootloader 在线获取地址: http://iot.rt-thread.com

1.注册账号、新建产品。

点击固件升级、然后是生成BootLoader。

2.根据自己板子配置情况填写硬件信息。

我的板子上是用的STM32F407VGT6,ROM是1M,RAM是192K。

串口1为调试口,有一个片外的SPI flash,W25Q128,大小是128MBit即16MByte。

分区表配置

扫描二维码关注公众号,回复: 12230344 查看本文章

按照图上配置即

Bootloader的地址是0x08000000到0x08020000,大小是128K。

APP程序的地址是0x08020000到0x080ffff,大小是896K。

Download下载到片外SPI flash,片外SPI flash的起始地址是0x00000000,SPI flash空间足够大,分配上1024K。

加密和压缩和logo这些根据个人需要配置吧。然后生成BootLoader。

第二步,下载Bootloader程序。

打开STM32 ST-LINK Utility软件,连接上电路板,打开下载好的Bootloader程序,下载的起始地址为0x08000000然后点击下载。

程序运行起来后显示这样。

当然   这只是Bootloader程序运行起来了,和我们的应用程序没啥关系,我们继续制作应用程序部分。

第三步 在APP应用程序中添加spi flash驱动

1.准备一个现成的带rt thread系统的程序,且网络部分可以使用的工程,打开menuconfig。

进入目录Hardware Drivers Config-->Onboard Peripheral Drivers

打开Enable SPI FLASH

进入目录Hardware Drivers Config-->On-chip Peripheral Drivers

打开Enable SPI BUS

保存退出后使用pkgs --update更新一下软件包

然后使用scons --target=mdk5重新生成一下工程。

编译无错后添加一个spi_w25q.c文件,添加一下spi flash测试程序,看一下驱动是否正常。

测试代码如下:

#define SPI_BUS_NAME                    "spi1"

#define W25Q_SPI_DEVICE_NAME                 "spi10"
#define W25Q_FLASH_NAME                         "W25Q128"


rt_uint8_t wData[4096] = {"SPI bus write data to W25Q flash."};
rt_uint8_t rData[4096];

static int rt_hw_spi_flash_init()
{
    rt_err_t ree = RT_EOK;

    ree = rt_hw_spi_device_attach(SPI_BUS_NAME, W25Q_SPI_DEVICE_NAME, GPIOE, GPIO_PIN_1);
    /* 使用 SFUD 探测 spi10 从设备,并将 spi10 连接的 flash 初始化为块设备,名称 W25Q128 */
    if (RT_NULL == rt_sfud_flash_probe(W25Q_FLASH_NAME, W25Q_SPI_DEVICE_NAME))
    {
            return -RT_ERROR;
    }
    return ree;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
static void spi_w25q_sample(void)
{
    struct rt_spi_device *spi_dev_w25q;
    rt_uint8_t w25x_read_id = 0x90;
    rt_uint8_t id[5] = {0};

    /* 查找 spi 设备获取设备句柄 */
    spi_dev_w25q = (struct rt_spi_device *)rt_device_find(W25Q_SPI_DEVICE_NAME);
    if (!spi_dev_w25q)
    {
        rt_kprintf("spi sample run failed! can't find %s device!\n", W25Q_SPI_DEVICE_NAME);
    }
    else
    {
            rt_kprintf("spi sample run ok!\n");
            {
                struct rt_spi_configuration cfg;
                cfg.data_width = 8;
                cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0*/
                cfg.max_hz = 50 * 1000 * 1000; /* 50M */
                rt_spi_configure(spi_dev_w25q, &cfg);
            }
            /* 方式1:使用 rt_spi_send_then_recv()发送命令读取ID */
            rt_spi_send_then_recv(spi_dev_w25q, &w25x_read_id, 1, id, 5);
            rt_kprintf("use rt_spi_send_then_recv() read w25q ID is:%x%x\n", id[3], id[4]);
    }
}
MSH_CMD_EXPORT(spi_w25q_sample, spi w25q128 sample);

编译下载后运行spi_w25q_sample函数,读取flash 的ID号。

第四步 添加SFUD管理框架

我们在menuconfig中打开了Enable SPI FLASH后会在rtconfig.h中增加如下定义

默认使用了SFUD框架

然后在spi_w25q.c文件中增加以下代码,编译下载。

static void sfud_w25q_sample(void)
{
    rt_spi_flash_device_t flash_dev;
    sfud_flash_t sfud_dev;
    struct rt_device_blk_geometry geometry;

    // 1- use sfud api
    rt_kprintf("\n 1 - Use SFUD API \n");

    sfud_dev = rt_sfud_flash_find_by_dev_name(W25Q_FLASH_NAME);
    if(sfud_dev == RT_NULL){
        rt_kprintf("sfud can't find %s device.\n", W25Q_FLASH_NAME);
    }else{
        rt_kprintf("sfud device name: %s, sector_count: %d, bytes_per_sector: %d, block_size: %d.\n",
                    sfud_dev->name, sfud_dev->chip.capacity / sfud_dev->chip.erase_gran,
                    sfud_dev->chip.erase_gran, sfud_dev->chip.erase_gran);

        if(sfud_erase_write(sfud_dev, 0x002000, sizeof(wData), wData) == SFUD_SUCCESS)
            rt_kprintf("sfud api write data to w25q128(address:0x2000) success.\n");

        if(sfud_read(sfud_dev, 0x002000, sizeof(rData), rData) == SFUD_SUCCESS)
            rt_kprintf("sfud api read data from w25q128(address:0x2000) is:%s\n", rData);
    }

    // 2- use rt_device api
    rt_kprintf("\n 2 - Use rt_device API \n");

    flash_dev = (rt_spi_flash_device_t)rt_device_find(W25Q_FLASH_NAME);
    if(flash_dev == RT_NULL){
        rt_kprintf("rt_device api can't find %s device.\n", W25Q_FLASH_NAME);
    }else{
        rt_device_open(&flash_dev->flash_device, RT_DEVICE_OFLAG_OPEN);

        if(rt_device_control(&flash_dev->flash_device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry) == RT_EOK)
            rt_kprintf("spi flash device name: %s, sector_count: %d, bytes_per_sector: %d, block_size: %d.\n",
                    flash_dev->flash_device.parent.name, geometry.sector_count, geometry.bytes_per_sector, geometry.block_size);

        if(rt_device_write(&flash_dev->flash_device, 0x03, wData, 1) > 0)
            rt_kprintf("rt_device api write data to w25q128(address:0x3000) success.\n");

        if(rt_device_read(&flash_dev->flash_device, 0x03, rData, 1) > 0)
            rt_kprintf("rt_device api read data from w25q128(address:0x3000) is:%s\n", rData);

        rt_device_close(&flash_dev->flash_device);
    }
}
MSH_CMD_EXPORT(sfud_w25q_sample, sfud w25q128 sample);

执行sfud_w25q_sample函数

可以使用sf命令测试flash初始化、读写、擦除等。

flash初始化、读写测试正常。

第五步 添加fal管理框架

从上图可以看出FAL抽象层位于SFUD框架的上层,可以将多个Flash硬件(包括片内Flash和片外Flash)统一进行管理,并向上层比如DFS文件系统层提供对底层多个Flash硬件的统一访问接口,方便上层应用对底层硬件的访问操作。

打开menuconfig,进入RT-Thread online packages-->system packages

打开fal

SFUD设备名默认为norflash0,可以更改设备名为W25Q128,配置界面如下。

然后进入Hardware Drivers config -->on-chip peripheral Drivers

打开Enable on-chip FLASH

保存退出后使用pkgs --update更新软件包到本地,再用scons --target=mdk5重新生成工程。

打开工程编译后报错,找不到fal_cfg.h文件,我们添加一下fal_cfg.h的文件路径

文件路径是packages\fal-v0.5.0\samples\porting

然后打开fal_flash_sfud_port.c文件,

我们的flash型号为W25Q128,大小为16M,这里改为16 * 1024 * 1024。

编译一下,提示这些没有定义

默认的fal_cfg.h文件里没有定义stm32_onchip_flash_16k这些,

由于stm32f4系列的内部flash分布如下

flash块的大小有16k、64k、和128k三种,所以需要定义三种块设备。

我们打开fal_cfg.h文件更改成如下

#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#include <rtconfig.h>
#include <board.h>


#define RT_APP_PART_ADDR                0x08020000

#ifndef FAL_USING_NOR_FLASH_DEV_NAME
#define NOR_FLASH_DEV_NAME             "norflash0"
#else
#define NOR_FLASH_DEV_NAME              FAL_USING_NOR_FLASH_DEV_NAME
#endif


#define FLASH_SIZE_GRANULARITY_16K        (4 * 16 * 1024)
#define FLASH_SIZE_GRANULARITY_64K        (64 * 1024)
#define FLASH_SIZE_GRANULARITY_128K        (7 * 128 * 1024)

#define STM32_FLASH_START_ADRESS_16K    STM32_FLASH_START_ADRESS
#define STM32_FLASH_START_ADRESS_64K    (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
#define STM32_FLASH_START_ADRESS_128K    (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32_onchip_flash_16k;
extern const struct fal_flash_dev stm32_onchip_flash_64k;
extern const struct fal_flash_dev stm32_onchip_flash_128k;


/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32_onchip_flash;
extern struct fal_flash_dev nor_flash0;

/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &stm32_onchip_flash_16k,                                         \
    &stm32_onchip_flash_64k,                                         \
    &stm32_onchip_flash_128k,                                        \
    &nor_flash0,                                                     \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE                                                                                                  \
{                                                                                                                       \
        {FAL_PART_MAGIC_WROD, "bootloader",     "onchip_flash",                                    0,       128 * 1024, 0}, \
    {FAL_PART_MAGIC_WROD,        "app",     "onchip_flash",                           128 * 1024,       896 * 1024, 0}, \
    {FAL_PART_MAGIC_WROD,   "download", NOR_FLASH_DEV_NAME,                                            0,      1024 * 1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

#endif /* _FAL_CFG_H_ */

然后再次编译,没有错误了,然后在main函数里添加fal_init();,编译下载。

第六步 添加easyflash

打开menuconfig

进入RT-Thread online packages-->tools packages

打开EasyFlash

然后打开RT-Thread online packages-->IOT-internet of things

打开ota_downloader

保存退出后使用pkgs --update更新软件包,再使用scons --target=mdk5重新生成工程。

然后在keil工程中EasyFlash目录下添加el_fal_port.c文件

el_fal_port.c在packages\EasyFlash-v4.1.0\ports目录下。

然后编译下载有个错误

这个是在sockets.h和time.h里都定义了timeval这个结构体了。

然后把time.h里的timeval结构体换个名字,在time.c里也顺便一换,然后编译没有错误了。

然后在main.c文件里更改中断向量表和打印版本信息。

然后在这里更改程序下载地址,

然后重新下载bootloader,在下载keil编译的程序。

版本为0.0.0,然后在keil里更改版本号为0.0.1,然后编译生成bin文件

使用rt_ota_packaging_tool.exe工具生成rbl文件

然后在Xshell 6里输入ymodem_ota

然后使用Xshell里的ymodem工具将rbl文件发送给单片机

然后芯片会自动重启并更新程序

更新完成后版本号变成0.0.1   说明升级成功。

进入目录RT_Thread online packages-->IoT-internet of things-->

打开ota_downloader:The firmware downloader which using on RT-Thread

然后选中Enable OTA downloader debug和Enable Ymoden OTA

然后进入Hardware Drivers Config-->on-chip Peripheral Drivers-->Enable on-chip FLASH

保存退出后使用scons --target=mdk5命令生成MDK5的工程。

打开MDK5的工程,在Applications中添加进已经写好的应用程序,然后编译一下。

提示没有找到fal_cfg.h

添加一下fal_cfg.h文件路径

在packages\fal-v0.5.0\samples\porting下

然后再编译提示STM32_FLASH_START_ADRESS_16K这些没有定义,

然后打开fal_cfg.h文件,发现和官方文档里的不太一样

然后编译了一下正点原子的bsp和官方给的一样,复制过来如下。

源代码

#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#include <rtconfig.h>
#include <board.h>


#define RT_APP_PART_ADDR                0x08040000

#define NOR_FLASH_DEV_NAME             "norflash0"

#define FLASH_SIZE_GRANULARITY_16K        (4 * 16 * 1024)
#define FLASH_SIZE_GRANULARITY_64K        (64 * 1024)
#define FLASH_SIZE_GRANULARITY_128K        (7 * 128 * 1024)

#define STM32_FLASH_START_ADRESS_16K    STM32_FLASH_START_ADRESS
#define STM32_FLASH_START_ADRESS_64K    (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
#define STM32_FLASH_START_ADRESS_128K    (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32_onchip_flash_16k;
extern const struct fal_flash_dev stm32_onchip_flash_64k;
extern const struct fal_flash_dev stm32_onchip_flash_128k;

/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &stm32_onchip_flash_16k,                                         \
    &stm32_onchip_flash_64k,                                         \
    &stm32_onchip_flash_128k,                                                     \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE                                                               \
{                                                                                    \
    {FAL_PART_MAGIC_WORD,        "bl",     "stm32_onchip",         0,   64*1024, 0}, \
    {FAL_PART_MAGIC_WORD,       "app",     "stm32_onchip",   64*1024,  704*1024, 0}, \
    {FAL_PART_MAGIC_WORD, "easyflash", NOR_FLASH_DEV_NAME,         0, 1024*1024, 0}, \
    {FAL_PART_MAGIC_WORD,  "download", NOR_FLASH_DEV_NAME, 1024*1024, 1024*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

#endif /* _FAL_CFG_H_ */

然后再编译没有错了,在main函数里添加如下内容。

最重要的一步,修改APP固件的链接地址。

官方给的文档里这里填的是0x08040000,我们这里改为0x08020000

因为我们在BootLoader里配置的APP的起始地址是0x08020000,而不是0x08040000。这里和官方配置的不一样,一定要修改哦。

然后在fal_cfg.h文件里定义的RT_APP_PART_ADDR也改为0x08020000

然后编译下载,打印出当前版本号V0.0.0

第四步  打包APP固件

使用 RT-Thread OTA 固件打包器对 app 固件进行打包,制作可以被下载到 download 分区的升级固件。固件打包工具可以在 ota_downloader 软件包下的 tools 文件夹内找到。

  1. 在对固件进行打包操作前,先修改 stm32f407-atk-explorer/applications/main.c 中 APP_VERSION 宏的值为 2.0.0 作为参照,然后重新编译一遍生成新的 rtthread.bin 文件,修改内容如下图所示:

2.双击打开 tools\ota_packager\rt_ota_packaging_tool.exe 程序,使用 OTA 固件打包工具将上一步编译出的 rtthread.bin 文件打包成可被升级的 rtthread.rbl 文件,如下图所示:

第五步 执行OTA升级

使用mywebserver软件找到rbl文件所在目录,IP地址选择本机IP地址然后点击启动。

开发板通电,等待获取IP地址成功后再shell里输入http_ota http://192.168.1.72/rtthread.rbl即可开始OTA升级

我这里使用了{"cmd":"robotset2","model":"b1","robot_id":"1503090496","data":{"updata":"http://192.168.2.119/rtthread.rbl"}}

这个命令通过TCP开始远程升级的。

使用shell过程是一样的,下载完成后系统自动重启

猜你喜欢

转载自blog.csdn.net/qq_25186745/article/details/107121699