嵌入式開發的最后階段是要將成果產品化,要交付工廠量產。對于NXP i.MXRT系列的芯片來說,除了要交付給工廠項目固件外,還需要工廠寫OTP區域來配置芯片啟動方式或者開啟芯片的安全功能。離線編程器燒寫固件和OTP的方法有多種,如ISP,SWD或者Jtag等。
今天就為大家介紹下,如何讓離線編程器利用SWD接口燒寫OTP。
編寫OTP燒寫算法
直接操作寄存器來寫OTP的過程很繁瑣。很多編程器借助Flash燒寫算法來燒寫Flash,我們也可以借助燒寫Flash的方法來燒寫OTP。 本加油站曾經有一篇《編寫Keil的自定義Flash燒寫算法FLM》,在這篇文章中,作者介紹了如何利用Keil來編寫Flash燒寫算法。 編寫OTP燒寫算法的方法和編寫Flash燒寫算法的方法一樣,只需要復用接口函數Init和UnInit,新增接口OTPWrite。和Flash相關的操作函數可以直接刪掉。OTP的燒寫算法接口聲明如下:
int Init (unsigned long adr, unsigned long clk, unsigned long fnc); int UnInit (unsigned long fnc); int OTPWrite (unsigned long idx, unsigned long value);每個燒寫算法接口函數都是對應OTP驅動函數的封裝。下面是這3個接口函數的參考實現:
int Init (unsigned long adr, unsigned long clk, unsigned long fnc) { BOARD_BootClockRUN(); #if (defined(FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) && FSL_FEATURE_OCOTP_HAS_TIMING_CTRL) OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk)); #else OCOTP_Init(OCOTP, 0U); #endif return (0); } int OTPWrite (unsigned long idx, unsigned long value) { status_t status = kStatus_Success; status = OCOTP_WriteFuseShadowRegister(OCOTP, idx, value); return (kStatus_Success == status) ? (0) : (1); } int UnInit (unsigned long fnc) { OCOTP_Deinit(OCOTP); return (0); }
以OCOTP_開頭的函數是OTP driver接口。函數BOARD_BootClockRUN的具體實現請查看SDK內OTP driver的示例。
提取算法代碼
Keil MDK生成的后綴為FLM的算法文件實質上是一段與地址無關的代碼。對于下載器來說,一種簡單的使用方法是把文件內的相關函數指令提取出來。這里需要用到開源項目pyocd里的python腳本FlashAlgo。該項目github地址為:
https://github.com/pyocd/FlashAlgo
FlashAlgo默認會從符號表里查找EraseSector等函數名。所以我們需要做一點改動,把flash相關操作的函數名換成OTP相關操作的函數名。
文件flash_algo.py中集合REQUIRED_SYMBOLS改動如下:
REQUIRED_SYMBOLS = set([ "Init", "UnInit", "OTPWrite", # EraseSector ])
文件generate_blobs.py中列表TEMPLATES改動如下:
TEMPLATES = [ ("c_blob.tmpl", "c_blob.c"), ]
c_blob.tmpl在文件夾templates中,將program_target_t改名為program_ocotp_t,并將其中和flash相關的Erase、Program等項刪掉,新增OTPWrite,新增項如下:
static const program_ocotp_t ocotp = { [...] {{'0x%08x' % (algo.symbols['OTPWrite'] + header_size + entry)}}, // OTPWrite [...] }
在執行腳本之前,先安裝python依賴的第三方庫,命令行如下:
pip install requirements.txt
執行腳本的命令行如下:
python generate_blobs.py --blob_start 0x20000000otp_prog.FLM
這里的0x20000000是將要運行算法的目標RAM地址,讀者可以根據芯片RAM位置配置。otp_prog.FLM為上一小節Keil MDK編譯出來的FLM文件。c_blob.c是生成的包含燒寫算法及相關信息的文件。
燒寫OTP
要通過SWD燒寫OTP,就需要實現一個SWD時序協議。ARM公司的開源項目DAPLINK實現了支持arm cortex系列MCU的SWD時序協議。具體的實現在文件swd_host.c內。
該項目地址是https://github.com/armmbed/daplink
這里我們使用swd_host.c中的接口來演示如何燒寫OTP。和OTP相關的操作接口函數主要有兩個:
uint8_t swd_write_memory(uint32_t address, uint8_t *data, uint32_t size); uint32_t swd_flash_syscall_exec(const program_syscall_t *sysCallParam, uint32_t entry, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, flash_algo_return_t return_type);
調用OTP算法需要的主要參數在文件c_blob.c中的結構體program_ocotp_t。我們仿照DAPLINK中program_target_t給出program_ocotp_t的聲明:
typedef struct { const uint32_t init; const uint32_t uninit; const uint32_t OCOTPWrite; const program_syscall_t sys_call_s; const uint32_t program_buffer; const uint32_t algo_start; const uint32_t algo_size; const uint32_t *algo_blob; const uint32_t program_buffer_size; } program_ocotp_t;
調用swd_write_memory來下載燒寫算法到目標地址的示例代碼如下:
swd_write_memory(ocotp.algo_start, (uint8_t *)ocotp.algo_blob, ocotp.algo_size);
調用OTP模塊初始化函數的示例代碼如下:
swd_flash_syscall_exec(&ocotp.sys_call_s, ocotp.init, 0, 0, 0, 0, FLASHALGO_RETURN_BOOL) ;
調用OTP模塊寫fuse函數的示例代碼如下:
swd_flash_syscall_exec(&ocotp.sys_call_s, ocotp.OTPWrite, fuse_idx, fuse_value, 0, 0, FLASHALGO_RETURN_BOOL);
到此,利用SWD燒寫OTP就介紹完了。
如果讀者熟悉燒寫flash的流程,會發現燒寫OTP和燒寫flash沒有差別。
OTP的值可以放在編程器的配置文件中,和固件存儲在一起。要想保護OTP的值,可以將它們存儲在硬件安全模塊(HSM)中。筆者參與的基于RT1020的離線編程器采用了文章中描述的方法燒寫OTP。該項目預計明年初會以應用筆記的方式發布在恩智浦官網。
限于篇幅,腳本中有些和flash相關的域我沒有刪掉,相信聰明的讀者可以自行完成。
審核編輯:湯梓紅出處。
-
NXP
+關注
關注
60文章
1278瀏覽量
184048 -
FlaSh
+關注
關注
10文章
1633瀏覽量
147942 -
OTP
+關注
關注
4文章
201瀏覽量
47143 -
燒寫
+關注
關注
0文章
57瀏覽量
14278 -
SWD
+關注
關注
1文章
57瀏覽量
11829
原文標題:基于SWD離線燒寫OTP
文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論