《APM32芯得》系列內容為用戶使用APM32系列產品的經驗總結,均轉載自21ic論壇極海半導體專區(qū),全文未作任何修改,未經原文作者授權禁止轉載。
前言
嗨,嵌入式開發(fā)的小伙伴們!用 Keil MDK(μVision)搭配 J-Link 或 DAPLink 調試器刷代碼到 MCU 的 Flash,是咱們日常開發(fā)的老套路了。里面有個關鍵角色——Flash 編程算法(FLM 文件),就像個“幕后大佬”,幫調試器搞定 Flash 的擦除、編程和驗證。可不少人(尤其是剛入門的小白)對 FLM 有點懵:這東西存哪兒?為啥非得加載到 SRAM?誰來管加載和跳轉?今天咱們就來把 FLM 的前世今生扒個底朝天,聊清楚它的加載和運行機制。
一、FLM 下載算法是個啥?
例如,F4的pack包中就包含了各種的flm文件。

1.1 FLM 文件:刷 Flash 的“臨時工”
簡單來說,FLM(Flash Loader Module)文件就是 Keil MDK 用來刷 MCU Flash 的“說明書”。它告訴調試器(J-Link 或 DAPLink)咋擦除 Flash、咋寫代碼、咋校驗數據。FLM 文件一般由 MCU 廠商或者 Keil 提供,藏在 Keil 的 CMSIS - Pack 包里,或者裝在 Keil 的安裝目錄(比如C:Keil_v5ARMFlash)。
對小白來說,FLM 文件就像個“臨時工”:刷代碼時它上場,干完活就撤,不占 MCU 的地兒。它跟你的用戶代碼沒啥關系,專門負責跟 Flash 硬件打交道。你在 Keil 點“Download”,FLM 就在后臺默默把代碼刷進 Flash,省心得很。
1.2 FLM 文件里裝了啥?
FLM 文件是個二進制的“黑盒子”,里頭有幾塊關鍵內容:
算法代碼:干活的核心邏輯,比如初始化 Flash 控制器、擦扇區(qū)、寫數據、校驗啥的。一般是用 C 或者匯編寫,針對某個 MCU 的 Flash 硬件量身定做。
元數據:相當于“說明書”,告訴你算法咋跑。比如:
oAlgoRamStart:算法代碼要加載到 SRAM 的哪個地址(比如0x20000000)。
oAlgoRamSize:算法占多少 SRAM(比如 4KB)。
oEntryPoint:代碼從哪兒開始跑(比如0x20000004)。
oDevInfo:Flash 的“戶口本”,比如基地址0x08000000、頁面大小 2KB、扇區(qū)大小 16KB。
函數表:一堆標準化的“接口”,比如Init(初始化)、EraseSector(擦扇區(qū))、ProgramPage(寫頁面),調試器靠這些接口調用算法。
對新手來說,FLM 就像個“神秘盒子”,你看不到代碼細節(jié),但 Keil 和調試器能讀懂它,靠它把代碼刷進 Flash。

