如何在Keil中添加Flash烧写算法

flash,相信大家一定都不陌生,作为一种非易失性内存,其显著特点就是即便系统掉电,其上的存储内容也不会丢失。也正因如此,其作为程序存储介质而被广泛应用。
当然,也有他的弊端或者说不便利性,那就是flash的读写操作往往不是那么的招人“喜欢”。即便是nor flash,也仅仅是能够实现按地址的随机读操作,而不能实现随机写。而且,数据的写入往往都是基于块操作的,也就是说,想要将数据写入flash中,即便只想更新哪怕一个字节,也要对一整个块来操作。并且要执行类似于:先擦除再写入的操作。
而既然我们想要将程序烧写到flash中,那不可避免地就要编写相应的flash操作程序来辅助实现。
本期小编就将为大家介绍下,如何在keil中添加flash烧写算法,能够让keil帮助我们进行程序的烧写工作。
何为flm文件
    回想一下,在keil这款ide中,如果想要将程序烧写到flash中,首先要干的一步就是打开项目属性页要选择合适的flash下载算法,而这个算法本身就是一个flm文件:
flm文件结构
那么flm文件是怎么构成呢?keil规定,一个flm文件中一般要有以下函数:
其中最为重要的有5个,我们来一一说明:
int init (unsigned long adr, unsigned long clk, unsigned long fnc); 负责flash器件的初始化工作,其中:
a)adr: 设备首地址
b)clk:时钟频率(hz)
c)fnc:要执行的flash操作,包括,1:erase,2:program,3:verify
int erasesector (unsigned long adr); 擦除addr所指定地址处的整个sector
int programpage (unsigned long adr, unsigned long sz, unsigned char *buf); 对flash进行烧写操作,其中:
a)adr:待烧写地址
b)sz:待烧写数据长度
c)bug:待烧写数据
int erasechip (void); 擦除整块flash
int uninit (unsigned long fnc); uninit flash, 并根据传入的fnc执行不同的flash后操作,fnc的定义同init
编写flm文件
keil很贴心的为我们准备了一个模板工程,可以以说包含了生成一个flm文件的所有,工程文件位置在 keil安装目录armflash\_template:
我们所需要修改的就是flashdev.c以及flashprg.c两个文件,为了方便测试,小编就直接在i.mx rt1170 evk上挂载的is25wp128-jble flash为例进行说明。
首先是flashdev.c文件,这里面主要提供了一些flash的基本硬件信息,定义了诸如flash器件名,sector大小,写入块大小等,参考实现如下:
struct flashdevice const flashdevice = { flash_drv_vers, // 别改!!! is25wp128-jble, // 简单粗暴,直接定义 extspi, // 设备类型,可选:onchip, ext8bit, ext16bit, // ext32bit, extspi 0x30000000, // flash首地址,挂载到ahb总线的地址 0x01000000, // flash大小,16mb 256, // 烧写page 大小 0, // reserved, must be 0 0xff, // initial content of erased memory 100, // program page timeout 100 msec 3000, // erase sector timeout 3000 msec 0x001000, 0x000000, // sector 大小 4kb sector_end};接下来是flashprg.c,负责实现与flash操作有关的所有函数。这里,让我们继续发扬大树下好乘凉的优良传统。下载rt1170_evk最新的sdk代码,找到基于flexspi的nor flash工程:boardsevkmimxrt1170driver_examplesflexspi orpolling_transfercm7,这里有一个flexspi_nor_flash_ops.c,里面已经包含了所有flash操作相关的操作函数,不过文件中缺少了flexspi引脚的初始化代码,需要进行添加:iomuxc_setpinmux(iomuxc_gpio_sd_b2_05_flexspi1_a_dqs, 1u);iomuxc_setpinmux(iomuxc_gpio_sd_b2_06_flexspi1_a_ss0_b, 1u);iomuxc_setpinmux(iomuxc_gpio_sd_b2_07_flexspi1_a_sclk, 1u);iomuxc_setpinmux(iomuxc_gpio_sd_b2_08_flexspi1_a_data00, 1u);iomuxc_setpinmux(iomuxc_gpio_sd_b2_09_flexspi1_a_data01, 1u);iomuxc_setpinmux(iomuxc_gpio_sd_b2_10_flexspi1_a_data02, 1u);iomuxc_setpinmux(iomuxc_gpio_sd_b2_11_flexspi1_a_data03, 1u);iomuxc_setpinconfig(iomuxc_gpio_sd_b2_05_flexspi1_a_dqs, 0x0au);iomuxc_setpinconfig(iomuxc_gpio_sd_b2_06_flexspi1_a_ss0_b, 0x0au);iomuxc_setpinconfig(iomuxc_gpio_sd_b2_07_flexspi1_a_sclk, 0x0au);iomuxc_setpinconfig(iomuxc_gpio_sd_b2_08_flexspi1_a_data00, 0x0au);iomuxc_setpinconfig(iomuxc_gpio_sd_b2_09_flexspi1_a_data01, 0x0au);iomuxc_setpinconfig(iomuxc_gpio_sd_b2_10_flexspi1_a_data02, 0x0au);iomuxc_setpinconfig(iomuxc_gpio_sd_b2_11_flexspi1_a_data03, 0x0au);  
到void flexspi_nor_flash_init(flexspi_type *base)函数中。
修改好之后,将文件拷贝并添加到我们刚才找到的flm工程中,当然还要将原sdk工程中的app.h文件一并拷贝过来。由于需要用到flexspi的底层操作,还需要添加fsl_flexspi.c文件,添加好后的工程长这个样子:
接下来就是修改flashprg.c,首先添加头文件以及函数引用:
#include fsl_flexspi.h#include app.h extern status_t flexspi_nor_flash_erase_sector(flexspi_type *base, uint32_t address);extern status_t flexspi_nor_flash_page_program(flexspi_type *base, uint32_t dstaddr, const uint32_t *src);extern status_t flexspi_nor_get_vendor_id(flexspi_type *base, uint8_t *vendorid);extern status_t flexspi_nor_enable_quad_mode(flexspi_type *base);extern status_t flexspi_nor_erase_chip(flexspi_type *base);extern void flexspi_nor_flash_init(flexspi_type *base);#define flexspi_base (flexspi1)#define flash_base_adr (0x30000000)  
接下来是相应函数的实现,这里有一点需要注意,针对函数传入的adr即地址变量,实际上已经被转换为了映射到ahb总线上的地址,而我们对于flash的操作都是基于flash本身的地址而言的,因此需要做一个简单的转换,减去一个偏移量(flash_base_adr):
int init (unsigned long adr, unsigned long clk, unsigned long fnc) { (void)adr; (void)clk; (void)fnc; flexspi_nor_flash_init(flexspi_base); return (0); }int uninit (unsigned long fnc) { return (0); }int erasechip (void) { return (flexspi_nor_erase_chip(flexspi_base)); }int erasesector (unsigned long adr) { return (flexspi_nor_flash_erase_sector(flexspi_base, adr - flash_base_adr)); }int programpage (unsigned long adr, unsigned long sz, unsigned char *buf) { return ( flexspi_nor_flash_page_program( flexspi_base, adr - flash_base_adr, (uint32_t*)buf)); }  
至此,我们就完成了所有的代码准备工作。当然,为了让程序能够正常编译,还需要对工程进行配置,其中最主要的是头文件路径以及预编译符号的添加,右键工程属性并添加:
头文件路径:
为输出文件起一个专属名字:
选择正确的芯片类型为mimxrt1170dvmaa:cm7:
这样,就完成了所有的准备工作,接下来就是熟悉的编译链接,不过注意,不能点击运行按钮。在当前目录下,找到生成的rt1170_validation_board.flm, 并将其拷贝到keil安装目录armflash下。
接下来进行测试,我们直接打开sdk中hello world工程,在工程属性中打开flash下载页面,点击add按钮即可看到我们所添加的flash算法并确定:
之后就是正常的编译链接烧写之路,最终显示:
证明我们已经烧写成功,之后进行调试即可正常调试。
至此,我们就完成了flm文件的编写,并且在hello_world的工程中进行了测试。


石墨烯“太阳能电池”领域应用
中科曙光携先进算力基础设施产品助力山西省数字经济持续增长
纯电动汽车要成新销售汽车主流
高云半导体签约两家北美代理商,国际化进程赢得业界关注
MC3406A升压/降压DCDC集成变换器
如何在Keil中添加Flash烧写算法
说好的改变手机新概念呢?魅族pro7发布仅两个月时间就多次降价,如今仅2499也没人要
江波龙:争做电力存储市场的行业尖兵
是距离还是速度,让设计RS485系统陷入困境
4G网络短期内不会被5G代替
云计算领域谁住沉浮?
科普常用功率电感的封装规格不同能不能通用 gujing
双镜头手机又火了 那种才是你真正需要的?
手机企业如何做项目管理
做好这九点,电网保平安
马斯克:modei3不会比modeis更先进
统信桌面操作系统V20专业版1030发布
MAX9670/MAX9671 +3.3V双SCART IC
祝贺神州十一号对接成功 接下来看看宇航员30天作业安排情况
平价降噪耳机有哪些?学生党降噪耳机推荐