Merge branch 'feature/efuse_example' into 'master'

examples: Add an example efuse API usage and the group writing mode

Closes IDF-773

See merge request espressif/esp-idf!5810
This commit is contained in:
Angus Gratton 2019-11-05 10:13:21 +08:00
commit 8b48a8e72e
14 changed files with 726 additions and 27 deletions

View file

@ -327,6 +327,59 @@ esp_err_t esp_efuse_update_secure_version(uint32_t secure_version);
*/
void esp_efuse_init(uint32_t offset, uint32_t size);
/* @brief Set the batch mode of writing fields.
*
* This mode allows you to write the fields in the batch mode.
* If this mode is enabled, esp_efuse_batch_write_commit() must be called
* to actually burn any written efuses.
* In this mode, reading efuse is not possible.
* This mode should be used when burning several efuses at one time.
*
* \code{c}
* // Example of using the batch writing mode.
*
* // set the batch writing mode
* esp_efuse_batch_write_begin();
*
* // use any writing functions as usual
* esp_efuse_write_field_blob(ESP_EFUSE_...);
* esp_efuse_write_field_cnt(ESP_EFUSE_...);
* esp_efuse_set_write_protect(EFUSE_BLKx);
* esp_efuse_write_reg(EFUSE_BLKx, ...);
* esp_efuse_write_block(EFUSE_BLKx, ...);
* ...
*
* // Write all of these fields to the efuse registers
* esp_efuse_batch_write_commit();
*
* \endcode
*
* @return
* - ESP_OK: Successful.
*/
esp_err_t esp_efuse_batch_write_begin(void);
/* @brief Reset the batch mode of writing fields.
*
* It will reset the batch writing mode and any written changes.
*
* @return
* - ESP_OK: Successful.
* - ESP_ERR_INVALID_STATE: Tha batch mode was not set.
*/
esp_err_t esp_efuse_batch_write_cancel(void);
/* @brief Writes all prepared data for the batch mode.
*
* Must be called to ensure changes are written to the efuse registers.
* After this the batch writing mode will be reset.
*
* @return
* - ESP_OK: Successful.
* - ESP_ERR_INVALID_STATE: The deferred writing mode was not set.
*/
esp_err_t esp_efuse_batch_write_commit(void);
#ifdef __cplusplus
}
#endif

View file

