前言
最近在做的一個項目中,需要經常把一些參數下載到I2C EEPROM中,然后MCU上電去讀取。如果在產品量產過程中,可以使用燒錄治具往EEPROM寫入一次即可。但是在調試開發階段,需要經常修改這些數據,調試起來非常不方便。
我調試的環境是MDK-Keil,于是網上了解了下如何制作Keil的下載算法,下面介紹下基于APM32F407如何制作I2C EEPROM(AT24C02型號)的Keil下載算法,這樣在我們下載代碼時可以一鍵把數據燒錄到EEPROM中。
對于 Keil 的下載算法文件相關的詳細介紹可以到官方在線文檔進行了解,這些文檔詳細介紹了下載算法的實現細節。文檔鏈接如下:
https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/flashAlgorithm.html
1. Keil如何調用下載算法
Keil的下載算法,我的理解就是可以通過Keil去調用該下載算法,然后可以去編程各種存儲設備,比如MCU內部的Flash,通過MCU外設連接外擴的SPI Flash或者I2C EEPROM等器件。
要想通過Keil IDE的下載按鈕一鍵編程這些存儲設備,那么需要有對應器件的下載算法才能去編程。對于Keil來說通過調試界面指定相應的下載算法 xxx.FLM 文件,然后就可以被調用了,如下圖:
??Keil 在調試下載階段,會把算法文件加載到芯片的內部 RAM 里面,加載的芯片內部的RAM地址和大小可以在上面的配置截圖進行設置。然后就可以在 RAM 中執行這個下載算法文件的擦除、編程等函數,從而實現對存儲設備下載程序或者在調試階段讀取數據等操作。
大致流程如下圖:??
主要是分為兩步:
通過SWD/JTAG調試接口,把下載算法加載到RAM。
執行下載算法的擦除、編程等函數,從而對內部Flash進行編程或者通過MCU的片上外設對外擴的SPI FLASH/I2C EEPROM執行編程操作。
另外,前面說到會把下載算法文件加載到 RAM 運行,而且我們可以設置加載到任何的 RAM 地址運行,那么對下載算法生成的代碼必須是與位置無關的代碼,這樣才能加載到任意 RAM 地址運行。
2.Keil下載算法函數和執行流程
2.1 下載算法需要實現哪些函數
根據官方文檔介紹,要制作一個新的下載算法需要實現函數有:
一共有7個函數,而且這些函數的原型已經規定好了的,只需要我們根據不同的存儲設備實現具體的功能即可。
其中有 mandatory 修飾的函數,是制作一個新的下載算法必須要實現的函數是,而 optional 修飾的函數則可根據需要實現還是不實現。
2.2 擦除流程
加載算法到芯片 RAM。
執行初始化函數 Init。
執行擦除操作。其中擦除操作會根據Keil的配置選項,選擇是擦除整個芯片還是扇區擦除。
執行 Uinit 函數。
擦除完成。
2.3 編程流程
編程流程,就是把編譯出來的可執行程序下載到Flash或者其他存儲器。
對于所有 AXF 文件內容,執行 Init 初始化函數
判斷 Flash 算法是否在FLM文件中。不在則編程結束,返回失敗。如果編程算法存在,則執行下面操作:
(1)加載算法到RAM
(2)執行Init函數
(3)加載應用程序(待編程的數據)到RAM Buffer中
(4)執行Program Page編程函數
(5)執行Uninit函數
編程完成。
2.4 校驗流程
校驗就是把 AXF 文件中需要下載到Flash的數據,與實際下載到Flash的數據讀出來進行比較。
判斷 Flash 算法是否在FLM文件中,不在則操作失敗。如果編程算法存在,則執行下面操作:
(1)加載算法到RAM
(2)執行Init函數
(3)判斷FLM文件是否存在校驗算法。
存在則加載應用程序到RAM,然后執行FLM文件中的校驗算法
不存在則計算和比較CRC值。把下載到Flash的數據讀出來計算的CRC值,與 加載 axf 文件的數據到RAM中計算的CRC值進行比較。
執行Uninit函數
執行完 Uninit 函數后面的步驟,不是很理解,這后面的步驟是不是和調試有關的,在下載代碼時并沒有關系?
3. 制作Keil環境的I2C EEPROM下載算法
下面我基于APM32F407,制作AT24C02 EEPROM存儲芯片的下載算法。
對于下載算法的制作流程,官網已經給出了詳細的步驟,下面的步驟是從官網翻譯過來的。一個新的下載算法制作步驟:
將ARM:CMSIS Pack文件夾(通常為 C:KeilARMPackARMCMSIS version Device_Template_Flash)中的內容復制到新文件夾。
重命名項目文件NewDevice.uvprojx以表示新的閃存 ROM 設備名稱,例如MyDevice.uvprojx。
使用 uVision 打開項目。從工具欄中,使用下拉菜單“選擇目標”來定義處理器架構。Cortex-M適用于所有 Cortex-M0/M0+、M3 和 M4 設備。該配置假定采用小端微控制器。如果是大端微控制器,請使用Project - Options for Target - Device選擇正確的處理器內核。
打開對話框“項目-目標選項-輸出” ,然后更改“可執行文件名稱”字段的內容以表示設備,例如MyDevice。
調整文件FlashPrg中的編程算法。
調整文件FlashDev中的設備參數。
使用Project - Build Target生成新的Flash 編程算法。輸出文件(例如MyDevice.FLM)必須添加到DFP中。
上面的步驟就是官網給出的,下面我們就根據官網給出的步驟制作一個新的下載算法。
3.1 準備下載算法模板
下載算法的模板,我們在安裝Keil的時候就有了的。官網說在 keil 的安裝目錄下能找到,但是我安裝的是 5.36 版本,Keil安裝目錄沒有找到,而是在C:Users你的用戶名目錄AppDataLocalArmPacksARMCMSIS5.8.0Device_Template_Flash 這個目錄找的的下載算法模板。
我們把該目錄復制一份備用,然后記得把該文件夾的只讀屬性去掉。
3.2 Keil環境設置
1、把復制的模板工程的工程名,可以根據我們基于什么芯片制作下載算法修改一下工程名稱,這樣更具有辨識度。
2、修改選擇的目標芯片。
我是基于APM32F407制作下載算法文件,所以選擇M4內核就行。
3、修改編譯生成的下載算法文件的名稱。
4、添加APM32F407的外設驅動庫以及I2C EEPROM的讀寫驅動文件
由于我們是要實現 I2C EEPROM 的下載算法,在編寫這些下載算法函數之前,我們必須要先確保I2C EEPROM 的驅動可以正常讀寫。I2C EEPROM 的驅動可以從我們實現的例程驗證可行之后,然后挪過來使用即可。
3.3 修改FlashPrg.c文件中的編程算法函數
這一步是最重要的,我們實現Keil編程算法主要就是要實現 FlashPrg.c 文件中的各個下載算法函數。根據前面的介紹,一個新的下載算法必須要實現的函數有:Init/EraseSector/ProgramPage/Uninit這4個函數,其他函數可以根據需要是否實現。下面我們來一一實現這些函數。
1、Init函數的實現
/*
* Initialize Flash Programming Functions
* Parameter: adr: Device Base Address
* clk: Clock Frequency (Hz)
* fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
* Return Value: 0 - OK, 1 - Failed
*/
int Init (unsigned long adr, unsigned long clk, unsigned long fnc)
{
/* 系統初始化 */
//SystemInit(); // 如果使用了庫文件的該函數會導致下載是0x08000000地址校驗失敗,但是實際測試又是下載進去了。不知道什么原因
I2C_Init();
return 0;
}
在該函數中,我們可以初始化編程存儲器的一些操作,比如配置時鐘,GPIO的初始化等等。
2、扇區擦除和整片芯片擦除函數
/*
* Erase complete Flash Memory
* Return Value: 0 - OK, 1 - Failed
*/
int EraseChip (void)
{
volatile int i = 0;
unsigned char tmepbuf[EE_PAGE_SIZE];
unsigned char adr = 0;
for(i = 0; i < EE_PAGE_SIZE; i++)
{
tmepbuf[i] = 0xFF;
}
for (i = 0; i < EE_SIZE / EE_PAGE_SIZE; i++)
{
ee_WriteBytes(tmepbuf, adr, EE_PAGE_SIZE);
adr += EE_PAGE_SIZE;
}
return 0;
}
/*
* Erase Sector in Flash Memory
* Parameter: adr: Sector Address
* Return Value: 0 - OK, 1 - Failed
*/
int EraseSector (unsigned long adr)
{
volatile int i = 0;
unsigned char tmepbuf[EE_PAGE_SIZE];
adr -= I2C_EEPROM_ADDR;
for(i = 0; i < EE_PAGE_SIZE; i++)
{
tmepbuf[i] = 0xFF;
}
ee_WriteBytes(tmepbuf, adr, EE_PAGE_SIZE);
return 0;
}
實際上對于EEPROM芯片,不需要擦除就能寫入數據的。不過為了示例,我們也實現這兩個擦除函數好了。對于EERPOM來說,擦除就是往它寫入0xFF數據即可。
3、ProgramPage 頁編程函數實現
#define I2C_EEPROM_ADDR 0x01000000
/*
* Program Page in Flash Memory
* Parameter: adr: Page Start Address
* sz: Page Size
* buf: Page Data
* Return Value: 0 - OK, 1 - Failed
*/
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf)
{
volatile int i = 0;
adr -= I2C_EEPROM_ADDR;
for(i = 0; i < sz/EE_PAGE_SIZE; i++)
{
ee_WriteBytes(buf+EE_PAGE_SIZE*i, adr+EE_PAGE_SIZE*i, EE_PAGE_SIZE);
}
if(sz%EE_PAGE_SIZE)
{
ee_WriteBytes(buf+EE_PAGE_SIZE*i, adr+EE_PAGE_SIZE*i, sz%EE_PAGE_SIZE);
}
return (0);
}
直接調用EEPROM的驅動寫函數即可。另外 I2C_EEPROM_ADDR 這個宏定義,是為了在我們的應用代碼中,定義數據時選擇哪一塊區域存儲EEPROM的數據,地址是我們可以隨意定義的。但是不能與MCU的外設地址,以及Flash、RAM等地址重合就行。
4、Uninit函數實現
該函數根據前面的Keil執行各編程流程,一般是退出編程時會被調用的,我們可以在該函數進行恢復的操作。該函數是必須實現的,如果不需要做任何動作,那么我們保持該函數為空函數就行。
/*
* De-Initialize Flash Programming Functions
* Parameter: fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
* Return Value: 0 - OK, 1 - Failed
*/
int UnInit (unsigned long fnc) {
/* Add your Code */
return (0); // Finished without Errors
}
3.4 修改FlashDev.c文件的設備參數
在FlashDev.c文件中有一個名為FlashDevice的結構體常量,這個結構體的信息是給 Keil 提供編程設備的信息的,比如編程的起始地址,總大小,一個扇區的大小,設備類型等等信息。我們根據自己的需要編程的設備類型修改即可。
struct FlashDevice const FlashDevice = {
FLASH_DRV_VERS, // Driver Version, do not modify!
"APM32F407_I2C_EEPROM_AT24C02", // Device Name
EXTSPI, // Device Type
0x01000000, // Device Start Address. EEPROM的編程地址。
0x00000100, // Device Size in Bytes
8, // Programming Page Size
0, // Reserved, must be 0
0xFF, // Initial Content of Erased Memory
6000, // Program Page Timeout 6000 mSec
6000, // Erase Sector Timeout 6000 mSec
// Specify Size and Address of Sectors
0x000008, 0x000000, // Sector Size 8B (32 Sectors)
// 0x010000, 0x010000, // Sector Size 64kB (2 Sectors)
// 0x002000, 0x030000, // Sector Size 8kB (8 Sectors)
SECTOR_END
};
3.5 生成算法文件
我們實現了 FlashPrg.c 文件的編程算法函數之后,直接編譯就可以生成 xxx.FLM 算法文件了。
在編譯之前,我們需要檢查生成的代碼是位置無關碼。在Keil設置如下:
C/C++和Asm選項卡都要檢查是否已經勾選了上面的配置。
點擊編譯即可生成Keil下載算法文件。
4. 新制作的下載算法文件使用和測試
1、把生成的下載算法文件放置到Keil安裝的目錄 C:Keil_v5ARMFlash 下待使用
2、Keil環境配置下載算法
3、APM32F407_I2C_EEPROM算法測試驗證。
我們使用下載算法下載數據到EERPOM,然后再通過應用程序讀出來進行對比寫進去的數據是否一致,就可以知道EEPROM下載算法是否起作用。
我們找一個 APM32F407 EEPROM 的例程進行測試。
(1)首先在例程里面定義下面待燒錄到EEPROM的數據:
const uint8_t EEPROM_FLM_Test1[16] __attribute__((at(0x01000000))) = {
0xCB,0xFF,0x01,0x02,0x03,0xAA,0x06,0x07,
0x08,0x09,0x10,0xA1,0xA2,0xA3,0xA4,0xBB
};
const uint8_t EEPROM_FLM_Test2[16] __attribute__((at(0x010000A0))) = {
0x12,0x34,0x01,0x02,0x03,0xAA,0x06,0x07,
0x08,0x09,0x10,0xA1,0xA2,0xA3,0xA4,0xBB
};
其中我們規定這些數組必須鏈接到 0x01000000 起始的地址,這是因為我們制作的 EEPROM 的下載算法編程地址就是在該范圍,這個地址會在下載算法內部轉換為EEPROM 編程的 0 地址,比如說 0x01000000 起始地址,對應的就算EEPROM的0地址。
(2)然后編譯下載代碼到Flash和EEPROM即可。
下載代碼時,檢測的0x01000000地址需要下載數據,Keil就會自動調用EEPROM的下載算法把數據編程到EEPROM了。
如下在下載程序沒有報錯,下載完成。
然后運行代碼,把EEPROM的數據讀出來,對比是否一致。
《APM32芯得》系列內容為用戶使用APM32系列產品的經驗總結,來自21ic論壇極海半導體專區。在此特別鳴謝!
-
算法
+關注
關注
23文章
4702瀏覽量
94971 -
EEPROM
+關注
關注
9文章
1084瀏覽量
83435 -
I2C
+關注
關注
28文章
1538瀏覽量
127248 -
keil
+關注
關注
69文章
1223瀏覽量
169196 -
極海半導體
+關注
關注
0文章
153瀏覽量
4825
原文標題:APM32芯得 EP.51 | 基于APM32F407制作I2C EEPROM的MDK-Keil下載算法
文章出處:【微信號:geehysemi,微信公眾號:Geehy極海半導體】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
國產優秀替代_APM32F407替代STM32F407記錄

《電子發燒友電子設計周報》聚焦硬科技領域核心價值 第7期:2025.04.7--2025.04.11
I2C—讀寫EEPROM
AT24C02與單片機連接的電路圖免費下載

EEPROM存儲芯片AT24C02芯片手冊

【STM32Cube_13】使用硬件I2C讀寫EEPROM(AT24C02)

STM32單片機基礎13——使用硬件I2C讀寫EEPROM(AT24C02)

Linux驅動開發-編寫(EEPROM)AT24C02驅動

評論