圖片 1:FLM 文件的“黑盒”結構
1.3 FLM 文件打哪兒來?
FLM 文件的來路有這幾種:
Keil 官方的 Pack 包:Keil 給主流 MCU(比如 APM32F4、APM32F1、STM32F4)準備了一堆 FLM 文件,裝完 Keil 就能在ARMFlash目錄找到。
MCU 廠商:像 ST、Geehy 這些廠商會為自家的 MCU 定制 FLM 文件,確保跟硬件完美匹配。
自己動手:硬核玩家可以用 Keil 的 Flash Algorithm Development Kit 自己寫 FLM 文件,適合搞非標 Flash 或者特殊場景(比如外接 SPI Flash)。
寫 FLM 文件得對 MCU 硬件了如指掌,比如 Flash 控制器的寄存器咋用、時序咋控制。論壇上有大佬分享過,我就不闡述怎么做了。
二、為啥 FLM 算法非得加載到 SRAM?
2.1 Flash 的“怪脾氣”
Flash 是 MCU 里存代碼的“倉庫”,掉電也不丟數據,可它有幾個“怪脾氣”,讓 FLM 算法沒法在 Flash 里跑:
擦除時不可用:Flash 要寫新數據,得先擦掉老數據(通常按 4KB 或 8KB 的扇區(qū)擦)。擦除期間,Flash 忙得不可開交,壓根兒沒法跑代碼。比如,擦一個扇區(qū)可能要 50 毫秒,Flash 這時候就是個“啞巴”。
寄存器操作:Flash 編程得通過 Flash 控制器搞一堆寄存器(比如控制寄存器 CR、狀態(tài)寄存器 SR)。這些操作要快、要靈活,Flash 自個兒的讀寫速度太慢,干不了這活。
慢得要命:Flash 的寫操作慢得像烏龜,可能得 100 微秒才能寫一次數據,讀也比 SRAM 慢多了(SRAM 是納秒級,Flash 是微秒級)。跑復雜算法(比如循環(huán)寫數據、查錯)在 Flash 里簡直是災難。
占地方:FLM 算法只是下載時用用,長期擱在 Flash 里純屬浪費空間。比如 APM32F4 的 Flash 就 512KB,存?zhèn)€ 4KB 的 FLM,擠占用戶代碼的地兒,太不劃算。
所以,Flash 只能當“倉庫”,沒法當 FLM 算法的“工作臺”。
2.2 SRAM:靈活又高效的“工作臺”
SRAM(Static Random Access Memory)是 MCU 里的易失性存儲器,干 FLM 算法的活簡直完美:
快如閃電:SRAM 讀寫速度超快,訪問延遲就幾個時鐘周期(比如 APM32F4 的 SRAM 訪問只要 1 - 2 個周期,納秒級)。跑寄存器操作、循環(huán)邏輯啥的,效率杠杠的。
隨時上場:SRAM 能直接加載代碼,CPU 一聲令下就能跑,不像 Flash 還得先擦后寫。
地址清楚:MCU 的 SRAM 地址范圍都寫在數據手冊里,比如 APM32F4 的 SRAM 從0x20000000開始,NXP LPC 系列可能是0x10000000。FLM 算法可以放心加載到 SRAM 的“安全地帶”。
用完就丟:SRAM 是易失性的,FLM 算法干完活就清空,不占資源,MCU 照常跑用戶代碼。

圖片 2:Flash vs. SRAM 的“性格”對比
2.3 調試器(J-Link/DAPLink)為啥不存 FLM?
有些小伙伴想:能不能把 FLM 算法塞到 J-Link 或 DAPLink 里?答案是:想得美!原因有幾大塊:
地方太小:J-Link 和 DAPLink 的固件存儲就幾百 KB(比如 J-Link 的 Flash 才 256KB-1MB)。FLM 文件少則幾 KB,多則幾十 KB,調試器得支持上百種 MCU,每個 MCU 可能要個 FLM 文件,哪兒裝得下?
得靈活點:J-Link 和 DAPLink 是“萬金油”調試器,啥 MCU 都能用。把 FLM 硬塞進去,遇到新 MCU 或者自定義 FLM 就抓瞎了,升級固件也麻煩。
傳數據麻煩:就算 FLM 存在調試器里,每次還得通過 SWD/JTAG 傳到 SRAM,速度慢不說,還增加通信開銷。還不如讓主機(PC)存 FLM,調試器只管傳數據,省事兒又高效。
固件得簡單:調試器的固件就干點 SWD/JTAG 的活,塞太多功能(比如管 FLM 文件)會讓固件復雜得像個“胖子”,維護起來頭大。