@ -24,13 +24,19 @@ const static char *TAG = "efuse";
#if defined(BOOTLOADER_BUILD)
#define EFUSE_LOCK_ACQUIRE()
#define EFUSE_LOCK_RELEASE()
#define EFUSE_LOCK_ACQUIRE_RUCURSIVE()
#define EFUSE_LOCK_RELEASE_RUCURSIVE()
#else
#include <sys/lock.h>
static _lock_t s_efuse_lock;
#define EFUSE_LOCK_ACQUIRE() _lock_acquire(&s_efuse_lock)
#define EFUSE_LOCK_RELEASE() _lock_release(&s_efuse_lock)
#define EFUSE_LOCK_ACQUIRE_RUCURSIVE() _lock_acquire_recursive(&s_efuse_lock)
#define EFUSE_LOCK_RELEASE_RUCURSIVE() _lock_release_recursive(&s_efuse_lock)
#endif
static bool s_batch_writing_mode = false;
// Public API functions
// read value from EFUSE, writing it into an array
@ -66,51 +72,62 @@ esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_
// write array to EFUSE
esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits)
{
EFUSE_LOCK_ACQUIRE();
EFUSE_LOCK_ACQUIRE_RUCURSIVE();
esp_err_t err = ESP_OK;
if (field == NULL || src == NULL || src_size_bits == 0) {
err = ESP_ERR_INVALID_ARG;
} else {
esp_efuse_utility_reset();
if (s_batch_writing_mode == false) {
esp_efuse_utility_reset();
}
err = esp_efuse_utility_process(field, (void*)src, src_size_bits, esp_efuse_utility_write_blob);
if (err == ESP_OK) {
err = esp_efuse_utility_apply_new_coding_scheme();
if (s_batch_writing_mode == false) {
if (err == ESP_OK) {
esp_efuse_utility_burn_efuses();
err = esp_efuse_utility_apply_new_coding_scheme();
if (err == ESP_OK) {
esp_efuse_utility_burn_efuses();
}
}
esp_efuse_utility_reset();
}
esp_efuse_utility_reset();
}
EFUSE_LOCK_RELEASE();
EFUSE_LOCK_RELEASE_RUCURSIVE();
return err;
}
// program cnt bits to "1"
esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt)
{
EFUSE_LOCK_ACQUIRE();
EFUSE_LOCK_ACQUIRE_RUCURSIVE();
esp_err_t err = ESP_OK;
if (field == NULL || cnt == 0) {
err = ESP_ERR_INVALID_ARG;
} else {
esp_efuse_utility_reset();
if (s_batch_writing_mode == false) {
esp_efuse_utility_reset();
}
err = esp_efuse_utility_process(field, &cnt, 0, esp_efuse_utility_write_cnt);
if (cnt != 0) {
ESP_LOGE(TAG, "The required number of bits can not be set. [Not set %d]", cnt);
err = ESP_ERR_EFUSE_CNT_IS_FULL;
}
if (err == ESP_OK_EFUSE_CNT || err == ESP_OK) {
err = esp_efuse_utility_apply_new_coding_scheme();
if (err == ESP_OK) {
esp_efuse_utility_burn_efuses();
}
if (err == ESP_OK_EFUSE_CNT) {
err = ESP_OK;
}
if (s_batch_writing_mode == false) {
if (err == ESP_OK) {
err = esp_efuse_utility_apply_new_coding_scheme();
if (err == ESP_OK) {
esp_efuse_utility_burn_efuses();
}
}
esp_efuse_utility_reset();
}
esp_efuse_utility_reset();
}
EFUSE_LOCK_RELEASE();
EFUSE_LOCK_RELEASE_RUCURSIVE();
return err;
}
@ -140,17 +157,21 @@ uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg)
// writing efuse register.
esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val)
{
EFUSE_LOCK_ACQUIRE();
esp_efuse_utility_reset();
esp_err_t err = esp_efuse_utility_write_reg(blk, num_reg, val);
if (err == ESP_OK) {
err = esp_efuse_utility_apply_new_coding_scheme();
if (err == ESP_OK) {
esp_efuse_utility_burn_efuses();
}
EFUSE_LOCK_ACQUIRE_RUCURSIVE();
if (s_batch_writing_mode == false) {
esp_efuse_utility_reset();
}
esp_efuse_utility_reset();
EFUSE_LOCK_RELEASE();
esp_err_t err = esp_efuse_utility_write_reg(blk, num_reg, val);
if (s_batch_writing_mode == false) {
if (err == ESP_OK) {
err = esp_efuse_utility_apply_new_coding_scheme();
if (err == ESP_OK) {
esp_efuse_utility_burn_efuses();
}
}
esp_efuse_utility_reset();
}
EFUSE_LOCK_RELEASE_RUCURSIVE();
return err;
}
@ -193,3 +214,39 @@ esp_err_t esp_efuse_write_block(esp_efuse_block_t blk, const void* src_key, size
}
return err;
}
esp_err_t esp_efuse_batch_write_begin(void)
{
EFUSE_LOCK_ACQUIRE();
s_batch_writing_mode = true;
esp_efuse_utility_reset();
ESP_LOGI(TAG, "Batch mode of writing fields is enabled");
return ESP_OK;
}
esp_err_t esp_efuse_batch_write_cancel(void)
{
if (s_batch_writing_mode == true) {
s_batch_writing_mode = false;
esp_efuse_utility_reset();
ESP_LOGI(TAG, "Batch mode of writing fields is disabled");
EFUSE_LOCK_RELEASE();
return ESP_OK;
} else {
return ESP_ERR_INVALID_STATE;
}
}
esp_err_t esp_efuse_batch_write_commit(void)
{
if (s_batch_writing_mode == false) {
return ESP_ERR_INVALID_STATE;
} else {
esp_err_t err = esp_efuse_utility_apply_new_coding_scheme();
if (err == ESP_OK) {
esp_efuse_utility_burn_efuses();
}
esp_efuse_batch_write_cancel();
return err;
}
}

