整理:MilerShao 某日,一來自北京的工程師跟我說在使用STM32L151芯片做產(chǎn)品開發(fā),,基本功能開發(fā)完畢,。他欲通過用戶程序?qū)π酒畔K的相關選項字節(jié)進行配置,,來完成芯片的讀保護,。結(jié)果他發(fā)現(xiàn)無法利用其用戶程序?qū)崿F(xiàn)芯片的讀保護加密,。 他把涉及芯片讀保護操作的代碼發(fā)給我,希望協(xié)助查看測試,。我簡單測試了下,,發(fā)現(xiàn)可以實現(xiàn)讀保加密并告知測試結(jié)果。他很快反饋說,,讀保護加密的確實現(xiàn)了,但程序沒法跑了,。因為忙碌,,沒做進一步測試,只是讓他再檢查下代碼,。 過了個周末,,客戶工程師還是充滿憂傷和委屈繼續(xù)追問此事。因為我覺得即使他自己寫不來那個讀保護加密代碼也沒關系,,交給其它燒錄工具來實現(xiàn)并沒啥不好或不方便,。可這哥們訴說他的經(jīng)理非要它用自己的代碼實現(xiàn),,不停追問結(jié)果,,折騰好幾天無果。 該工程師是利用ST官方標準固件庫做的,,跟我手頭上的一樣,,都是STM32L1系列標準固件庫1.3.
隨便搭建了個項目,并在代碼里做讀保護代碼的編寫。編譯生成機器碼,,燒錄程序進入STM32L15x所在目標板,。復位目標板,發(fā)現(xiàn)程序真的無法運行,。通過STLINK UTLITY或STVP連接目標板,,發(fā)現(xiàn)芯片的確已經(jīng)做了LEVEL 1讀保護加密。 去掉源代碼里相關讀保護的程序代碼,,再次編譯,、燒錄,程序運行 一切正常,。當代碼里加了讀保護代碼后程序無法正常運行,,那問題一定出在那段讀保護操作的代碼上。用戶的代碼主要就下面幾句,,那最有可能出問題應該在藍色那句,。該句函數(shù)調(diào)用做實質(zhì)的讀保護操作。 Rdp_Status=FLASH_OB_GetRDP(); //查詢當前芯片讀保護狀態(tài) if(Rdp_Status== RESET) { FLASH_Unlock(); FLASH_OB_Unlock(); FLASH_OB_RDPConfig(OB_RDP_Level_1);//做讀保護配置操作 FLASH_OB_Lock(); FLASH_Lock(); FLASH_OB_Launch(); } ********************************************************************* 打開上面藍色語句的函數(shù)調(diào)用,,其具體函數(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; } 上面代碼應該說也很簡單,,就幾條賦值語句。目的就是給讀保護相關選項賦予適當?shù)臄?shù)值,。這里代碼有無問題就有必要結(jié)合手冊相關部分和相關定義來做解讀,。不妨看看RDP操作相關部分。
每個OPTION項都是一個32位字,,高16位與低16位必須成互補關系,。 其中讀保護項是在上面的第一個選項字中配置的,除了 RDP和nRDP外,,還有SPRMOD和nSPROMOD,他們共同組成一個完整的,、可互補校驗的配置字。 結(jié)合上面的原則再過來看上面提到的讀保護配置函數(shù): FLASH_OB_RDPConfig( uint8_t OB_RDP); 這里OB_RDP為0xBB,目的是為了實現(xiàn)LEVEL 1讀保護加密,。 當按照如下代碼換算后: 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所在的選項字。這樣寫顯然不符合上面的約定:選項字的高16位與低16位應該成互補關系,。即使這樣強行寫進去,,校驗還是會出錯。這應該就是執(zhí)行該操作程序無法運行的原因,。 將上面代碼的兩個地方簡單修改下,,其它不動。 uint8_t tmp1 = 0; ==> uint16_t tmp1 = 0; tmp1 = (uint8_t)(~(OB_RDP )); ==> tmp1 =(~((uint16_t)(OB_RDP ))); 按照上面描述修改后,,賦給RDP選項字的值便是0xFF4400BB.將修改過的代碼重新燒錄,。斷電、復位等都不出現(xiàn)死機現(xiàn)象,程序運行正常,,利用相關工具查看芯片證實已經(jīng)做了LEVEL 1級別讀保護,。 看來導致上面問題的原因可以歸結(jié)于ST官方參考庫函數(shù)的問題,是個BUG.不過結(jié)合芯片參考手冊還是可以發(fā)現(xiàn)和調(diào)整的,。后來我去ST官網(wǎng)找了下有無關于SMT32L15X系列的最新固件庫,,發(fā)現(xiàn)了1.31版本,比上面提到的版本新一點,,特地查看了新版本的相關函數(shù),,新版在這個地方已經(jīng)做了更正。 他們修改時跟我上面提到的有些差異,,是因為考慮到做RDP調(diào)整時不要影響當前各SECTOR讀寫保護狀態(tài)的設置,。 所以在利用庫函數(shù)編程遇到某些感覺很可能非自己軟件代碼原因?qū)е翸CU功能異常時,不妨點進相關庫函數(shù)結(jié)合技術手冊仔細查看確認下,,或者找找有無更新版本的固件庫,。雖說ST官方庫做得相當不錯了,但BUG或多或少都存在,。建議剛著手開發(fā)時,,盡可能下載最新版本的固件庫和相關技術資料。 |