圖片 3:調試器存儲 FLM 的“不可能任務”
2.4 為啥不擱 Flash 里?
把 FLM 算法塞到 Flash 里也不靠譜:
擦了就沒了:Flash 編程得先擦扇區(qū),FLM 算法要是住在 Flash 里,擦除的時候自個兒就沒了,咋跑?
浪費空間:FLM 就下載時用一次,長期占著 Flash 的地兒,擠占用戶代碼的空間。
慢得要命:Flash 的讀寫速度慢(寫一次得 100 微秒),跑 FLM 算法效率低得可憐,SRAM 的納秒級速度完勝。
2.5 咋挑 SRAM 地址?
FLM 算法加載到 SRAM 的地址(比如`0x20000000`)不是隨便挑的,有講究:
MCU 內存地圖:每個 MCU 的 SRAM 地址范圍都寫在數據手冊里。比如 APM32F4 的 SRAM 從`0x20000000`開始,NXP LPC1768 是`0x10000000`。
安全第一:FLM 算法選 SRAM 的低地址(比如`0x20000000`),避開用戶代碼的堆棧、變量啥的。用戶代碼一般用高地址(比如`0x20010000`),大家井水不犯河水。
廠商定好了:MCU 廠商做 FLM 文件時,參考 SRAM 大小和硬件特性,挑個安全地址。比如 APM32F4 的 SRAM 有 192KB,FLM 算法占 4KB 綽綽有余,選低地址穩(wěn)妥。
三、FLM 算法咋加載到 SRAM 又咋跑起來的?
3.1 整個流程:誰干啥?
FLM 算法從 PC 加載到 MCU 的 SRAM,再到跑起來,是個團隊作戰(zhàn)的過程,Keil MDK、調試器(J-Link 或 DAPLink)、目標 MCU 各干各的活。咱們一步步拆開看:
3.1.1 Keil MDK:大腦指揮中心
Keil MDK 是你開發(fā)時的“總指揮”,負責讀懂 FLM 文件、發(fā)號施令:
讀 FLM 文件:Keil 打開 FLM 文件(比如`APM32F4xx_512.FLM`),從里頭掏出關鍵信息:
oSRAM 起始地址(`AlgoRamStart`,比如`0x20000000`):算法代碼放哪兒。
o算法大小(`AlgoRamSize`,比如 4KB):得占多少地兒。
o入口地址(`EntryPoint`,比如`0x20000004`):代碼從哪兒開始跑。
oFlash 參數(`DevInfo`):Flash 的地址、大小啥的,比如基地址`0x08000000`、頁面 2KB。
發(fā)指令:Keil 把 FLM 的代碼和地址信息打包,通過調試器協(xié)議(J-Link 協(xié)議或 CMSIS-DAP 協(xié)議)甩給調試器,說:“兄弟,把這算法塞到 SRAM 里去!”
管全局:Keil 還得管整個下載流程:先加載 FLM 算法,再調用算法的函數(比如擦扇區(qū)、寫數據),最后把用戶代碼刷進 Flash。
Keil 就像個“導演”,不親自干活,但得把任務分配好。
3.1.2 調試器:勤勞的搬運工
調試器(J-Link 或 DAPLink)是干活的“搬運工”,負責把 FLM 算法塞進 SRAM,還要讓它跑起來:
J-Link:
o軟件端:J-Link 軟件(J-Link DLL)接到 Keil 的指令,拿著 FLM 算法的代碼和 SRAM 地址(比如`0x20000000`)。
o硬件端:J-Link 的固件通過 SWD/JTAG 接口,直接把算法代碼寫到 MCU 的 SRAM 里。SWD 就用兩條線(SWDIO 和 SWCLK),效率高得很。
o啟動:寫完后,J-Link 再把 MCU 的程序計數器(PC)設到入口地址(比如`0x20000004`),通過調試寄存器(DHCSR)讓 CPU 跑起來。
o優(yōu)點:J-Link 速度快(SWD 可達 50MHz),跟 Keil 配合得像老搭檔,日志也詳細(J-Link Commander 能告訴你每一步干了啥)。
DAPLink:
o軟件端:DAPLink 靠主機端的工具(比如 pyOCD 或 Keil 的 CMSIS-DAP 驅動)來解析 FLM 文件,生成指令。
o硬件端:DAPLink 的固件(跑在開發(fā)板的次級 MCU 上,比如 Cortex-M0)通過 CMSIS-DAP 協(xié)議,把 FLM 算法寫到 SRAM。
o啟動:跟 J-Link 一樣,DAPLink 設好 PC(比如`0x20000004`),讓 CPU 跑起來。
o特點:DAPLink 速度慢點(SWD 一般 1-10MHz),但便宜,適合 DIY 小伙伴。
3.1.3 目標 MCU:干活的主角
MCU 是 FLM 算法的“舞臺”:
SRAM 存貨:MCU 的 SRAM 接到調試器送來的 FLM 算法代碼,存在指定地址(比如`0x20000000`)。SRAM 快,寫個 4KB 的算法分分鐘搞定。
跑代碼:調試器把 PC 設好(比如`0x20000004`),CPU 從暫停(halt)狀態(tài)切到運行(run)狀態(tài),從 SRAM 里取指令,開始干活。
刷 Flash:FLM 算法跑起來后,直接搞 Flash 控制器的寄存器,擦扇區(qū)、寫數據、校驗啥的,忙得不亦樂乎。