View file

@ -12,6 +12,10 @@
#include "esp_efuse_test_table.h"
#include "esp32/rom/efuse.h"
#include "bootloader_random.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "test_utils.h"
#include "sdkconfig.h"
static const char* TAG = "efuse_test";
@ -608,4 +612,82 @@ TEST_CASE("Test Bits are not empty. Write operation is forbidden", "[efuse]")
}
}
#ifndef CONFIG_FREERTOS_UNICORE
static const int delay_ms = 2000;
static xSemaphoreHandle sema;
static void task1(void* arg)
{
TEST_ESP_OK(esp_efuse_batch_write_begin());
ESP_LOGI(TAG, "Start work in batch mode");
xSemaphoreGive(sema);
vTaskDelay((delay_ms + 100) / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Finish work in batch mode");
TEST_ESP_OK(esp_efuse_batch_write_cancel());
vTaskDelete(NULL);
}
static void task2(void* arg)
{
xSemaphoreTake(sema, portMAX_DELAY);
uint8_t mac[6];
int64_t t1 = esp_timer_get_time();
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, sizeof(mac) * 8));
int64_t t2 = esp_timer_get_time();
int diff_ms = (t2 - t1) / 1000;
TEST_ASSERT_GREATER_THAN(delay_ms, diff_ms);
ESP_LOGI(TAG, "read MAC address: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
xSemaphoreGive(sema);
vTaskDelete(NULL);
}
static void task3(void* arg)
{
xSemaphoreTake(sema, portMAX_DELAY);
size_t test3_len_6 = 2;
int64_t t1 = esp_timer_get_time();
TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, test3_len_6));
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6));
int64_t t2 = esp_timer_get_time();
ESP_LOGI(TAG, "write&read test3_len_6: %d", test3_len_6);
int diff_ms = (t2 - t1) / 1000;
TEST_ASSERT_GREATER_THAN(delay_ms, diff_ms);
TEST_ASSERT_EQUAL_INT(2, test3_len_6);
xSemaphoreGive(sema);
vTaskDelete(NULL);
}
TEST_CASE("Batch mode is thread-safe", "[efuse]")
{
// Batch mode blocks work with efuse on other tasks.
esp_efuse_utility_update_virt_blocks();
esp_efuse_utility_debug_dump_blocks();
sema = xSemaphoreCreateBinary();
printf("\n");
xTaskCreatePinnedToCore(task1, "task1", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, NULL, 0);
xTaskCreatePinnedToCore(task2, "task2", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, NULL, 1);
vTaskDelay(3000 / portTICK_PERIOD_MS);
xSemaphoreTake(sema, portMAX_DELAY);
esp_efuse_utility_reset();
esp_efuse_utility_erase_virt_blocks();
printf("\n");
xTaskCreatePinnedToCore(task1, "task1", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, NULL, 0);
xTaskCreatePinnedToCore(task3, "task3", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, NULL, 1);
vTaskDelay(3000 / portTICK_PERIOD_MS);
xSemaphoreTake(sema, portMAX_DELAY);
printf("\n");
vSemaphoreDelete(sema);
esp_efuse_utility_reset();
esp_efuse_utility_erase_virt_blocks();
}
#endif // #ifndef CONFIG_FREERTOS_UNICORE
#endif // #ifdef CONFIG_EFUSE_VIRTUAL

View file

