今天开始写日志总结顺便再复习一下。
软件:RT-Thread Studio
硬件:正点原子探索者开发板 芯片 STM32F407ZG
(一)BOOTLOADER:
相比较引导Linux使用的Uboot而言,RTThread使用的bootloader 系统引导程序稍微简单一点。
RTThread 官方BOOTLOADER生成地址:http://iot.rt-thread.com
贴一下生成步骤
使用STM32 ST-LINK Utility软件将收到的rtboot_f4.bin烧入到板子的flash
验证一下bootloader,由于此时app分区还没有对应的app程序,所以会卡住:
(二)APP
1.使用RTThread Studio新建F4工程;
2.可以使用有线或者无线将开发板联网。这里使用的时ESP8266接入wifi连入互联网。
3.添加FAL分区表,使APP对应的分区和bootloader分区一致,否则在使用OTA升级时下载的分区不对,重启时,bootloader无法获取到新的的固件。
4.添加OTA软件包
5.修改APP的中断向量表存放地址以及APP开始地址。
实现上述四个步骤即可完成开发板的OTA升级功能。
使能ESP8266:
在board.h中添加对UART3的定义,是能UART3
至此,esp8266已经可以工作。
FAL对ON_CHIP_FLASH进行分区:
打开BSP_USING_ON_CHIP_FLASH与HAL_FLASH_MODULE_ENABLED宏
定义FAL分区表,创建fal_cfg.h,内容如下
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-06-13 rwz the first version
*/
#ifndef DRIVERS_INCLUDE_FAL_CFG_C_
#define DRIVERS_INCLUDE_FAL_CFG_C_
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-06-11 rwz the first version
*/
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#include <rtthread.h>
#include <board.h>
#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)
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_128k, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WROD, "app", "onchip_flash_128k", 0 , 256*1024 , 0}, \
{FAL_PART_MAGIC_WROD, "download","onchip_flash_128k", 256*1024 ,256*1024, 0}, \
{FAL_PART_MAGIC_WROD, "factory","onchip_flash_128k", 512*1024,256*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
#endif /* DRIVERS_INCLUDE_FAL_CFG_C_ */
修改中断向量表位置
#define RT_APP_PART_ADDR 0x8020000
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);
修改程序链接脚本中ROM的起始地址
在main函数中调用fal_init()对设置的分区表进行初始化;
int main(void)
{
int count = 1;
fal_init();
while (count++)
{
// LOG_D("Hello RT-Thread!");
rt_thread_mdelay(1000);
}
return RT_EOK;
}
编译程序,下载到开发板试运行一下FAL分区表是否正确。
根据结果可以看到程序已经成功的加载运行,对应的分区表也是对的。剩下的问题就是类似tftp的功能,把对应的升级固件获取到,然后写入到对应的downloaderFLASH分区就可以了,
我是直接使用的RT-Thread对应的ota软件包(因为懒)。
打开RT-Thread Settings,添加ota-downloader软件包,设置如下:
编译下载到开发板进行http_ota升级,发现下载到一定位置会下载失败,如图所示。
在不断的摸索和问度娘下,发现在http_ota_fw_download函数里出现了问题。原函数如下,大概分为以下几步:
1.创建session
2.get连接webserver
3.获取文件大小
4.擦除分区对应的大小
5.接收文件写入FLASH
可能是因为擦除FLASH十分耗时,导致web连接失败的情况。
static int http_ota_fw_download(const char* uri)
{
int ret = 0, resp_status;
int file_size = 0, length, total_length = 0;
rt_uint8_t *buffer_read = RT_NULL;
struct webclient_session* session = RT_NULL;
const struct fal_partition * dl_part = RT_NULL;
/* create webclient session and set header response size */
session = webclient_session_create(GET_HEADER_BUFSZ);
if (!session)
{
LOG_E("open uri failed.");
ret = -RT_ERROR;
goto __exit;
}
/* send GET request by default header */
if ((resp_status = webclient_get(session, uri)) != 200)
{
LOG_E("webclient GET request failed, response(%d) error.", resp_status);
ret = -RT_ERROR;
goto __exit;
}
file_size = webclient_content_length_get(session);
rt_kprintf("http file_size:%d\n",file_size);
if (file_size == 0)
{
LOG_E("Request file size is 0!");
ret = -RT_ERROR;
goto __exit;
}
else if (file_size < 0)
{
LOG_E("webclient GET request type is chunked.");
ret = -RT_ERROR;
goto __exit;
}
/* Get download partition information and erase download partition data */
if ((dl_part = fal_partition_find("download")) == RT_NULL)
{
LOG_E("Firmware download failed! Partition (%s) find error!", "download");
ret = -RT_ERROR;
goto __exit;
}
LOG_I("Start erase flash (%s) partition!", dl_part->name);
if (fal_partition_erase(dl_part, 0, file_size) < 0)
{
LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name);
ret = -RT_ERROR;
goto __exit;
}
LOG_I("Erase flash (%s) partition success!", dl_part->name);
buffer_read = web_malloc(HTTP_OTA_BUFF_LEN);
if (buffer_read == RT_NULL)
{
LOG_E("No memory for http ota!");
ret = -RT_ERROR;
goto __exit;
}
memset(buffer_read, 0x00, HTTP_OTA_BUFF_LEN);
LOG_I("OTA file size is (%d)", file_size);
do
{
length = webclient_read(session, buffer_read, file_size - total_length > HTTP_OTA_BUFF_LEN ?
HTTP_OTA_BUFF_LEN : file_size - total_length);
if (length > 0)
{
/* Write the data to the corresponding partition address */
if (fal_partition_write(dl_part, total_length, buffer_read, length) < 0)
{
LOG_E("Firmware download failed! Partition (%s) write data error!", dl_part->name);
ret = -RT_ERROR;
goto __exit;
}
total_length += length;
print_progress(total_length, file_size);
}
else
{
LOG_E("Exit: server return err (%d)!", length);
ret = -RT_ERROR;
goto __exit;
}
} while(total_length != file_size);
ret = RT_EOK;
if (total_length == file_size)
{
if (session != RT_NULL)
webclient_close(session);
if (buffer_read != RT_NULL)
web_free(buffer_read);
LOG_I("Download firmware to flash success.");
LOG_I("System now will restart...");
rt_thread_delay(rt_tick_from_millisecond(5));
/* Reset the device, Start new firmware */
extern void rt_hw_cpu_reset(void);
rt_hw_cpu_reset();
}
__exit:
if (session != RT_NULL)
webclient_close(session);
if (buffer_read != RT_NULL)
web_free(buffer_read);
return ret;
}
最终的解决是在连接之前可以针对整个download分区进行擦除,然后在进行web连接,或者先l连接获取文件大小--->断开连接--->进行擦除--->再次 连接--->获取文件大小进行比对--->传输文件写入FLASH。
再次尝试结果:
注意:固件打包器中的选项跟BOOTLOADER选项必须一致。BOOTLOADER我选择了GZIP压缩,这里也必须选上。