圖片 4:FLM 算法加載流程
3.2 為啥代碼里找不到 SRAM 地址?
好多小伙伴翻 FLM 工程的 C 代碼,愣是找不到0x20000000這樣的地址,為啥?答案藏在這些地方:
鏈接腳本:FLM 工程里有個鏈接腳本(Keil 用`.sct`,GNU 用`.ld`),指定了算法代碼的“住址”。比如:
- 代碼加載到 SRAM 的`0x20000000`,占 4KB。
- 入口地址是`0x20000004`(ARM Cortex-M 的 Thumb 指令得用奇數地址)。
FLM 元數據:編譯好的 FLM 文件里,元數據明確說了:
-`AlgoRamStart`:SRAM 起始地址(比如`0x20000000`)。
-`AlgoRamSize`:占多大地方(比如`0x1000`,也就是 4KB)。
-`EntryPoint`:從哪兒開始跑(比如`0x20000004`)。
廠商的安排:MCU 廠商做 FLM 文件時,參考數據手冊的內存地圖,挑個安全的 SRAM 地址。
編譯過程:Keil 的編譯器和鏈接器把 C 代碼和鏈接腳本“捏”成 FLM 文件,地址信息直接嵌到元數據里。你看 C 代碼沒地址,是因為這活兒都讓鏈接腳本干了。