@ -146,6 +146,10 @@ Also, 3/4 coding scheme imposes restrictions on writing bits belonging to one co
It turns out that only one field can be written into one coding unit. Repeated rewriting in one coding unit is prohibited. But if the record was made in advance or through a :cpp:func:`esp_efuse_write_block` function, then reading the fields belonging to one coding unit is possible.
In case ``3/4`` coding scheme, the writing process is divided into the coding units and we can not use the usual mode of writing some fields. We can prepare all the data for writing and burn it in one time. You can also use this mode for ``None`` coding scheme but it is not necessary. It is important for ``3/4`` coding scheme.
To write some fields in one time need to use ``the batch writing mode``. Firstly set this mode through :cpp:func:`esp_efuse_batch_write_begin` function then write some fields as usual use the ``esp_efuse_write_...`` functions. At the end to burn they, need to call the :cpp:func:`esp_efuse_batch_write_commit` function. It burns prepared data to the efuse blocks and disable the ``batch recording mode``.
``The batch writing mode`` blocks ``esp_efuse_read_...`` operations.
After changing the coding scheme, run ``efuse_common_table`` and ``efuse_custom_table`` commands to check the tables of the new coding scheme.
eFuse API
@ -163,6 +167,9 @@ Access to the fields is via a pointer to the description structure. API function
* :cpp:func:`esp_efuse_get_coding_scheme` - returns eFuse coding scheme for blocks.
* :cpp:func:`esp_efuse_read_block` - reads key to eFuse block starting at the offset and the required size.
* :cpp:func:`esp_efuse_write_block` - writes key to eFuse block starting at the offset and the required size.
* :cpp:func:`esp_efuse_batch_write_begin` - set the batch mode of writing fields.
* :cpp:func:`esp_efuse_batch_write_commit` - writes all prepared data for batch writing mode and reset the batch writing mode.
* :cpp:func:`esp_efuse_batch_write_cancel` - reset the batch writing mode and prepared data.
For frequently used fields, special functions are made, like this :cpp:func:`esp_efuse_get_chip_ver`, :cpp:func:`esp_efuse_get_pkg_ver`.

