一结澄、Bootloader固件升級
RT-Thread 通用 Bootloader 的軟件框架
RT-Thread 通用 Bootloader 特點
- 以 bin 文件的形式提供,無需修改即可使用
- 資源占用小快鱼,ROM 最小只需要 16KB读第,最大 32KB
- 適用于多系列 STM32 芯片(目前支持 F1 和 F4 系列 )
- 支持各種 SPI Flash 存儲固件
- 支持固件加解密功能
- 支持多種固件壓縮方式
- 支持恢復(fù)出廠固件功能
1.固件升級過程
當(dāng)系統(tǒng)需要升級固件時曙博,Bootloader 將從 download
分區(qū)將固件搬運到 app
分區(qū),主要功能流程如下所示:
- Bootloader 啟動時檢查
download
分區(qū)和app
分區(qū)中的固件版本怜瞒。 - 如果兩個固件版本相同父泳,則跳轉(zhuǎn)到 app 分區(qū),Bootloader 運行結(jié)束吴汪。
- 固件版本不同則將
download
分區(qū)中的固件搬運到app
分區(qū)惠窄。 - 在搬運的過程中 Bootloader 可以對固件進(jìn)行校驗、解密漾橙、解壓縮等操作杆融。
- 搬運完畢后,刪除
download
分區(qū)中存儲的固件霜运。 - 重啟系統(tǒng)跳轉(zhuǎn)到
app
分區(qū)中的固件運行脾歇,Bootloader 運行結(jié)束。
2.獲取 Bootloader
根據(jù)板級實際情況選擇硬件配置和分區(qū)
3.工程設(shè)置分區(qū)表
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WROD, "download", "onchip_flash_128k", 0 , (128*1024), 0}, \
{FAL_PART_MAGIC_WROD, "app", "onchip_flash_128k", (1*128*1024) , FLASH_SIZE_GRANULARITY_128K-(128*1024), 0}, \
}
//onchip_flash_128k代表首地址為地址0x08020000基礎(chǔ)淘捡,偏移0, 長度為(128*1024)藕各,即128k
二、example程序使用
將示例程序添加到bsp/xxx/application文件夾下焦除,工程文件夾路徑下座韵,并在SConscript文件中加入其文件,在編譯時或生成工程時踢京,就會將文件加入工程之中執(zhí)行編譯
-
application的SConscript文件
import rtconfig from building import * cwd = GetCurrentDir() CPPPATH = [cwd, str(Dir('#'))] src = Split(""" application.c startup.c """) # add UI engine demo. if GetDepend('PKG_USING_GUIENGINE'): src += ['rtgui_demo.c'] src += ['tofile.c'] #將需要添加的文件加入src變量中 src += ['rtc_test.c'] group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) Return('group')
通過FINSH_FUNCTION_EXPORT或MSH_CMD_EXPORT 宏定義誉碴,可以將函數(shù)加入到Finsh或MSH的命令之中
1.使用Ymodem協(xié)議傳輸文件到RT-Thread文件系統(tǒng)
1)使能Ymodem組件
- 開啟RT-Thread Components ---> Utilities ---> Enable Ymodem
2)添加tofile.c應(yīng)用程序
- 將rt-thread\examples\ymodem\tofile.c文件添加到bsp工程的application文件夾中,并在其SConscript文件中添加tofile.c
3)修改文件默認(rèn)保存路徑
-
tofile.c默認(rèn)使用根目錄/保存文件瓣距,但ST的SPI Flash關(guān)連的文件系統(tǒng)掛載在/spi路徑下黔帕,所以需要將修改文件保存路徑,否則無法生成文件
static enum rym_code _rym_bg( struct rym_ctx *ctx, rt_uint8_t *buf, rt_size_t len) { struct custom_ctx *cctx = (struct custom_ctx*)ctx; cctx->fpath[0] = '/'; cctx->fpath[1] = 's'; cctx->fpath[2] = 'p'; cctx->fpath[3] = 'i'; cctx->fpath[4] = '/'; /* the buf should be the file name */ strcpy(&(cctx->fpath[5]), (const char*)buf);
4)增加msh命令
-
tofile.c默認(rèn)使用FinSH命令蹈丸,增加一個msh命令方便使用
//在tofile.c末尾添加 rt_err_t ymodem_rec(uint8_t argc, char **argv) { rt_err_t res; rt_device_t dev = rt_device_find(argv[1]); if (!dev) { rt_kprintf("could not find device:%s\n", argv[1]); return -RT_ERROR; } res = rym_write_to_file(dev); return res; } MSH_CMD_EXPORT(ymodem_rec, receive files by ymodem protocol);
5)使用Ymodem
- 編譯并燒錄程序成黄,使用SecureCRT連接調(diào)試串口
- 在msh命令中輸入:ymodem_rec uart1呐芥,準(zhǔn)備接收文件,在SecureCRT選擇Ymodem傳輸方式奋岁,選擇文件傳輸思瘟。
三、設(shè)備和驅(qū)動
RT_Thread設(shè)備類型定義
enum rt_device_class_type
{
RT_Device_Class_Char = 0, /**< character device */
RT_Device_Class_Block, /**< block device */
RT_Device_Class_NetIf, /**< net interface */
RT_Device_Class_MTD, /**< memory device */
RT_Device_Class_CAN, /**< CAN device */
RT_Device_Class_RTC, /**< RTC device */
RT_Device_Class_Sound, /**< Sound device */
RT_Device_Class_Graphic, /**< Graphic device */
RT_Device_Class_I2CBUS, /**< I2C bus device */
RT_Device_Class_USBDevice, /**< USB slave device */
RT_Device_Class_USBHost, /**< USB host bus */
RT_Device_Class_SPIBUS, /**< SPI bus device */
RT_Device_Class_SPIDevice, /**< SPI device */
RT_Device_Class_SDIO, /**< SDIO bus device */
RT_Device_Class_PM, /**< PM pseudo device */
RT_Device_Class_Pipe, /**< Pipe device */
RT_Device_Class_Portal, /**< Portal device */
RT_Device_Class_Timer, /**< Timer device */
RT_Device_Class_Miscellaneous, /**< Miscellaneous device */
RT_Device_Class_Sensor, /**< Sensor device */
RT_Device_Class_Unknown /**< unknown device */
};
char *const device_type_str[] =
{
"Character Device",
"Block Device",
"Network Interface",
"MTD Device",
"CAN Device",
"RTC",
"Sound Device",
"Graphic Device",
"I2C Bus",
"USB Slave Device",
"USB Host Bus",
"SPI Bus",
"SPI Device",
"SDIO Bus",
"PM Pseudo Device",
"Pipe",
"Portal Device",
"Timer Device",
"Miscellaneous Device",
"Sensor Device",
"Unknown"
};
rt-thread\bsp\stm32的資源配置在drv_config.h中選擇闻伶。
rt-thread\bsp\stm32\stm32f429-atk-apollo\board\CubeMX_Config\Src\stm32f4xx_hal_msp.c是芯片具體的資 源配置滨攻。
可以通過stm32cubemx生成資源配置文件。
1.Pin設(shè)備
應(yīng)用程序通過 RT-Thread 提供的 PIN 設(shè)備管理接口來訪問 GPIO蓝翰,相關(guān)接口如下所示:
函數(shù) | 描述 |
---|---|
rt_pin_mode() | 設(shè)置引腳模式 |
rt_pin_write() | 設(shè)置引腳電平 |
rt_pin_read() | 讀取引腳電平 |
rt_pin_attach_irq() | 綁定引腳中斷回調(diào)函數(shù) |
rt_pin_irq_enable() | 使能引腳中斷 |
rt_pin_detach_irq() | 脫離引腳中斷回調(diào)函數(shù) |
- 這些函數(shù)默認(rèn)沒有使用宏定義RTM_EXPORT將其導(dǎo)出到符號表光绕,如果動態(tài)模塊需要使用,則需要將其導(dǎo)出畜份。
1)獲取引腳編號
- 如果使用
rt-thread/bsp/stm32
目錄下的 BSP 則可以使用下面的宏獲取引腳編號- GET_PIN(port, pin)
- 如果使用其他 BSP 則需要查看 PIN 驅(qū)動代碼 drv_gpio.c 文件確認(rèn)引腳編號诞帐。此文件里有一個數(shù)組存放了每個 PIN 腳對應(yīng)的編號信息
- 如:STM32F429-apollo是基于STM32F4xx_PIN_NUMBERS == 176的芯片,參考rt-thread\bsp\stm32f429-apollo\drivers\drv_gpio.c的pins[]數(shù)組爆雹,PB.0和PB.1分別對應(yīng)index 56和57停蕉。
2.ADC
-
開啟adc需要把RT_USING_DEVICE_OPS也打開,否則看不到adc設(shè)備
- RT-Thread Kernel → Kernel Device Object → Using ops for each device object
-
rt-thread\bsp\stm32f429-apollo的drivers默認(rèn)沒有注冊adc設(shè)備的驅(qū)動钙态,需要自行添加
- 其stm32f4xx_hal_conf.h中也沒有define HAL_ADC_MODULE_ENABLED 需要自行打開注釋
3.UART
-
bsp\stm32\stm32f429-atk-apollo中只會初始化uart1慧起,需要在底層文件中添加uart2和uart3的初始化程序
- rt-thread\bsp\stm32\stm32f429-atk-apollo\board\CubeMX_Config\Src\stm32f4xx_hal_msp.c是芯片具體的資源配置
- stm32_configure -> HAL_UART_Init -> HAL_UART_MspInit(UART_HandleTypeDef* huart)
void HAL_UART_MspInit(UART_HandleTypeDef* huart) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(huart->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ } if (huart->Instance == USART2) { /* Enable USARTx clock */ __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PA2 ------> USART2_TX PA3 ------> USART2_RX */ GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART2_IRQn, 0, 1); HAL_NVIC_EnableIRQ(USART2_IRQn); } if (huart->Instance == USART3) { /* Enable USARTx clock */ __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PB10 ------> USART3_TX PB11 ------> USART3_RX */ GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART3; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART2_IRQn, 0, 1); HAL_NVIC_EnableIRQ(USART2_IRQn); } }