基于SWD离线烧写OTP

嵌入式开发的最后阶段是要将成果产品化,要交付工厂量产。对于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 0x20000000 otp_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相关的域我没有删掉,相信聪明的读者可以自行完成。


常见的数字货币钱包有哪些
电池维修技术学习——放电化学反应方程式(网友问题解答)
深度神经网络变革发展迅速正对半导体IC设计与制造形成深刻的变革
如何增强双层石墨烯的超导性
世界芯片排名一览表 2021年芯片十大品牌有哪些?
基于SWD离线烧写OTP
直线马达立体式车库市场占有率正逐年增加
奥比中光发布Femto W与Persee+深度相机
美萍网络技术有限公司研发出AI智能电销机器人,适用于销售行业
400G OSFP SR8光模块最新解决方案
基于FPGA和DDS+PLL器件实现跳频信号发生器的设计
工控机在电力系统中的作用
医疗物联网的的解析
可穿戴设备功能新趋势:有能力预判新冠症状
2018合肥网络安全大会成功召开:致力中国数字化转型
对话吴恩达:Landing.ai为何重要?或许以下几点值得注意
碾压高通击溃欧美!华为拿下5G时代
电子元器件行业:下游需求带动电子元器件行业蓬勃发展
变频器充电电阻的作用是什么
机器人离线编程技术的具体应用