View file

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(efuse)

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := efuse
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,184 @@
# eFuse Example
## Overview
This example shows how to use the eFuse API. It demonstrates read and write operations with fields from the common and custom eFuse tables. For more information about eFuse, see the “eFuse Manager” chapter in the documentation and the “eFuse Controller” chapter in ESP32 TRM.
The eFuse is a single bit of non-volatile memory with the restriction that once an eFuse bit is programmed to 1, it can not be reverted to 0.
The eFuse fields can be useful to store: device types, serial numbers, some system variables, etc.
Note that the bits already written cannot be reset to the original state. For debugging purposes, the `CONFIG_EFUSE_VIRTUAL` option is provided. This option will block physical burning. All work happens with an array in RAM.
In this example, all write operations are wrapped in `#ifdef CONFIG_EFUSE_VIRTUAL ... # endif` to prevent accidental burn while testing the features.
## How to use example
This example first reads the eFuse field, then writes a value, then reads it again. The program can be seen in the logs.
The program uses two eFuse tables:
* The common table (for IDF purposes).
* The custom table (for custom purposes).
The custom table has five fields:
```
MODULE_VERSION, EFUSE_BLK3, 56, 8, Module version
DEVICE_ROLE, EFUSE_BLK3, 64, 3, Device role
SETTING_1, EFUSE_BLK3, 67, 6, Setting 1
SETTING_2, EFUSE_BLK3, 73, 5, Setting 2
CUSTOM_SECURE_VERSION, EFUSE_BLK3, 78, 16, Custom secure version
```
### Hardware Required
To run this example, you need to use the ESP32 developer board. If your ESP32 has the `None` coding scheme of eFuse, then write and read operations have no limitations. But if it has the `3/4` or `RS` coding scheme, the writing may lead to an error due to the fact that some coded value was written earlier. A simple way to find out what coding scheme your chip has, you can see in the log while esptool is working or the log of the program:
```
esptool.py v2.7-dev
Serial port /dev/ttyUSB0
Connecting........_____.....__
Detecting chip type... ESP32
Chip is ESP32-PICO-D4 (revision 1)
Features: WiFi, BT, Dual Core, Embedded Flash, Coding Scheme None
MAC: d8:a0:1d:40:ac:90
```
The esptool also has a command to get general information about the chip `esptool.py chip_id`:
```
esptool.py v2.8-dev
Found 1 serial ports
Serial port /dev/ttyUSB0
Connecting........_
Detecting chip type... ESP32
Chip is ESP32-PICO-D4 (revision 1)
Features: WiFi, BT, Dual Core, Embedded Flash, Coding Scheme None
Crystal is 40MHz
MAC: d8:a0:1d:40:ac:90
Uploading stub...
Running stub...
Stub running...
Warning: ESP32 has no Chip ID. Reading MAC instead.
MAC: d8:a0:1d:40:ac:90
Hard resetting via RTS pin...
```
### Configure the project
```
idf.py menuconfig
```
In this example, there is `sdkconfig.default`, which already includes all the necessary settings. No need to configure.
* `CONFIG_EFUSE_CUSTOM_TABLE=y` - It allows using the custom table.
* `CONFIG_EFUSE_VIRTUAL=y` - All read and writes operations are redirected to RAM instead of eFuse registers. Not really burning eFuses.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
For ``None`` coding scheme:
```
I (0) cpu_start: Starting scheduler on APP CPU.
I (323) example: Coding Scheme NONE
I (323) example: Uses common and custom tables
I (333) example: read efuse fields
I (333) example: 1. read MAC address: d8:a0:1d:40:ac:90
I (343) example: 2. read secure_version: 0
I (343) example: 3. read custom fields
I (353) example: module_version = 0
I (353) example: device_role = None
I (363) example: setting_1 = 0
I (363) example: setting_2 = 0
I (363) example: custom_secure_version = 0
W (373) example: This example does not burn any efuse in reality only virtually
W (383) example: Write operations in efuse fields are performed virtually
I (383) example: write custom efuse fields
W (393) efuse: Virtual efuses enabled: Not really burning eFuses
W (403) efuse: Virtual efuses enabled: Not really burning eFuses
W (403) efuse: Virtual efuses enabled: Not really burning eFuses
W (413) efuse: Virtual efuses enabled: Not really burning eFuses
W (423) efuse: Virtual efuses enabled: Not really burning eFuses
I (423) example: module_version = 1
I (433) example: device_role = Slave
I (433) example: setting_1 = 3
I (433) example: setting_2 = 4
I (443) example: custom_secure_version = 5
I (443) example: Done
```
And for ``3/4`` coding scheme:
```
I (0) cpu_start: Starting scheduler on APP CPU.
I (327) example: Coding Scheme 3/4
I (327) example: Uses common and custom tables
I (337) example: read efuse fields
I (337) example: 1. read MAC address: 84:0d:8e:18:8e:44
I (347) example: 2. read secure_version: 0
I (347) example: 3. read custom fields
I (357) example: module_version = 0
I (357) example: device_role = None
I (367) example: setting_1 = 0
I (367) example: setting_2 = 0
I (367) example: custom_secure_version = 0
W (377) example: This example does not burn any efuse in reality only virtually
W (387) example: Write operations in efuse fields are performed virtually
I (387) example: In the case of 3/4 coding scheme, you cannot write efuse fields separately
I (397) example: You should use the batch mode of writing fields for this
I (407) efuse: Batch mode of writing fields is enabled
W (417) efuse: Virtual efuses enabled: Not really burning eFuses
I (417) efuse: Batch mode of writing fields is disabled
I (427) example: module_version = 1
I (427) example: device_role = Slave
I (437) example: setting_1 = 3
I (437) example: setting_2 = 4
I (437) example: custom_secure_version = 5
I (447) example: Done
```
### How to create the new custom table
In the main folder of the example there is a custom eFuse table - `esp_efuse_custom_table.csv`. You can add there some fields and run `idf.py efuse_custom_table`, it will generate all the necessary source files. If all is ok then you will see:
```
...
Parsing efuse CSV input file /home/kostia/esp/esp-idf/components/efuse/esp32/esp_efuse_table.csv ...
Verifying efuse table...
Parsing efuse CSV input file /home/kostia/esp/esp-idf/examples/system/efuse/main/esp_efuse_custom_table.csv ...
Verifying efuse table...
Creating efuse *.h file /home/kostia/esp/esp-idf/examples/system/efuse/main/include/esp_efuse_custom_table.h ...
Creating efuse *.c file /home/kostia/esp/esp-idf/examples/system/efuse/main/esp_efuse_custom_table.c ...
Max number of bits in BLK 192
```
If the following fields were not changed in the CSV file: field_name, efuse_block, bit_start or bit_count, then a new generation will not occur, and you will see this message `Source files do not require updating correspond to csv file`.
This command will create into main folder two files: `esp_efuse_custom_table.c` and `include/esp_efuse_custom_table.h`.
Do not forget to add these files for the Cmake build system:
```
idf_component_register(SRCS "efuse_main.c" "esp_efuse_custom_table.c"
INCLUDE_DIRS "." "include")
```
If you are not sure which eFuse bits are free you can run `idf.py show_efuse_table`. It prints a sorted list of the common and custom tables.

