You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32 IDF:如何将字符数组转为字节数组写入EFUSE?

问题

基于ESP32 IDF开发功能:通过UART接收命令并提取子串写入ESP32 EFUSE。现有uart_event_task函数可正常提取序列号字符串(如exampleserial123),也能将其转为十六进制字符串,但直接将char数组传入write_efuse_fields调用esp_efuse_write_field_blob时,EFUSE写入结果异常;使用uint8_t类型数组(如unique_id)则能得到预期结果。需解决如何将char数组转换为类似unique_id的字节数组,使esp_efuse_write_field_blob正确处理。

相关代码

static void uart_event_task()
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t *dtmp = (uint8_t *)malloc(RD_BUF_SIZE);
    char cmd[30];
    char serialNum[20];
    for (;;)
    {
        if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY))
        {
            bzero(dtmp, RD_BUF_SIZE);
            ESP_LOGI(TAG_CONFIG, "uart[%d] event:", EX_UART_NUM);
            switch (event.type)
            {
            case UART_DATA:
                ESP_LOGI(TAG_CONFIG, "[UART DATA]: %d", event.size);
                uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
                int lastChar = 0;
                for (int i = 0; i <= event.size; i++)
                {
                    const char letter = (const char)dtmp[i];
                    if (dtmp[i] == 10 || dtmp[i] == 0)
                    {
                        break;
                    }
                    cmd[i] = letter;
                    lastChar = i;
                }
                cmd[++lastChar] = '\0';
                ESP_LOGE(TAG_CONFIG, "Your command: %s ", cmd);
                if (strstr(cmd, set_serial) != NULL)
                {
                    int lastChar2 = 0;
                    for (int i = strlen(set_serial) + 1; i < lastChar; i++)
                    {
                        int index = i - strlen(set_serial) - 1;
                        serialNum[index] = cmd[i];
                        lastChar2 = index;
                    }
                    serialNum[++lastChar2] = '\0';
                    ESP_LOGW(TAG_CONFIG, "setting serial: %s ", serialNum);
                    int len = strlen(serialNum);
                    char hex_str[(len * 2) + 1];
                    string2hexString(serialNum, hex_str);
                    printf("serialNum: %s\n", serialNum);
                    printf("hex_str: %s\n", hex_str);
                    esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK3);
                    write_efuse_fields(serialNum, coding_scheme);
                }
            }
        }
    }
}
static void write_efuse_fields(char *serial_num, esp_efuse_coding_scheme_t coding_scheme)
{
    // uint8_t unique_id[16] = {0x48, 0x42, 0x30, 0x31, 0x39, 0x39, 0x39, 0x39, 0x30, 0x31, 0x32, 0x33};
    ESP_ERROR_CHECK_WITHOUT_ABORT(esp_efuse_write_field_blob(ESP_EFUSE_USER_DATA, &serial_num, 128));
}

当前异常写入结果

  • 写入serialNum后EFUSE读取结果:ee 17 fd 3f 00 00 00 ff e4 38 fd 3f 0f 00 00 00(转文本:îý?ÿä8ý?)
  • 写入hex_str后结果:90 17 fd 3f 00 00 00 ff e4 38 fd 3f 0f 00 00 00(转文本:ý?ÿä8ý?)
  • 使用uint8_t数组unique_id写入则结果正常

解决方案

问题根源

  1. 参数传递错误:write_efuse_fields中调用esp_efuse_write_field_blob时,传入的是&serial_num(char指针的地址),而非字符串的首地址,导致函数写入指针本身的内存值而非字符串内容。
  2. 数据类型不匹配:直接传入char字符串时,需将其转换为uint8_t字节数组,确保与esp_efuse_write_field_blob的参数要求一致。

具体修复步骤

步骤1:修正参数传递与类型转换

如果需要直接写入字符串的ASCII字节,修改write_efuse_fields函数,将char字符串转为uint8_t字节数组,并传入正确的首地址:

static void write_efuse_fields(char *serial_num, esp_efuse_coding_scheme_t coding_scheme)
{
    uint8_t byte_buf[16] = {0}; // 128位EFUSE对应16字节,初始化补零
    size_t copy_len = strlen(serial_num) > 16 ? 16 : strlen(serial_num);
    memcpy(byte_buf, serial_num, copy_len); // 将char字符串转为uint8_t字节数组

    ESP_ERROR_CHECK_WITHOUT_ABORT(esp_efuse_write_field_blob(ESP_EFUSE_USER_DATA, byte_buf, 128));
}

如果需要将十六进制字符串(如hex_str)转为字节数组写入,需实现十六进制转字节的工具函数:

// 十六进制字符串转字节数组,返回转换后的有效字节长度
size_t hexstr_to_bytes(const char *hex_str, uint8_t *byte_buf, size_t buf_len)
{
    size_t hex_len = strlen(hex_str);
    if (hex_len % 2 != 0 || buf_len < hex_len / 2) {
        return 0; // 非法长度或缓冲区不足
    }
    size_t byte_idx = 0;
    for (size_t i = 0; i < hex_len; i += 2) {
        char hex_byte[3] = {hex_str[i], hex_str[i+1], '\0'};
        byte_buf[byte_idx++] = strtoul(hex_byte, NULL, 16);
    }
    return byte_idx;
}

再修改write_efuse_fields适配十六进制字符串:

static void write_efuse_fields(char *hex_str, esp_efuse_coding_scheme_t coding_scheme)
{
    uint8_t byte_buf[16] = {0};
    size_t byte_len = hexstr_to_bytes(hex_str, byte_buf, sizeof(byte_buf));
    if (byte_len == 0) {
        ESP_LOGE(TAG_CONFIG, "Invalid hex string");
        return;
    }
    ESP_ERROR_CHECK_WITHOUT_ABORT(esp_efuse_write_field_blob(ESP_EFUSE_USER_DATA, byte_buf, 128));
}

步骤2:调整调用逻辑

  • 若写入字符串ASCII字节:保持write_efuse_fields(serialNum, coding_scheme)调用即可
  • 若写入十六进制对应字节:将调用改为write_efuse_fields(hex_str, coding_scheme)

关键注意事项

  • EFUSE写入后不可逆,测试时先开启sdkconfig中的CONFIG_EFUSE_EMULATE模拟模式,避免硬件损坏
  • 确保写入的字节长度与EFUSE字段位长匹配(128位对应16字节),超出部分会被截断,不足部分自动补零

内容的提问来源于stack exchange,提问作者shachaf zilberman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 21:45:47