圖片 5:SRAM 地址的“安全地帶”
3.3 入口地址和跳轉咋搞?
FLM 文件不光說了 SRAM 地址,還指定了入口地址(`EntryPoint`,比如`0x20000004`),這是代碼跑起來的“起跑線”。跳轉過程是這樣的:
- 設 PC:調試器通過 SWD/JTAG 搞 MCU 的調試端口(Debug Port, DP),把 PC 寄存器設到入口地址(比如`0x20000004`)。這得用 DCRSR 寄存器來寫。
- 配寄存器:調試器可能還得設下堆棧指針(SP,比如`0x20001000`)和其他寄存器(R0-R3),讓算法跑得順順當當。
- 跑起來:調試器通過 DHCSR 寄存器把 MCU 從“暫停”切到“跑”,CPU 就從 SRAM 里取指令,開始執(zhí)行 FLM 算法。
- 干活:FLM 算法跑起來后,調試器通過函數表調用它的接口(比如擦扇區(qū)的`EraseSector`、寫數據的`ProgramPage`),把用戶代碼刷進 Flash。
四、深挖 FLM 算法的底層原理:硬核來了!
好了,前面聊了 FLM 是啥、為啥用 SRAM、咋加載和跑起來,現在咱們來點硬核的,深入扒一扒 FLM 算法的底層機制,從編譯生成到寄存器操作,再到性能優(yōu)化。
4.1 FLM 文件咋生成的?
FLM 文件不是憑空冒出來的,它得經過編譯和打包,過程有點復雜:
寫代碼:FLM 工程的源代碼(一般是 C 或匯編)是核心,負責實現 Flash 編程的邏輯。比如:
- 解鎖 Flash:往 KEYR 寄存器寫特定值(比如 APM32F4 要寫`0x45670123`和`0xCDEF89AB`)。
- 擦扇區(qū):設 CR 寄存器的 ERASE 位,指定扇區(qū)地址。
- 寫數據:循環(huán)把數據寫到 Flash 的頁面,每次寫完查 SR 寄存器的狀態(tài)。
- 這些代碼得對 MCU 的 Flash 控制器了如指掌,比如寄存器地址、時序要求。
鏈接腳本:FLM 工程有個鏈接腳本(Keil 用`.sct`,GNU 用`.ld`),定好代碼的“住址”。比如:
- 算法代碼放 SRAM 的`0x20000000`,占 4KB。
- 入口地址設為`0x20000004`(Thumb 指令要求奇數地址)。
- 鏈接腳本還得保證代碼對齊,避開 SRAM 的“雷區(qū)”(比如用戶代碼的地兒)。
編譯打包:Keil 的編譯器(比如 ARMCC 或 ARMClang)把 C/匯編代碼編譯成二進制,鏈接器按腳本生成 FLM 文件,順手把 SRAM 地址、入口地址、Flash 參數塞進元數據。
元數據結構:FLM 文件的頭部是個結構化數據塊,包含:
- `AlgoRamStart`:SRAM 起始地址(比如`0x20000000`)。
- `AlgoRamSize`:占多大空間(比如`0x1000`)。
- `EntryPoint`:入口地址(比如`0x20000004`)。
- `DevInfo`:Flash 參數,比如基地址`0x08000000`、頁面大小 2KB。
- 這些元數據是 Keil 和調試器的“導航圖”,告訴它們算法咋加載、咋跑。
再提一下哈,為啥源代碼里看不到 SRAM 地址?因為地址是鏈接腳本和元數據的事兒,C 代碼只管邏輯,地址全靠編譯器和鏈接器搞定。
4.2 SWD/JTAG 接口:調試器的“魔法通道”
J-Link 和 DAPLink 靠 SWD(Serial Wire Debug)或 JTAG 接口跟 MCU 聊天,加載 FLM 算法全靠這倆通道:
內存寫入:調試器通過 SWD/JTAG 訪問 MCU 的內存接口(通常是 AHB 或 APB 總線),把 FLM 算法寫到 SRAM(比如`0x20000000`)。
- SWD 用兩條線(SWDIO 和 SWCLK),簡單高效,速度可達 50MHz(J-Link)。
- JTAG 用四條線(TCK、TMS、TDI、TDO),老派但可靠,適合復雜場景。
寄存器操作:調試器通過調試端口(Debug Port, DP)和訪問端口(Access Port, AP)搞寄存器:
- 設 PC:用 DCRSR 寄存器把 PC 寫成入口地址(比如`0x20000004`)。
- 設 SP:堆棧指針(SP)可能設到 SRAM 的高地址(比如`0x20001000`),保證算法跑得穩(wěn)。
- 控制 CPU:用 DHCSR 寄存器把 CPU 從 halt 切到 run,啟動算法。
調試模式:MCU 在調試模式下暫停(halt),調試器可以隨便折騰內存和寄存器,干完活再讓 CPU 跑起來。SWD/JTAG 是調試器的“魔法通道”,讓 FLM 算法從 PC 到 SRAM,再到跑起來,全程無縫銜接。

圖片 6:SWD/JTAG 的“魔法通道”
4.3 FLM 算法的“內功心法”
FLM 算法跑起來后,直接跟 Flash 控制器的寄存器“過招”,干這些活:
初始化(Init):
- 解鎖 Flash:比如 APM32F4 要往 KEYR 寄存器寫`0x45670123`和`0xCDEF89AB`,解開 Flash 的“鎖”。
- 設參數:調 Flash 控制器的時鐘(FLASH_ACR 寄存器)、電壓、模式,保證后續(xù)操作不出岔子。
擦扇區(qū)(EraseSector):
- 往 CR 寄存器寫 ERASE 命令,指定扇區(qū)地址(比如`0x08004000`)。
- 盯著 SR 寄存器的 BSY 位,等擦除完成(可能要 50ms)。
- 檢查錯誤:比如看 WRPERR(寫保護錯誤)或 PGERR(編程錯誤)位。
寫數據(ProgramPage):
- 把用戶代碼按頁面(比如 2KB)寫進 Flash,每次寫完查 SR 寄存器的 EOP(操作結束)位。
- 循環(huán)寫:一般是 32 位或 64 位對齊寫,效率高點。
校驗(Verify):
- 讀 Flash 的數據,跟原數據比對,確認沒寫錯。
- 可能用 CRC 或校驗和,確保數據靠譜。
錯誤處理:FLM 算法得有點“智商”,比如檢測 Flash 控制器的錯誤標志(PGERR、WRPERR),返回給調試器,報個錯。這些操作全靠 FLM 算法直接戳 Flash 控制器的寄存器,效率高、針對性強。

