STM32 HAL库形式制作SPI Flash(W25Q16)的 Keil下载算法

常见的SPI Flash:W25Qxx系列,本文以W25Q16为实例制作Keil下载算法。

如下图,红框内的东西就是下载算法。

只要导入下载算法后,就可以在烧录MCU的同时对W25Q16页进行烧录。此操作可方便LCD运用场景,字库、图片存放在外部Flash的烧录。

实际操作:

1、硬件:STM32G030C8T6、W25Q16(2MB FLASH)

2、算法对应的硬件连接图:

3、工程搭建:

①进入keil安装目录下的 \ARM\Pack\ARM\CMSIS\version\Device 路径(vesion为实际安装的keil pack的版本号),将 _Template_Flash 文件夹拷贝出来,以此为工程模板。

②用keil打开工程,点击“魔术棒”,Target页面下,编译器版本要选择V5.xx的。

Device页面,选择对应的单片机型号。

Ouput页面,设置生成文件的名称。

User页面,设置如下:

cmd.exe /C copy "Flash_Algx\%L" ".\@L.FLM"

cmd.exe /C copy ".\@L.FLM" "C:\Keil_v5\ARM\Flash\@L.FLM"

(C:\Keil_v5 为Keil的安装路径,ARM\Flash为路径下的下载算法存放地址)

C/C++页面,设置如下。

ASM页面,设置如下。

Linker页面,设置如下。

点击中间那个红框中的“Edit”,

打开后的文件内容为(如果与下面的代码不符,则手动修改):

; Linker Control File (scatter-loading)

;

PRG 0 PI ; Programming Functions

{

PrgCode +0 ; Code

{

* (+RO)

}

PrgData +0 ; Data

{

* (+RW,+ZI)

}

}

DSCR +0 ; Device Description

{

DevDscr +0

{

FlashDev.o

}

}

③以上设置完成后,开始生成工程。

点击下图红框内的按钮。

打开后,从上到下点击对应的框。

点击“STM32Cube HAL”后面按钮后,

跳出STM32Cube页面,开始配置MCU

配置完IO口和时钟频率之后(注意时钟频率会影响SPI的通讯速率),配置结束之后,点击项目设置,只需要设置如下选项即可,

设置完成后直接点击生成代码。

生成代码之后,用keil打开项目工程后会多出以下两个代码集,

此时,需要左击“Device”,如下图,点击红框中设置,

进入设置后,如下图,从上到下依次点击红框中的信息,

当点击确定之后,会发现STM32Cube生成的system_stm32g0xx.c不能用了。

此时需要自己从别的项目工程中拷贝一份system_stm32g0xx.c放到本工程中,同时在工程文件中添加,此时顺便将W25Qxx.c(FLASH驱动代码)和system_stm32g0xx.c一起添加进来,如下图。

④开始修改代码

点击main.c

先在main.c中重定义如下代码。

之后将“int main(void)”改为“int Init_main(void)”,同时对原本“int main(void)”中的函数做出修改,如下图

之后开始修改FlashDev.c,如下图所示文件,

做出如下修改,

注意超时时间要合理,全片擦除可能在10-20s左右。

之后开始修改FlashPrg.c,代码如下,

由于在FlashDev.c定义了地址为0x90000000所以先设置一个基础地址宏:

#define SPI_FLASH_MEM_ADDR 0x90000000

初始化函数:

extern int Init_main(void);

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {

/* Add your Code */

Init_main();

if(BSP_W25qxx_ReadID() != W25Q16)

{

//return (1);

}

return (0); // Finished without Errors

}

注意:在FlashPrg.c中的函数都有返回值,同时返回0表示正常,返回1表示异常。

清除初始化函数不修改:

int UnInit (unsigned long fnc) {

/* Add your Code */

return (0); // Finished without Errors

}

全片擦除函数:

int EraseChip (void) {

/* Add your Code */

for(uint16_t i = 0; i < 512; i++)

{

BSP_W25qxx_Erase_Sector(i * 0x1000);

}

return (0); // Finished without Errors

}

扇区擦除函数:

int EraseSector (unsigned long adr) {

/* Add your Code */

adr -= SPI_FLASH_MEM_ADDR;

BSP_W25qxx_Erase_Sector(adr);

return (0); // Finished without Errors

}

写入函数:

int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {

/* Add your Code */

adr -= SPI_FLASH_MEM_ADDR;

B_W25qxx_Write(buf,adr,sz);

return (0); // Finished without Errors

}

添加校验函数:

unsigned long Verify(unsigned long adr, unsigned long sz, unsigned char *buf)

{

adr -= SPI_FLASH_MEM_ADDR;

adr += SPI_FLASH_MEM_ADDR;

return (adr + sz); /* 校验成功 */

}

注意:当前检验函数未作任何操作,只是为了下载时如果选择“Verify”了,依旧可以正常下载。

添加块擦除检查函数:

int BlankCheck(unsigned long adr, unsigned long sz, unsigned char pat)

{

// adr -= SPI_FLASH_MEM_ADDR;

/* 强制擦除 */

return 1;

}

注意:当前块擦除检查函数依旧未做任何操作。

⑤完成以上操作则修改完成,点击编译,生成FLM文件。

4、FLM下载算法验证

打开一份测试代码工程。

①修改测试工程设置,以下方式二选一。

方式一:打开“魔术棒”,Linker页面下,做出如下修改,

然后点击“Edit”,对.sct文件进行修改,在末尾添加如下代码:

LR_EROM1 0x90000000 0x00200000 { ; load region size_region

ER_EROM1 0x90000000 0x00200000 { ; load address = execution address

*(USE_EXT_FLASH_2MB_BUF_SPACE)

}

}

方式二:Traget页面,添加对应外部FLASH的虚拟地址和大小,如下图,

以上两种方式设置任意一种之后,进入下载设置界面,添加我们的FLM算法,然后将RAM空间暂时改大,否则算法下不进去(算法是下载到MCU中运行的),如下图,

②在测试工程中添加代码

实现将静态全局变量的值存储在外部FLASH中。

为了适配编译器,不然参数被编译器优化掉,定义宏:

#ifdef __CC_ARM /* ARM Compiler */

#define SECTION(x) __attribute__((section(x)))

#define USED __attribute__((used))

#define UNUSEDX __attribute__((unused))

#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */

#define SECTION(x) @ x

#define USED __root

#elif defined (__GNUC__) /* GNU GCC Compiler */

#define SECTION(x) __attribute__((section(x)))

#define USED __attribute__((used))

#define UNUSED __attribute__((unused))

#else

#error not supported tool chain

#endif /* __CC_ARM */

之后定义静态全局变量:

USED static const uint16_t Flash_Value SECTION("USE_EXT_FLASH_2MB_BUF_SPACE") = 0x1010;

5、连接实际板子点击下载即可。

附加说明:

1、可尝试屏蔽一些无用的库代码,例如内部flash的HAL代码,这样可以减小代码量,因为算法是临时加载到RAM中运行。

2、如遇到如下问题:

说明FLM算法存在问题,可尝试把自写的驱动代码屏蔽掉测试看看,屏蔽掉之后依旧不正常则可能是时钟设置或系统初始不对;屏蔽之后正常,则可能是IO初始化不对。

猜你喜欢

转载自blog.csdn.net/weixin_39457767/article/details/131329413