|
本帖最后由 zwmasdf 于 2018-1-11 17:04 编辑
之前在i.MX rt板块经常看到i.MX RT最新支持XXX Flash的下载算法,于是冒出一个问题,下载算法是啥。故花时间研究了一下
1、首先了解一下下载算法是啥东东
研究过程中参考了这篇文章:https://jingyan.baidu.com/article/414eccf64f03be6b431f0af8.html
经过研究得出结论(可能结论不是很准),下载算法本身是一段读写存储介质的接口函数(生动的说法应该是驱动函数),
这里的存储介质可以是内部/外部RAM,也可以是内部/外部FLASH/EEPROM,FLASH可以是并口也可以是串口等等,这里不一一列举。
仿真器应该通过调试接口将驱动接口程序下载到单片机内部默认的RAM中,这种RAM只能是内置的默认首选RAM,且上电无需初始化就能直接用的
然后通过驱动接口将程序代码烧录至指定的位置。
2.那么怎么实现下载到SPI FLASH呢
1.首先准备1块开发板,我手头有1块STM32F103RCT6的开发板,并且PA4(CS),PA5(SCK),PA6(MISO),PA7(MOSI)连到W25Q32FV上
2.打开 MDK安装目录/ARM/Flash 发现有1个STM32F10x_M25P64的文件夹,发现这个文件夹用于生成STM32F10x_M25P64.FLM,
也就是MDK提供了一份SPI FLASH下载的模板,但是不能直接用于W25Q32,需要稍加修改
于是将STM32F10x_M25P64文件夹拷贝一份并改名为STM32F10x_W25Q32,打开工程,由于该工程针对STM32F1系列的外部FLASH,故不需要重新选定单片机型号
打开option选项设置界面,进入User,将Run#1中的内容改为cmd.exe /C copy Out\STM32F10x_M25P64.axf ..\STM32F10x_W25Q32.FLM,这样编译后会生成对应的W25Q的下载算法文件
如图
接着修改文件FlashDev.c,修改FlashDevice的相关属性,这里我将Device Name改为STM32F10X W25Q32 SPI Flash,便于MDK识别
Device Type保持EXTSPI不变,Device Start Address保持0xC0000000不变, Device Size in Bytes改为0x00400000,因为W25Q32是4MBFlash
这2个值很重要,凡是程序中位于Device Start Address及其长度范围内的代码及数据(RO段)都会下载到SPI Flash中去
还有1个关键的数据是倒数第2行数,扇区大小是4KB,扇区起始地址是0,若后面每个扇区大小都一致,则以SECTOR_END结尾即可(其原理参考MDK下的_Template工程)
参考图
然后是spi_flash.c,修改如下
#define RDID 0x90 /* Read identification */
#define SE 0x20 /* Sector Erase instruction */
#define BE 0xD8 /* Bulk Erase instruction */
#define Dummy_Byte 0xFF
- void SPI_FLASH_Init(void)
- {
- SPI_InitTypeDef SPI_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
-
- /* Enable SPI1, GPIOA and GPIOBclocks */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE);
-
- /* Configure SPI1 pins: SCK, MISO and MOSI */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- /* Configure PA.4 as Output push-pull, used as Flash Chip select */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- /* Deselect the FLASH: Chip Select high */
- SPI_FLASH_CS_HIGH();
- /* SPI1 configuration */
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CRCPolynomial = 7;
- SPI_Init(SPI1, &SPI_InitStructure);
-
- /* Enable SPI1 */
- SPI_Cmd(SPI1, ENABLE);
- }
复制代码 然后修改spi_flas.h,修改spi的CS引脚硬件信息 #define SPI_FLASH_CS_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_4)
/* Deselect SPI FLASH: ChipSelect pin high */
#define SPI_FLASH_CS_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_4)
最后编译,发现Flash文件夹下多了STM32F10x_W25Q32.FLM这个文件
3. 为了测试是否能正常下载,我写了一个写SPI Flash数据的代码,目的是将SPI FLASH中第1个扇区的数据全部设为0xa5,核心代码如下
uint8_t wr[4096] = {0}, rd[4096] = {0};
W25QXX_Erase_Sector(0x00);
memset(wr, 0xa5, sizeof(wr));
W25QXX_Write_NoCheck(wr, 0, sizeof(wr));
W25QXX_Read(rd, 0, sizeof(rd));//这里读出来,通过仿真器得知确实所有数据变成了0Xa5
4. 写1个针对SPI Flash下载算法的程序,目的是能自动烧录数据至 SPI FLASH
通过STMCubeMX生成1个STM32F103RCT6的最小程序,修改配置信息,增加1个外部ROM字段,起始地址和之前算法程序中的Device Start Address一致,由于我们就烧录几个字节, 长度这里调小点我们先设为0x100,实际可以设为1个扇区或直接整个FLASH大小(前提扇区信息填完整),如下
新建1个dat.c,里面就假如几行代码,如下所示
#include "stm32f1xx_hal.h"
const uint8_t dat[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
右击dat.c,选择options for File 'dat.c',将Code /Const: 区域改为ROM1[0xC0000000-0xC00000FF],
这样dat.c生成的dat.o将位于0xc0000000区域,即位于SPI Flash区域
注意为了防止编译器优化dat数组,务必将工程编译等级调为-O0,同时去掉One ELF Section per Function勾选
添加SPI FLASH的烧录算法,如图
编译,下载(注意不是Debug下载,直接点Flash下载,不用调试)
5.写一个读Flash代码,将之前的写Flash代码注释写部分
uint8_t wr[4096] = {0}, rd[4096] = {0};
//W25QXX_Erase_Sector(0x00);
//memset(wr, 0xa5, sizeof(wr));
//W25QXX_Write_NoCheck(wr, 0, sizeof(wr));
W25QXX_Read(rd, 0, sizeof(rd));//这里读出来,通过仿真器得知rd[0]和rd[9]确实变成了dat数组的内容, 至于rd[10]和rd[11]变成0是由于dat数组4字节对齐补了2个0导致的,rd[12]以上则全变为了0XFF
如图
至此,实验成功
这里注意的1点是整片文章共有4个工程,1.写Flash工程,用于初始化SPI Flash数据 2.烧录算法工程,用来第3个工程下载用
3.执行烧录算法的工程 4.读Flash工程,用于验证烧录算法是否将工程3的外部Flash数据烧进外部Flash中去(可以从工程1改)
烧录顺序从1,3,4, (2不用烧录)
|
评分
-
查看全部评分
|