Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
Bootloader
flash
STM32F103
基于stm32f103rct6的bootloader写入flash
发布于 2021-06-22 16:31:43 浏览:1783
订阅该版
用到的**rt-thread studio**组件有:**finsh命令、DFS、Fatfs ** 用到的**Drivers**有:**串口、Pin、SPI、SFUD** IDE环境:RT-Thread Studio 2.1.0 ------------------------------------------------------------------------ 首先是打开**CubeMX Settings**把时钟、串口、SPI等打开 因为默认的**STM32F103RC**的封装是16k+256k的那种,所以要先点击左上角的芯片名字,把封装改为**LQFP64**,如果用的不是这种就不用改。 随后就是点击**System Core---RCC**一栏的HSE和LSE都设为**Crystal/Cerammic Resonator** 再配置时钟树**Clock Configuration**,我设置为最大的频率**72mhz**,随后在**Connectivity**一栏中打开SPI1,模式为**Full-Duplex Master**全双工主机模式。因为频率设为了**72mhz**,所以在SPI1下面的**Parameter Settings**中要把**Clock Parameters**的**Prescaler(for Baoud Rate)**改为4。 接下来设置USART1的Mode为**Asynchronous**,RS232默认为Disable。 可以将**PA2**设为**GPIO_Output**,因为F103RC的片选脚为PA2. 随后就是点击**Project Manager**,因为改了芯片的封装,所以这里的**Project Name**消失了,要手动把**cubemx**写上去,还要**ProjectLocation**和**Toolchain Folder Location**也要和项目的路径对上,**Toolchain/IDE**默认为EWARM就可以了。**Code Generator**中选择**Copy only the necessary library files**。另外把**Application Stucture**设置为**Basic** 然后点击右上角**Generate code**生成芯片配置。 ------------------------------------------------------------------------ 接下来是设置**RT-Thread Settings** 默认打开的组件有**finsh命令**、**串口**、**Pin**,所以我们要把接下来用到的**SPI**、**SFUD**、**DFS**、**Fatfs**单击鼠标左键打开。 其中**Fatfs**右键点击详细配置,把**设置要处理的最大扇区大小**改为**4096**,这是根据flash的性质设置的。 随后是点击上方的软件包的Add,把fal添加进去,这个软件包用了管理Flash和分区,右键详细配置,把FAL使用SFUD驱动程序勾选上,下面的扩展栏可以设置我们的使用FAL的设备名称,即我们的**片外Flash**名称。 设置好上面的组件和软件包后,按ctrl+s保存设置等待保存即可。 ------------------------------------------------------------------------ 接下来找到drivers中的board.h,找到**#define BSP_USING_SPI1**,把这行的注释取消,打开SPI1,在这一步可以把文件拉到最下面,把**#define BSP_USING_ON_CHIP_FLASH**片上Flash也打开。 随后可以在applications目录右键添加xxx.c源文件,进行spi flash的挂载。 用到的头文件有(可能有的并没有用到,具体看实现): ```c #include
#include "rtdevice.h" #include
#include
#include "spi_flash_sfud.h" #include
#include
#include "dfs_private.h" #include "fal.h" ``` **挂载spi_flash**用到了**_rt_hw_spi_device_attach(const char *bus_name, const char *device_name, GPIO_TypeDef *cs_gpiox, uint16_t cs_gpio_pin)_**函数,参数分别为:**bus_name**-挂载的总线名字,选用了**SPI1**,所以这里填“**spi1**”,**device_name**-设备名字,这里填“spi10”表示挂载在**spi1**上的0号设备,**gpiox**是打开哪个**GPIO**,看芯片资料知道**PA2**是我们的片选脚,所以这里填“GPIOA”,后面的**cs_gpio_pin**填“**GPIO_PIN_2**”。 还用到了**rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name)**函数把**spi flash**挂载到**spi10**设备上 详细代码: ``` static int rt_hw_spi_flash_init(void) { __HAL_RCC_GPIOA_CLK_ENABLE(); rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_2);// spi10 表示挂载在 spi1 总线上的 0 号设备,PA2是片选,这一步就可以将从设备挂在到总线中 if(RT_NULL == rt_sfud_flash_probe("w25qxx", "spi10")) { return -RT_ERROR; } return RT_EOK; } //初始化自动挂载设备 INIT_DEVICE_EXPORT(rt_hw_spi_flash_init); ``` ------------------------------------------------------------------------ 随后我们要对挂载的flash进行分区,才能进行后续的bootloader写入以及文件系统的创建。 找到项目中**fal-v0.5.0文件夹,打开里面的samples,点击README.md有详细教程**,主要要设置的是**fal_cfg.h**,并且要把项目drivers文件夹中的**drv_flash_f1.c**也要做相应设置。 要注意的地方就是**FAL_FLASH_DEV_TABLE**里面放的就是**flash分区表的内容** **FAL_PART_TABLE **就是进一步如何进行分区,这个要根据具体需求设置。不过要注意的就是用文档上的stm32通用bootload创建的话,必须要有“app”、“download”两个分区。 fal_cfg.h代码如下: ``` #ifndef _FAL_CFG_H_ #define _FAL_CFG_H_ #include
#include
#define NOR_FLASH_DEV_NAME "w25qxx" //自定义的片外flash名称 #define RT_APP_PART_ADDR 0x08020000 //修改app分区的首地址为0x08020000 #define FLASH_SIZE_GRANULARITY_16K (4 * 16 * 1024) #define FLASH_SIZE_GRANULARITY_64K (64 * 1024) #define FLASH_SIZE_GRANULARITY_128K (1 * 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_WORD, "bootloader", "onchip_flash_16k", 0, 48*1024, 0}, \ {FAL_PART_MAGIC_WORD, "release", "onchip_flash_16k", 48*1024, 16*1024, 0}, \ {FAL_PART_MAGIC_WORD, "easyflash", "onchip_flash_64k", 0, 64*1024, 0}, \ {FAL_PART_MAGIC_WORD, "app", "onchip_flash_128k", 0, 128*1024, 0}, \ {FAL_PART_MAGIC_WORD, "download", "w25qxx", 0, 1*1024*1024, 0}, \ {FAL_PART_MAGIC_WORD, "filesystem", "w25qxx", 1*1024*1024, 7*1024*1024, 0}, \ } #endif /* FAL_PART_HAS_TABLE_CFG */ #endif /* _FAL_CFG_H_ */ ``` 这里直接进行编译是过不了的,因为没有stm32_onchip_flash_16k、stm32_onchip_flash_64k、stm32_onchip_flash_128k的定义,所以我们要去到drivers文件夹中的drv_flash_f1.c中,找到 ``` const struct fal_flash_dev stm32_onchip_flash = { "onchip_flash", STM32_FLASH_START_ADRESS, STM_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase} }; ``` 改成相应的 ``` const struct fal_flash_dev stm32_onchip_flash_16k = { "onchip_flash_16k", STM32_FLASH_START_ADRESS_16K, FLASH_SIZE_GRANULARITY_16K, FLASH_PAGE_SIZE, {NULL, fal_flash_read_16k, fal_flash_write_16k, fal_flash_erase_16k} }; const struct fal_flash_dev stm32_onchip_flash_64k = { "onchip_flash_64k", STM32_FLASH_START_ADRESS_64K, FLASH_SIZE_GRANULARITY_64K, FLASH_PAGE_SIZE, {NULL, fal_flash_read_64k, fal_flash_write_64k, fal_flash_erase_64k} }; const struct fal_flash_dev stm32_onchip_flash_128k = { "onchip_flash_128k", STM32_FLASH_START_ADRESS_128K, FLASH_SIZE_GRANULARITY_128K, FLASH_PAGE_SIZE, {NULL, fal_flash_read_128k, fal_flash_write_128k, fal_flash_erase_128k} }; ``` 同理,要把上面的 ``` static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size); static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size); static int fal_flash_erase(long offset, size_t size); ``` 改为 ``` static int fal_flash_read_16k(long offset, rt_uint8_t *buf, size_t size); static int fal_flash_write_16k(long offset, const rt_uint8_t *buf, size_t size); static int fal_flash_erase_16k(long offset, size_t size); 。。。。。。 ``` 然后就是具体函数实现中的返回 ``` return stm32_flash_read(stm32_onchip_flash.addr + offset, buf, size); ``` stm32_onchip_flash改成对应的stm32_onchip_flash_16k、stm32_onchip_flash_64k、stm32_onchip_flash_128k。 然后samples中的fal_flash_sfud_port.c文件中,可以把宏定义的norflash0改为自己设置的名字“w25qxx”,修改结构体中的.name为 = “w25qxx”。 如无意外到这里可以进行spi flash的分区了。 ------------------------------------------------------------------------ 返回我们创建的xxx.c文件,在下面添加上 ``` static int flash_fal_init(void) { int res; res = fal_init(); //if(res) { //res = easyflash_init(); //} return res; } INIT_COMPONENT_EXPORT(flash_fal_init); ``` 或者main.c中while()循环外添加fal_init();进行flash分区。 ------------------------------------------------------------------------ 接下来就是文件系统的挂载写入。(同样在xxx.c文件下添加代码) 先定义一个宏 ``` #define FS_PARTITION_NAME "filesystem" ``` 随后在我们的flash分区上创建一个块设备,调用**fal_blk_device_create**函数 ``` struct rt_device *flash_dev = fal_blk_device_create(FS_PARTITION_NAME); if (flash_dev == NULL) { LOG_E("Can't create a block device on '%s' partition.", FS_PARTITION_NAME); } else { LOG_D("Create a block device on the %s partition of flash successful.", FS_PARTITION_NAME); } ``` 成功后在该块设备上挂载我们的文件系统 ``` /* 挂载 spi flash 中名为 "fs" 的分区上的文件系统 */ if (dfs_mount(flash_dev->parent.name, "/", "elm", 0, 0) == 0) { //这个dfs_mount()函数完成文件系统的挂载 LOG_I("Filesystem initialized!"); /* 初始化日志输出 */ //init_ulog_logfile(); } else { if (dfs_mkfs("elm", flash_dev->parent.name) == 0) { if (dfs_mount(flash_dev->parent.name, "/", "elm", 0, 0) == 0) { LOG_I("Filesystem initialized!"); /* 初始化日志输出 */ //init_ulog_logfile(); } else { LOG_E("Failed to mount filesystem!"); } } else { LOG_E("Failed to initialize filesystem!"); } } ``` 整个函数代码为: ``` static int app_mount(void) { /* 在 spi flash 中名为 "fs" 的分区上创建一个块设备 */ struct rt_device *flash_dev = fal_blk_device_create(FS_PARTITION_NAME); if (flash_dev == NULL) { LOG_E("Can't create a block device on '%s' partition.", FS_PARTITION_NAME); } else { LOG_D("Create a block device on the %s partition of flash successful.", FS_PARTITION_NAME); } /* 挂载 spi flash 中名为 "fs" 的分区上的文件系统 */ if (dfs_mount(flash_dev->parent.name, "/", "elm", 0, 0) == 0) { LOG_I("Filesystem initialized!"); /* 初始化日志输出 */ //init_ulog_logfile(); } else { if (dfs_mkfs("elm", flash_dev->parent.name) == 0) { if (dfs_mount(flash_dev->parent.name, "/", "elm", 0, 0) == 0) { LOG_I("Filesystem initialized!"); /* 初始化日志输出 */ //init_ulog_logfile(); } else { LOG_E("Failed to mount filesystem!"); } } else { LOG_E("Failed to initialize filesystem!"); } } return 0; } //初始化自动调用 INIT_ENV_EXPORT(app_mount); ``` ------------------------------------------------------------------------ 接下来就是**bootloader**的制作和下载。 首先就是跟着rt-thread官方stm32通用bootloader文档完成bootloader的制作,然后通过jlink等烧录工具烧录到芯片上。 需要注意的就是,bootloader制作时的app、download的偏移要和你分区的偏移对上,我这里因为rct6的片上flash只有256k,bootload还要128k保留空间地址,所以我把**app偏移地址设为0x20000**,大小为128k,**download放在了片外flash上**,因为片外flash起始地址为0,所以偏移地址设为0,大小设置为1024,剩下的7*1024留给文件系统使用。另外用到片外flash要勾选支持spi flash,引脚都要和芯片手册对应上。 看资料知道**rct6的ROM为256k、RAM为48k**,然后点击右上角生成等待即可。 烧写bootloader的起始地址选**0x08000000**,芯片选对应芯片。 ------------------------------------------------------------------------ 烧写bootload后再发现程序跑不动,因为这里烧写的app地址偏移了,我们要去项目的**linkscripts-stm32f103rc文件夹的link.lds修改ROM(rx)起始地址为0x08020000,大小为128k**(256减去bootload保留的128),另外要去**libraries-CMSIS-DEVICE-ST-STM32F1XX-Source-Templates找到system_stm32f1xx.c文件**,找到 ``` /*#define VECT_TAB_SRAM */ #define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field. This value must be a multiple of 0x200. */ ``` **修改0x00000000U为0x20000U,我们的app偏移量**。 ------------------------------------------------------------------------ 接下来返回到我们的fal_cfg.h文件,添加这个宏 ``` #define RT_APP_PART_ADDR 0x08020000 //修改app分区的首地址为0x08020000 ``` 然后去到我们的xxx.c文件,添加中断向量表的重定向函数 ``` /* * board 中断向量表重定向 */ 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); ``` ------------------------------------------------------------------------ 好像差不多就这样了,第一次写log,有说错或讲得不好的地方请多多包涵,谢谢~
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
巴菲特不非
这家伙很懒,什么也没写!
文章
3
回答
7
被采纳
1
关注TA
发私信
相关文章
1
Linux下通过USBTinyISP为Arduino开发板烧?写Bootloader
2
请教修改NVIC后RTT调度函数失效的问题[已解决 bootloader中打开了不必要的中断]
3
进入bootloader的方式探讨
4
求助:IAP里的APP使用的RTT,跳转后出错。[已解决]
5
有没有人在STM32F103上用UART IAP跑过RT-Thread?
6
想做网口的IAP远程升级,不知可不可行
7
IAP问题
8
[已解决]请教基于RTT的IAP程序切换到应用程序不成功的问题(基于STM32F4)?
9
stm32f4xx-----IAP移植APP程序需要注意的地方
10
在调试IAP网络升级遇到跳转之后bootloader程序网络不通
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
10
个答案
3
次被采纳
xiaorui
3
个答案
2
次被采纳
winfeng
2
个答案
2
次被采纳
三世执戟
8
个答案
1
次被采纳
KunYi
8
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
lizimu
2
篇文章
9
次点赞
swet123
1
篇文章
4
次点赞
Days
1
篇文章
4
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部