View file

@ -0,0 +1,4 @@
idf_component_register(SRCS "efuse_main.c"
"esp_efuse_custom_table.c"
INCLUDE_DIRS "."
"include")

View file

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,155 @@
/* efuse example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_efuse_custom_table.h"
#include "sdkconfig.h"
static const char* TAG = "example";
typedef struct {
uint8_t module_version; /*!< Module version: length 8 bits */
uint8_t device_role; /*!< Device role: length 3 bits */
uint8_t setting_1; /*!< Setting 1: length 6 bits */
uint8_t setting_2; /*!< Setting 2: length 5 bits */
size_t custom_secure_version; /*!< Custom secure version: length 16 bits */
uint16_t reserv; /*!< Reserv */
} device_desc_t;
static void print_device_desc(device_desc_t *desc)
{
ESP_LOGI(TAG, "module_version = %d", desc->module_version);
if (desc->device_role == 0) {
ESP_LOGI(TAG, "device_role = None");
} else if (desc->device_role == 1) {
ESP_LOGI(TAG, "device_role = Master");
} else if (desc->device_role == 2) {
ESP_LOGI(TAG, "device_role = Slave");
} else {
ESP_LOGI(TAG, "device_role = Not supported");
}
ESP_LOGI(TAG, "setting_1 = %d", desc->setting_1);
ESP_LOGI(TAG, "setting_2 = %d", desc->setting_2);
ESP_LOGI(TAG, "custom_secure_version = %d", desc->custom_secure_version);
}
static void read_device_desc_efuse_fields(device_desc_t *desc)
{
ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_MODULE_VERSION, &desc->module_version, 8));
ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_DEVICE_ROLE, &desc->device_role, 3));
ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_SETTING_1, &desc->setting_1, 6));
ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_SETTING_2, &desc->setting_2, 5));
ESP_ERROR_CHECK(esp_efuse_read_field_cnt(ESP_EFUSE_CUSTOM_SECURE_VERSION, &desc->custom_secure_version));
print_device_desc(desc);
}
static void read_efuse_fields(device_desc_t *desc)
{
ESP_LOGI(TAG, "read efuse fields");
uint8_t mac[6];
ESP_ERROR_CHECK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, sizeof(mac) * 8));
ESP_LOGI(TAG, "1. read MAC address: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
size_t secure_version = 0;
ESP_ERROR_CHECK(esp_efuse_read_field_cnt(ESP_EFUSE_SECURE_VERSION, &secure_version));
ESP_LOGI(TAG, "2. read secure_version: %d", secure_version);
ESP_LOGI(TAG, "3. read custom fields");
read_device_desc_efuse_fields(desc);
}
static void write_efuse_fields(device_desc_t *desc, esp_efuse_coding_scheme_t coding_scheme)
{
#ifdef CONFIG_EFUSE_VIRTUAL
#if CONFIG_IDF_TARGET_ESP32
const esp_efuse_coding_scheme_t coding_scheme_for_batch_mode = EFUSE_CODING_SCHEME_3_4;
#else
const esp_efuse_coding_scheme_t coding_scheme_for_batch_mode = EFUSE_CODING_SCHEME_RS;
#endif
ESP_LOGI(TAG, "write custom efuse fields");
if (coding_scheme == coding_scheme_for_batch_mode) {
ESP_LOGI(TAG, "In the case of 3/4 or RS coding scheme, you cannot write efuse fields separately");
ESP_LOGI(TAG, "You should use the batch mode of writing fields for this");
ESP_ERROR_CHECK(esp_efuse_batch_write_begin());
}
ESP_ERROR_CHECK(esp_efuse_write_field_blob(ESP_EFUSE_MODULE_VERSION, &desc->module_version, 8));
ESP_ERROR_CHECK(esp_efuse_write_field_blob(ESP_EFUSE_DEVICE_ROLE, &desc->device_role, 3));
ESP_ERROR_CHECK(esp_efuse_write_field_blob(ESP_EFUSE_SETTING_1, &desc->setting_1, 6));
ESP_ERROR_CHECK(esp_efuse_write_field_blob(ESP_EFUSE_SETTING_2, &desc->setting_2, 5));
ESP_ERROR_CHECK(esp_efuse_write_field_cnt(ESP_EFUSE_CUSTOM_SECURE_VERSION, desc->custom_secure_version));
if (coding_scheme == coding_scheme_for_batch_mode) {
ESP_ERROR_CHECK(esp_efuse_batch_write_commit());
}
#endif // CONFIG_EFUSE_VIRTUAL
}
static esp_efuse_coding_scheme_t get_coding_scheme(void)
{
// The coding scheme is used for EFUSE_BLK1, EFUSE_BLK2 and EFUSE_BLK3.
// We use EFUSE_BLK3 (custom block) to verify it.
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK3);
if (coding_scheme == EFUSE_CODING_SCHEME_NONE) {
ESP_LOGI(TAG, "Coding Scheme NONE");
#if CONFIG_IDF_TARGET_ESP32
} else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
ESP_LOGI(TAG, "Coding Scheme 3/4");
} else {
ESP_LOGI(TAG, "Coding Scheme REPEAT");
}
#else
} else if (coding_scheme == EFUSE_CODING_SCHEME_RS) {
ESP_LOGI(TAG, "Coding Scheme RS (Reed-Solomon coding)");
}
#endif
return coding_scheme;
}
void app_main(void)
{
esp_efuse_coding_scheme_t coding_scheme = get_coding_scheme();
device_desc_t device_desc = { 0 };
read_efuse_fields(&device_desc);
ESP_LOGW(TAG, "This example does not burn any efuse in reality only virtually");
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGW(TAG, "Write operations in efuse fields are performed virtually");
if (device_desc.device_role == 0) {
device_desc.module_version = 1;
device_desc.device_role = 2;
device_desc.setting_1 = 3;
device_desc.setting_2 = 4;
device_desc.custom_secure_version = 5;
write_efuse_fields(&device_desc, coding_scheme);
read_device_desc_efuse_fields(&device_desc);
}
#else
ESP_LOGW(TAG, "The part of the code that writes efuse fields is disabled");
#endif
ESP_LOGI(TAG, "Done");
}

