跳转至

OTP使用指南*

1
本文档描述了OTP的功能,OTP的读写。本文仅适用于GX8008、GX8008C、GX8009、GX8010芯片.

1. OTP区域介绍*

  • OTP数据区域是芯片内部的一个只读区域,该区域用于存储一些用户数据,可用于加密
  • OTP区域Bit只能从0到1进行写操作,不能从1到0进行写操作。
  • 写操作需要硬件上2.5V伏电源供电
  • OTP可以lock, lock后不能进行写操作。
  • 芯片内部供读写的OTP区域有2个
mcu dsp
usr_data 64Byte 可写可读 不可写不可读
dsp_key 8Byte 可写不可读 不可写可读

2. OTP读写接口*

2.1 mcu端读写接口*

  • API
// 读写usr_data
#define OTP_USER_DATA_LENGTH (64)
int OtpSetUserData(unsigned int index, char *data, unsigned int length);
int OtpGetUserData(unsigned int index, char *data, unsigned int length);

// 读写dsp_key
#define OTP_DSP_KEY_LENGTH (8)
int OtpSetDspKey(unsigned int index, char *data, unsigned int length);
// Attention: MCU does not have permission to view this section
int OtpGetDspKey(unsigned int index, char *data, unsigned int length);

// 锁和获取锁状态
int OtpLock(void);
int OtpGetLock(unsigned int *lock);
  • 使用参考:
    OtpInit(OTP_MODE_READWRITE);
    mdelay(200);

#define USR_DATA_SIZE 1
    char usr_data[USR_DATA_SIZE] = {0x02};
    for (int i = 0; i < 10; i++)
    OtpSetUserData(0, usr_data, USR_DATA_SIZE);

    char get_data[USR_DATA_SIZE] = {0};
    OtpGetUserData(0, get_data, USR_DATA_SIZE);

    for (int i = 0; i < USR_DATA_SIZE; i++) {
        printf(LOG_TAG"get_data[%d] = %d\n", i, get_data[i]);
    }

#define OTP_KEY_SIZE 1
    char otp_data[OTP_KEY_SIZE] = {0x00,0x02,0x01,0x01, 0x01};

    int res = OtpSetDspKey(0, otp_data, OTP_KEY_SIZE);
    if (res != 0) {
        printf(LOG_TAG"OtpSetDspKey Failed %d!\n", OTP_KEY_SIZE);
    }
    else {
        printf(LOG_TAG"OtpSetDspKey Success %d!\n", OTP_KEY_SIZE);
        OtpReset(); // dsp key区域写入后要reset,dsp端才能读到最新的值
    }

2.2 dsp端读接口*

  • API
/**
 * Get the public ID from the OTP.
 *
 * @param public_id Pointer to a buffer to store the public ID.
 */
int OtpGetPublicID(char *public_id);


/**
 * Get the DSP key from the OTP.
 *
 * @param dsp_key Pointer to a buffer to store the DSP key.
 */
int OtpGetDspKey(char *dsp_key);
  • 使用参考。来自dsp/vpa/example_lib/src/vsp_process.c
static void _VspGetOtpInfo(VSP_PARAM *vsp_param)
{
    if (vsp_param->param.key.buff_size != 56) {
        printf ("Invalid param_addr\n");
        while(1);
    }

    // Get usr_data from mcu
    memcpy ((void *)sr, (void *)(vsp_param->param.key.buff_addr), 56);

    // Get dsp key
    char dsp_key[8] = {0};
    OtpGetDspKey(dsp_key);
    memcpy ((void *)(&sr[56]), (void *)dsp_key, 8);

    // Get public id
    unsigned long long public_id = 0;
    OtpGetPublicID((char *)&public_id);

    printf("PUBLIC ID: [%016llx]\n", public_id);
    printf ("sr: \n");
    for (int i = 0; i < 64; i++) {
        printf ("0x%02x ", sr[i]);
        if (i % 16 == 15) {
            printf ("\n");
        }
    }
}

