前言
最近拿到了一塊APM32F103VC的MINI開(kāi)發(fā)板,在學(xué)習(xí)了一段時(shí)間后發(fā)現(xiàn)其有非常豐富的外設(shè)資源,主頻能達(dá)到96Mhz。最近在項(xiàng)目中使用到了IAP(In Application Programming)功能,特來(lái)評(píng)估一下APM32F103的IAP實(shí)現(xiàn)方式。
在應(yīng)用編程IAP(In-Application Programming)是應(yīng)用在Flash程序存儲(chǔ)器的一種編程模式。它可以在應(yīng)用程序正常運(yùn)行的情況下,通過(guò)調(diào)用特定的IAP程序?qū)α硗庖欢纬绦騀lash空間進(jìn)行讀/寫(xiě)操作,甚至可以控制對(duì)某段、某頁(yè)甚至某個(gè)字節(jié)的讀/寫(xiě)操作,這為數(shù)據(jù)存儲(chǔ)和固件的現(xiàn)場(chǎng)升級(jí)帶來(lái)了更大的靈活性。
話接上回,我們提及到了 程序跳轉(zhuǎn)運(yùn)行就是修改PC指針至我們的APP程序,然后修改我們的中斷向量寄存器以使得我們的APP程序能夠正確相應(yīng)中斷。
那我們本章節(jié)就在IAP實(shí)現(xiàn)的第三部分內(nèi)容,F(xiàn)lash編程的基礎(chǔ)進(jìn)行梳理。
1 為什么要編程Flash?
眾所周知,MCU的Flash保存著我們的程序,一般情況下我們?cè)谏a(chǎn)或者調(diào)試的時(shí)候是通過(guò)我們的燒錄器或者仿真器對(duì)MCU的Flash進(jìn)行編程。在這個(gè)過(guò)程中我們無(wú)需關(guān)系Flash的編程流程,僅需要通過(guò)工具即可完成對(duì)Flash的編程操作。
那為什么做IAP需要關(guān)心Flash編程呢?因?yàn)镮AP的一個(gè)關(guān)鍵因素就能夠通過(guò)BootLoader去編程我們的APP區(qū)域的內(nèi)容。
即我們需要實(shí)現(xiàn)對(duì)MCU的Flash編程操作。
2 Flash的編程流程
在APM32F103的手冊(cè),我們可以看到Flash編程一共分為解鎖,擦除,編程,上鎖的四個(gè)步驟。下面我們一步步看一下我們需要完成哪些操作。
2.1 Flash解鎖與上鎖
Flash是我們程序保存的地方,需要編程FLash必須是“確定的”,而不是我們“一時(shí)興起”。所以涉及較為繁瑣的“解鎖”步驟,以防我們重要的程序內(nèi)容被改動(dòng)。
APM32F1的標(biāo)準(zhǔn)庫(kù)函數(shù)如下所示:
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url] Unlocks the FMC Program Erase Controller
*
* @param None
*
* @retval None
*/
void FMC_Unlock(void)
{
FMC->KEY = 0x45670123;
FMC->KEY = 0xCDEF89AB;
}
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url] Locks the FMC Program Erase Controller.
*
* @param None
*
* @retval None
*/
void FMC_Lock(void)
{
FMC->CTRL2_B.LOCK = BIT_SET;
}
2.2 Flash的擦除
由于APM32F1 的Flash的特性,對(duì)Flash寫(xiě)入數(shù)據(jù)的地址內(nèi)容必須是0xFFFF,打個(gè)比方來(lái)說(shuō),我們要在一張紙上畫(huà)一幅精彩的畫(huà)作,那我們的紙張必須要是空白的,這樣子才能不受紙張上的污漬影響我們。
那對(duì)于APM32F1的Flash來(lái)說(shuō),0xFFFF是“空白”狀態(tài),這個(gè)狀態(tài)下我們才能盡情的“書(shū)寫(xiě)”內(nèi)容。
那Flash的擦除操作,便是把Flash變回“空白”的操作。
擦除有分“全擦除”和“頁(yè)擦除”,由于我們的BootLoader也是存儲(chǔ)于Flash中的,我們?nèi)羰鞘褂谩叭脸辈僮魑覀兊腂ootLoader程序也會(huì)被擦除掉,使得MCU處于“空片”狀態(tài)。所以我們會(huì)使用“頁(yè)擦除”完成對(duì)APP存儲(chǔ)的區(qū)域進(jìn)行擦除操作。
APM32F1的標(biāo)準(zhǔn)庫(kù)函數(shù)如下所示:
/*!
* @brief Erases a specified FMC page.
*
* @param pageAddr: The page address to be erased.
*
* @retval Returns the flash state.It can be one of value:
* [url=home.php?mod=space&uid=2817080]@ARG[/url] FMC_STATUS_BUSY
* [url=home.php?mod=space&uid=2817080]@ARG[/url] FMC_STATUS_ERROR_PG
* @arg FMC_STATUS_ERROR_WRP
* @arg FMC_STATUS_COMPLETE
* @arg FMC_STATUS_TIMEOUT
*/
FMC_STATUS_T FMC_ErasePage(uint32_t pageAddr)
{
FMC_STATUS_T status = FMC_STATUS_COMPLETE;
status = FMC_WaitForLastOperation(0x000B0000);
if(status == FMC_STATUS_COMPLETE)
{
FMC->CTRL2_B.PAGEERA = BIT_SET;
FMC->ADDR = pageAddr;
FMC->CTRL2_B.STA = BIT_SET;
status = FMC_WaitForLastOperation(0x000B0000);
FMC->CTRL2_B.PAGEERA = BIT_RESET;
}
return status;
}
/*!
* @brief Erases all FMC pages.
*
* @param None
*
* @retval Returns the flash state.It can be one of value:
* @arg FMC_STATUS_ERROR_PG
* @arg FMC_STATUS_ERROR_WRP
* @arg FMC_STATUS_COMPLETE
* @arg FMC_STATUS_TIMEOUT
*/
FMC_STATUS_T FMC_EraseAllPage(void)
{
FMC_STATUS_T status = FMC_STATUS_COMPLETE;
status = FMC_WaitForLastOperation(0x000B0000);
if(status == FMC_STATUS_COMPLETE)
{
FMC->CTRL2_B.MASSERA = BIT_SET;
FMC->CTRL2_B.STA = BIT_SET;
status = FMC_WaitForLastOperation(0x000B0000);
FMC->CTRL2_B.MASSERA = BIT_RESET;
}
return status;
}
2.3 Flash的編程
在上面我們完成對(duì)目標(biāo)區(qū)域的擦除操作后,便可以對(duì)Flash進(jìn)行編程操作了。
在APM32F1的標(biāo)準(zhǔn)庫(kù)函數(shù)中給我們提供了字編程與半字編程操作。
/*!
* @brief Programs a word at a specified address.
*
* @param address:the address to be programmed.
*
* @param data: the data to be programmed.
*
* @retval Returns the flash state.It can be one of value:
* @arg FMC_STATUS_ERROR_PG
* @arg FMC_STATUS_ERROR_WRP
* @arg FMC_STATUS_COMPLETE
* @arg FMC_STATUS_TIMEOUT
*/
FMC_STATUS_T FMC_ProgramWord(uint32_t address, uint32_t data)
{
FMC_STATUS_T status = FMC_STATUS_COMPLETE;
__IOM uint32_t temp = 0;
#ifdef APM32F10X_HD
__set_PRIMASK(1);
#endif
status = FMC_WaitForLastOperation(0x000B0000);
if(status == FMC_STATUS_COMPLETE)
{
FMC->CTRL2_B.PG = BIT_SET;
*(__IOM uint16_t *)address = data;
status = FMC_WaitForLastOperation(0x000B0000);
if(status == FMC_STATUS_COMPLETE)
{
temp = address + 2;
*(__IOM uint16_t*) temp = data >> 16;
status = FMC_WaitForLastOperation(0x000B0000);
FMC->CTRL2_B.PG = BIT_RESET;
}
else
{
FMC->CTRL2_B.PG = BIT_RESET;
}
}
#ifdef APM32F10X_HD
__set_PRIMASK(0);
#endif
return status;
}
/*!
* @brief Programs a half word at a specified address.
*
* @param address:the address to be programmed.
*
* @param data: the data to be programmed.
*
* @retval Returns the flash state.It can be one of value:
* @arg FMC_STATUS_ERROR_PG
* @arg FMC_STATUS_ERROR_WRP
* @arg FMC_STATUS_COMPLETE
* @arg FMC_STATUS_TIMEOUT
*/
FMC_STATUS_T FMC_ProgramHalfWord(uint32_t address, uint16_t data)
{
FMC_STATUS_T status = FMC_STATUS_COMPLETE;
#ifdef APM32F10X_HD
__set_PRIMASK(1);
#endif
status = FMC_WaitForLastOperation(0x000B0000);
if(status == FMC_STATUS_COMPLETE)
{
FMC->CTRL2_B.PG = BIT_SET;
*(__IOM uint16_t *)address = data;
status = FMC_WaitForLastOperation(0x000B0000);
FMC->CTRL2_B.PG = BIT_RESET;
}
#ifdef APM32F10X_HD
__set_PRIMASK(0);
#endif
return status;
}
3 Flash的讀取
完成對(duì)目標(biāo)區(qū)域的Flash的編程后,我們一般情況下都需要進(jìn)行校驗(yàn),校驗(yàn)我們寫(xiě)入到Flash的實(shí)際內(nèi)容與我們的期望內(nèi)容是否一致。
我們可以使用直接讀取比較,或者CRC校驗(yàn)的方式進(jìn)行校驗(yàn)。校驗(yàn)的方法多種多樣,但是都離不開(kāi)Flash的讀取。APM32F1的Flash讀取較為簡(jiǎn)單,可以直接使用地址指針直接讀取相應(yīng)地址的內(nèi)容。
data = *(__IOM uint16_t *)address;
data = *(__IOM uint32_t *)address;
審核編輯 :李倩
-
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7455瀏覽量
163623 -
編程
+關(guān)注
關(guān)注
88文章
3596瀏覽量
93610 -
開(kāi)發(fā)板
+關(guān)注
關(guān)注
25文章
4959瀏覽量
97214
原文標(biāo)題:APM32芯得 EP.13 | APM32F103_IAP的簡(jiǎn)單實(shí)現(xiàn)_flash編程基礎(chǔ)
文章出處:【微信號(hào):geehysemi,微信公眾號(hào):Geehy極海半導(dǎo)體】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論