目前越來(lái)越多的微控器(MCU)應(yīng)用需要使用到復(fù)雜的算法及中間件解決方案(middleware solution),因此,如何保護(hù)軟件方案商開發(fā)出來(lái)的核心算法等知識(shí)產(chǎn)權(quán)代碼(IP-Code),便成為微控制器應(yīng)用中一項(xiàng)很重要的課題。因?yàn)檫@一重要的需求,AT32F402/405系列提供了安全庫(kù)區(qū)(SLIB)的功能,以防止重要的IP-Code被終端用戶的程序做修改或讀取,進(jìn)而達(dá)到保護(hù)的目的。本文檔將詳細(xì)闡述AT32F402/405系列安全庫(kù)區(qū)的應(yīng)用原理和軟件使用方法。
應(yīng)用原理
安全庫(kù)區(qū)的應(yīng)用原理
- 設(shè)定以密碼保護(hù)主閃存中指定范圍的程序區(qū)(即安全庫(kù)區(qū)),軟件方案商可將核心算法存放到此區(qū)域,以達(dá)到保護(hù)的功能,其余空白程序區(qū)可以提供給終端商客戶進(jìn)行二次開發(fā)。
- 安全庫(kù)區(qū)劃分為唯讀區(qū)(SLIB_READ_ONLY)及指令區(qū)(SLIB_INSTRUCTION),并可選擇部分或是整個(gè)安全庫(kù)區(qū)存放唯讀區(qū)或者指令區(qū)。
- 唯讀安全庫(kù)區(qū)(SLIB_READ_ONLY)的數(shù)據(jù)能透過I-Code和D-Code總線讀取,不能寫入。
- 指令安全庫(kù)區(qū)(SLIB_INSTRUCTION)內(nèi)的程序代碼僅能被MCU透過I-Code總線抓取指令(僅能被執(zhí)行),不能透過D-Code總線以讀取數(shù)據(jù)的方式讀取(包含ISP/ICP/調(diào)試模式以及從內(nèi)部RAM啟動(dòng)的程序),以讀取數(shù)據(jù)的方式去訪問SLIB_INSTRUCTION時(shí),讀到的數(shù)值全都是0xFF。
- 安全庫(kù)區(qū)的程序代碼及數(shù)據(jù),除非輸入正確的密碼,否則無(wú)法被擦除。在密碼不正確時(shí),對(duì)安全庫(kù)區(qū)執(zhí)行寫入或擦除,將會(huì)在FLASH_STS寄存器的EPPERR位置"1"提出警告。
- 終端用戶執(zhí)行主閃存的整片擦除時(shí),安全庫(kù)區(qū)的程序代碼及數(shù)據(jù)不會(huì)被擦除。
- 當(dāng)安全庫(kù)區(qū)的保護(hù)功能被啟動(dòng)后,可以透過在SLIB_PWD_CLR寄存器寫入先前設(shè)置的密碼來(lái)解除保護(hù)功能。解除安全庫(kù)區(qū)的保護(hù)時(shí),芯片將會(huì)執(zhí)行主閃存的整片擦除(包含安全庫(kù)區(qū)的內(nèi)容)。因此即使軟件方案商設(shè)置的密碼被泄漏,也不會(huì)有程序代碼外泄的疑慮。
下圖是包含安全庫(kù)區(qū)的主閃存區(qū)映射示意圖,安全庫(kù)區(qū)的程序代碼可以很容易地被終端用戶調(diào)用并執(zhí)行, 但不能直接被讀取,因而達(dá)到保護(hù)的功能。
圖1. 帶有安全庫(kù)區(qū)的主閃存區(qū)映射
安全庫(kù)區(qū)的范圍大小是以扇區(qū)(sector)為單位做設(shè)定,每一扇區(qū)的大小以實(shí)際MCU型號(hào)為準(zhǔn)。表1是AT32F402/405系列各型號(hào)的主閃存大小、每扇區(qū)大小及可設(shè)置范圍。另外啟動(dòng)程序代碼區(qū)在開啟了主存擴(kuò)展功能后,整個(gè)20KB區(qū)域也是可以作為安全庫(kù)區(qū)。
表1. AT32F402/405各型號(hào)閃存大小總表
如何啟動(dòng)安全庫(kù)區(qū)保護(hù)
默認(rèn)狀態(tài)下,安全庫(kù)區(qū)設(shè)定寄存器始終是不可讀且被寫保護(hù)。要想對(duì)安全庫(kù)區(qū)設(shè)定寄存器進(jìn)行寫操作,首先要對(duì)安全庫(kù)區(qū)設(shè)定寄存器解鎖,對(duì)SLIB_UNLOCK寄存器寫入解鎖0xA35F6D24值,通過查看SLIB_MISC_STS寄存器的SLIB_ULKF位確認(rèn)解鎖成功,隨后便允許對(duì)安全庫(kù)區(qū)設(shè)定寄存器寫入設(shè)定值。
啟動(dòng)主閃存安全庫(kù)區(qū)的步驟如下:
- 檢查FLASH_STS寄存器的OBF位,以確認(rèn)沒有其他正在進(jìn)行的閃存操作;
- 對(duì)SLIB_UNLOCK寄存器寫入0xA35F6D24,以進(jìn)行安全庫(kù)區(qū)解鎖;
- 檢查SLIB_MISC_STS寄存器的SLIB_ULKF位,以確認(rèn)解鎖成功;
- 在SLIB_SET_RANGE寄存器設(shè)定要保護(hù)的區(qū)域,包含SLIB的起始和結(jié)束地址以及SLIB指令區(qū)的起始地址;
- 等待OBF位變?yōu)椤?’;
- 在SLIB_SET_PWD寄存器設(shè)定安全區(qū)域密碼;
- 等待OBF位變?yōu)椤?’;
- 燒錄將存入安全庫(kù)區(qū)的代碼;
- 進(jìn)行系統(tǒng)復(fù)位,重裝載安全庫(kù)區(qū)設(shè)定字;
- 讀出SLIB_STS0/STS1寄存器用于判斷安全庫(kù)區(qū)設(shè)定結(jié)果。
注意事項(xiàng):
- 可在主閃存和主閃存擴(kuò)展區(qū)中設(shè)置安全庫(kù)區(qū),實(shí)際可設(shè)置范圍參見表1;
- 安全庫(kù)區(qū)代碼必須以扇區(qū)為單位進(jìn)行燒錄,且起始地址必須與主閃存地址或者擴(kuò)展區(qū)地址對(duì)齊;
- 中斷向量表是數(shù)據(jù)型態(tài)且通常會(huì)被放置在閃存的第一扇區(qū)(扇區(qū)0)內(nèi),請(qǐng)勿將閃存的第一扇區(qū)設(shè)定為安全庫(kù)區(qū)的指令區(qū);
關(guān)于安全庫(kù)區(qū)設(shè)定寄存器的詳細(xì)說(shuō)明,請(qǐng)參閱AT32F402/405系列技術(shù)手冊(cè)。
啟動(dòng)安全庫(kù)區(qū)的程序可參考安全庫(kù)區(qū)應(yīng)用范例project_l0中位于main.c中的slib_enable()函數(shù)。亦可使用雅特力的ICP或ISP刻錄工具做設(shè)定,后面章節(jié)將會(huì)有詳細(xì)的說(shuō)明。
如何解除安全庫(kù)區(qū)保護(hù)
當(dāng)安全庫(kù)區(qū)的保護(hù)功能被啟動(dòng)后,可以透過在SLIB_PWD_CLR寄存器寫入先前設(shè)置的密碼來(lái)解除保護(hù)功能。解除安全庫(kù)區(qū)的保護(hù)時(shí),芯片將會(huì)執(zhí)行主閃存的整片擦除(包含安全庫(kù)區(qū)的內(nèi)容)。解除主閃存安全庫(kù)區(qū)的步驟如下:
- 檢查FLASH_STS寄存器的OBF位,以確認(rèn)沒有其他正在進(jìn)行的編程操作;
- 在SLIB_PWD_CLR寄存器寫入先前設(shè)置的安全區(qū)域密碼;
- 進(jìn)行系統(tǒng)復(fù)位,重裝載安全庫(kù)區(qū)設(shè)定字;
- 讀出SLIB_STS0寄存器用于判斷安全庫(kù)區(qū)設(shè)定結(jié)果。
編排及執(zhí)行安全庫(kù)區(qū)的程序
如前面章節(jié)所提到,在指令安全庫(kù)區(qū)(SLIB_INSTRUCTION)內(nèi)的的程序代碼可以被MCU經(jīng)由I-Code總線抓取,但不能經(jīng)由D-Code總線以讀取數(shù)據(jù)的方式去讀出,這樣的保護(hù)是全面性的,也就是說(shuō)在指令安全庫(kù)區(qū)之內(nèi)的程序代碼,也不能讀取同樣被放置在指令安全庫(kù)區(qū)之內(nèi)的數(shù)據(jù),例如C程序代碼常被編譯成的文字池(literal pool)、分支表(branch table)或常數(shù)(constant)等之類當(dāng)指令被執(zhí)行時(shí)會(huì)經(jīng)由D-Code總線去讀取的數(shù)據(jù)。這代表指令安全庫(kù)區(qū)之內(nèi)只能放置指令,不能放置任何數(shù)據(jù)。因此用戶在編排要放置在指令安全庫(kù)區(qū)之內(nèi)的程序代碼時(shí),必須配置編譯程序(compiler)的設(shè)定去產(chǎn)生只執(zhí)行(execute-only)的代碼以避免上述那些型態(tài)的數(shù)據(jù)產(chǎn)生。圖2及圖3是一般常見的文字池跟分支表的例子:switch()是C程序中常用的跳轉(zhuǎn)指令,此例子中的sclk_source變量是去讀取CRM_CFG寄存器,圖2可看到編譯出來(lái)的匯編代碼(assembly code)“LDR R7, [PC, #288]”,會(huì)用程序計(jì)數(shù)器(program counter, PC)間接尋址的方式去取得CRM_CFG寄存器的地址,而CRM_CFG的地址會(huì)被以常數(shù)的方式存放在鄰近的指令區(qū)(也在指令安全庫(kù)區(qū)之內(nèi)),因此執(zhí)行switch()指令時(shí)就會(huì)發(fā)生數(shù)據(jù)的讀取。如果指令安全庫(kù)區(qū)內(nèi)有這類的程序代碼,在執(zhí)行的時(shí)候就會(huì)產(chǎn)生錯(cuò)誤。第三章的范例程序?qū)?huì)說(shuō)明如何設(shè)定編譯程序的配置來(lái)避免這樣的問題。
圖2. 文字池例子(1)
圖3. 文字池例子(2)
一、不可將中斷向量表設(shè)置為安全庫(kù)區(qū)的指令區(qū)
中斷向量表包含每個(gè)中斷處理程序的入口點(diǎn)地址,由MCU通過D-Code總線讀取。通常,中斷向量表位于主閃存第一扇區(qū)(sector 0)的起始地址0x08000000,因此在設(shè)置指令安全庫(kù)區(qū)時(shí),必須遵守以下的規(guī)則:
- 不可將主閃存的第一扇區(qū)設(shè)置為安全庫(kù)區(qū)的指令區(qū)。
二、安全庫(kù)區(qū)代碼與用戶區(qū)代碼的關(guān)聯(lián)性
受安全庫(kù)區(qū)保護(hù)的程序代碼(IP-Code)可以從位于用戶代碼區(qū)(安全庫(kù)區(qū)之外的區(qū)域)的函數(shù)庫(kù)中調(diào)用函數(shù)。在這種情形下,IP-Code將會(huì)包含這些函數(shù)的地址,允許PC(程序計(jì)數(shù)器)在執(zhí)行IP-Code時(shí)跳轉(zhuǎn)到這些函數(shù)。一旦安全庫(kù)區(qū)被啟動(dòng),這些函數(shù)的地址就不能被改變,此時(shí),這些位于用戶代碼區(qū)的函數(shù)的地址就必須固定下來(lái),否則PC將跳轉(zhuǎn)到錯(cuò)誤的地址而無(wú)法正常工作。因此在設(shè)置安全庫(kù)區(qū)的時(shí)候,應(yīng)該將所有與IP-Code相關(guān)聯(lián)的函數(shù)都一起編排到安全庫(kù)區(qū)之內(nèi)以避免此情況發(fā)生。下圖顯示出一個(gè)被保護(hù)的函數(shù)Function_A()調(diào)用到用戶區(qū)內(nèi)的函數(shù)Function_B()的例子。圖4. 安全庫(kù)區(qū)的函數(shù)調(diào)用用戶區(qū)函數(shù)的例子
此外,另一個(gè)最常見的情形就是使用到C語(yǔ)言的標(biāo)準(zhǔn)函式庫(kù),例如memset()及memcpy()這類函數(shù)。如果IP-Code跟用戶區(qū)代碼都有調(diào)用到這類函數(shù),就會(huì)有上述問題的困擾。列舉兩種常用的解決方法:1) 將其編譯到安全庫(kù)區(qū)范圍內(nèi),具體如何實(shí)現(xiàn)可以查看keil或IAR的相關(guān)文檔。2) 避免在IP-Code內(nèi)使用C的標(biāo)準(zhǔn)函式庫(kù),若非要使用,就必須將用到的函數(shù)改寫為其他名稱,以下是一個(gè)范例,在IP-Code 中寫一個(gè)my_memset()函數(shù)取代原先的memset()。圖5. 自定義函數(shù)范例
安全庫(kù)區(qū)范例程序
本章節(jié)將以為例介紹安全庫(kù)區(qū)的使用范例,并詳述完成此范例程序所需的每一個(gè)步驟。
范例需求
一、硬件需求
- 帶有AT32F402RCT7芯片的AT-START-F402實(shí)驗(yàn)板
- AT-Link仿真器,用來(lái)調(diào)試范例程序
二、軟件需求
- Keil μvision IDE(本范例使用μvision V5.36.0.0)或IAREmbedded workbench IDE(本范例使用IAR V8.22.2)
- 雅特力ICP或ISP刻錄工具,主要是用來(lái)啟動(dòng)或解除安全庫(kù)區(qū)的設(shè)置
范例概述
本應(yīng)用指南提供了兩個(gè)范例項(xiàng)目,展示了軟件開發(fā)商開發(fā)智權(quán)代碼(IP-Code)給終端用戶應(yīng)用的場(chǎng)景。其中
- Project_L0為方案商開發(fā)算法并編排到安全庫(kù)區(qū)的示例
- Project_L1為終端用戶應(yīng)用此算法的示例
Project_L0完成的算法將預(yù)先下載刻錄到AT32F402芯片并設(shè)置安全庫(kù)區(qū)保護(hù),同時(shí)提供下列各項(xiàng)設(shè)定訊息給終端客戶應(yīng)用程序使用:
- 主閃存區(qū)塊的映像,說(shuō)明安全庫(kù)區(qū)所占用的區(qū)域以及用戶可開發(fā)程序的區(qū)域
- 包含算法函數(shù)定義的頭文件,讓終端用戶可以用來(lái)調(diào)用相關(guān)的函數(shù)
- 符號(hào)定義文件(symbol definition file),此符號(hào)文件內(nèi)含IP-Code的各個(gè)函數(shù)的實(shí)際地址,讓終端用戶程序可以正確的調(diào)用,下圖為此范例的示意圖。
圖6. 范例流程示意圖
軟件方案商可以參考Project_L0范例開發(fā)算法代碼,并參考Project_L1提供終端用戶使用,下圖為應(yīng)用示意圖。圖7. 應(yīng)用示意圖
安全庫(kù)區(qū)保護(hù)的代碼:FIR低通濾波器
本范例使用CMSIS-DSP庫(kù)提供的FIR低通濾波器(FIR lowpass filter)算法作為被安全庫(kù)保護(hù)的IPCode,關(guān)于FIR低通濾波器算法可詳閱CMSIS-DSP的相關(guān)文件,這里僅著重在說(shuō)明如何設(shè)置安全庫(kù)以保護(hù)此算法及如何被終端用戶的程序代碼調(diào)用。范例中的低通濾波器的輸入信號(hào)是一個(gè)混和了頻率各為1KHz及15KHz的兩個(gè)正弦波的訊號(hào),而低通濾波器的截止頻率約為6KHz。經(jīng)過低通濾波后,將15KHz的訊號(hào)濾除而僅剩下1KHz的正弦波輸出。下圖為FIR低通濾波功能的示意圖。圖8. FIR低通濾波器
使用到的CMSIS DSP庫(kù)的函數(shù)及文件包括:
- arm_fir_init_f32()
此函數(shù)的功能是做濾波器函數(shù)的初始化設(shè)定,包含在arm_fir_init_f32.c文件里
- arm_fir_f32()
此函數(shù)為濾波器算法的主要部分,包含在arm_fir_f32.c文件里
- FIR_lowpass_filter()
此函數(shù)為使用上述兩個(gè)基本函數(shù)寫成的FIR低通濾波器全局函數(shù),供終端用戶調(diào)用,包含在fir_filter.c文件里
- fir_coefficient.c
此C文件內(nèi)含F(xiàn)IR濾波器函數(shù)所使用的系數(shù)(只讀的常數(shù)),在范例中會(huì)將這些系數(shù)放置到唯讀安全庫(kù)區(qū)
在此范例中,MCU內(nèi)嵌的FPU及DSP指令會(huì)被用來(lái)做信號(hào)處理以及浮點(diǎn)運(yùn)算,以達(dá)到準(zhǔn)確的運(yùn)算及正確的輸出信號(hào)。
Project_L0: 方案商范例
在此階段的范例程序,將完成下列幾個(gè)項(xiàng)目:
- 將算法的相關(guān)函數(shù)編譯成只可執(zhí)行(execute-only)的代碼
- 將算法的程序代碼編排放置到主閃存區(qū)的指定扇區(qū),以下用扇區(qū)A指示
- 將濾波器函數(shù)的系數(shù)編排放置到主閃存區(qū)的指定扇區(qū),以下用扇區(qū)B指示
- 在主程序中執(zhí)行FIR_lowpass_filter()以驗(yàn)證其正確性
- 驗(yàn)證成功后,將扇區(qū)A設(shè)置為指令安全庫(kù)區(qū),并將扇區(qū)B設(shè)置為唯讀安全庫(kù)區(qū),此部分可在范例的主程序中以調(diào)用slib_enable()函數(shù)來(lái)完成,或使用Artery ICP Programmer來(lái)完成(建議使用ICP工具完成設(shè)置)
- 產(chǎn)出終端用戶程序調(diào)用低通濾波函數(shù)時(shí)需用到的頭文件及符號(hào)定義文件
一、產(chǎn)生只執(zhí)行(Execute-only)代碼
每一種工具鏈(toolchain)都有自己的設(shè)定選項(xiàng),可以防止編譯程序生成文字池(literal pools)和分支表(branch table)這些在指令執(zhí)行時(shí)會(huì)發(fā)生讀取數(shù)據(jù)的指令格式,例如”LDR Rn, [PC, #offset]”這類指令。關(guān)于文字池及分支表的例子可參照章節(jié)2.4的說(shuō)明。以Keil μvision為例,Keil μvision有Execute-only Code的選項(xiàng)來(lái)做設(shè)定,設(shè)定的方式如下:Keil μvision:使用Execute-only Code選項(xiàng)設(shè)置的方式是:
- 選擇C文件群組或個(gè)別的C文件,范例中是把要保護(hù)的相關(guān)C文件都放在fir_filter群組
- 按鼠標(biāo)右鍵然后選擇對(duì)應(yīng)文件,例如本例程的Option for File ‘a(chǎn)rm_fir_f32.c’,如下圖
圖9. Keil進(jìn)入Option界面
- 勾選C/C++窗口里的Execute-only Code選項(xiàng),然后--execute_only命令就會(huì)被加到編譯過程控制字符串里,如下圖
圖10. Keil選擇Execute-only Code
- 本例程中有三個(gè)文件位于SLIB_INSTRUCTION區(qū),分別是arm_fir_f32.c、arm_fir_init_f32.c和fir_filter.c,這三個(gè)文件都需要配置產(chǎn)生為只執(zhí)行代碼。
IAR:使用No data read in code memory選項(xiàng)設(shè)置的方式是:
- 選擇fir_filter群組里對(duì)應(yīng)的文件,按鼠標(biāo)右鍵選擇Option
圖11. IAR進(jìn)入Option界面
- 如下圖,在"C/C++"窗口內(nèi)勾選Override inherited settings以及No data read in code memory
圖12. IAR設(shè)置C/C++窗口選項(xiàng)
- 本例程中有三個(gè)文件位于SLIB_INSTRUCTION區(qū),分別是arm_fir_f32.c、arm_fir_init_f32.c和fir_filter.c,這三個(gè)文件都需要配置產(chǎn)生為只執(zhí)行代碼。
AT32 IDE:添加Other compiler flags關(guān)鍵字設(shè)置的方式是:
- 選擇工程中fir_filter群組里對(duì)應(yīng)的文件,按鼠標(biāo)右鍵選擇Properties
圖13. AT32 IDE進(jìn)入Properties界面
- 點(diǎn)選C/C++Build->Settings->GNU ARM Cross C Complier->Miscellaneous,在”O(jiān)ther compiler flags”填入-mpure-code以及-mslow-flash-data這兩個(gè)關(guān)鍵字,然后按Apply設(shè)定生效
圖14. AT32 IDE設(shè)置Miscellaneous
二、編排安全庫(kù)區(qū)的地址
前面章節(jié)提到的,主閃存的第一扇區(qū)(sector 0)會(huì)被用來(lái)存放中斷向量表。下圖為主閃存的映射及RAM的使用分區(qū)。RAM的分區(qū)主要是為了避免SLIB保護(hù)區(qū)的代碼與終端用戶的代碼用到相同的RAM而產(chǎn)生的沖突問題。圖15. 范例程序的主閃存映像及RAM分區(qū)
Keil μvision的scatter file步驟如下:
- 到Project→Optios for Target→Linker窗口,取消Use memory layout from Target Dialog選項(xiàng),然后按Edit按鍵來(lái)開啟slib-w-xo.sct文件做修改,如下圖
圖16. Keil設(shè)置Linker窗口選項(xiàng)
- 打開scatter file之后,將需要放到指令安全庫(kù)區(qū)(SLIB_INSTRUCTION)的代碼的目標(biāo)文件(object file)放到名為L(zhǎng)R_SLIB_INSTRUCTION的專用加載區(qū),并將標(biāo)示修改為execute-only(+XO),同時(shí)也要將SLIB_READ_ONLY占用的區(qū)域保留起來(lái)放到名為L(zhǎng)R_SLIB_READ_ONLY的專用加載區(qū),避免編譯程序?qū)⑵渌荌P-Code的函數(shù)編排到SLIB區(qū)內(nèi),RW_IRAM1是指定給安全庫(kù)區(qū)算法的函數(shù)使用,目的是為了避免終端用戶的項(xiàng)目也用到同樣的RAM區(qū)塊,而造成程序執(zhí)行時(shí)發(fā)生錯(cuò)誤,如下所示
圖17. Keil scatter修改
- IP-Code用到的RAM以及數(shù)據(jù)安全庫(kù)區(qū)FIR低通濾波器函數(shù)使用到的常數(shù)編排地址,除了上述的修改scatter file方式之外,也可以代碼中使用Keil的__attribute__((at(address)))描述元將變量或常數(shù)放置到固定的地址
IAR的ICF file步驟如下:
- 開啟\project_l0\IAR_V8.2\目錄下的icf文件,添加三個(gè)新的加載區(qū),如下所示,其中SLIB_RAM區(qū)塊的RAM保留給算法的函數(shù)使用
圖18. icf文件中SLIB地址定義
- 在ICF文件中,也要將SLIB占用的區(qū)域保留起來(lái),避免編譯程序?qū)⑵渌荌P-Code的函數(shù)編排到SLIB區(qū)內(nèi),同時(shí)將IP-Code使用的RAM區(qū)域保留起來(lái)
圖19. icf文件中地址分配
- IP-Code用到的RAM和ROM,修改icf文件,如下圖
圖20. icf文件中SLIB使用的RAM修改
- IP-Code用到的RAM以及數(shù)據(jù)安全庫(kù)區(qū)FIR低通濾波器函數(shù)使用到的常數(shù)編排地址,除了上述的修改ICF文件方式之外,也可以代碼中使用IAR的@描述元將變量或常數(shù)放置到固定的地址
AT32 IDE的ld file步驟如下:
- 修改ld文件,劃出安全庫(kù)區(qū)所需的區(qū)域,如下圖
圖21. ld文件中使用的RAM和ROM范圍修改
- 將算法代碼放到.slib_inst section,低通濾波器的系數(shù)放到.slib_read_only section,并將算法使用到的全局變量指定到.slib_ram section,如下圖
圖22. ld文件中編排放置位置
- 在Project->Properties->C/C++Build->Setting->GNU ARM Cross C Linker->General設(shè)定中的Script files,加入改好后的ld文件。
圖23. 添加修改后的ld文件
- 本范例會(huì)使用到gcc的數(shù)學(xué)運(yùn)算函數(shù)庫(kù)libm.a,在Properties->GNU ARM Cross C Linker->Miscellaneous設(shè)定中的Other linker flags填入--specs=rdimon.specs,linker才不會(huì)出現(xiàn)錯(cuò)誤訊息,如下圖
圖24. 添加額外關(guān)鍵字避免編譯報(bào)錯(cuò)
三、啟用安全庫(kù)區(qū)保護(hù)
要啟用安全庫(kù)區(qū)的保護(hù)功能,有以下兩種方式:(1) 使用ICP刻錄工具Artery ICP Programmer(建議用此方式)要使用ICP Programmer,請(qǐng)參照以下步驟:
- 連接AT-Link到AT-START-F402板子上并上電
- 開啟ICP Programmer,選擇用AT-Link連接,然后添加Project_L0范例編譯后產(chǎn)出的HEX或BIN文件,如下圖
圖25. 配置ICP Programmer
- 按下載按鍵,會(huì)出現(xiàn)下載選項(xiàng)的頁(yè)面,此頁(yè)面會(huì)顯示SLIB的狀態(tài)及相關(guān)的參數(shù),設(shè)定啟用密碼0x55665566(可自定義)并勾選啟用SLIB,然后按開始下載,即可完成程序的燒錄并啟用SLIB,如下圖
圖26. 設(shè)置下載選項(xiàng)參數(shù)
關(guān)于ICP Programmer的詳細(xì)說(shuō)明,請(qǐng)參閱ICP Programmer用戶手冊(cè)。(2) 使用范例程序main.c之中的slib_enable()函數(shù)在低通濾波函數(shù)測(cè)試正確后執(zhí)行過一次此函數(shù),就可以啟用安全庫(kù)區(qū)的保護(hù)功能。要執(zhí)行此函數(shù),只要在main.c中使能#define USE_SLIB_FUNCTION即可。
四、Project_L0執(zhí)行流程
在此范例中,F(xiàn)IR低通濾波器會(huì)針對(duì)混和1KHz及15KHz正弦波的輸入信號(hào)testInput_f32_1kHz_15kHz 做計(jì)算,計(jì)算后輸出的1KHz正弦波數(shù)據(jù)存放到testOutput,然后會(huì)跟預(yù)先用MATLAB軟件計(jì)算好且存放在refOutput中的數(shù)據(jù)做比對(duì),如果誤差值小于預(yù)期值(訊噪比SNR大于預(yù)設(shè)的門坎),板子上綠色的LED燈會(huì)一值閃爍,反之則是紅色的LED燈一值閃爍,下圖是Project_L0的整個(gè)流程圖27. Project_L0執(zhí)行流程
要執(zhí)行此范例程序,請(qǐng)按照下列步驟:(1) 使用Keil μvision開啟\utilities\AT32F402_405_slib_demo\project_l0\mdk_v5\目錄下的Project_L0項(xiàng)目,并重新編譯。(2) 在下載代碼之前,先檢查AT-START-F402板子上的芯片是否已經(jīng)有SLIB或讀寫保護(hù)(FAP/EPP),如果有,就請(qǐng)先用ICP刻錄工具將這些保護(hù)都解除,然后再下載代碼。(3) 下載成功后并開始值執(zhí)行后,會(huì)看到板子上的LED3燈持續(xù)快速閃爍。(4) 按下板子上的USER按鍵,就會(huì)執(zhí)行低通濾波器的運(yùn)算。(5) 比對(duì)運(yùn)算結(jié)果,若結(jié)果正確,綠色LED4燈會(huì)持續(xù)閃爍。反之,則是紅色LED2燈持續(xù)閃爍。(6) 在比對(duì)結(jié)果正確的條件下,如果main.c中的USE_SLIB_FUNCTION有被定義且芯片未啟用過SLIB的話,就會(huì)執(zhí)行slib_enable()函數(shù)去設(shè)置SLIB,若設(shè)置失敗,紅色LED2燈會(huì)一直亮著。若設(shè)置成功,綠色LED4燈會(huì)點(diǎn)亮約3秒鐘然后執(zhí)行系統(tǒng)重置(system reset)來(lái)啟動(dòng)SLIB。然后程序又回到步驟(3)。
五、產(chǎn)生頭文件及符號(hào)定義文件
頭文件(header file)跟符號(hào)定義文件(symbol definition file)是終端客戶應(yīng)用范例Project_L1在調(diào)用FIR低通濾波函數(shù)時(shí)需要用到。在范例中,就是main.c中包含的fir_filter.h文件。符號(hào)定義文件的產(chǎn)出方法跟使用的工具鏈(toolchain)相關(guān)。使用Keil μvision產(chǎn)生符號(hào)定義文件方法如下:
- 進(jìn)入Ottions forTarget→Linker設(shè)定畫面
- 在Misc controls這一欄,添加--symdefs=fir_filter_symbol.txt命令,如下圖
圖28. 設(shè)置Keil Misc controls選項(xiàng)
- 重新編譯整個(gè)項(xiàng)目后,在project_l0\mdk_v5\Objects 目錄下就會(huì)產(chǎn)生一個(gè)名為fir_filter_symbol.txt的符號(hào)定義文件
- 這個(gè)符號(hào)定義文件包含了整個(gè)項(xiàng)目全部的符號(hào)定義,所以需要修改,只保留終端用戶會(huì)調(diào)用的低通濾波函數(shù)的定義,刪減后的fir_filter_symbol.txt顯示如下
圖29. 修改后的fir_filter_symbol.txt內(nèi)容
使用IAR產(chǎn)生符號(hào)定義文件方法如下:
- 選擇Project→Option→Build Actions
圖30. 設(shè)置IAR Build Actions選項(xiàng)
- 然后在Post-build命令行中輸入以下命令
$TOOLKIT_DIR$\bin\isymexport.exe--edit "$PROJ_DIR$\steering_file.txt"
"$TARGET_PATH$" "$PROJ_DIR$\fir_filter_symbol.o"
- 此處fir_filter_symbol.o是要產(chǎn)出的符號(hào)定義文件,steering_file.txt放在project_l0\iar_v8.2目錄下,是用來(lái)選擇要產(chǎn)生哪些函數(shù)的符號(hào),需根據(jù)安全庫(kù)區(qū)調(diào)用的內(nèi)容進(jìn)行手動(dòng)編輯,內(nèi)容如下,其中"show"是用來(lái)選擇函數(shù)的命令
圖31. 編輯的steering_file.txt內(nèi)容
使用AT32 IDE產(chǎn)生符號(hào)定義文件方法如下:
- 創(chuàng)建一個(gè)keep_sym.txt文件,用來(lái)選擇要產(chǎn)生哪些函數(shù)的符號(hào),需根據(jù)安全庫(kù)區(qū)調(diào)用的內(nèi)容進(jìn)行手動(dòng)編輯
- 創(chuàng)建一個(gè)postbuild.sh文件,文件內(nèi)容見工程,主要是用于生成包含函數(shù)名稱和地址的.ld文件
- 選中project_l0工程,按鼠標(biāo)右鍵選擇Properties
- 點(diǎn)選C/C++Build->Settings->Build Steps->Post-build steps->Command中,填入"../postbuild.sh" "${BuildArtifactFileName}",點(diǎn)擊Apply生效
- 編譯后,DEBUG文件夾中會(huì)生成一個(gè)keep_sym_app.ld文件
圖32. AT32 IDE添加post-build命令
Project_L1: 終端用戶范例
Project_L1范例會(huì)使用到在Project_L0中調(diào)試好,并已經(jīng)被刻錄到AT32F402芯片的主閃存中且被SLIB保護(hù)的FIR低通濾波器函數(shù)。根據(jù)Project_L0提供的頭文件、符號(hào)定義文件以及主閃存區(qū)塊映像,終端用戶就可以參照Project_L1做到
- 建立一個(gè)應(yīng)用項(xiàng)目
- 引用Project_L0提供的頭文件及符號(hào)定義文件到項(xiàng)目里
- 調(diào)用FIR低通濾波器函數(shù)
- 開發(fā)并調(diào)試用戶自己的應(yīng)用程序
注意事項(xiàng):Project_L1必須使用跟Project_L0開發(fā)時(shí)一樣的工具鏈及相同版本的編譯程序,不然有可能會(huì)因?yàn)榘姹静町惖募嫒菪詥栴},而無(wú)法使用Project_L0提供的代碼。例如本范例中Project_L0使用的是Keil μvision V5.36.0.0,那Project_L1也要使用同樣的這個(gè)版本。
一、建立用戶的應(yīng)用項(xiàng)目
因?yàn)镻roject_L0啟用的安全庫(kù)區(qū)已經(jīng)占用了一些特定的主閃存扇區(qū),Project_L1的代碼必須參照Project_L0提供的主閃存區(qū)塊映像來(lái)編排放置的地址。圖15為此范例的主閃存區(qū)塊映射,其中sector2至sector 5為安全庫(kù)區(qū)所占用,終端用戶需使用linker control file將這個(gè)區(qū)域隔離起來(lái),避免代碼在編譯時(shí)被編排到這個(gè)區(qū)域內(nèi),方式如下:Keil μvision的scatter file可參照project_l1\mdk_v5\目錄的end_user_code.sct文件,將主閃存空間切成兩個(gè)區(qū)塊,中間空出來(lái)的區(qū)域就是SLIB保護(hù)區(qū)。此外,RAM的區(qū)域也要保留0x20017000之后的區(qū)域。如下圖圖33. 修改后的scatter文件
IAR的ICF file可參照project_l1\iar_V8.2\目錄下enduser.icf文件中如下圖的部分圖34. 修改后的icf文件AT32 IDE的ld file可參照project_l1\at32_ide\目錄下FLASH_enduser.ld文件修改,添加如下圖的行圖35. ld文件添加project_l0生成的文件
二、在項(xiàng)目中加入符號(hào)定義文件
Project_L0所產(chǎn)生的符號(hào)定義文件fir_filter_symbol.txt必須被添加到Project_L1項(xiàng)目中,才能被正確的編譯并鏈結(jié)到SLIB保護(hù)區(qū)的代碼。在Keil μvision中加入符號(hào)定義文件工程中添加fir_filter_symbol.txt這個(gè)符號(hào)定義文件,如下圖:圖36. 在Keil加入symbol definition file
將文件加入fir_filter群組后,必須將它的文件類型更改為Object文件,而不是原來(lái)的文本(text)文件,修改方式如下圖37. 修改符號(hào)定義文件的類型為Object file
在IAR中加入符號(hào)定義文件將fir_filter_symbol.o這個(gè)Object文件加到加到fir_filter群組即可,如下圖圖38. 在IAR中加入符號(hào)定義文件
在AT32 IDE中加入符號(hào)定義文件例程中將keep_sym_app.ld放在了fir_filter文件夾內(nèi)添加進(jìn)工程,在Project->Properties->C/C++Build->Setting->GNU ARM Cross C Linker->Library中添加keep_sym_app.ld所在路徑圖39. 在AT32 IDE中添加ld路徑
三、調(diào)用SLIB保護(hù)區(qū)的函數(shù)
當(dāng)filter.h頭文件被main.c引用且符號(hào)定義文件也正確地加入項(xiàng)目之后,保護(hù)區(qū)的低通波器函數(shù)就可以被調(diào)用。方式如下:FIR_lowpass_filter(inputF32, outputF32, TEST_LENGTH_SAMPLES);其中:inputF32 :指向包含輸入信號(hào)數(shù)據(jù)表的指針outputF32 :指向存放輸出信號(hào)數(shù)據(jù)表的指針TEST_LENGTH_SAMPLES :要被處理的信號(hào)樣本數(shù)
四、Project_L1執(zhí)行流程
Project_L1的執(zhí)行流程如下圖,說(shuō)明如下:
- 開始執(zhí)行后LED3燈會(huì)持續(xù)閃爍
- 按下AT-START板子上的USER按鍵,F(xiàn)IR_lowpass_filter()開始做運(yùn)算
- 如運(yùn)算結(jié)果正確,綠色LED4燈持續(xù)閃爍,如運(yùn)算結(jié)果錯(cuò)誤則紅色LED2燈持續(xù)閃爍
圖40. Project_L1流程圖
五、調(diào)試模式下的SLIB保護(hù)
當(dāng)終端用戶在開發(fā)應(yīng)用程序時(shí),會(huì)用到開發(fā)工具調(diào)試代碼,以下將以Keil μvision為例,說(shuō)明在調(diào)試模式下,SLIB如何防止保護(hù)區(qū)內(nèi)的代碼被以數(shù)據(jù)的方式讀取
- 開啟Project_L1項(xiàng)目并重新編譯
- 點(diǎn)擊”Start/Stop Debug Session”進(jìn)入調(diào)試模式
- 在”Disassembly”窗口點(diǎn)擊數(shù)標(biāo)右鍵,然后選擇”Show Disassembly at Address”,如下圖
圖41. 進(jìn)入Show Disassembly at Address
- 輸入SLIB_INSTRUCTION扇區(qū)地址
圖42. 設(shè)置Show Code at Address可以看到代碼都是0x00圖43. 代碼查看
- 同樣地在Memory窗口輸入地址,也會(huì)看到全部是0x00
圖44. Memory窗口查看代碼
- 在Memory窗口,輸入SLIB_READ_ONLY地址,因?yàn)檫@個(gè)區(qū)塊允許被D-Code數(shù)據(jù)總線讀取,所以可以看到原來(lái)的數(shù)值
圖45. Memory窗口查看SLIB_READ_ONLY起始頁(yè)面對(duì)安全庫(kù)區(qū)的數(shù)據(jù)嘗試做修改,F(xiàn)LASH_STS寄存器的EPPERR位置”1”提出警告,顯示寫保護(hù)發(fā)生作用圖46. SLIB寫測(cè)試如果有使能寫保護(hù)錯(cuò)誤中斷,繼續(xù)執(zhí)行程序就會(huì)進(jìn)入中斷程序里面圖47. 寫保護(hù)錯(cuò)誤中斷
方案商和終端用戶代碼整合及下載操作流程
方案商和終端用戶的代碼設(shè)計(jì)完成后,需要下載到同一個(gè)MCU中,這就涉及到各自代碼的安全性問題。以下列舉兩種常用下載操作流程供用戶參考,仍然是以上面Project_L0和Project_L1為例。操作中涉及到AT-Link的離線下載模式,詳細(xì)描述可以參考ICP使用文檔及AT-Link使用文檔。
方案商和終端用戶代碼分別燒錄
方案商先燒錄SLIB代碼到MCU,然后終端用戶再燒錄應(yīng)用代碼到MCU,步驟如下:(1)方案商將編譯完成的工程中SLIB部分的代碼提取并保存成BIN或者HEX檔,這步可以通過各個(gè)IDE軟件或者ICP工具實(shí)現(xiàn),例如在KEIL工程中,user選項(xiàng)中添加fromelf.exe--bin--output.\Listings\@L.bin !L,編譯生成對(duì)應(yīng)固件的bin檔,將對(duì)應(yīng)的SLIB段文件添加后綴名.bin格式,本例中修改為ER_SLIB_INSTRUCTION.bin和ER_SLIB_READ_ONLY.bin,對(duì)應(yīng)的就是SLIB-INSTRUCTION文件和SLIB-DATA文件,也可以新版ICP直接打開工程完整HEX檔然后點(diǎn)擊文件->文件另存為bin格式,分段的bin名對(duì)應(yīng)地址,如下圖。圖48. 生成SLIB代碼部分bin文件(2) 將bin通過ICP工具,在線燒錄到MCU,如下圖圖49. ICP在線燒錄MCU(3) 或者通過ICP工具配置成離線項(xiàng)目工程保存到AT-Link,然后經(jīng)過AT-Link離線燒錄到MCU,保存離線項(xiàng)目工程如下圖。圖50. AT-Link離線燒錄到????MCU(4) 經(jīng)過步驟2或者步驟3,終端用戶拿到燒錄好SLIB部分的MCU,此時(shí)SLIB狀態(tài)會(huì)顯示為已啟用,終端用戶通過在線燒錄或者離線燒錄應(yīng)用代碼到MCU完成整個(gè)過程,在線燒錄如下圖。圖51. 終端用戶燒錄代碼到MCU
方案商和終端用戶代碼合并燒錄
方案商的SLIB代碼和終端用戶的應(yīng)用代碼整合到一個(gè)離線項(xiàng)目工程中,通過AT-Link離線燒錄一次下載到MCU,步驟如下:(1) 方案商將編譯完成的工程按照上一章節(jié)所述方法處理,得到SLIB部分的BIN檔。(2) 方案商通過ICP制作離線項(xiàng)目工程并保存到PC,可以根據(jù)最終需求配置各種參數(shù),比如限制下載次數(shù)、項(xiàng)目文件綁定AT-Link、下載完成后開啟FAP等,保存離線項(xiàng)目工程如下圖注意:離線項(xiàng)目工程本身已經(jīng)經(jīng)過加密,為進(jìn)一步提升安全性,方案商還可以將slib.bin制作成加密的slib.benc文件再添加到離線項(xiàng)目工程中,但此時(shí)的離線項(xiàng)目工程只能在對(duì)應(yīng)匹配加密秘鑰的AT-Link上才能使用圖52. 制作離線項(xiàng)目工程(3) 終端用戶拿到該離線項(xiàng)目工程,用ICP打開項(xiàng)目文件,通過添加文件功能,可以添加應(yīng)用代碼部分到該離線項(xiàng)目工程,然后再保存到PC或者直接存儲(chǔ)到AT-Link,通過執(zhí)行離線下載完成操作,項(xiàng)目文件添加方法如下圖。注意:為防止代碼泄露被破解等風(fēng)險(xiǎn),離線項(xiàng)目工程添加代碼文件時(shí)其余配置都不可更改,所以需要方案商預(yù)先將最終配置設(shè)置好圖53. 添加項(xiàng)目文件
-
mcu
+關(guān)注
關(guān)注
146文章
17307瀏覽量
352176 -
雅特力
+關(guān)注
關(guān)注
0文章
168瀏覽量
8093 -
AT32
+關(guān)注
關(guān)注
1文章
118瀏覽量
2122
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論