圖片 7:FLM 算法的“內功心法”
4.4 SRAM 地址沖突:隱藏的“雷區(qū)”
FLM 算法用 SRAM 地址得小心,別跟用戶代碼“搶地盤”:
用戶代碼的地兒:用戶程序可能在 SRAM 里放堆棧、全局變量、緩沖區(qū)。比如 APM32F4 的用戶代碼常從`0x20010000`開始用。
中斷向量表:Cortex-M 核的中斷向量表可能也在 SRAM(比如`0x20000000`),FLM 得避開。
廠商的招:FLM 算法選 SRAM 低地址(比如`0x20000000`),用戶代碼用高地址,分開走,互不干擾。
風險:要是地址重了,可能數據被覆蓋,程序崩了。比如 FLM 算法占了`0x20000000-0x20001000`,用戶代碼也用這塊,堆棧就廢了。
解法:開發(fā)自定義 FLM 時,查數據手冊的內存地圖,挑安全地址。廠商的 FLM 一般都考慮好了這點。

圖片 8:地址沖突的“雷區(qū)”示意圖
4.5 性能優(yōu)化:讓刷代碼更快點
FLM 算法的效率直接影響刷代碼的速度,幾個關鍵點:
SRAM 快:SRAM 訪問只要 1-2 個時鐘周期,跑算法效率高。
調試器速度:J-Link 的 SWD 最高 50MHz,DAPLink 才 1-10MHz,J-Link 刷得更快。
算法優(yōu)化:
- 批量寫:一次寫 2KB 頁面,比多次寫 256 字節(jié)塊省時間。
- 少輪詢:優(yōu)化 FLM 算法,減少查 SR 寄存器 BSY 位的次數。
- 用緩存:有些 MCU 的 Flash 控制器支持緩存(比如 APM32F4 的 FLASH_ACR),FLM 算法能用上,寫得更快。
MCU 硬件:Flash 控制器的性能(比如 APM32F4 擦扇區(qū)要 50ms)是瓶頸,FLM 得調好參數(比如 FLASH_ACR 的時鐘設置)。

圖片 9:性能優(yōu)化的“加速器”
五、總結:FLM 算法的“前世今生”
FLM 下載算法是 Keil MDK 刷代碼的“幕后大佬”,從存儲到運行,全程靠團隊配合:
是啥:FLM 文件是個二進制“黑盒”,裝著 Flash 編程的算法代碼和元數據,告訴調試器咋刷 Flash。
為啥用 SRAM:Flash 擦除時不能跑代碼,速度還慢;調試器存不下 FLM;SRAM 快、靈活、用完就丟,完美!
咋干的:Keil 讀 FLM 文件,調試器(J-Link 或 DAPLink)把算法塞到 SRAM,設好 PC 讓它跑,搞定 Flash 擦寫。
硬核咋來:FLM 從源代碼到二進制,靠鏈接腳本和元數據定地址;SWD/JTAG 負責內存和寄存器操作;算法直接戳 Flash 控制器,效率拉滿。

圖片 10:整體流程的“大合照”
這篇從 FLM 是啥開始,講到為啥選 SRAM,再到咋加載、咋跑,最后深挖編譯、寄存器、性能優(yōu)化的硬核細節(jié),層層遞進。希望大家看完后,對 FLM 算法不再懵逼,刷代碼更有底氣!有啥具體問題,歡迎留言與交流!
注:文章作者在原帖中提供了代碼文件,有需要請至原文21ic論壇
原文地址:https://bbs.21ic.com/icview-3477484-1-1.html
-
mcu
+關注
關注
147文章
18924瀏覽量
397987 -
嵌入式
+關注
關注
5198文章
20442瀏覽量
333961 -
keil
+關注
關注
69文章
1230瀏覽量
172624
原文標題:APM32芯得 EP.68 | 聊聊MCU下載算法(FLM)在Keil MDK里的那些事兒:從入門到硬核
文章出處:【微信號:geehysemi,微信公眾號:Geehy極海半導體】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
聊聊MCU下載算法在Keil MDK里的那些事兒
評論