今天開始寫日志總結順便再復習一下。
軟件: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壓縮,這里也必須選上。