3. bootx读写OTP*

  • 命令行使用bootx工具执行 bootx -m leo_mini -t u -c "如下OTP的命令" 或者win下使用支持输入命令的ui工具版本
   otp print <chip_name/public_id/user_data/lock/all> [file_name]
      打印otp的chip_name,public_id,user_data,lock
        otp print all
        效果:
          Excute cmd : otp print all
          chip_name: 8010A-NNNA
          public_id: 8cc1491281a58180
          user_data:
          0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f
          0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f
          0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f
          0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f

          lock stasus: locked
          done
      读取otp的chip_name并以打印格式写到文件
        otp print chip_name a.txt

    otp lock
      锁定otp
        otp lock

    otp_user tread <addr> <len>
      以十六进制打印user data
        otp_user tread 0x0 10
        效果:
          Excute cmd : otp tread 0x0 10
          addr =0x100, len = 0xa
          0x38 0x30 0x31 0x30 0x41 0x2d 0x4e 0x4e 0x4e 0x41
          done

    otp_user twrite <addr> <hex digits string>
      设置user data的数据
        otp_user twrite 0x0 11223344
        效果:
          Excute cmd : otp_user twrite 0x0 11223344
          addr =0x0, len = 0x4
          0x11 0x22 0x33 0x44
          done

    otp_user read <addr> <len> <file_name>
      读取user data并以二进制写到文件
        otp_user read 0 64 a.txt

    otp_user write <addr> <file_name>
      以二进制读取文件数据写到user data
        otp_user write 0x10 a.txt
  • eg:
 bootx -m leo_mini -t s -c "otp print all" -d /dev/ttyUSB1 -r 3000000 # 串口方式
或
❯ bootx -m leo_mini -t u -c "otp print all" # USB方式
Version : v1.9.5 (20240816)
NationalChip AIoT Download Tools
Copyright (C) 2001-2024 NationalChip Co., Ltd
ALL RIGHTS RESERVED!

wait ROM request... please power on or restart the board...
Using Leo mini boot
Found serial: /dev/ttyUSB1
downloading [1/2] :
[==========][100%]
downloading [2/2] :
[==========][100%]
Excute cmd : otp print all
chip_name  : 8008C-NNNB
public_id  : 30841600000007e
user_data  :
0xfd 0xa5 0x85 0xd4 0x59 0x73 0xf2 0x63 0xdd 0xcc 0x52 0x8c 0x00 0xff 0xd8 0x01
0x3c 0x09 0x60 0x5c 0x8a 0x08 0x56 0x8d 0x88 0x63 0x59 0x5c 0x4a 0xf0 0xb2 0x53
0x1c 0x6c 0xb2 0xb1 0x82 0x02 0x1f 0xb3 0x06 0xb0 0x67 0xe0 0xf8 0xc3 0x0f 0x11
0xf7 0x83 0x3d 0x52 0x94 0x43 0xb5 0xdb 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

lock status: locked
done

4. 串口集成版本*

  • 代码位于 vsp_sdk/tools/otp_uart, 直接在Ubuntu下编译可以测试。代码里修改对应的串口 uart_fd = Open("/dev/ttyUSB1");
 make
❯ ./otp_test
please reboot the board
...
please reboot the board
[OTP_CORE]uart_cmd: otp print lock
lock status: unlocked
otp is unlocked!
[OTP_CORE]uart_cmd: otp print public_id
public_id  : 8cb95154c60d1652
PUBLIC ID: [8cb95154c60d1652]
[OTP_CORE]uart_cmd: otp_user tread 0 64
Read User data:
01 02 03 04 05 06 07 08 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[OTP_CORE]uart_cmd: otp_user twrite 8 0102030405060708
Write User data Done
[OTP_CORE]uart_cmd: otp_user tread 8 8
Read User data:
01 02 03 04 05 06 07 08
Data are identical.
  • 只适用8008c
  • 集成只需要host实现 porting_uart.h里的接口。
  • otp操作接口看otp_uart.h
  • otp操作的例子参考main.c