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的工程中進行了測試。
-
程序
+關注
關注
116文章
3778瀏覽量
80860 -
keil
+關注
關注
68文章
1212瀏覽量
166701 -
燒寫
+關注
關注
0文章
57瀏覽量
14264
原文標題:編寫Keil的自定義Flash燒寫算法FLM
文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論