Flash,相信大家一定都不陌生,作為一種非易失性內(nèi)存,其顯著特點(diǎn)就是即便系統(tǒng)掉電,其上的存儲(chǔ)內(nèi)容也不會(huì)丟失。也正因如此,其作為程序存儲(chǔ)介質(zhì)而被廣泛應(yīng)用。
當(dāng)然,也有他的弊端或者說不便利性,那就是Flash的讀寫操作往往不是那么的招人“喜歡”。即便是Nor Flash,也僅僅是能夠?qū)崿F(xiàn)按地址的隨機(jī)讀操作,而不能實(shí)現(xiàn)隨機(jī)寫。而且,數(shù)據(jù)的寫入往往都是基于塊操作的,也就是說,想要將數(shù)據(jù)寫入flash中,即便只想更新哪怕一個(gè)字節(jié),也要對(duì)一整個(gè)塊來操作。并且要執(zhí)行類似于:先擦除再寫入的操作。
而既然我們想要將程序燒寫到flash中,那不可避免地就要編寫相應(yīng)的flash操作程序來輔助實(shí)現(xiàn)。
本期小編就將為大家介紹下,如何在Keil中添加Flash燒寫算法,能夠讓Keil幫助我們進(jìn)行程序的燒寫工作。
何為FLM文件
回想一下,在Keil這款I(lǐng)DE中,如果想要將程序燒寫到Flash中,首先要干的一步就是打開項(xiàng)目屬性頁要選擇合適的flash下載算法,而這個(gè)算法本身就是一個(gè)FLM文件:
FLM文件結(jié)構(gòu)
那么FLM文件是怎么構(gòu)成呢?Keil規(guī)定,一個(gè)FLM文件中一般要有以下函數(shù):
其中最為重要的有5個(gè),我們來一一說明:
int Init (unsigned long adr, unsigned long clk, unsigned long fnc);負(fù)責(zé)flash器件的初始化工作,其中:
a)adr: 設(shè)備首地址
b)clk:時(shí)鐘頻率(Hz)
c)fnc:要執(zhí)行的flash操作,包括,1:Erase,2:Program,3:Verify
int EraseSector (unsigned long adr);擦除addr所指定地址處的整個(gè)sector
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf);對(duì)flash進(jìn)行燒寫操作,其中:
a)adr:待燒寫地址
b)sz:待燒寫數(shù)據(jù)長度
c)bug:待燒寫數(shù)據(jù)
int EraseChip (void); 擦除整塊flash
int UnInit (unsigned long fnc); Uninit flash, 并根據(jù)傳入的fnc執(zhí)行不同的flash后操作,fnc的定義同Init
編寫FLM文件
Keil很貼心的為我們準(zhǔn)備了一個(gè)模板工程,可以以說包含了生成一個(gè)FLM文件的所有,工程文件位置在 Keil安裝目錄ARMFlash\_Template:
我們所需要修改的就是FlashDev.c以及FlashPrg.c兩個(gè)文件,為了方便測試,小編就直接在i.MX RT1170 EVK上掛載的IS25WP128-JBLE Flash為例進(jìn)行說明。
首先是FlashDev.c文件,這里面主要提供了一些Flash的基本硬件信息,定義了諸如Flash器件名,sector大小,寫入塊大小等,參考實(shí)現(xiàn)如下:
struct FlashDevice const FlashDevice = { FLASH_DRV_VERS, // 別改!!! "IS25WP128-JBLE", // 簡單粗暴,直接定義 EXTSPI, // 設(shè)備類型,可選: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,負(fù)責(zé)實(shí)現(xiàn)與Flash操作有關(guān)的所有函數(shù)。這里,讓我們繼續(xù)發(fā)揚(yáng)大樹下好乘涼的優(yōu)良傳統(tǒng)。下載RT1170_EVK最新的SDK代碼,找到基于flexspi的nor flash工程:boardsevkmimxrt1170driver_examplesflexspi orpolling_transfercm7,這里有一個(gè)flexspi_nor_flash_ops.c,里面已經(jīng)包含了所有flash操作相關(guān)的操作函數(shù),不過文件中缺少了FlexSPI引腳的初始化代碼,需要進(jìn)行添加:
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)函數(shù)中。
修改好之后,將文件拷貝并添加到我們剛才找到的FLM工程中,當(dāng)然還要將原SDK工程中的app.h文件一并拷貝過來。由于需要用到flexspi的底層操作,還需要添加fsl_flexspi.c文件,添加好后的工程長這個(gè)樣子:
接下來就是修改FlashPrg.c,首先添加頭文件以及函數(shù)引用:
#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)
接下來是相應(yīng)函數(shù)的實(shí)現(xiàn),這里有一點(diǎn)需要注意,針對(duì)函數(shù)傳入的adr即地址變量,實(shí)際上已經(jīng)被轉(zhuǎn)換為了映射到AHB總線上的地址,而我們對(duì)于Flash的操作都是基于Flash本身的地址而言的,因此需要做一個(gè)簡單的轉(zhuǎn)換,減去一個(gè)偏移量(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)); }
至此,我們就完成了所有的代碼準(zhǔn)備工作。當(dāng)然,為了讓程序能夠正常編譯,還需要對(duì)工程進(jìn)行配置,其中最主要的是頭文件路徑以及預(yù)編譯符號(hào)的添加,右鍵工程屬性并添加:
頭文件路徑:
為輸出文件起一個(gè)專屬名字:
選擇正確的芯片類型為MIMXRT1170DVMAA:cm7:
這樣,就完成了所有的準(zhǔn)備工作,接下來就是熟悉的編譯鏈接,不過注意,不能點(diǎn)擊運(yùn)行按鈕。在當(dāng)前目錄下,找到生成的rt1170_validation_board.FLM, 并將其拷貝到Keil安裝目錄ARMFlash下。
接下來進(jìn)行測試,我們直接打開SDK中hello world工程,在工程屬性中打開Flash下載頁面,點(diǎn)擊Add按鈕即可看到我們所添加的Flash算法并確定:
之后就是正常的編譯鏈接燒寫之路,最終顯示:
證明我們已經(jīng)燒寫成功,之后進(jìn)行調(diào)試即可正常調(diào)試。
至此,我們就完成了FLM文件的編寫,并且在hello_world的工程中進(jìn)行了測試。
-
程序
+關(guān)注
關(guān)注
117文章
3819瀏覽量
82320 -
keil
+關(guān)注
關(guān)注
69文章
1222瀏覽量
168843 -
燒寫
+關(guān)注
關(guān)注
0文章
57瀏覽量
14531
原文標(biāo)題:編寫Keil的自定義Flash燒寫算法FLM
文章出處:【微信號(hào):NXP_SMART_HARDWARE,微信公眾號(hào):恩智浦MCU加油站】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
28335燒寫flash的問題
單片機(jī)如何在flash中運(yùn)行程序
TMS320F2812片內(nèi)Flash在線燒寫技術(shù)
基于CCS的DSP片外Flash直接燒寫設(shè)計(jì)

JTAG接口在線燒寫Flash的實(shí)現(xiàn)

FPGA配置– 使用JTAG是如何燒寫SPI/BPI Flash的?

使用JTAG燒寫Nand Flash實(shí)驗(yàn)解析

Keil中燒寫STM32F750內(nèi)部Flash的方法有哪些

Keil MDK下的串行Flash下載算法設(shè)計(jì)

Jlink使用技巧之燒寫SPI Flash存儲(chǔ)芯片

可供用戶修改的FLASH燒寫驅(qū)動(dòng)介紹

評(píng)論