標(biāo)題: 一個(gè)關(guān)于MCU讀保護(hù)操作后程序不能運(yùn)行的話題 [打印本頁(yè)]

作者: taoran    時(shí)間: 2015-12-8 03:04
標(biāo)題: 一個(gè)關(guān)于MCU讀保護(hù)操作后程序不能運(yùn)行的話題
整理:MilerShao

某日,一來(lái)自北京的工程師跟我說在使用STM32L151芯片做產(chǎn)品開發(fā),基本功能開發(fā)完畢。他欲通過用戶程序?qū)π酒畔K的相關(guān)選項(xiàng)字節(jié)進(jìn)行配置,來(lái)完成芯片的讀保護(hù)。結(jié)果他發(fā)現(xiàn)無(wú)法利用其用戶程序?qū)崿F(xiàn)芯片的讀保護(hù)加密。

他把涉及芯片讀保護(hù)操作的代碼發(fā)給我,希望協(xié)助查看測(cè)試。我簡(jiǎn)單測(cè)試了下,發(fā)現(xiàn)可以實(shí)現(xiàn)讀保加密并告知測(cè)試結(jié)果。他很快反饋說,讀保護(hù)加密的確實(shí)現(xiàn)了,但程序沒法跑了。因?yàn)槊β,沒做進(jìn)一步測(cè)試,只是讓他再檢查下代碼。

過了個(gè)周末,客戶工程師還是充滿憂傷和委屈繼續(xù)追問此事。因?yàn)槲矣X得即使他自己寫不來(lái)那個(gè)讀保護(hù)加密代碼也沒關(guān)系,交給其它燒錄工具來(lái)實(shí)現(xiàn)并沒啥不好或不方便?蛇@哥們?cè)V說他的經(jīng)理非要它用自己的代碼實(shí)現(xiàn),不停追問結(jié)果,折騰好幾天無(wú)果。

該工程師是利用ST官方標(biāo)準(zhǔn)固件庫(kù)做的,跟我手頭上的一樣,都是STM32L1系列標(biāo)準(zhǔn)固件庫(kù)1.3.

隨便搭建了個(gè)項(xiàng)目,并在代碼里做讀保護(hù)代碼的編寫。編譯生成機(jī)器碼,燒錄程序進(jìn)入STM32L15x所在目標(biāo)板。復(fù)位目標(biāo)板,發(fā)現(xiàn)程序真的無(wú)法運(yùn)行。通過STLINK UTLITY或STVP連接目標(biāo)板,發(fā)現(xiàn)芯片的確已經(jīng)做了LEVEL 1讀保護(hù)加密。

去掉源代碼里相關(guān)讀保護(hù)的程序代碼,再次編譯、燒錄,程序運(yùn)行

一切正常。當(dāng)代碼里加了讀保護(hù)代碼后程序無(wú)法正常運(yùn)行,那問題一定出在那段讀保護(hù)操作的代碼上。用戶的代碼主要就下面幾句,那最有可能出問題應(yīng)該在藍(lán)色那句。該句函數(shù)調(diào)用做實(shí)質(zhì)的讀保護(hù)操作。

Rdp_Status=FLASH_OB_GetRDP(); //查詢當(dāng)前芯片讀保護(hù)狀態(tài)

if(Rdp_Status== RESET)

{

FLASH_Unlock();

FLASH_OB_Unlock();

FLASH_OB_RDPConfig(OB_RDP_Level_1);//做讀保護(hù)配置操作

FLASH_OB_Lock();

FLASH_Lock();

FLASH_OB_Launch();

}

*********************************************************************

打開上面藍(lán)色語(yǔ)句的函數(shù)調(diào)用,其具體函數(shù)實(shí)現(xiàn)代碼如下:

FLASH_Status FLASH_OB_RDPConfig(uint8_t OB_RDP)

{

FLASH_Status status = FLASH_COMPLETE;

uint8_t tmp1 = 0;

uint32_t tmp2 = 0;

/* Check the parameters */

assert_param(IS_OB_RDP(OB_RDP));

status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

/* calculate the option byte to write */

tmp1=(uint8_t)(~(OB_RDP ));

tmp2=(uint32_t)(((uint32_t)((uint32_t)(tmp1)<<16))|((uint32_t)OB_RDP));

if(status == FLASH_COMPLETE)

{

OB->RDP = tmp2; /* program read protection level */

}

/* Wait for last operation to be completed */

status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

/* Return the Read protection operation Status */

return status;

}

