mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
efuse: Add the batch writing mode
This mode should be used when burning several efuses at one time.
This commit is contained in:
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user