efuse: Add the batch writing mode

This mode should be used when burning several efuses at one time.
This commit is contained in:
KonstantinKondrashov
2019-09-18 21:19:48 +08:00
parent d7fa288a6c
commit cf762d91c2
4 changed files with 226 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