上面代碼應(yīng)該說也很簡(jiǎn)單,就幾條賦值語(yǔ)句。目的就是給讀保護(hù)相關(guān)選項(xiàng)賦予適當(dāng)?shù)臄?shù)值。這里代碼有無(wú)問題就有必要結(jié)合手冊(cè)相關(guān)部分和相關(guān)定義來(lái)做解讀。不妨看看RDP操作相關(guān)部分。




每個(gè)OPTION項(xiàng)都是一個(gè)32位字,高16位與低16位必須成互補(bǔ)關(guān)系。

其中讀保護(hù)項(xiàng)是在上面的第一個(gè)選項(xiàng)字中配置的,除了 RDP和nRDP外,還有SPRMOD和nSPROMOD,他們共同組成一個(gè)完整的、可互補(bǔ)校驗(yàn)的配置字。

結(jié)合上面的原則再過來(lái)看上面提到的讀保護(hù)配置函數(shù):

FLASH_OB_RDPConfig( uint8_t OB_RDP); 這里OB_RDP為0xBB,目的是為了實(shí)現(xiàn)LEVEL 1讀保護(hù)加密。 當(dāng)按照如下代碼換算后:

tmp1 = (uint8_t)(~(OB_RDP ));

tmp2=(uint32_t)(((uint32_t)((uint32_t)(tmp1)<<16))|((uint32_t)OB_RDP));

OB->RDP = tmp2; /* program read protection level */

Tmp2的結(jié)果是0x004400BB,然后把它寫給RDP所在的選項(xiàng)字。這樣寫顯然不符合上面的約定:選項(xiàng)字的高16位與低16位應(yīng)該成互補(bǔ)關(guān)系。即使這樣強(qiáng)行寫進(jìn)去,校驗(yàn)還是會(huì)出錯(cuò)。這應(yīng)該就是執(zhí)行該操作程序無(wú)法運(yùn)行的原因。

將上面代碼的兩個(gè)地方簡(jiǎn)單修改下,其它不動(dòng)。

uint8_t tmp1 = 0; ==> uint16_t tmp1 = 0;

tmp1 = (uint8_t)(~(OB_RDP )); ==> tmp1 =(~((uint16_t)(OB_RDP )));

按照上面描述修改后,賦給RDP選項(xiàng)字的值便是0xFF4400BB.將修改過的代碼重新燒錄。斷電、復(fù)位等都不出現(xiàn)死機(jī)現(xiàn)象,程序運(yùn)行正常,利用相關(guān)工具查看芯片證實(shí)已經(jīng)做了LEVEL 1級(jí)別讀保護(hù)。

看來(lái)導(dǎo)致上面問題的原因可以歸結(jié)于ST官方參考庫(kù)函數(shù)的問題,是個(gè)BUG.不過結(jié)合芯片參考手冊(cè)還是可以發(fā)現(xiàn)和調(diào)整的。后來(lái)我去ST官網(wǎng)找了下有無(wú)關(guān)于SMT32L15X系列的最新固件庫(kù),發(fā)現(xiàn)了1.31版本,比上面提到的版本新一點(diǎn),特地查看了新版本的相關(guān)函數(shù),新版在這個(gè)地方已經(jīng)做了更正。

他們修改時(shí)跟我上面提到的有些差異,是因?yàn)榭紤]到做RDP調(diào)整時(shí)不要影響當(dāng)前各SECTOR讀寫保護(hù)狀態(tài)的設(shè)置。

所以在利用庫(kù)函數(shù)編程遇到某些感覺很可能非自己軟件代碼原因?qū)е翸CU功能異常時(shí),不妨點(diǎn)進(jìn)相關(guān)庫(kù)函數(shù)結(jié)合技術(shù)手冊(cè)仔細(xì)查看確認(rèn)下,或者找找有無(wú)更新版本的固件庫(kù)。雖說ST官方庫(kù)做得相當(dāng)不錯(cuò)了,但BUG或多或少都存在。建議剛著手開發(fā)時(shí),盡可能下載最新版本的固件庫(kù)和相關(guān)技術(shù)資料。






歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1