View file

@ -0,0 +1,81 @@
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at",
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#include "sdkconfig.h"
#include "esp_efuse.h"
#include <assert.h>
#include "esp_efuse_custom_table.h"
// md5_digest_table 584317af6a850ee16ef6206c139d6cf5
// This file was generated from the file esp_efuse_custom_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_custom_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
// To show efuse_table run the command 'show_efuse_table'.
#define MAX_BLK_LEN CONFIG_EFUSE_MAX_BLK_LEN
// The last free bit in the block is counted over the entire file.
#define LAST_FREE_BIT_BLK3 94
_Static_assert(LAST_FREE_BIT_BLK3 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. Edit the table and restart the efuse_common_table or efuse_custom_table command to regenerate the new files.");
static const esp_efuse_desc_t MODULE_VERSION[] = {
{EFUSE_BLK3, 56, 8}, // Module version,
};
static const esp_efuse_desc_t DEVICE_ROLE[] = {
{EFUSE_BLK3, 64, 3}, // Device role,
};
static const esp_efuse_desc_t SETTING_1[] = {
{EFUSE_BLK3, 67, 6}, // Setting 1,
};
static const esp_efuse_desc_t SETTING_2[] = {
{EFUSE_BLK3, 73, 5}, // Setting 2,
};
static const esp_efuse_desc_t CUSTOM_SECURE_VERSION[] = {
{EFUSE_BLK3, 78, 16}, // Custom secure version,
};
const esp_efuse_desc_t* ESP_EFUSE_MODULE_VERSION[] = {
&MODULE_VERSION[0], // Module version
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_DEVICE_ROLE[] = {
&DEVICE_ROLE[0], // Device role
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_SETTING_1[] = {
&SETTING_1[0], // Setting 1
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_SETTING_2[] = {
&SETTING_2[0], // Setting 2
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CUSTOM_SECURE_VERSION[] = {
&CUSTOM_SECURE_VERSION[0], // Custom secure version
NULL
};

View file

@ -0,0 +1,18 @@
# field_name, | efuse_block, | bit_start, | bit_count, |comment #
# | (EFUSE_BLK0 | (0..255) | (1..-) | #
# | EFUSE_BLK1 | |MAX_BLK_LEN*| #
# | EFUSE_BLK2 | | | #
# | EFUSE_BLK3) | | | #
##########################################################################
# *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_MAX_BLK_LEN, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128.
# !!!!!!!!!!! #
# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table"
# this will generate new source files, next rebuild all the sources.
# !!!!!!!!!!! #
MODULE_VERSION, EFUSE_BLK3, 56, 8, Module version
DEVICE_ROLE, EFUSE_BLK3, 64, 3, Device role
SETTING_1, EFUSE_BLK3, 67, 6, Setting 1
SETTING_2, EFUSE_BLK3, 73, 5, Setting 2
CUSTOM_SECURE_VERSION, EFUSE_BLK3, 78, 16, Custom secure version
Can't render this file because it contains an unexpected character in line 7 and column 87.

View file

@ -0,0 +1,36 @@
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at",
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#ifdef __cplusplus
extern "C" {
#endif
// md5_digest_table 584317af6a850ee16ef6206c139d6cf5
// This file was generated from the file esp_efuse_custom_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_custom_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
// To show efuse_table run the command 'show_efuse_table'.
extern const esp_efuse_desc_t* ESP_EFUSE_MODULE_VERSION[];
extern const esp_efuse_desc_t* ESP_EFUSE_DEVICE_ROLE[];
extern const esp_efuse_desc_t* ESP_EFUSE_SETTING_1[];
extern const esp_efuse_desc_t* ESP_EFUSE_SETTING_2[];
extern const esp_efuse_desc_t* ESP_EFUSE_CUSTOM_SECURE_VERSION[];
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,2 @@
CONFIG_EFUSE_CUSTOM_TABLE=y
CONFIG_EFUSE_VIRTUAL=y