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写入则结果正常
解决方案
问题根源
- 参数传递错误:
write_efuse_fields中调用esp_efuse_write_field_blob时,传入的是&serial_num(char指针的地址),而非字符串的首地址,导致函数写入指针本身的内存值而非字符串内容。 - 数据类型不匹配:直接传入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
相关产品推荐
相关产品推荐

