请选择 进入手机版 | 继续访问电脑版
查看: 4764|回复: 35

[分享] 编写Keil的自定义Flash烧写算法FLM

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3298

    主题

    6545

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32001
    最后登录
    2024-4-9
    发表于 2022-9-20 09:49:13 | 显示全部楼层 |阅读模式
    编写Keil的自定义Flash烧写算法FLM


    Flash,相信大家一定都不陌生,作为一种非易失性内存,其显著特点就是即便系统掉电,其上的存储内容也不会丢失。也正因如此,其作为程序存储介质而被广泛应用。


    当然,也有他的弊端或者说不便利性,那就是Flash的读写操作往往不是那么的招人“喜欢”。即便是Nor Flash,也仅仅是能够实现按地址的随机读操作,而不能实现随机写。而且,数据的写入往往都是基于块操作的,也就是说,想要将数据写入flash中,即便只想更新哪怕一个字节,也要对一整个块来操作。并且要执行类似于:先擦除再写入的操作。


    而既然我们想要将程序烧写到flash中,那不可避免地就要编写相应的flash操作程序来辅助实现。


    本期小编就将为大家介绍下,如何在Keil中添加Flash烧写算法,能够让Keil帮助我们进行程序的烧写工作。

    何为FLM文件

    回想一下,在Keil这款IDE中,如果想要将程序烧写到Flash中,首先要干的一步就是打开项目属性页要选择合适的flash下载算法,而这个算法本身就是一个FLM文件:
    11.png
    FLM文件结构

    那么FLM文件是怎么构成呢?Keil规定,一个FLM文件中一般要有以下函数:
    12.png
    其中最为重要的有5个,我们来一一说明:


    1、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
    2、int EraseSector (unsigned long adr); 擦除addr所指定地址处的整个sector
    3、int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf); 对flash进行烧写操作,其中:
    a) adr:待烧写地址
    b) sz:待烧写数据长度
    c) bug:待烧写数据
    4、int EraseChip (void); 擦除整块flash
    5、int UnInit (unsigned long fnc); Uninit flash, 并根据传入的fnc执行不同的flash后操作,fnc的定义同Init

    编写FLM文件


    Keil很贴心的为我们准备了一个模板工程,可以以说包含了生成一个FLM文件的所有,工程文件位置在 Keil安装目录\ARM\Flash\_Template:
    13.png
    我们所需要修改的就是FlashDev.c以及FlashPrg.c两个文件,为了方便测试,小编就直接在i.MX RT1170 EVK上挂载的IS25WP128-JBLE Flash为例进行说明。


    首先是FlashDev.c文件,这里面主要提供了一些Flash的基本硬件信息,定义了诸如Flash器件名,sector大小,写入块大小等,参考实现如下:
    1. struct FlashDevice const FlashDevice  =  {
    2.    FLASH_DRV_VERS,     // 别改!!!
    3.    "IS25WP128-JBLE",   // 简单粗暴,直接定义
    4.    EXTSPI,             // 设备类型,可选:ONCHIP, EXT8BIT, EXT16BIT,
    5.                        // EXT32BIT, EXTSPI
    6.    0x30000000,         // Flash首地址,挂载到AHB总线的地址
    7.    0x01000000,         // Flash大小,16MB
    8.    256,                // 烧写Page 大小
    9.    0,                  // Reserved, must be 0
    10.    0xFF,               // Initial Content of Erased Memory
    11.    100,                // Program Page Timeout 100 mSec
    12.    3000,               // Erase Sector Timeout 3000 mSec

    13.    0x001000, 0x000000, // Sector 大小  4KB
    14.    SECTOR_END
    15. };
    复制代码
    接下来是FlashPrg.c,负责实现与Flash操作有关的所有函数。这里,让我们继续发扬大树下好乘凉的优良传统。下载RT1170_EVK最新的SDK代码,找到基于flexspi的nor flash工程:boards\evkmimxrt1170\driver_examples\flexspi\nor\polling_transfer\cm7,这里有一个flexspi_nor_flash_ops.c,里面已经包含了所有flash操作相关的操作函数,不过文件中缺少了FlexSPI引脚的初始化代码,需要进行添加:
    1. IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_05_FLEXSPI1_A_DQS, 1U);
    2. IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_06_FLEXSPI1_A_SS0_B, 1U);
    3. IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_07_FLEXSPI1_A_SCLK, 1U);
    4. IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_08_FLEXSPI1_A_DATA00, 1U);
    5. IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_09_FLEXSPI1_A_DATA01, 1U);
    6. IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_10_FLEXSPI1_A_DATA02, 1U);
    7. IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_11_FLEXSPI1_A_DATA03, 1U);

    8. IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_05_FLEXSPI1_A_DQS,   0x0AU);
    9. IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_06_FLEXSPI1_A_SS0_B,  0x0AU);
    10. IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_07_FLEXSPI1_A_SCLK,  0x0AU);
    11. IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_08_FLEXSPI1_A_DATA00, 0x0AU);
    12. IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_09_FLEXSPI1_A_DATA01, 0x0AU);
    13. IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_10_FLEXSPI1_A_DATA02, 0x0AU);
    14. 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文件,添加好后的工程长这个样子:
    14.png
    接下来就是修改FlashPrg.c,首先添加头文件以及函数引用:
    1. #include "fsl_flexspi.h"
    2. #include "app.h"
    3. extern status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
    4. extern status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src);
    5. extern status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId);
    6. extern status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base);
    7. extern status_t flexspi_nor_erase_chip(FLEXSPI_Type *base);
    8. extern void flexspi_nor_flash_init(FLEXSPI_Type *base);
    9. #define FLEXSPI_BASE (FLEXSPI1)
    10. #define FLASH_BASE_ADR (0x30000000)
    复制代码
    接下来是相应函数的实现,这里有一点需要注意,针对函数传入的adr即地址变量,实际上已经被转换为了映射到AHB总线上的地址,而我们对于Flash的操作都是基于Flash本身的地址而言的,因此需要做一个简单的转换,减去一个偏移量(FLASH_BASE_ADR):


    至此,我们就完成了所有的代码准备工作。当然,为了让程序能够正常编译,还需要对工程进行配置,其中最主要的是头文件路径以及预编译符号的添加,右键工程属性并添加:
    10.png
    头文件路径:
    15.png
    为输出文件起一个专属名字:
    16.png
    选择正确的芯片类型为MIMXRT1170DVMAA:cm7:
    17.png
    这样,就完成了所有的准备工作,接下来就是熟悉的编译链接,不过注意,不能点击运行按钮。在当前目录下,找到生成的rt1170_validation_board.FLM, 并将其拷贝到Keil安装目录\ARM\Flash下。


    接下来进行测试,我们直接打开SDK中hello world工程,在工程属性中打开Flash下载页面,点击Add按钮即可看到我们所添加的Flash算法并确定:
    18.png
    之后就是正常的编译链接烧写之路,最终显示:
    19.png
    证明我们已经烧写成功,之后进行调试即可正常调试。
    20.png
    至此,我们就完成了FLM文件的编写,并且在hello_world的工程中进行了测试。



















    签到签到
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    4 小时前
  • 签到天数: 1932 天

    [LV.Master]伴坛终老

    61

    主题

    1万

    帖子

    3

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    17214
    最后登录
    2024-4-18
    发表于 2022-9-20 11:04:15 | 显示全部楼层
    这个有用,学**怎么写下载算法
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2021-11-30 16:16
  • 签到天数: 206 天

    [LV.7]常住居民III

    74

    主题

    2793

    帖子

    5

    金牌会员

    Rank: 6Rank: 6

    积分
    7423
    最后登录
    2024-1-28
    发表于 2022-9-20 16:09:47 | 显示全部楼层
    感谢分享,学习一下
    来根华子
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    3 小时前
  • 签到天数: 814 天

    [LV.10]以坛为家III

    71

    主题

    2435

    帖子

    24

    金牌会员

    Rank: 6Rank: 6

    积分
    5487
    最后登录
    2024-4-18
    发表于 2022-9-20 17:50:56 来自手机 | 显示全部楼层
    谢谢分享
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-4-7 20:47
  • 签到天数: 537 天

    [LV.9]以坛为家II

    69

    主题

    2521

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    7070
    最后登录
    2024-4-9
    发表于 2022-9-23 14:28:59 | 显示全部楼层
    学无止境,感谢分享
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2022-2-25 10:20
  • 签到天数: 32 天

    [LV.5]常住居民I

    1

    主题

    289

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1129
    最后登录
    2023-10-31
    发表于 2022-9-23 16:11:08 | 显示全部楼层
    哪天用到再来研究下
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    12

    主题

    789

    帖子

    1

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    2689
    最后登录
    2024-4-4
    发表于 2022-9-23 16:13:31 | 显示全部楼层
    mark一下,学习了
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    2

    主题

    11

    帖子

    0

    注册会员

    Rank: 2

    积分
    113
    最后登录
    2023-3-21
    发表于 2022-9-23 18:04:44 | 显示全部楼层
    为什么STM32这种内部有FLASH的芯片 不需要这个动作?
    直接有上位机操作内部flash
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 20:11
  • 签到天数: 2030 天

    [LV.Master]伴坛终老

    17

    主题

    4810

    帖子

    5

    金牌会员

    Rank: 6Rank: 6

    积分
    9869
    最后登录
    2024-4-17
    发表于 2022-9-23 21:22:17 | 显示全部楼层
    谢谢分享!
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    6 小时前
  • 签到天数: 360 天

    [LV.8]以坛为家I

    0

    主题

    384

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1155
    最后登录
    2024-4-18
    发表于 2022-9-24 10:53:42 | 显示全部楼层
    非常有用,学习如何在Keil中添加Flash烧写算法
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-18 15:52 , Processed in 0.146499 second(s), 28 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表