小熊派开发板移植RT-FOTA
前言
买了小熊派的开发板,将demo code验证完成之后就放下了。刚好最近工作也在做OTA相关的开发,发现自己对于升级的功能还不够了解,在码云找到了一位大神基于RTThread的RT-FOTA代码,基本与RTThread的BootLoader功能一致,闲来无事,将这个移植适配到小熊派开发板。
一、RT-FOTA介绍
码云仓库中的地址为 https://gitee.com/Aladdin-Wang/RT-FOTA-STM32L431
摘抄自仓库的readme:
为了能让开发者快速掌握 OTA 升级这把利器,RT-Thread 开发团队提供了通用的Bootloader。开发者通过该 Bootloader 即可直接使用 RT-Thread OTA 功能,轻松实现对设备端固件的管理、升级与维护。
下图展示了 RT-Thread 通用 Bootloader 的软件框架:
RT-Thread 开发团队的官方Bootloader以bin文件形式提供, 在线获取地址: http://iot.rt-thread.com
RT-FOTA功能介绍:
- 支持RTT官方的RBL打包软件,使用方式也一致。目前支持包括CRC32、AES256、quicklz和fastlz功能;
- 支持命令行模式(FINSH组件)和出厂固件恢复;
- 支持FLASH分区(FAL组件);
- 增加fota和ymdown命令;
- 其他功能可自行方便扩展;
关于RT-FOTA的基本移植操作请参看代码仓库的readme
二、适配驱动外设的代码
下载源码之后,里面包括了stm32f429和stm32l431的两个boot工程和一个stm32f429的app工程。
由于小熊派开发板使用的stm32L431,我们基于stm32L431的工程进行代码适配移植。
2.1 修改signal_led的配置
在rtconfig.h中配置小熊派开发板LED
#define RT_FOTA_SIGNAL_LED
#define RT_FOTA_SIGNAL_LED_GPIOX GPIOC
#define RT_FOTA_SIGNAL_LED_GPIO_PIN GPIO_PIN_13
#define RT_FOTA_SIGNAL_LED_ON_LEVEL GPIO_PIN_RESET
2.2 修改按键的配置
在rtconfig.h中配置小熊派开发板KEY1
#define RT_FOTA_DEFAULT_KEY
#define RT_FOTA_DEFAULT_KEY_CHK_TIME 10
#define RT_FOTA_DEFAULT_KEY_GPIOX GPIOB
#define RT_FOTA_DEFAULT_KEY_GPIO_PIN GPIO_PIN_2
#define RT_FOTA_DEFAULT_KEY_LEVEL GPIO_PIN_SET
2.3 修改QSPI配置
由于小熊派开发板的spi flash使用的QSPI,与传统SPI配置方式不同,这里需要进行修改。
2.3.1 在cubeMX中配置小熊派的QSPI脚,生成对应代码
在rtconfig.h中修改如下
#define SFUD_USING_QSPI
/* Onboard Peripheral Drivers */
#define BSP_DATAFALSH_CS_GPIOX GPIOB
#define BSP_DATAFALSH_CS_GPIO_PIN GPIO_PIN_11
#define FAL_USING_SFUD_PORT
#define FAL_USING_NOR_FLASH_DEV_NAME "W25Q64JV"
这里我使用了SFUD库,所以需要在SFUD中进行QSPI接口的适配。在sfud.port.c中增加
#include "quadspi.h"
typedef struct
{
QSPI_HandleTypeDef *spix;
GPIO_TypeDef *cs_gpiox;
uint16_t cs_gpio_pin;
} spi_user_data, *spi_user_data_t;
#ifdef SFUD_USING_QSPI
extern QSPI_HandleTypeDef hqspi;
static spi_user_data user_spi = { .spix = &hqspi, .cs_gpiox = GPIOB, .cs_gpio_pin = GPIO_PIN_11 };
#define MX_SPI_Init() MX_QUADSPI_Init();
#endif
sfud_err sfud_spi_port_init(sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
/**
* add your port spi bus and device object initialize code like this:
* 1. rcc initialize
* 2. gpio initialize
* 3. spi device initialize
* 4. flash->spi and flash->retry item initialize
* flash->spi.wr = spi_write_read; //Required
* flash->spi.qspi_read = qspi_read; //Required when QSPI mode enable
* flash->spi.lock = spi_lock;
* flash->spi.unlock = spi_unlock;
* flash->spi.user_data = &spix;
* flash->retry.delay = null;
* flash->retry.times = 10000; //Required
*/
rt_mutex_init(&lock, "sfud_lock", RT_IPC_FLAG_FIFO);
MX_SPI_Init();
// #if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F0) \
// || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32G0)
//
// SET_BIT(hqspi.Instance->CR2, SPI_RXFIFO_THRESHOLD_HF);
// #endif
switch (flash->index) {
case SFUD_W25Q64JV_DEVICE_INDEX: {
/* ͬ²½ Flash ÒÆÖ²ËùÐèµÄ½Ó¿Ú¼°Êý¾Ý */
flash->spi.wr = spi_write_read;
flash->spi.lock = spi_lock;
flash->spi.unlock = spi_unlock;
flash->spi.user_data = &user_spi;
/* about 100 microsecond delay */
flash->retry.delay = retry_delay_100us;
/* adout 60 seconds timeout */
flash->retry.times = 60 * 10000;
break;
}
}
return result;
}
在sfud_cfg.h中修改flash设备name
enum {
SFUD_W25Q64JV_DEVICE_INDEX = 0,
};
#define SFUD_FLASH_DEVICE_TABLE \
{ \
[SFUD_W25Q64JV_DEVICE_INDEX] = {.name = "W25Q64JV", .spi.name = "SPI1"}, \
}
三、配置分区表
这里我没有再去修改代码中的分区大小设置,因为感觉BootLoader的功能非常多,后续可能也会拓展一些新功能进来,所以仍然采用如下的分区方式:
#define PKG_USING_FAL
#define FAL_DEBUG 1
#define FAL_PART_HAS_TABLE_CFG
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WROD, "app", "onchip_flash", 64*1024, 192*1024, 0}, \
{FAL_PART_MAGIC_WROD, "ef", FAL_USING_NOR_FLASH_DEV_NAME, 0 , 1024 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "download", FAL_USING_NOR_FLASH_DEV_NAME, 1024 * 1024 , 512 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "factory", FAL_USING_NOR_FLASH_DEV_NAME, (1024 + 512) * 1024 , 512 * 1024, 0}, \
}
四、编译运行
进行编译后单独烧录BootLoader,可以看到启动的日志如下:
这里整个的移植就完成了。