Merge branch 'feature/efuse_manager' into 'master'

Feature/efuse manager

See merge request idf/esp-idf!2819
This commit is contained in:
Angus Gratton
2019-02-28 17:47:22 +08:00
40 changed files with 4107 additions and 213 deletions

View File

@@ -593,6 +593,22 @@ test_esp_err_to_name_on_host:
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./gen_esp_err_to_name.py
- git diff --exit-code -- ../components/esp32/esp_err_to_name.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; }
test_esp_efuse_table_on_host:
<<: *host_test_template
artifacts:
when: on_failure
paths:
- components/efuse/esp32/esp_efuse_table.c
expire_in: 1 week
script:
- cd ${IDF_PATH}/components/efuse/
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 2.7.15 ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv
- git diff --exit-code -- esp32/esp_efuse_table.c || { echo 'Differences found. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; }
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv
- git diff --exit-code -- ../components/esp32/esp_efuse_table.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; }
- cd ${IDF_PATH}/components/efuse/test_efuse_host
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./efuse_tests.py
test_espcoredump:
<<: *host_test_template
artifacts:

View File

@@ -10,7 +10,7 @@ if(NOT IDF_PATH)
"in by the parent build process.")
endif()
set(COMPONENTS bootloader esptool_py esp32 partition_table soc bootloader_support log spi_flash micro-ecc soc main)
set(COMPONENTS bootloader esptool_py esp32 partition_table soc bootloader_support log spi_flash micro-ecc soc main efuse)
set(BOOTLOADER_BUILD 1)
add_definitions(-DBOOTLOADER_BUILD=1)

View File

@@ -8,7 +8,7 @@ endif
PROJECT_NAME := bootloader
COMPONENTS := esptool_py bootloader_support log spi_flash micro-ecc soc main
COMPONENTS := esptool_py bootloader_support log spi_flash micro-ecc soc main efuse
# Clear C and CXX from top level project
CFLAGS =

View File

@@ -45,7 +45,6 @@ SECTIONS
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:efuse.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
@@ -54,6 +53,7 @@ SECTIONS
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
*libsoc.a:rtc_wdt.*(.literal .text .literal.* .text.*)
*libefuse.a:*.*(.literal .text .literal.* .text.*)
*(.fini.literal)
*(.fini)
*(.gnu.version)

View File

@@ -4,7 +4,6 @@ set(COMPONENT_SRCS "src/bootloader_clock.c"
"src/bootloader_random.c"
"src/bootloader_sha.c"
"src/bootloader_utility.c"
"src/efuse.c"
"src/esp_image_format.c"
"src/flash_encrypt.c"
"src/flash_partitions.c"
@@ -15,7 +14,7 @@ set(COMPONENT_SRCS "src/bootloader_clock.c"
if(${BOOTLOADER_BUILD})
set(COMPONENT_ADD_INCLUDEDIRS "include include_bootloader")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc)
set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc efuse)
list(APPEND COMPONENT_SRCS "src/bootloader_init.c")
if(CONFIG_SECURE_SIGNED_APPS)
@@ -55,7 +54,7 @@ else()
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls micro-ecc)
set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls micro-ecc efuse)
endif()
register_component()

View File

@@ -1,136 +0,0 @@
// Copyright 2015-2016 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.
#ifndef _ESP_EFUSE_H
#define _ESP_EFUSE_H
#include "soc/efuse_reg.h"
#include "esp_err.h"
#include "stdbool.h"
#ifdef __cplusplus
extern "C" {
#endif
/* @brief Permanently update values written to the efuse write registers
*
* After updating EFUSE_BLKx_WDATAx_REG registers with new values to
* write, call this function to permanently write them to efuse.
*
* @note Setting bits in efuse is permanent, they cannot be unset.
*
* @note Due to this restriction you don't need to copy values to
* Efuse write registers from the matching read registers, bits which
* are set in the read register but unset in the matching write
* register will be unchanged when new values are burned.
*
* @note This function is not threadsafe, if calling code updates
* efuse values from multiple tasks then this is caller's
* responsibility to serialise.
*
* After burning new efuses, the read registers are updated to match
* the new efuse values.
*/
void esp_efuse_burn_new_values(void);
/* @brief Reset efuse write registers
*
* Efuse write registers are written to zero, to negate
* any changes that have been staged here.
*/
void esp_efuse_reset(void);
/* @brief Disable BASIC ROM Console via efuse
*
* By default, if booting from flash fails the ESP32 will boot a
* BASIC console in ROM.
*
* Call this function (from bootloader or app) to permanently
* disable the console on this chip.
*/
void esp_efuse_disable_basic_rom_console(void);
/* @brief Encode one or more sets of 6 byte sequences into
* 8 bytes suitable for 3/4 Coding Scheme.
*
* This function is only useful if the CODING_SCHEME efuse
* is set to value 1 for 3/4 Coding Scheme.
*
* @param[in] in_bytes Pointer to a sequence of bytes to encode for 3/4 Coding Scheme. Must have length in_bytes_len. After being written to hardware, these bytes will read back as little-endian words.
* @param[out] out_words Pointer to array of words suitable for writing to efuse write registers. Array must contain 2 words (8 bytes) for every 6 bytes in in_bytes_len. Can be a pointer to efuse write registers.
* @param in_bytes_len. Length of array pointed to by in_bytes, in bytes. Must be a multiple of 6.
*
* @return ESP_ERR_INVALID_ARG if either pointer is null or in_bytes_len is not a multiple of 6. ESP_OK otherwise.
*/
esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len);
/* @brief Write random data to efuse key block write registers
*
* @note Caller is responsible for ensuring efuse
* block is empty and not write protected, before calling.
*
* @note Behaviour depends on coding scheme: a 256-bit key is
* generated and written for Coding Scheme "None", a 192-bit key
* is generated, extended to 256-bits by the Coding Scheme,
* and then writtten for 3/4 Coding Scheme.
*
* @note This function does not burn the new values, caller should
* call esp_efuse_burn_new_values() when ready to do this.
*
* @param blk_wdata0_reg Address of the first data write register
* in the block
*/
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg);
/* @brief Return secure_version from efuse field.
* @return Secure version from efuse field
*/
uint32_t esp_efuse_read_secure_version();
/* @brief Check secure_version from app and secure_version and from efuse field.
*
* @param secure_version Secure version from app.
* @return
* - True: If version of app is equal or more then secure_version from efuse.
*/
bool esp_efuse_check_secure_version(uint32_t secure_version);
/* @brief Write efuse field by secure_version value.
*
* Update the secure_version value is available if the coding scheme is None.
* Note: Do not use this function in your applications. This function is called as part of the other API.
*
* @param[in] secure_version Secure version from app.
* @return
* - ESP_OK: Successful.
* - ESP_FAIL: secure version of app cannot be set to efuse field.
* - ESP_ERR_NOT_SUPPORTED: Anti rollback is not supported with the 3/4 and Repeat coding scheme.
*/
esp_err_t esp_efuse_update_secure_version(uint32_t secure_version);
/* @brief Initializes variables: offset and size to simulate the work of an eFuse.
*
* Note: To simulate the work of an eFuse need to set CONFIG_EFUSE_SECURE_VERSION_EMULATE option
* and to add in the partition.csv file a line `efuse_em, data, efuse, , 0x2000,`.
*
* @param[in] offset The starting address of the partition where the eFuse data will be located.
* @param[in] size The size of the partition.
*/
void esp_efuse_init(uint32_t offset, uint32_t size);
#ifdef __cplusplus
}
#endif
#endif /* __ESP_EFUSE_H */

View File

@@ -0,0 +1,43 @@
set(SOC_NAME ${IDF_TARGET})
if(EXISTS "${COMPONENT_PATH}/${SOC_NAME}")
include(${COMPONENT_PATH}/${SOC_NAME}/sources.cmake)
spaces2list(EFUSE_SOC_SRCS)
add_prefix(COMPONENT_SRCS "${SOC_NAME}/" ${EFUSE_SOC_SRCS})
set(COMPONENT_ADD_INCLUDEDIRS include
${SOC_NAME}/include)
endif()
list(APPEND COMPONENT_SRCS "src/esp_efuse_api.c"
"src/esp_efuse_fields.c"
"src/esp_efuse_utility.c")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES bootloader_support)
register_component()
set(GEN_EFUSE_TABLE_ARG --max_blk_len ${CONFIG_EFUSE_MAX_BLK_LEN})
###################
# Make common files esp_efuse_table.c and include/esp_efuse_table.h files.
set(EFUSE_COMMON_TABLE_CSV_PATH "${COMPONENT_PATH}/${SOC_NAME}/esp_efuse_table.csv")
add_custom_target(efuse_common_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})
###################
# Make custom files project/main/esp_efuse_custom_table.c and project/main/include/esp_efuse_custom_table.h files.
# Path to CSV file is relative to project path for custom CSV files.
if(${CONFIG_EFUSE_CUSTOM_TABLE})
# Custom filename expands any path relative to the project
get_filename_component(EFUSE_CUSTOM_TABLE_CSV_PATH "${CONFIG_EFUSE_CUSTOM_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${IDF_PROJECT_PATH}")
add_custom_target(efuse_custom_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})
else()
add_custom_target(efuse_custom_table COMMAND)
endif()#if(${CONFIG_EFUSE_CUSTOM_TABLE})
add_custom_target(show_efuse_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG} "--info")
###################
# Generates files for unit test. This command is run manually.
set(EFUSE_TEST_TABLE_CSV_PATH "${COMPONENT_PATH}/test/esp_efuse_test_table.csv")
add_custom_target(efuse_test_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_TEST_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})

45
components/efuse/Kconfig Normal file
View File

@@ -0,0 +1,45 @@
menu "eFuse Bit Manager"
config EFUSE_CUSTOM_TABLE
bool "Use custom eFuse table"
default n
help
Allows to generate a structure for eFuse from the CSV file.
config EFUSE_CUSTOM_TABLE_FILENAME
string "Custom eFuse CSV file"
depends on EFUSE_CUSTOM_TABLE
default main/esp_efuse_custom_table.csv
help
Name of the custom eFuse CSV filename. This path is evaluated
relative to the project root directory.
config EFUSE_VIRTUAL
bool "Simulate eFuse operations in RAM"
default n
help
All read and writes operations are redirected to RAM instead of eFuse registers.
If this option is set, all permanent changes (via eFuse) are disabled.
Log output will state changes which would be applied, but they will not be.
choice EFUSE_CODE_SCHEME_SELECTOR
prompt "Coding Scheme Compatibility"
default EFUSE_CODE_SCHEME_COMPAT_3_4
help
Selector eFuse code scheme.
config EFUSE_CODE_SCHEME_COMPAT_NONE
bool "None Only"
config EFUSE_CODE_SCHEME_COMPAT_3_4
bool "3/4 and None"
config EFUSE_CODE_SCHEME_COMPAT_REPEAT
bool "Repeat, 3/4 and None (common table does not support it)"
endchoice
config EFUSE_MAX_BLK_LEN
int
default 256 if EFUSE_CODE_SCHEME_COMPAT_NONE
default 192 if EFUSE_CODE_SCHEME_COMPAT_3_4
default 128 if EFUSE_CODE_SCHEME_COMPAT_REPEAT
endmenu

View File

@@ -0,0 +1,49 @@
#
# eFuse Manager ganeretes header file.
#
.PHONY: efuse_custom_table efuse_common_table efuse_test_table show_efuse_table
GEN_EFUSE_TABLE := $(PYTHON) $(COMPONENT_PATH)/efuse_table_gen.py
GEN_EFUSE_TABLE_ARG := --max_blk_len $(CONFIG_EFUSE_MAX_BLK_LEN)
###################
# Make common files esp_efuse_table.c and include/esp_efuse_table.h files.
SOC_NAME := $(IDF_TARGET)
EFUSE_COMMON_TABLE_CSV_PATH := $(COMPONENT_PATH)/$(SOC_NAME)/esp_efuse_table.csv
efuse_common_table:
@echo "COMMON_TABLE_CSV: $(EFUSE_COMMON_TABLE_CSV_PATH)"
$(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG)
###################
# Make custom files project/main/esp_efuse_custom_table.c and project/main/include/esp_efuse_custom_table.h files.
ifdef CONFIG_EFUSE_CUSTOM_TABLE
# Path to CSV file is relative to project path for custom CSV files.
EFUSE_CUSTOM_TABLE_CSV_PATH := $(call dequote,$(abspath $(call dequote, $(PROJECT_PATH))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME))))
efuse_custom_table:
@echo "COMMON_TABLE_CSV: $(EFUSE_COMMON_TABLE_CSV_PATH)"
@echo "CUSTOM_TABLE_CSV: $(EFUSE_CUSTOM_TABLE_CSV_PATH)"
$(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG)
else
efuse_custom_table:
EFUSE_CUSTOM_TABLE_CSV_PATH :=
EFUSE_CUSTOM_TABLE_OUT_PATH :=
endif # ifdef CONFIG_EFUSE_CUSTOM_TABLE
###################
# print to console efuse table
show_efuse_table:
$(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) --info
###################
# Generates files for unit test. This command is run manually.
EFUSE_TEST_TABLE_CSV_PATH := $(COMPONENT_PATH)/test/esp_efuse_test_table.csv
efuse_test_table:
$(GEN_EFUSE_TABLE) $(EFUSE_TEST_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG)

View File

@@ -0,0 +1,10 @@
#
# Component Makefile
# currently the only SoC supported; to be moved into Kconfig
SOC_NAME := $(IDF_TARGET)
COMPONENT_SRCDIRS := $(SOC_NAME) src
COMPONENT_ADD_INCLUDEDIRS := $(SOC_NAME)/include include
-include $(COMPONENT_PATH)/$(SOC_NAME)/component.mk

View File

@@ -0,0 +1,506 @@
#!/usr/bin/env python
#
# ESP32 efuse table generation tool
#
# Converts efuse table to header file efuse_table.h.
#
# 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.
from __future__ import print_function, division
import argparse
import os
import re
import sys
import hashlib
__version__ = '1.0'
quiet = False
max_blk_len = 256
copyright = '''// 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
'''
def status(msg):
""" Print status message to stderr """
if not quiet:
critical(msg)
def critical(msg):
""" Print critical message to stderr """
sys.stderr.write(msg)
sys.stderr.write('\n')
class FuseTable(list):
def __init__(self):
super(FuseTable, self).__init__(self)
self.md5_digest_table = ""
@classmethod
def from_csv(cls, csv_contents):
res = FuseTable()
lines = csv_contents.splitlines()
def expand_vars(f):
f = os.path.expandvars(f)
m = re.match(r'(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)', f)
if m:
raise InputError("unknown variable '%s'" % (m.group(1)))
return f
for line_no in range(len(lines)):
line = expand_vars(lines[line_no]).strip()
if line.startswith("#") or len(line) == 0:
continue
try:
res.append(FuseDefinition.from_csv(line))
except InputError as e:
raise InputError("Error at line %d: %s" % (line_no + 1, e))
except Exception:
critical("Unexpected error parsing line %d: %s" % (line_no + 1, line))
raise
# fix up missing bit_start
last_efuse_block = None
for e in res:
if last_efuse_block != e.efuse_block:
last_end = 0
if e.bit_start is None:
e.bit_start = last_end
last_end = e.bit_start + e.bit_count
last_efuse_block = e.efuse_block
res.verify_duplicate_name()
# fix up missing field_name
last_field = None
for e in res:
if e.field_name == "" and last_field is None:
raise InputError("Error at line %d: %s missing field name" % (line_no + 1, e))
elif e.field_name == "" and last_field is not None:
e.field_name = last_field.field_name
last_field = e
# fill group
names = [p.field_name for p in res]
duplicates = set(n for n in names if names.count(n) > 1)
if len(duplicates) != 0:
i_count = 0
for p in res:
if len(duplicates.intersection([p.field_name])) != 0:
p.group = str(i_count)
i_count += 1
else:
i_count = 0
res.verify_duplicate_name()
# clac md5 for table
res.calc_md5()
return res
def verify_duplicate_name(self):
# check on duplicate name
names = [p.field_name for p in self]
duplicates = set(n for n in names if names.count(n) > 1)
# print sorted duplicate partitions by name
if len(duplicates) != 0:
fl_error = False
for p in self:
field_name = p.field_name + p.group
if field_name != "" and len(duplicates.intersection([field_name])) != 0:
fl_error = True
print("Field at %s, %s, %s, %s have dublicate field_name" %
(p.field_name, p.efuse_block, p.bit_start, p.bit_count))
if fl_error is True:
raise InputError("Field names must be unique")
def verify(self, type_table=None):
for p in self:
p.verify(type_table)
self.verify_duplicate_name()
# check for overlaps
last = None
for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)):
if last is not None and last.efuse_block == p.efuse_block and p.bit_start < last.bit_start + last.bit_count:
raise InputError("Field at %s, %s, %s, %s overlaps %s, %s, %s, %s" %
(p.field_name, p.efuse_block, p.bit_start, p.bit_count,
last.field_name, last.efuse_block, last.bit_start, last.bit_count))
last = p
def calc_md5(self):
txt_table = ''
for p in self:
txt_table += "%s %s %d %s %s" % (p.field_name, p.efuse_block, p.bit_start, str(p.get_bit_count()), p.comment) + "\n"
self.md5_digest_table = hashlib.md5(txt_table.encode('utf-8')).hexdigest()
def show_range_used_bits(self):
# print used and free bits
rows = ''
rows += 'Sorted efuse table:\n'
num = 1
rows += "{0} \t{1:<30} \t{2} \t{3} \t{4}".format("#", "field_name", "efuse_block", "bit_start", "bit_count") + "\n"
for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)):
rows += "{0} \t{1:<30} \t{2} \t{3:^8} \t{4:^8}".format(num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + "\n"
num += 1
rows += '\nUsed bits in efuse table:\n'
last = None
for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)):
if last is None:
rows += '%s \n[%d ' % (p.efuse_block, p.bit_start)
if last is not None:
if last.efuse_block != p.efuse_block:
rows += '%d] \n\n%s \n[%d ' % (last.bit_start + last.bit_count - 1, p.efuse_block, p.bit_start)
elif last.bit_start + last.bit_count != p.bit_start:
rows += '%d] [%d ' % (last.bit_start + last.bit_count - 1, p.bit_start)
last = p
rows += '%d] \n' % (last.bit_start + last.bit_count - 1)
rows += '\nNote: Not printed ranges are free for using. (bits in EFUSE_BLK0 are reserved for Espressif)\n'
return rows
def get_str_position_last_free_bit_in_blk(self, blk):
last_used_bit = 0
for p in self:
if p.efuse_block == blk:
if p.define is not None:
return p.get_bit_count()
else:
if last_used_bit < p.bit_start + p.bit_count:
last_used_bit = p.bit_start + p.bit_count
if last_used_bit == 0:
return None
return str(last_used_bit)
def to_header(self, file_name):
rows = [copyright]
rows += ["#ifdef __cplusplus",
'extern "C" {',
"#endif",
"",
"",
"// md5_digest_table " + self.md5_digest_table,
"// This file was generated from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.",
"// If you want to change some fields, you need to change " + file_name + ".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'.",
"",
""]
last_field_name = ''
for p in self:
if (p.field_name != last_field_name):
rows += ["extern const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[];"]
last_field_name = p.field_name
rows += ["",
"#ifdef __cplusplus",
"}",
"#endif",
""]
return '\n'.join(rows) + "\n"
def to_c_file(self, file_name, debug):
rows = [copyright]
rows += ['#include "sdkconfig.h"',
'#include "esp_efuse.h"',
'#include <assert.h>',
'#include "' + file_name + '.h"',
"",
"// md5_digest_table " + self.md5_digest_table,
"// This file was generated from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.",
"// If you want to change some fields, you need to change " + file_name + ".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'."]
rows += [""]
rows += ["#define MAX_BLK_LEN CONFIG_EFUSE_MAX_BLK_LEN"]
rows += [""]
last_free_bit_blk1 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK1")
last_free_bit_blk2 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK2")
last_free_bit_blk3 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK3")
rows += ["// The last free bit in the block is counted over the entire file."]
if last_free_bit_blk1 is not None:
rows += ["#define LAST_FREE_BIT_BLK1 " + last_free_bit_blk1]
if last_free_bit_blk2 is not None:
rows += ["#define LAST_FREE_BIT_BLK2 " + last_free_bit_blk2]
if last_free_bit_blk3 is not None:
rows += ["#define LAST_FREE_BIT_BLK3 " + last_free_bit_blk3]
rows += [""]
if last_free_bit_blk1 is not None:
rows += ['_Static_assert(LAST_FREE_BIT_BLK1 <= 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.");']
if last_free_bit_blk2 is not None:
rows += ['_Static_assert(LAST_FREE_BIT_BLK2 <= 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.");']
if last_free_bit_blk3 is not None:
rows += ['_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.");']
rows += [""]
last_name = ''
for p in self:
if (p.field_name != last_name):
if last_name != '':
rows += ["};\n"]
rows += ["static const esp_efuse_desc_t " + p.field_name + "[] = {"]
last_name = p.field_name
rows += [p.to_struct(debug) + ","]
rows += ["};\n"]
rows += ["\n\n\n"]
last_name = ''
for p in self:
if (p.field_name != last_name):
if last_name != '':
rows += [" NULL",
"};\n"]
rows += ["const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[] = {"]
last_name = p.field_name
index = str(0) if str(p.group) == "" else str(p.group)
rows += [" &" + p.field_name + "[" + index + "], \t\t// " + p.comment]
rows += [" NULL",
"};\n"]
return '\n'.join(rows) + "\n"
class FuseDefinition(object):
def __init__(self):
self.field_name = ""
self.group = ""
self.efuse_block = ""
self.bit_start = None
self.bit_count = None
self.define = None
self.comment = ""
@classmethod
def from_csv(cls, line):
""" Parse a line from the CSV """
line_w_defaults = line + ",,,," # lazy way to support default fields
fields = [f.strip() for f in line_w_defaults.split(",")]
res = FuseDefinition()
res.field_name = fields[0]
res.efuse_block = res.parse_block(fields[1])
res.bit_start = res.parse_num(fields[2])
res.bit_count = res.parse_bit_count(fields[3])
if res.bit_count is None or res.bit_count == 0:
raise InputError("Field bit_count can't be empty")
res.comment = fields[4]
return res
def parse_num(self, strval):
if strval == "":
return None # Field will fill in default
return self.parse_int(strval)
def parse_bit_count(self, strval):
if strval == "MAX_BLK_LEN":
self.define = strval
return self.get_max_bits_of_block()
else:
return self.parse_num(strval)
def parse_int(self, v):
try:
return int(v, 0)
except ValueError:
raise InputError("Invalid field value %s" % v)
def parse_block(self, strval):
if strval == "":
raise InputError("Field 'efuse_block' can't be left empty.")
if strval not in ["EFUSE_BLK0", "EFUSE_BLK1", "EFUSE_BLK2", "EFUSE_BLK3"]:
raise InputError("Field 'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3")
return strval
def get_max_bits_of_block(self):
'''common_table: EFUSE_BLK0, EFUSE_BLK1, EFUSE_BLK2, EFUSE_BLK3
custom_table: ----------, ----------, ----------, EFUSE_BLK3(some reserved in common_table)
'''
if self.efuse_block == "EFUSE_BLK0":
return 256
else:
return max_blk_len
def verify(self, type_table):
if self.efuse_block is None:
raise ValidationError(self, "efuse_block field is not set")
if self.bit_count is None:
raise ValidationError(self, "bit_count field is not set")
if type_table is not None:
if type_table == "custom_table":
if self.efuse_block != "EFUSE_BLK3":
raise ValidationError(self, "custom_table should use only EFUSE_BLK3")
max_bits = self.get_max_bits_of_block()
if self.bit_start + self.bit_count > max_bits:
raise ValidationError(self, "The field is outside the boundaries(max_bits = %d) of the %s block" % (max_bits, self.efuse_block))
def get_full_name(self):
def get_postfix(group):
postfix = ""
if group != "":
postfix = "_PART_" + group
return postfix
return self.field_name + get_postfix(self.group)
def get_bit_count(self, check_define=True):
if check_define is True and self.define is not None:
return self.define
else:
return self.bit_count
def to_struct(self, debug):
start = " {"
if debug is True:
start = " {" + '"' + self.field_name + '" ,'
return ", ".join([start + self.efuse_block,
str(self.bit_start),
str(self.get_bit_count()) + "}, \t // " + self.comment])
def process_input_file(file, type_table):
status("Parsing efuse CSV input file " + file.name + " ...")
input = file.read()
table = FuseTable.from_csv(input)
status("Verifying efuse table...")
table.verify(type_table)
return table
def ckeck_md5_in_file(md5, filename):
if os.path.exists(filename):
with open(filename, 'r') as f:
for line in f:
if md5 in line:
return True
return False
def create_output_files(name, output_table, debug):
file_name = os.path.splitext(os.path.basename(name))[0]
gen_dir = os.path.dirname(name)
dir_for_file_h = gen_dir + "/include"
try:
os.stat(dir_for_file_h)
except Exception:
os.mkdir(dir_for_file_h)
file_h_path = os.path.join(dir_for_file_h, file_name + ".h")
file_c_path = os.path.join(gen_dir, file_name + ".c")
# src files are the same
if ckeck_md5_in_file(output_table.md5_digest_table, file_c_path) is False:
status("Creating efuse *.h file " + file_h_path + " ...")
output = output_table.to_header(file_name)
with open(file_h_path, 'w') as f:
f.write(output)
status("Creating efuse *.c file " + file_c_path + " ...")
output = output_table.to_c_file(file_name, debug)
with open(file_c_path, 'w') as f:
f.write(output)
else:
print("Source files do not require updating correspond to csv file.")
def main():
global quiet
global max_blk_len
parser = argparse.ArgumentParser(description='ESP32 eFuse Manager')
parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true')
parser.add_argument('--debug', help='Create header file with debug info', default=False, action="store_false")
parser.add_argument('--info', help='Print info about range of used bits', default=False, action="store_true")
parser.add_argument('--max_blk_len', help='Max number of bits in BLK1, BLK2 and BLK3', type=int, default=256)
parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('r'))
parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('r'), nargs='?', default=None)
args = parser.parse_args()
max_blk_len = args.max_blk_len
print("Max number of bits in BLK %d" % (max_blk_len))
if max_blk_len not in [256, 192, 128]:
raise InputError("Unsupported block length = %d" % (max_blk_len))
quiet = args.quiet
debug = args.debug
info = args.info
common_table = process_input_file(args.common_input, "common_table")
two_table = common_table
if args.custom_input is not None:
custom_table = process_input_file(args.custom_input, "custom_table")
two_table += custom_table
two_table.verify()
# save files.
if info is False:
if args.custom_input is None:
create_output_files(args.common_input.name, common_table, debug)
else:
create_output_files(args.custom_input.name, custom_table, debug)
else:
print(two_table.show_range_used_bits())
return 0
class InputError(RuntimeError):
def __init__(self, e):
super(InputError, self).__init__(e)
class ValidationError(InputError):
def __init__(self, p, message):
super(ValidationError, self).__init__("Entry %s invalid: %s" % (p.field_name, message))
if __name__ == '__main__':
try:
main()
except InputError as e:
print(e, file=sys.stderr)
sys.exit(2)

View File

View File

@@ -0,0 +1,383 @@
// 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_table.h"
// md5_digest_table 840523b9e1313240e6102615e3a497a5
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_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_BLK1 MAX_BLK_LEN
#define LAST_FREE_BIT_BLK2 MAX_BLK_LEN
#define LAST_FREE_BIT_BLK3 192
_Static_assert(LAST_FREE_BIT_BLK1 <= 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_assert(LAST_FREE_BIT_BLK2 <= 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_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 MAC_FACTORY[] = {
{EFUSE_BLK0, 72, 8}, // Factory MAC addr [0],
{EFUSE_BLK0, 64, 8}, // Factory MAC addr [1],
{EFUSE_BLK0, 56, 8}, // Factory MAC addr [2],
{EFUSE_BLK0, 48, 8}, // Factory MAC addr [3],
{EFUSE_BLK0, 40, 8}, // Factory MAC addr [4],
{EFUSE_BLK0, 32, 8}, // Factory MAC addr [5],
};
static const esp_efuse_desc_t MAC_FACTORY_CRC[] = {
{EFUSE_BLK0, 80, 8}, // CRC8 for factory MAC address,
};
static const esp_efuse_desc_t MAC_CUSTOM_CRC[] = {
{EFUSE_BLK3, 0, 8}, // CRC8 for custom MAC address.,
};
static const esp_efuse_desc_t MAC_CUSTOM[] = {
{EFUSE_BLK3, 8, 48}, // Custom MAC,
};
static const esp_efuse_desc_t MAC_CUSTOM_VER[] = {
{EFUSE_BLK3, 184, 8}, // Custom MAC version,
};
static const esp_efuse_desc_t SECURE_BOOT_KEY[] = {
{EFUSE_BLK2, 0, MAX_BLK_LEN}, // Security boot. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128),
};
static const esp_efuse_desc_t ABS_DONE_0[] = {
{EFUSE_BLK0, 196, 1}, // Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0,
};
static const esp_efuse_desc_t ENCRYPT_FLASH_KEY[] = {
{EFUSE_BLK1, 0, MAX_BLK_LEN}, // Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128),
};
static const esp_efuse_desc_t ENCRYPT_CONFIG[] = {
{EFUSE_BLK0, 188, 4}, // Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M,
};
static const esp_efuse_desc_t DISABLE_DL_ENCRYPT[] = {
{EFUSE_BLK0, 199, 1}, // Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT.,
};
static const esp_efuse_desc_t DISABLE_DL_DECRYPT[] = {
{EFUSE_BLK0, 200, 1}, // Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT.,
};
static const esp_efuse_desc_t DISABLE_DL_CACHE[] = {
{EFUSE_BLK0, 201, 1}, // Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.,
};
static const esp_efuse_desc_t DISABLE_JTAG[] = {
{EFUSE_BLK0, 198, 1}, // Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.,
};
static const esp_efuse_desc_t CONSOLE_DEBUG_DISABLE[] = {
{EFUSE_BLK0, 194, 1}, // Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.,
};
static const esp_efuse_desc_t FLASH_CRYPT_CNT[] = {
{EFUSE_BLK0, 20, 8}, // Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT.,
};
static const esp_efuse_desc_t WR_DIS_FLASH_CRYPT_CNT[] = {
{EFUSE_BLK0, 2, 1}, // Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT,
};
static const esp_efuse_desc_t WR_DIS_BLK1[] = {
{EFUSE_BLK0, 7, 1}, // Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1,
};
static const esp_efuse_desc_t WR_DIS_BLK2[] = {
{EFUSE_BLK0, 8, 1}, // Security boot. Write protection security key. EFUSE_WR_DIS_BLK2,
};
static const esp_efuse_desc_t WR_DIS_BLK3[] = {
{EFUSE_BLK0, 9, 1}, // Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3,
};
static const esp_efuse_desc_t RD_DIS_BLK1[] = {
{EFUSE_BLK0, 16, 1}, // Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1,
};
static const esp_efuse_desc_t RD_DIS_BLK2[] = {
{EFUSE_BLK0, 17, 1}, // Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2,
};
static const esp_efuse_desc_t RD_DIS_BLK3[] = {
{EFUSE_BLK0, 18, 1}, // Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3,
};
static const esp_efuse_desc_t CHIP_VER_DIS_APP_CPU[] = {
{EFUSE_BLK0, 96, 1}, // EFUSE_RD_CHIP_VER_DIS_APP_CPU,
};
static const esp_efuse_desc_t CHIP_VER_DIS_BT[] = {
{EFUSE_BLK0, 97, 1}, // EFUSE_RD_CHIP_VER_DIS_BT,
};
static const esp_efuse_desc_t CHIP_VER_PKG[] = {
{EFUSE_BLK0, 105, 3}, // EFUSE_RD_CHIP_VER_PKG,
};
static const esp_efuse_desc_t CHIP_CPU_FREQ_LOW[] = {
{EFUSE_BLK0, 108, 1}, // EFUSE_RD_CHIP_CPU_FREQ_LOW,
};
static const esp_efuse_desc_t CHIP_CPU_FREQ_RATED[] = {
{EFUSE_BLK0, 109, 1}, // EFUSE_RD_CHIP_CPU_FREQ_RATED,
};
static const esp_efuse_desc_t CHIP_VER_REV1[] = {
{EFUSE_BLK0, 111, 1}, // EFUSE_RD_CHIP_VER_REV1,
};
static const esp_efuse_desc_t XPD_SDIO_REG[] = {
{EFUSE_BLK0, 142, 1}, // EFUSE_RD_XPD_SDIO_REG,
};
static const esp_efuse_desc_t SDIO_TIEH[] = {
{EFUSE_BLK0, 143, 1}, // EFUSE_RD_SDIO_TIEH,
};
static const esp_efuse_desc_t SDIO_FORCE[] = {
{EFUSE_BLK0, 144, 1}, // EFUSE_RD_SDIO_FORCE,
};
static const esp_efuse_desc_t ADC_VREF_AND_SDIO_DREF[] = {
{EFUSE_BLK0, 136, 6}, // EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1],
};
static const esp_efuse_desc_t ADC1_TP_LOW[] = {
{EFUSE_BLK3, 96, 7}, // TP_REG EFUSE_RD_ADC1_TP_LOW,
};
static const esp_efuse_desc_t ADC2_TP_LOW[] = {
{EFUSE_BLK3, 112, 7}, // TP_REG EFUSE_RD_ADC2_TP_LOW,
};
static const esp_efuse_desc_t ADC1_TP_HIGH[] = {
{EFUSE_BLK3, 103, 9}, // TP_REG EFUSE_RD_ADC1_TP_HIGH,
};
static const esp_efuse_desc_t ADC2_TP_HIGH[] = {
{EFUSE_BLK3, 119, 9}, // TP_REG EFUSE_RD_ADC2_TP_HIGH,
};
static const esp_efuse_desc_t SECURE_VERSION[] = {
{EFUSE_BLK3, 128, 32}, // Secure version for anti-rollback,
};
const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY[] = {
&MAC_FACTORY[0], // Factory MAC addr [0]
&MAC_FACTORY[1], // Factory MAC addr [1]
&MAC_FACTORY[2], // Factory MAC addr [2]
&MAC_FACTORY[3], // Factory MAC addr [3]
&MAC_FACTORY[4], // Factory MAC addr [4]
&MAC_FACTORY[5], // Factory MAC addr [5]
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY_CRC[] = {
&MAC_FACTORY_CRC[0], // CRC8 for factory MAC address
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_CRC[] = {
&MAC_CUSTOM_CRC[0], // CRC8 for custom MAC address.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM[] = {
&MAC_CUSTOM[0], // Custom MAC
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_VER[] = {
&MAC_CUSTOM_VER[0], // Custom MAC version
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY[] = {
&SECURE_BOOT_KEY[0], // Security boot. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128)
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ABS_DONE_0[] = {
&ABS_DONE_0[0], // Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_FLASH_KEY[] = {
&ENCRYPT_FLASH_KEY[0], // Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128)
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_CONFIG[] = {
&ENCRYPT_CONFIG[0], // Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_ENCRYPT[] = {
&DISABLE_DL_ENCRYPT[0], // Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_DECRYPT[] = {
&DISABLE_DL_DECRYPT[0], // Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_CACHE[] = {
&DISABLE_DL_CACHE[0], // Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[] = {
&DISABLE_JTAG[0], // Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[] = {
&CONSOLE_DEBUG_DISABLE[0], // Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[] = {
&FLASH_CRYPT_CNT[0], // Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT.
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT[] = {
&WR_DIS_FLASH_CRYPT_CNT[0], // Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK1[] = {
&WR_DIS_BLK1[0], // Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK2[] = {
&WR_DIS_BLK2[0], // Security boot. Write protection security key. EFUSE_WR_DIS_BLK2
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK3[] = {
&WR_DIS_BLK3[0], // Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK1[] = {
&RD_DIS_BLK1[0], // Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK2[] = {
&RD_DIS_BLK2[0], // Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK3[] = {
&RD_DIS_BLK3[0], // Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_APP_CPU[] = {
&CHIP_VER_DIS_APP_CPU[0], // EFUSE_RD_CHIP_VER_DIS_APP_CPU
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_BT[] = {
&CHIP_VER_DIS_BT[0], // EFUSE_RD_CHIP_VER_DIS_BT
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[] = {
&CHIP_VER_PKG[0], // EFUSE_RD_CHIP_VER_PKG
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[] = {
&CHIP_CPU_FREQ_LOW[0], // EFUSE_RD_CHIP_CPU_FREQ_LOW
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[] = {
&CHIP_CPU_FREQ_RATED[0], // EFUSE_RD_CHIP_CPU_FREQ_RATED
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[] = {
&CHIP_VER_REV1[0], // EFUSE_RD_CHIP_VER_REV1
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[] = {
&XPD_SDIO_REG[0], // EFUSE_RD_XPD_SDIO_REG
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[] = {
&SDIO_TIEH[0], // EFUSE_RD_SDIO_TIEH
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[] = {
&SDIO_FORCE[0], // EFUSE_RD_SDIO_FORCE
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC_VREF_AND_SDIO_DREF[] = {
&ADC_VREF_AND_SDIO_DREF[0], // EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1]
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_LOW[] = {
&ADC1_TP_LOW[0], // TP_REG EFUSE_RD_ADC1_TP_LOW
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_LOW[] = {
&ADC2_TP_LOW[0], // TP_REG EFUSE_RD_ADC2_TP_LOW
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_HIGH[] = {
&ADC1_TP_HIGH[0], // TP_REG EFUSE_RD_ADC1_TP_HIGH
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_HIGH[] = {
&ADC2_TP_HIGH[0], // TP_REG EFUSE_RD_ADC2_TP_HIGH
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_SECURE_VERSION[] = {
&SECURE_VERSION[0], // Secure version for anti-rollback
NULL
};

View File

@@ -0,0 +1,85 @@
# 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.
# !!!!!!!!!!! #
# Factory MAC address #
#######################
MAC_FACTORY, EFUSE_BLK0, 72, 8, Factory MAC addr [0]
, EFUSE_BLK0, 64, 8, Factory MAC addr [1]
, EFUSE_BLK0, 56, 8, Factory MAC addr [2]
, EFUSE_BLK0, 48, 8, Factory MAC addr [3]
, EFUSE_BLK0, 40, 8, Factory MAC addr [4]
, EFUSE_BLK0, 32, 8, Factory MAC addr [5]
MAC_FACTORY_CRC, EFUSE_BLK0, 80, 8, CRC8 for factory MAC address
# Custom MAC address #
######################
MAC_CUSTOM_CRC, EFUSE_BLK3, 0, 8, CRC8 for custom MAC address.
MAC_CUSTOM, EFUSE_BLK3, 8, 48, Custom MAC
MAC_CUSTOM_VER, EFUSE_BLK3, 184, 8, Custom MAC version
# Security boot #
#################
SECURE_BOOT_KEY, EFUSE_BLK2, 0, MAX_BLK_LEN, Security boot. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128)
ABS_DONE_0, EFUSE_BLK0, 196, 1, Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0
# Flash encrypt #
#################
ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, MAX_BLK_LEN, Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128)
ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M
DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT.
DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT.
DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.
DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.
CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
FLASH_CRYPT_CNT, EFUSE_BLK0, 20, 8, Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT.
# Write protection #
####################
WR_DIS_FLASH_CRYPT_CNT, EFUSE_BLK0, 2, 1, Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT
WR_DIS_BLK1, EFUSE_BLK0, 7, 1, Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1
WR_DIS_BLK2, EFUSE_BLK0, 8, 1, Security boot. Write protection security key. EFUSE_WR_DIS_BLK2
WR_DIS_BLK3, EFUSE_BLK0, 9, 1, Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3
# Read protection #
###################
RD_DIS_BLK1, EFUSE_BLK0, 16, 1, Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1
RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2
RD_DIS_BLK3, EFUSE_BLK0, 18, 1, Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3
# Chip info #
#############
CHIP_VER_DIS_APP_CPU, EFUSE_BLK0, 96, 1, EFUSE_RD_CHIP_VER_DIS_APP_CPU
CHIP_VER_DIS_BT, EFUSE_BLK0, 97, 1, EFUSE_RD_CHIP_VER_DIS_BT
CHIP_VER_PKG, EFUSE_BLK0, 105, 3, EFUSE_RD_CHIP_VER_PKG
CHIP_CPU_FREQ_LOW, EFUSE_BLK0, 108, 1, EFUSE_RD_CHIP_CPU_FREQ_LOW
CHIP_CPU_FREQ_RATED, EFUSE_BLK0, 109, 1, EFUSE_RD_CHIP_CPU_FREQ_RATED
CHIP_VER_REV1, EFUSE_BLK0, 111, 1, EFUSE_RD_CHIP_VER_REV1
XPD_SDIO_REG, EFUSE_BLK0, 142, 1, EFUSE_RD_XPD_SDIO_REG
SDIO_TIEH, EFUSE_BLK0, 143, 1, EFUSE_RD_SDIO_TIEH
SDIO_FORCE, EFUSE_BLK0, 144, 1, EFUSE_RD_SDIO_FORCE
#SDIO_DREFH, EFUSE_BLK0, 136, 2, EFUSE_RD_SDIO_DREFH
#SDIO_DREFM, EFUSE_BLK0, 138, 2, EFUSE_RD_SDIO_DREFM
#SDIO_DREFL, EFUSE_BLK0, 140, 2, EFUSE_RD_SDIO_DREFL
# esp_adc_cal #
###############
ADC_VREF_AND_SDIO_DREF, EFUSE_BLK0, 136, 6, EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1], SDIO_DREFM[2 3], SDIO_DREFL[4 5] )
ADC1_TP_LOW, EFUSE_BLK3, 96, 7, TP_REG EFUSE_RD_ADC1_TP_LOW
ADC2_TP_LOW, EFUSE_BLK3, 112, 7, TP_REG EFUSE_RD_ADC2_TP_LOW
ADC1_TP_HIGH, EFUSE_BLK3, 103, 9, TP_REG EFUSE_RD_ADC1_TP_HIGH
ADC2_TP_HIGH, EFUSE_BLK3, 119, 9, TP_REG EFUSE_RD_ADC2_TP_HIGH
# anti-rollback #
#################
SECURE_VERSION, EFUSE_BLK3, 128, 32, Secure version for anti-rollback
Can't render this file because it contains an unexpected character in line 7 and column 87.

View File

@@ -0,0 +1,68 @@
// 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 840523b9e1313240e6102615e3a497a5
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_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_MAC_FACTORY[];
extern const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY_CRC[];
extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_CRC[];
extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM[];
extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_VER[];
extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY[];
extern const esp_efuse_desc_t* ESP_EFUSE_ABS_DONE_0[];
extern const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_FLASH_KEY[];
extern const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_CONFIG[];
extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_ENCRYPT[];
extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_DECRYPT[];
extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_CACHE[];
extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[];
extern const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[];
extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK1[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK2[];
extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK3[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK1[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK2[];
extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK3[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_APP_CPU[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_BT[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[];
extern const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[];
extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[];
extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC_VREF_AND_SDIO_DREF[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_LOW[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_LOW[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_HIGH[];
extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_HIGH[];
extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_VERSION[];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1 @@
set(EFUSE_SOC_SRCS "esp_efuse_table.c")

View File

@@ -0,0 +1,362 @@
// 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.
#ifndef _ESP_EFUSE_MANAGER_H_
#define _ESP_EFUSE_MANAGER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "esp_err.h"
#include "esp_log.h"
#define ESP_ERR_EFUSE 0x1600 /*!< Base error code for efuse api. */
#define ESP_OK_EFUSE_CNT (ESP_ERR_EFUSE + 0x01) /*!< OK the required number of bits is set. */
#define ESP_ERR_EFUSE_CNT_IS_FULL (ESP_ERR_EFUSE + 0x02) /*!< Error field is full. */
#define ESP_ERR_EFUSE_REPEATED_PROG (ESP_ERR_EFUSE + 0x03) /*!< Error repeated programming of programmed bits is strictly forbidden. */
#define ESP_ERR_CODING (ESP_ERR_EFUSE + 0x04) /*!< Error while a encoding operation. */
/**
* @brief Type of eFuse blocks
*/
typedef enum {
EFUSE_BLK0 = 0, /**< Number of eFuse block. Reserved. */
EFUSE_BLK1 = 1, /**< Number of eFuse block. Used for Flash Encryption. If not using that Flash Encryption feature, they can be used for another purpose. */
EFUSE_BLK2 = 2, /**< Number of eFuse block. Used for Secure Boot. If not using that Secure Boot feature, they can be used for another purpose. */
EFUSE_BLK3 = 3 /**< Number of eFuse block. Uses for the purpose of the user. */
} esp_efuse_block_t;
/**
* @brief Type of coding scheme
*/
typedef enum {
EFUSE_CODING_SCHEME_NONE = 0, /**< None */
EFUSE_CODING_SCHEME_3_4 = 1, /**< 3/4 coding */
EFUSE_CODING_SCHEME_REPEAT = 2, /**< Repeat coding */
} esp_efuse_coding_scheme_t;
/**
* @brief Structure eFuse field
*/
typedef struct {
esp_efuse_block_t efuse_block: 8; /**< Block of eFuse */
uint8_t bit_start; /**< Start bit [0..255] */
uint16_t bit_count; /**< Length of bit field [1..-]*/
} esp_efuse_desc_t;
/**
* @brief Reads bits from EFUSE field and writes it into an array.
*
* The number of read bits will be limited to the minimum value
* from the description of the bits in "field" structure or "dst_size_bits" required size.
* Use "esp_efuse_get_field_size()" function to determine the length of the field.
* @param[in] field A pointer to the structure describing the fields of efuse.
* @param[out] dst A pointer to array that will contain the result of reading.
* @param[in] dst_size_bits The number of bits required to read.
* If the requested number of bits is greater than the field,
* the number will be limited to the field size.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_INVALID_ARG: Error in the passed arguments.
*/
esp_err_t esp_efuse_read_field_blob(const esp_efuse_desc_t* field[], void* dst, size_t dst_size_bits);
/**
* @brief Reads bits from EFUSE field and returns number of bits programmed as "1".
*
* If the bits are set not sequentially, they will still be counted.
* @param[in] field A pointer to the structure describing the fields of efuse.
* @param[out] out_cnt A pointer that will contain the number of programmed as "1" bits.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_INVALID_ARG: Error in the passed arguments.
*/
esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_cnt);
/**
* @brief Writes array to EFUSE field.
*
* The number of write bits will be limited to the minimum value
* from the description of the bits in "field" structure or "src_size_bits" required size.
* Use "esp_efuse_get_field_size()" function to determine the length of the field.
* After the function is completed, the writing registers are cleared.
* @param[in] field A pointer to the structure describing the fields of efuse.
* @param[in] src A pointer to array that contains the data for writing.
* @param[in] src_size_bits The number of bits required to write.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_INVALID_ARG: Error in the passed arguments.
* - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits is strictly forbidden.
* - ESP_ERR_CODING: Error range of data does not match the coding scheme.
*/
esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits);
/**
* @brief Writes a required count of bits as "1" to EFUSE field.
*
* If there are no free bits in the field to set the required number of bits to "1",
* ESP_ERR_EFUSE_CNT_IS_FULL error is returned, the field will not be partially recorded.
* After the function is completed, the writing registers are cleared.
* @param[in] field A pointer to the structure describing the fields of efuse.
* @param[in] cnt Required number of programmed as "1" bits.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_INVALID_ARG: Error in the passed arguments.
* - ESP_ERR_EFUSE_CNT_IS_FULL: Not all requested cnt bits is set.
*/
esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt);
/**
* @brief Sets a write protection for the whole block.
*
* After that, it is impossible to write to this block.
* The write protection does not apply to block 0.
* @param[in] blk Block number of eFuse. (EFUSE_BLK1, EFUSE_BLK2 and EFUSE_BLK3)
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_INVALID_ARG: Error in the passed arguments.
* - ESP_ERR_EFUSE_CNT_IS_FULL: Not all requested cnt bits is set.
* - ESP_ERR_NOT_SUPPORTED: The block does not support this command.
*/
esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk);
/**
* @brief Sets a read protection for the whole block.
*
* After that, it is impossible to read from this block.
* The read protection does not apply to block 0.
* @param[in] blk Block number of eFuse. (EFUSE_BLK1, EFUSE_BLK2 and EFUSE_BLK3)
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_INVALID_ARG: Error in the passed arguments.
* - ESP_ERR_EFUSE_CNT_IS_FULL: Not all requested cnt bits is set.
* - ESP_ERR_NOT_SUPPORTED: The block does not support this command.
*/
esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk);
/**
* @brief Returns the number of bits used by field.
*
* @param[in] field A pointer to the structure describing the fields of efuse.
*
* @return Returns the number of bits used by field.
*/
int esp_efuse_get_field_size(const esp_efuse_desc_t* field[]);
/**
* @brief Returns value of efuse register.
*
* This is a thread-safe implementation.
* Example: EFUSE_BLK2_RDATA3_REG where (blk=2, num_reg=3)
* @param[in] blk Block number of eFuse.
* @param[in] num_reg The register number in the block.
*
* @return Value of register
*/
uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg);
/**
* @brief Write value to efuse register.
*
* Apply a coding scheme if necessary.
* This is a thread-safe implementation.
* Example: EFUSE_BLK3_WDATA0_REG where (blk=3, num_reg=0)
* @param[in] blk Block number of eFuse.
* @param[in] num_reg The register number in the block.
* @param[in] val Value to write.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits is strictly forbidden.
*/
esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val);
/**
* @brief Return efuse coding scheme for blocks.
*
* Note: The coding scheme is applicable only to 1, 2 and 3 blocks. For 0 block, the coding scheme is always ``NONE``.
*
* @param[in] blk Block number of eFuse.
* @return Return efuse coding scheme for blocks
*/
esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk);
/**
* @brief Read key to efuse block starting at the offset and the required size.
*
* @param[in] blk Block number of eFuse.
* @param[in] dst_key A pointer to array that will contain the result of reading.
* @param[in] offset_in_bits Start bit in block.
* @param[in] size_bits The number of bits required to read.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_INVALID_ARG: Error in the passed arguments.
* - ESP_ERR_CODING: Error range of data does not match the coding scheme.
*/
esp_err_t esp_efuse_read_block(esp_efuse_block_t blk, void* dst_key, size_t offset_in_bits, size_t size_bits);
/**
* @brief Write key to efuse block starting at the offset and the required size.
*
* @param[in] blk Block number of eFuse.
* @param[in] src_key A pointer to array that contains the key for writing.
* @param[in] offset_in_bits Start bit in block.
* @param[in] size_bits The number of bits required to write.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_INVALID_ARG: Error in the passed arguments.
* - ESP_ERR_CODING: Error range of data does not match the coding scheme.
* - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits
*/
esp_err_t esp_efuse_write_block(esp_efuse_block_t blk, const void* src_key, size_t offset_in_bits, size_t size_bits);
/**
* @brief Returns chip version from efuse
*
* @return chip version
*/
uint8_t esp_efuse_get_chip_ver(void);
/**
* @brief Returns chip package from efuse
*
* @return chip package
*/
uint32_t esp_efuse_get_pkg_ver(void);
/* @brief Permanently update values written to the efuse write registers
*
* After updating EFUSE_BLKx_WDATAx_REG registers with new values to
* write, call this function to permanently write them to efuse.
*
* @note Setting bits in efuse is permanent, they cannot be unset.
*
* @note Due to this restriction you don't need to copy values to
* Efuse write registers from the matching read registers, bits which
* are set in the read register but unset in the matching write
* register will be unchanged when new values are burned.
*
* @note This function is not threadsafe, if calling code updates
* efuse values from multiple tasks then this is caller's
* responsibility to serialise.
*
* After burning new efuses, the read registers are updated to match
* the new efuse values.
*/
void esp_efuse_burn_new_values(void);
/* @brief Reset efuse write registers
*
* Efuse write registers are written to zero, to negate
* any changes that have been staged here.
*
* @note This function is not threadsafe, if calling code updates
* efuse values from multiple tasks then this is caller's
* responsibility to serialise.
*/
void esp_efuse_reset(void);
/* @brief Disable BASIC ROM Console via efuse
*
* By default, if booting from flash fails the ESP32 will boot a
* BASIC console in ROM.
*
* Call this function (from bootloader or app) to permanently
* disable the console on this chip.
*/
void esp_efuse_disable_basic_rom_console(void);
/* @brief Encode one or more sets of 6 byte sequences into
* 8 bytes suitable for 3/4 Coding Scheme.
*
* This function is only useful if the CODING_SCHEME efuse
* is set to value 1 for 3/4 Coding Scheme.
*
* @param[in] in_bytes Pointer to a sequence of bytes to encode for 3/4 Coding Scheme. Must have length in_bytes_len. After being written to hardware, these bytes will read back as little-endian words.
* @param[out] out_words Pointer to array of words suitable for writing to efuse write registers. Array must contain 2 words (8 bytes) for every 6 bytes in in_bytes_len. Can be a pointer to efuse write registers.
* @param in_bytes_len. Length of array pointed to by in_bytes, in bytes. Must be a multiple of 6.
*
* @return ESP_ERR_INVALID_ARG if either pointer is null or in_bytes_len is not a multiple of 6. ESP_OK otherwise.
*/
esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len);
/* @brief Write random data to efuse key block write registers
*
* @note Caller is responsible for ensuring efuse
* block is empty and not write protected, before calling.
*
* @note Behaviour depends on coding scheme: a 256-bit key is
* generated and written for Coding Scheme "None", a 192-bit key
* is generated, extended to 256-bits by the Coding Scheme,
* and then writtten for 3/4 Coding Scheme.
*
* @note This function does not burn the new values, caller should
* call esp_efuse_burn_new_values() when ready to do this.
*
* @param blk_wdata0_reg Address of the first data write register
* in the block
*/
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg);
/* @brief Return secure_version from efuse field.
* @return Secure version from efuse field
*/
uint32_t esp_efuse_read_secure_version();
/* @brief Check secure_version from app and secure_version and from efuse field.
*
* @param secure_version Secure version from app.
* @return
* - True: If version of app is equal or more then secure_version from efuse.
*/
bool esp_efuse_check_secure_version(uint32_t secure_version);
/* @brief Write efuse field by secure_version value.
*
* Update the secure_version value is available if the coding scheme is None.
* Note: Do not use this function in your applications. This function is called as part of the other API.
*
* @param[in] secure_version Secure version from app.
* @return
* - ESP_OK: Successful.
* - ESP_FAIL: secure version of app cannot be set to efuse field.
* - ESP_ERR_NOT_SUPPORTED: Anti rollback is not supported with the 3/4 and Repeat coding scheme.
*/
esp_err_t esp_efuse_update_secure_version(uint32_t secure_version);
/* @brief Initializes variables: offset and size to simulate the work of an eFuse.
*
* Note: To simulate the work of an eFuse need to set CONFIG_EFUSE_SECURE_VERSION_EMULATE option
* and to add in the partition.csv file a line `efuse_em, data, efuse, , 0x2000,`.
*
* @param[in] offset The starting address of the partition where the eFuse data will be located.
* @param[in] size The size of the partition.
*/
void esp_efuse_init(uint32_t offset, uint32_t size);
#ifdef __cplusplus
}
#endif
#endif // _ESP_EFUSE_MANAGER_H_

View File

@@ -0,0 +1,242 @@
// 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 "esp_efuse.h"
#include "esp_efuse_utility.h"
#include "soc/efuse_reg.h"
#include "assert.h"
#include "sdkconfig.h"
#include "esp_efuse_table.h"
const static char *TAG = "efuse";
#if defined(BOOTLOADER_BUILD)
#define EFUSE_LOCK_ACQUIRE()
#define EFUSE_LOCK_RELEASE()
#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)
#endif
// Public API functions
// read value from EFUSE, writing it into an array
esp_err_t esp_efuse_read_field_blob(const esp_efuse_desc_t* field[], void* dst, size_t dst_size_bits)
{
EFUSE_LOCK_ACQUIRE();
esp_err_t err = ESP_OK;
if (field == NULL || dst == NULL || dst_size_bits == 0) {
err = ESP_ERR_INVALID_ARG;
} else {
memset((uint8_t *)dst, 0, esp_efuse_utility_get_number_of_items(dst_size_bits, 8));
err = esp_efuse_utility_process(field, dst, dst_size_bits, esp_efuse_utility_fill_buff);
}
EFUSE_LOCK_RELEASE();
return err;
}
// read number of bits programmed as "1" in the particular field
esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_cnt)
{
EFUSE_LOCK_ACQUIRE();
esp_err_t err = ESP_OK;
if (field == NULL || out_cnt == NULL) {
err = ESP_ERR_INVALID_ARG;
} else {
*out_cnt = 0;
err = esp_efuse_utility_process(field, out_cnt, 0, esp_efuse_utility_count_once);
}
EFUSE_LOCK_RELEASE();
return err;
}
// 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();
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();
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 (err == ESP_OK) {
esp_efuse_utility_burn_efuses();
}
}
esp_efuse_utility_reset();
}
EFUSE_LOCK_RELEASE();
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();
esp_err_t err = ESP_OK;
if (field == NULL || cnt == 0) {
err = ESP_ERR_INVALID_ARG;
} else {
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();
}
}
esp_efuse_utility_reset();
}
EFUSE_LOCK_RELEASE();
return err;
}
// Sets a write protection for the whole block.
esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK1) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK1, 1);
} else if (blk == EFUSE_BLK2) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK2, 1);
} else if (blk == EFUSE_BLK3) {
return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK3, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// read protect for blk.
esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk)
{
if (blk == EFUSE_BLK1) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK1, 1);
} else if (blk == EFUSE_BLK2) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK2, 1);
} else if (blk == EFUSE_BLK3) {
return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK3, 1);
}
return ESP_ERR_NOT_SUPPORTED;
}
// get the length of the field in bits
int esp_efuse_get_field_size(const esp_efuse_desc_t* field[])
{
int bits_counter = 0;
if (field != NULL) {
int i = 0;
while (field[i] != NULL) {
bits_counter += field[i]->bit_count;
++i;
}
}
return bits_counter;
}
// reading efuse register.
uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg)
{
EFUSE_LOCK_ACQUIRE();
uint32_t ret_val = esp_efuse_utility_read_reg(blk, num_reg);
EFUSE_LOCK_RELEASE();
return ret_val;
}
// 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();
}
}
esp_efuse_utility_reset();
EFUSE_LOCK_RELEASE();
return err;
}
// get efuse coding_scheme.
esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk)
{
esp_efuse_coding_scheme_t scheme;
if (blk == EFUSE_BLK0) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else {
uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME);
if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE ||
coding_scheme == (EFUSE_CODING_SCHEME_VAL_34 | EFUSE_CODING_SCHEME_VAL_REPEAT)) {
scheme = EFUSE_CODING_SCHEME_NONE;
} else if (coding_scheme == EFUSE_CODING_SCHEME_VAL_34) {
scheme = EFUSE_CODING_SCHEME_3_4;
} else {
scheme = EFUSE_CODING_SCHEME_REPEAT;
}
}
ESP_LOGD(TAG, "coding scheme %d", scheme);
return scheme;
}
// This function reads the key from the efuse block, starting at the offset and the required size.
esp_err_t esp_efuse_read_block(esp_efuse_block_t blk, void* dst_key, size_t offset_in_bits, size_t size_bits)
{
esp_err_t err = ESP_OK;
if (blk == EFUSE_BLK0 || blk > EFUSE_BLK3 || dst_key == NULL || size_bits == 0) {
err = ESP_ERR_INVALID_ARG;
} else {
const esp_efuse_desc_t field_desc[] = {
{blk, offset_in_bits, size_bits},
};
const esp_efuse_desc_t* field[] = {
&field_desc[0],
NULL
};
err = esp_efuse_read_field_blob(field, dst_key, size_bits);
}
return err;
}
// This function writes the key from the efuse block, starting at the offset and the required size.
esp_err_t esp_efuse_write_block(esp_efuse_block_t blk, const void* src_key, size_t offset_in_bits, size_t size_bits)
{
esp_err_t err = ESP_OK;
if (blk == EFUSE_BLK0 || blk > EFUSE_BLK3 || src_key == NULL || size_bits == 0) {
err = ESP_ERR_INVALID_ARG;
} else {
const esp_efuse_desc_t field_desc[] = {
{blk, offset_in_bits, size_bits},
};
const esp_efuse_desc_t* field[] = {
&field_desc[0],
NULL
};
err = esp_efuse_write_field_blob(field, src_key, size_bits);
}
return err;
}

View File

@@ -1,4 +1,4 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// 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.
@@ -11,53 +11,56 @@
// 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 "esp_efuse.h"
#include "esp_efuse_utility.h"
#include "esp_efuse_table.h"
#include "stdlib.h"
#include "esp_types.h"
#include "rom/efuse.h"
#include "assert.h"
#include "esp_err.h"
#include "esp_log.h"
#include <string.h>
#include "soc/efuse_reg.h"
#include "bootloader_random.h"
#define EFUSE_CONF_WRITE 0x5A5A /* efuse_pgm_op_ena, force no rd/wr disable */
#define EFUSE_CONF_READ 0x5AA5 /* efuse_read_op_ena, release force */
const static char *TAG = "efuse";
#define EFUSE_CMD_PGM 0x02
#define EFUSE_CMD_READ 0x01
// Contains functions that provide access to efuse fields which are often used in IDF.
static const char *TAG = "efuse";
// Returns chip version from efuse
uint8_t esp_efuse_get_chip_ver(void)
{
uint8_t chip_ver;
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &chip_ver, 1);
return chip_ver;
}
// Returns chip package from efuse
uint32_t esp_efuse_get_pkg_ver(void)
{
uint32_t pkg_ver;
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_PKG, &pkg_ver, 3);
return pkg_ver;
}
// Permanently update values written to the efuse write registers
void esp_efuse_burn_new_values(void)
{
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE);
REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM);
while (REG_READ(EFUSE_CMD_REG) != 0) {
}
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ);
REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_READ);
while (REG_READ(EFUSE_CMD_REG) != 0) {
}
esp_efuse_reset();
esp_efuse_utility_burn_efuses();
}
// Reset efuse write registers
void esp_efuse_reset(void)
{
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ);
const uint32_t block_start[4] = { EFUSE_BLK0_WDATA0_REG, EFUSE_BLK1_WDATA0_REG,
EFUSE_BLK2_WDATA0_REG, EFUSE_BLK3_WDATA0_REG };
const uint32_t block_end[4] = { EFUSE_BLK0_WDATA6_REG, EFUSE_BLK1_WDATA7_REG,
EFUSE_BLK2_WDATA7_REG, EFUSE_BLK3_WDATA7_REG };
for (int i = 0; i < 4; i++) {
for (uint32_t r = block_start[i]; r <= block_end[i]; r+= 4) {
REG_WRITE(r, 0);
}
}
esp_efuse_utility_reset();
}
// Disable BASIC ROM Console via efuse
void esp_efuse_disable_basic_rom_console(void)
{
if ((REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_CONSOLE_DEBUG_DISABLE) == 0) {
if (esp_efuse_write_field_cnt(ESP_EFUSE_CONSOLE_DEBUG_DISABLE, 1) == ESP_OK) {
ESP_EARLY_LOGI(TAG, "Disable BASIC ROM Console fallback via efuse...");
esp_efuse_reset();
REG_WRITE(EFUSE_BLK0_WDATA6_REG, EFUSE_RD_CONSOLE_DEBUG_DISABLE);
esp_efuse_burn_new_values();
}
}
@@ -113,10 +116,9 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
bzero(raw, sizeof(raw));
}
#ifdef CONFIG_EFUSE_SECURE_VERSION_EMULATE
#include "bootloader_flash.h"
#include "../include_bootloader/bootloader_flash.h"
#include "esp_flash_encrypt.h"
static uint32_t esp_efuse_flash_offset = 0;

View File

@@ -0,0 +1,512 @@
// 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 "esp_efuse_utility.h"
#include "soc/efuse_reg.h"
#include "esp_log.h"
#include "assert.h"
#include "sdkconfig.h"
#include <sys/param.h>
static const char *TAG = "efuse";
#define COUNT_EFUSE_BLOCKS 4 /* The number of blocks. */
#define COUNT_EFUSE_REG_PER_BLOCK 8 /* The number of registers per block. */
#define EFUSE_CONF_WRITE 0x5A5A /* eFuse_pgm_op_ena, force no rd/wr disable. */
#define EFUSE_CONF_READ 0x5AA5 /* eFuse_read_op_ena, release force. */
#define EFUSE_CMD_PGM 0x02 /* Command to program. */
#define EFUSE_CMD_READ 0x01 /* Command to read. */
// Array for emulate efuse registers.
#ifdef CONFIG_EFUSE_VIRTUAL
static uint32_t virt_blocks[COUNT_EFUSE_BLOCKS][COUNT_EFUSE_REG_PER_BLOCK];
#endif
/**
* @brief Structure range address by blocks
*/
typedef struct {
uint32_t start;
uint32_t end;
} esp_efuse_range_addr_t;
/*Range addresses to read blocks*/
static const esp_efuse_range_addr_t range_read_addr_blocks[] = {
{EFUSE_BLK0_RDATA0_REG, EFUSE_BLK0_RDATA6_REG}, // range address of EFUSE_BLK0
{EFUSE_BLK1_RDATA0_REG, EFUSE_BLK1_RDATA7_REG}, // range address of EFUSE_BLK1
{EFUSE_BLK2_RDATA0_REG, EFUSE_BLK2_RDATA7_REG}, // range address of EFUSE_BLK2
{EFUSE_BLK3_RDATA0_REG, EFUSE_BLK3_RDATA7_REG} // range address of EFUSE_BLK3
};
/*Range addresses to write blocks*/
static const esp_efuse_range_addr_t range_write_addr_blocks[] = {
{EFUSE_BLK0_WDATA0_REG, EFUSE_BLK0_WDATA6_REG}, // range address of EFUSE_BLK0
{EFUSE_BLK1_WDATA0_REG, EFUSE_BLK1_WDATA7_REG}, // range address of EFUSE_BLK1
{EFUSE_BLK2_WDATA0_REG, EFUSE_BLK2_WDATA7_REG}, // range address of EFUSE_BLK2
{EFUSE_BLK3_WDATA0_REG, EFUSE_BLK3_WDATA7_REG} // range address of EFUSE_BLK3
};
static int get_reg_num(int bit_start, int bit_count, int i_reg);
static int get_starting_bit_num_in_reg(int bit_start, int i_reg);
static uint32_t get_mask(unsigned int bit_count, unsigned int shift);
static int get_count_bits_in_reg(int bit_start, int bit_count, int i_reg);
static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value);
static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob);
static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt);
static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits);
// This function processes the field by calling the passed function.
esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, size_t ptr_size_bits, efuse_func_proc_t func_proc)
{
esp_err_t err = ESP_OK;
int bits_counter = 0;
// get and check size.
int field_len = esp_efuse_get_field_size(field);
int req_size = (ptr_size_bits == 0) ? field_len : MIN(ptr_size_bits, field_len);
int i = 0;
while (err == ESP_OK && req_size > bits_counter && field[i] != NULL) {
if (check_range_of_bits(field[i]->efuse_block, field[i]->bit_start, field[i]->bit_count) == false) {
ESP_LOGE(TAG, "Range of data does not match the coding scheme");
err = ESP_ERR_CODING;
}
int i_reg = 0;
int num_reg;
while (err == ESP_OK && req_size > bits_counter &&
(num_reg = get_reg_num(field[i]->bit_start, field[i]->bit_count, i_reg)) != -1) {
int start_bit = get_starting_bit_num_in_reg(field[i]->bit_start, i_reg);
int num_bits = get_count_bits_in_reg(field[i]->bit_start, field[i]->bit_count, i_reg);
if ((bits_counter + num_bits) > req_size) { // Limits the length of the field.
num_bits = req_size - bits_counter;
}
ESP_LOGD(TAG, "In EFUSE_BLK%d__DATA%d_REG is used %d bits starting with %d bit",
(int)field[i]->efuse_block, num_reg, num_bits, start_bit);
err = func_proc(num_reg, field[i]->efuse_block, start_bit, num_bits, ptr, &bits_counter);
++i_reg;
}
i++;
}
assert(bits_counter <= req_size);
return err;
}
// Read efuse register and write this value to array.
esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_out, int* bits_counter)
{
uint8_t* blob = (uint8_t *) arr_out;
uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
uint64_t reg_of_aligned_bits = (reg >> bit_start) & get_mask(bit_count, 0);
int shift_bit = (*bits_counter) % 8;
if (shift_bit != 0) {
blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits << shift_bit);
shift_bit = ((8 - shift_bit) < bit_count) ? (8 - shift_bit) : bit_count;
(*bits_counter) += shift_bit;
bit_count -= shift_bit;
}
int sum_shift = 0;
while (bit_count > 0) {
sum_shift += shift_bit;
blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits >> sum_shift);
shift_bit = (bit_count > 8) ? 8 : bit_count;
(*bits_counter) += shift_bit;
bit_count -= shift_bit;
};
return ESP_OK;
}
// Count a set bits.
esp_err_t esp_efuse_utility_count_once(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* out_cnt, int* bits_counter)
{
uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
*((size_t *)out_cnt) += __builtin_popcount(reg & get_mask(bit_count, bit_start)); // Returns the number of 1-bits in reg.
*bits_counter += bit_count;
return ESP_OK;
}
// Fill registers from array for writing.
esp_err_t esp_efuse_utility_write_blob(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_in, int* bits_counter)
{
uint32_t reg_to_write = fill_reg(bit_start, bit_count, (uint8_t *)arr_in, bits_counter);
return esp_efuse_utility_write_reg(efuse_block, num_reg, reg_to_write);
}
// fill registers with the required number of bits for writing.
esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* cnt, int* bits_counter)
{
esp_err_t err = ESP_OK;
uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
size_t* set_bits = (size_t*)cnt;
uint32_t mask = get_mask(bit_count, bit_start);
uint32_t reg_masked_bits = reg & mask;
if ((reg_masked_bits ^ mask) != 0) {// register has free bits to set them to 1?
uint32_t reg_to_write = set_cnt_in_reg(bit_start, bit_count, reg_masked_bits, set_bits);
write_reg(efuse_block, num_reg, reg_to_write);
}
*bits_counter += bit_count;
if ((*set_bits) == 0) {
err = ESP_OK_EFUSE_CNT;
}
return err;
}
// Reset efuse write registers
void esp_efuse_utility_reset(void)
{
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ);
for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) {
REG_WRITE(addr_wr_block, 0);
}
}
}
// Burn values written to the efuse write registers
void esp_efuse_utility_burn_efuses(void)
{
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGE(TAG, "Not really burning any efuses!");
for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block);
if (scheme == EFUSE_CODING_SCHEME_3_4) {
uint8_t buf[COUNT_EFUSE_REG_PER_BLOCK * 4] = { 0 };
int i = 0;
for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4, ++i) {
*((uint32_t*)buf + i) = REG_READ(addr_wr_block);
}
int j = 0;
uint32_t out_buf[COUNT_EFUSE_REG_PER_BLOCK] = { 0 };
for (int k = 0; k < 4; ++k, ++j) {
memcpy((uint8_t*)out_buf + j * 6, &buf[k * 8], 6);
}
for (int k = 0; k < COUNT_EFUSE_REG_PER_BLOCK; ++k) {
REG_WRITE(range_write_addr_blocks[num_block].start + k * 4, out_buf[k]);
}
}
int subblock = 0;
for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) {
virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block);
}
}
#else
// Permanently update values written to the efuse write registers
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE);
REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM);
while (REG_READ(EFUSE_CMD_REG) != 0) {};
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ);
REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_READ);
while (REG_READ(EFUSE_CMD_REG) != 0) {};
#endif
esp_efuse_utility_reset();
}
// Erase the virt_blocks array.
void esp_efuse_utility_erase_virt_blocks()
{
#ifdef CONFIG_EFUSE_VIRTUAL
memset(virt_blocks, 0, sizeof(virt_blocks));
#endif
}
// Fills the virt_blocks array by values from efuse_Rdata.
void esp_efuse_utility_update_virt_blocks()
{
#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGI(TAG, "Emulate efuse is enabled");
for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
int subblock = 0;
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) {
virt_blocks[num_block][subblock++] = REG_READ(addr_rd_block);
}
ESP_LOGD(TAG, "virt_blocks[%d] is filled by EFUSE_BLOCK%d", num_block, num_block);
}
#else
ESP_LOGI(TAG, "Emulate efuse is disabled");
#endif
}
// Prints efuse values for all registers.
void esp_efuse_utility_debug_dump_blocks()
{
printf("EFUSE_BLKx:\n");
#ifdef CONFIG_EFUSE_VIRTUAL
for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
int num_reg = 0;
printf("%d) ", num_block);
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, num_reg++) {
printf("0x%08x ", virt_blocks[num_block][num_reg]);
}
printf("\n");
}
#else
for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
printf("%d) ", num_block);
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) {
printf("0x%08x ", REG_READ(addr_rd_block));
}
printf("\n");
}
#endif
printf("\n");
}
// returns the number of array elements for placing these bits in an array with the length of each element equal to size_of_base.
int esp_efuse_utility_get_number_of_items(int bits, int size_of_base)
{
return bits / size_of_base + (bits % size_of_base > 0 ? 1 : 0);
}
// Writing efuse register with checking of repeated programming of programmed bits.
esp_err_t esp_efuse_utility_write_reg(esp_efuse_block_t efuse_block, unsigned int num_reg, uint32_t reg_to_write)
{
esp_err_t err = ESP_OK;
uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
if (reg & reg_to_write) {
ESP_LOGE(TAG, "Repeated programming of programmed bits is strictly forbidden 0x%08x", reg & reg_to_write);
err = ESP_ERR_EFUSE_REPEATED_PROG;
} else {
write_reg(efuse_block, num_reg, reg_to_write);
}
return err;
}
// Reading efuse register.
uint32_t esp_efuse_utility_read_reg(esp_efuse_block_t blk, unsigned int num_reg)
{
assert(blk >= 0 && blk <= 3);
if (blk == 0) {
assert(num_reg <= 6);
} else {
assert(num_reg <= 7);
}
uint32_t value;
#ifdef CONFIG_EFUSE_VIRTUAL
value = virt_blocks[blk][num_reg];
#else
value = REG_READ(range_read_addr_blocks[blk].start + num_reg * 4);
#endif
return value;
}
// Private functions
// writing efuse register.
static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value)
{
assert(blk >= 0 && blk <= 3);
if (blk == 0) {
assert(num_reg <= 6);
} else {
assert(num_reg <= 7);
}
uint32_t addr_wr_reg = range_write_addr_blocks[blk].start + num_reg * 4;
uint32_t reg_to_write = REG_READ(addr_wr_reg) | value;
// The register can be written in parts so we combine the new value with the one already available.
REG_WRITE(addr_wr_reg, reg_to_write);
}
// return mask with required the number of ones with shift.
static uint32_t get_mask(unsigned int bit_count, unsigned int shift)
{
uint32_t mask;
if (bit_count != 32) {
mask = (1 << bit_count) - 1;
} else {
mask = 0xFFFFFFFF;
}
return mask << shift;
}
// return the register number in the array. return -1 if all registers for field was selected.
static int get_reg_num(int bit_start, int bit_count, int i_reg)
{
int num_reg = i_reg + bit_start / 32;
if (num_reg > (bit_start + bit_count - 1) / 32) {
return -1;
}
return num_reg;
}
// returns the starting bit number in the register.
static int get_starting_bit_num_in_reg(int bit_start, int i_reg)
{
return (i_reg == 0) ? bit_start % 32 : 0;
}
// Returns the number of bits in the register.
static int get_count_bits_in_reg(int bit_start, int bit_count, int i_reg)
{
int ret_count = 0;
int num_reg = 0;
int last_used_bit = (bit_start + bit_count - 1);
for (int num_bit = bit_start; num_bit <= last_used_bit; ++num_bit) {
++ret_count;
if ((((num_bit + 1) % 32) == 0) || (num_bit == last_used_bit)) {
if (i_reg == num_reg++) {
return ret_count;
}
ret_count = 0;
}
}
return 0;
}
// fill efuse register from array.
static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob)
{
uint32_t reg_to_write = 0;
uint32_t temp_blob_32;
int shift_bit = (*filled_bits_blob) % 8;
if (shift_bit != 0) {
temp_blob_32 = blob[(*filled_bits_blob) / 8] >> shift_bit;
shift_bit = ((8 - shift_bit) < bit_count_in_reg) ? (8 - shift_bit) : bit_count_in_reg;
reg_to_write = temp_blob_32 & get_mask(shift_bit, 0);
(*filled_bits_blob) += shift_bit;
bit_count_in_reg -= shift_bit;
}
int shift_reg = shift_bit;
while (bit_count_in_reg > 0) {
temp_blob_32 = blob[(*filled_bits_blob) / 8];
shift_bit = (bit_count_in_reg > 8) ? 8 : bit_count_in_reg;
reg_to_write |= (temp_blob_32 & get_mask(shift_bit, 0)) << shift_reg;
(*filled_bits_blob) += shift_bit;
bit_count_in_reg -= shift_bit;
shift_reg += 8;
};
return reg_to_write << bit_start_in_reg;
}
// sets a required count of bits as "1".
static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt)
{
assert((bit_start_in_reg + bit_count_used_in_reg) <= 32);
uint32_t reg_to_write = 0;
for (int i = bit_start_in_reg; i < bit_start_in_reg + bit_count_used_in_reg; ++i) {
if ((reg_masked & (1 << i)) == 0) {
reg_to_write |= (1 << i);
if (--(*cnt) == 0) {
break;
}
}
}
return reg_to_write;
}
// check range of bits for any coding scheme.
static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits)
{
esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(blk);
int max_num_bit = offset_in_bits + size_bits;
if ((scheme == EFUSE_CODING_SCHEME_NONE && max_num_bit > 256) ||
(scheme == EFUSE_CODING_SCHEME_3_4 && max_num_bit > 192) ||
(scheme == EFUSE_CODING_SCHEME_REPEAT && max_num_bit > 128)) {
return false;
}
return true;
}
static bool read_w_data_and_check_fill(esp_efuse_block_t num_block, uint32_t *buf_w_data)
{
bool blk_is_filled = false;
int i = 0;
for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4, ++i) {
buf_w_data[i] = REG_READ(addr_wr_block);
if (buf_w_data[i] != 0) {
REG_WRITE(addr_wr_block, 0);
blk_is_filled = true;
}
}
return blk_is_filled;
}
static void read_r_data(esp_efuse_block_t num_block, uint32_t* buf_r_data)
{
int i = 0;
for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, ++i) {
buf_r_data[i] = REG_READ(addr_rd_block);
}
}
// After esp_efuse_write.. functions EFUSE_BLKx_WDATAx_REG were filled is not coded values.
// This function reads EFUSE_BLKx_WDATAx_REG registers, applies coding scheme and writes encoded values back to EFUSE_BLKx_WDATAx_REG.
esp_err_t esp_efuse_utility_apply_new_coding_scheme()
{
uint8_t buf_w_data[COUNT_EFUSE_REG_PER_BLOCK * 4];
uint8_t buf_r_data[COUNT_EFUSE_REG_PER_BLOCK * 4];
uint32_t reg[COUNT_EFUSE_REG_PER_BLOCK];
// start with EFUSE_BLK1. EFUSE_BLK0 - always uses EFUSE_CODING_SCHEME_NONE.
for (int num_block = 1; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block);
// check and apply a new coding scheme.
if (scheme != EFUSE_CODING_SCHEME_NONE) {
memset(buf_w_data, 0, sizeof(buf_w_data));
memset((uint8_t*)reg, 0, sizeof(reg));
if (read_w_data_and_check_fill(num_block, (uint32_t*)buf_w_data) == true) {
read_r_data(num_block, (uint32_t*)buf_r_data);
if (scheme == EFUSE_CODING_SCHEME_3_4) {
if (*((uint32_t*)buf_w_data + 6) != 0 || *((uint32_t*)buf_w_data + 7) != 0) {
return ESP_ERR_CODING;
}
for (int i = 0; i < 24; ++i) {
if (buf_w_data[i] != 0) {
int st_offset_buf = (i / 6) * 6;
// check that place is free.
for (int n = st_offset_buf; n < st_offset_buf + 6; ++n) {
if (buf_r_data[n] != 0) {
ESP_LOGE(TAG, "Bits are not empty. Write operation is forbidden.");
return ESP_ERR_CODING;
}
}
esp_err_t err = esp_efuse_apply_34_encoding(&buf_w_data[st_offset_buf], reg, 6);
if (err != ESP_OK) {
return err;
}
int num_reg = (st_offset_buf / 6) * 2;
for (int r = 0; r < 2; r++) {
REG_WRITE(range_write_addr_blocks[num_block].start + (num_reg + r) * 4, reg[r]);
}
i = st_offset_buf + 5;
}
}
} else if (scheme == EFUSE_CODING_SCHEME_REPEAT) {
uint32_t* buf_32 = (uint32_t*)buf_w_data;
for (int i = 4; i < 8; ++i) {
if (*(buf_32 + i) != 0) {
return ESP_ERR_CODING;
}
}
for (int i = 0; i < 4; ++i) {
if (buf_32[i] != 0) {
REG_WRITE(range_write_addr_blocks[num_block].start + i * 4, buf_32[i]);
REG_WRITE(range_write_addr_blocks[num_block].start + (i + 4) * 4, buf_32[i]);
}
}
}
}
}
}
return ESP_OK;
}

View File

@@ -0,0 +1,140 @@
// 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.
#ifndef _ESP_EFUSE_UTILITY_H_
#define _ESP_EFUSE_UTILITY_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include "esp_types.h"
#include "esp_err.h"
#include "esp_efuse.h"
/**
* @brief This is type of function that will handle the efuse field register.
*
* @param[in] num_reg The register number in the block.
* @param[in] efuse_block Block number.
* @param[in] bit_start Start bit in the register.
* @param[in] bit_count The number of bits used in the register.
* @param[in/out] arr A pointer to an array or variable.
* @param[in/out] bits_counter Counter bits.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - other efuse component errors.
*/
typedef esp_err_t (*efuse_func_proc_t) (unsigned int num_reg, esp_efuse_block_t efuse_block, int starting_bit_num_in_reg, int num_bits_used_in_reg, void* arr, int* bits_counter);
/**
* @brief This function processes the field by calling the passed function.
*
* This function selects the field, checks the length, and calls the register processing function.
* @param[in] field A pointer to the structure describing the fields of efuse.
* @param[in/out] ptr A pointer to an array that is used to read / write from / to the efuse field.
* @param[in] ptr_size_bits The size of the data in bits for the efuse field. if = 0 then read all field bits.
* @param[in] func_proc This is the function that will handle the efuse fields.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - other efuse component errors.
*/
esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, size_t ptr_size_bits, efuse_func_proc_t func_proc);
/**
* @brief Write register with the required number of "1" bits.
* @param[in/out] cnt The number of bits you need to set in the field.
*/
esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* cnt, int* bits_counter);
/**
* @brief Fill registers from array for writing.
* @param[in] arr_in A pointer to an array in which the data for the writing.
*/
esp_err_t esp_efuse_utility_write_blob(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_in, int* bits_counter);
/**
* @brief Count a set bits in register.
* @param[in/out] out_cnt A pointer to size_t variable which will contain the number of "1" bits.
*/
esp_err_t esp_efuse_utility_count_once(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* out_cnt, int* bits_counter);
/**
* @brief Read efuse register and write this value to array.
* @param[out] arr_out A pointer to array that will contain the result of reading.
*/
esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_out, int* bits_counter);
/**
* @brief Burn values written to the efuse write registers.
*
* If CONFIG_EFUSE_VIRTUAL is set, writing will not be performed.
* After the function is completed, the writing registers are cleared.
*/
void esp_efuse_utility_burn_efuses(void);
/**
* @brief Returns the number of array elements for placing these "bits" in an array with the length of each element equal to "size_of_base".
*/
int esp_efuse_utility_get_number_of_items(int bits, int size_of_base);
/**
* @brief Reading efuse register.
*/
uint32_t esp_efuse_utility_read_reg(esp_efuse_block_t blk, unsigned int num_reg);
/**
* @brief Writing efuse register with checking of repeated programming of programmed bits.
*/
esp_err_t esp_efuse_utility_write_reg(unsigned int num_reg, esp_efuse_block_t efuse_block, uint32_t reg_to_write);
/* @brief Reset efuse write registers
*
* Efuse write registers are written to zero, to negate
* any changes that have been staged here.
*/
void esp_efuse_utility_reset(void);
/**
* @brief Fills the virt_blocks array by values from efuse_Rdata.
*/
void esp_efuse_utility_update_virt_blocks();
/**
* @brief Prints efuse values for all registers.
*/
void esp_efuse_utility_debug_dump_blocks();
/**
* @brief Erase the virt_blocks array.
*/
void esp_efuse_utility_erase_virt_blocks();
/**
* @brief Apply coding_scheme to write registers.
*
* @return
* - ESP_OK: The operation was successfully completed.
* - ESP_ERR_CODING: Error range of data does not match the coding scheme.
*/
esp_err_t esp_efuse_utility_apply_new_coding_scheme();
#ifdef __cplusplus
}
#endif
#endif // _ESP_EFUSE_UTILITY_H_

View File

@@ -0,0 +1,6 @@
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS "." "include")
set(COMPONENT_REQUIRES unity test_utils efuse bootloader_support)
register_component()

View File

@@ -0,0 +1,6 @@
#
#Component Makefile
#
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View File

@@ -0,0 +1,103 @@
// 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 "esp_efuse.h"
#include "esp_efuse_test_table.h"
// md5_digest_table 7d587827a6f6134241dce7d3713b3edc
// This file was generated automatically from the file esp_efuse_test_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_test_table.csv file then build system will generate this header file
// To show efuse_table run the command 'make show_efuse_table'.
static const esp_efuse_desc_t TEST1_LEN_8[] = {
{EFUSE_BLK3, 0, 8}, // TEST field,
};
static const esp_efuse_desc_t TEST2_LEN_16[] = {
{EFUSE_BLK3, 10, 8}, // TEST field,
{EFUSE_BLK3, 80, 8}, // TEST field,
};
static const esp_efuse_desc_t TEST3_LEN_6[] = {
{EFUSE_BLK3, 22, 6}, // TEST field,
};
static const esp_efuse_desc_t TEST4_LEN_182[] = {
{EFUSE_BLK1, 22, 49}, // TEST field,
{EFUSE_BLK1, 89, 39}, // TEST field,
{EFUSE_BLK1, 71, 18}, // TEST field,
{EFUSE_BLK1, 0, 16}, // TEST field,
{EFUSE_BLK2, 0, 17}, // TEST field,
{EFUSE_BLK2, 60, 43}, // TEST field,
};
static const esp_efuse_desc_t TEST5_LEN_1[] = {
{EFUSE_BLK1, 16, 1}, // TEST field,
};
static const esp_efuse_desc_t TEST6_LEN_17[] = {
{EFUSE_BLK1, 17, 1}, // TEST field,
{EFUSE_BLK2, 17, 2}, // TEST field,
{EFUSE_BLK3, 29, 4}, // TEST field,
{EFUSE_BLK2, 31, 3}, // TEST field,
{EFUSE_BLK3, 60, 6}, // TEST field,
{EFUSE_BLK2, 127, 1}, // TEST field,
};
const esp_efuse_desc_t* ESP_EFUSE_TEST1_LEN_8[] = {
&TEST1_LEN_8[0], // TEST field
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_TEST2_LEN_16[] = {
&TEST2_LEN_16[0], // TEST field
&TEST2_LEN_16[1], // TEST field
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_TEST3_LEN_6[] = {
&TEST3_LEN_6[0], // TEST field
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_TEST4_LEN_182[] = {
&TEST4_LEN_182[0], // TEST field
&TEST4_LEN_182[1], // TEST field
&TEST4_LEN_182[2], // TEST field
&TEST4_LEN_182[3], // TEST field
&TEST4_LEN_182[4], // TEST field
&TEST4_LEN_182[5], // TEST field
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_TEST5_LEN_1[] = {
&TEST5_LEN_1[0], // TEST field
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_TEST6_LEN_17[] = {
&TEST6_LEN_17[0], // TEST field
&TEST6_LEN_17[1], // TEST field
&TEST6_LEN_17[2], // TEST field
&TEST6_LEN_17[3], // TEST field
&TEST6_LEN_17[4], // TEST field
&TEST6_LEN_17[5], // TEST field
NULL
};

View File

@@ -0,0 +1,33 @@
# field_name, | efuse_block, | bit_start, | bit_count, |comment #
# | (EFUSE_BLK0 | (0..255) | (1..256) | #
# | EFUSE_BLK1 | | | #
# | EFUSE_BLK2 | | | #
# | EFUSE_BLK3) | | | #
##########################################################################
# To generate a new source files. Run two commands:
# cd ~/esp/esp-idf/components/efuse/
# ./efuse_table_gen.py test/esp_efuse_test_table.csv
TEST1_LEN_8, EFUSE_BLK3, 0, 8, TEST field
TEST2_LEN_16, EFUSE_BLK3, 10, 8, TEST field
, EFUSE_BLK3, 80, 8, TEST field
TEST3_LEN_6, EFUSE_BLK3, 22, 6, TEST field
TEST4_LEN_182, EFUSE_BLK1, 22, 49, TEST field
, EFUSE_BLK1, 89, 39, TEST field
, EFUSE_BLK1, 71, 18, TEST field
, EFUSE_BLK1, 0, 16, TEST field
, EFUSE_BLK2, 0, 17, TEST field
, EFUSE_BLK2, 60, 43, TEST field
TEST5_LEN_1, EFUSE_BLK1, 16, 1, TEST field
TEST6_LEN_17, EFUSE_BLK1, 17, 1, TEST field
, EFUSE_BLK2, 17, 2, TEST field
, EFUSE_BLK3, 29, 4, TEST field
, EFUSE_BLK2, 31, 3, TEST field
, EFUSE_BLK3, 60, 6, TEST field
, EFUSE_BLK2, 127, 1, TEST field
1 # field_name, | efuse_block, | bit_start, | bit_count, |comment #
2 # | (EFUSE_BLK0 | (0..255) | (1..256) | #
3 # | EFUSE_BLK1 | | | #
4 # | EFUSE_BLK2 | | | #
5 # | EFUSE_BLK3) | | | #
6 ##########################################################################
7 # To generate a new source files. Run two commands:
8 # cd ~/esp/esp-idf/components/efuse/
9 # ./efuse_table_gen.py test/esp_efuse_test_table.csv
10 TEST1_LEN_8, EFUSE_BLK3, 0, 8, TEST field
11 TEST2_LEN_16, EFUSE_BLK3, 10, 8, TEST field
12 , EFUSE_BLK3, 80, 8, TEST field
13 TEST3_LEN_6, EFUSE_BLK3, 22, 6, TEST field
14 TEST4_LEN_182, EFUSE_BLK1, 22, 49, TEST field
15 , EFUSE_BLK1, 89, 39, TEST field
16 , EFUSE_BLK1, 71, 18, TEST field
17 , EFUSE_BLK1, 0, 16, TEST field
18 , EFUSE_BLK2, 0, 17, TEST field
19 , EFUSE_BLK2, 60, 43, TEST field
20 TEST5_LEN_1, EFUSE_BLK1, 16, 1, TEST field
21 TEST6_LEN_17, EFUSE_BLK1, 17, 1, TEST field
22 , EFUSE_BLK2, 17, 2, TEST field
23 , EFUSE_BLK3, 29, 4, TEST field
24 , EFUSE_BLK2, 31, 3, TEST field
25 , EFUSE_BLK3, 60, 6, TEST field
26 , EFUSE_BLK2, 127, 1, TEST field

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 7d587827a6f6134241dce7d3713b3edc
// This file was generated automatically from the file esp_efuse_test_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_test_table.csv file then build system will generate this header file
// To show efuse_table run the command 'make show_efuse_table'.
extern const esp_efuse_desc_t* ESP_EFUSE_TEST1_LEN_8[];
extern const esp_efuse_desc_t* ESP_EFUSE_TEST2_LEN_16[];
extern const esp_efuse_desc_t* ESP_EFUSE_TEST3_LEN_6[];
extern const esp_efuse_desc_t* ESP_EFUSE_TEST4_LEN_182[];
extern const esp_efuse_desc_t* ESP_EFUSE_TEST5_LEN_1[];
extern const esp_efuse_desc_t* ESP_EFUSE_TEST6_LEN_17[];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,594 @@
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include "unity.h"
#include "esp_log.h"
#include <string.h>
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "../src/esp_efuse_utility.h"
#include "esp_efuse_test_table.h"
#include "rom/efuse.h"
#include "bootloader_random.h"
#include "sdkconfig.h"
static const char* TAG = "efuse_test";
static void test_read_blob(void)
{
esp_efuse_utility_update_virt_blocks();
esp_efuse_utility_debug_dump_blocks();
uint8_t mac[6];
ESP_LOGI(TAG, "1. Read MAC address");
memset(mac, 0, sizeof(mac));
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, sizeof(mac) * 8));
TEST_ASSERT_EQUAL_INT(sizeof(mac) * 8, esp_efuse_get_field_size(ESP_EFUSE_MAC_FACTORY));
ESP_LOGI(TAG, "MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
ESP_LOGI(TAG, "2. Check CRC by MAC");
uint8_t crc;
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY_CRC, &crc, 8));
TEST_ASSERT_EQUAL_HEX8(crc, esp_crc8(mac, sizeof(mac)));
ESP_LOGI(TAG, "3. Test check args");
uint32_t test_var;
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, NULL, 1));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &test_var, 0));
uint8_t half_byte;
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &half_byte, 4));
TEST_ASSERT_EQUAL_HEX8(mac[0]&0x0F, half_byte);
uint8_t buff[7] = {0x59};
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &buff, sizeof(buff) * 8));
TEST_ASSERT_TRUE_MESSAGE(memcmp(mac, buff, sizeof(mac)) == 0, "Operation read blob is not success");
TEST_ASSERT_EQUAL_HEX8(0, buff[6]);
}
TEST_CASE("efuse test read_field_blob", "[efuse]")
{
test_read_blob();
}
static void test_read_cnt(void)
{
esp_efuse_utility_update_virt_blocks();
esp_efuse_utility_debug_dump_blocks();
ESP_LOGI(TAG, "1. Test check args");
size_t cnt;
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_cnt(ESP_EFUSE_MAC_FACTORY, NULL));
ESP_LOGI(TAG, "2. Read MAC address");
uint8_t mac[6];
memset(mac, 0, sizeof(mac));
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, 48));
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_MAC_FACTORY, &cnt));
size_t cnt_summ = 0;
for (int i = 0; i < sizeof(mac); ++i) {
cnt_summ += __builtin_popcount(mac[i]);
}
TEST_ASSERT_EQUAL_INT(cnt_summ, cnt);
}
TEST_CASE("efuse test read_field_cnt", "[efuse]")
{
test_read_cnt();
}
// If using efuse is real, then turn off writing tests.
#ifdef CONFIG_EFUSE_VIRTUAL
static void test_write_blob(void)
{
esp_efuse_utility_erase_virt_blocks();
esp_efuse_utility_debug_dump_blocks();
ESP_LOGI(TAG, "1. Test check args");
uint16_t test1_len_8 = 0x5FAA;
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_blob(ESP_EFUSE_MAC_FACTORY, &test1_len_8, 0));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, NULL, 8));
TEST_ASSERT_EQUAL_HEX16(0x5FAA, test1_len_8);
ESP_LOGI(TAG, "2. Test write operation");
TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 7));
TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 9));
uint16_t val_read1 = 0;
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST1_LEN_8, &val_read1, 8));
TEST_ASSERT_EQUAL_HEX16(test1_len_8&((1 << 7) - 1), val_read1);
uint16_t test1_len_8_hi = test1_len_8 & ~((1 << 7) - 1);
TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8_hi, 8));
TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 8));
val_read1 = 0;
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST1_LEN_8, &val_read1, 16));
TEST_ASSERT_EQUAL_HEX16(test1_len_8&0x00FF, val_read1);
uint16_t test2_len_16 = 0xAA55;
uint32_t val_32 = test2_len_16;
TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST2_LEN_16, &val_32, 17));
TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST2_LEN_16, &test2_len_16, 16));
uint16_t test_16 = 0;
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST2_LEN_16, &test_16, 16));
TEST_ASSERT_EQUAL_HEX16(test2_len_16, test_16);
ESP_LOGI(TAG, "3. Test field with one bit");
uint8_t test5_len_1;
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1));
TEST_ASSERT_EQUAL_HEX8(0, test5_len_1);
test5_len_1 = 0;
TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1));
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1));
TEST_ASSERT_EQUAL_HEX8(0, test5_len_1);
test5_len_1 = 1;
TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1));
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1));
TEST_ASSERT_EQUAL_HEX8(1, test5_len_1);
test5_len_1 = 1;
TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1));
esp_efuse_utility_debug_dump_blocks();
}
TEST_CASE("efuse test write_field_blob", "[efuse]")
{
test_write_blob();
}
static void test_write_cnt(void)
{
esp_efuse_utility_erase_virt_blocks();
esp_efuse_utility_debug_dump_blocks();
ESP_LOGI(TAG, "1. Test check args");
size_t test3_len_6 = 5;
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(ESP_EFUSE_MAC_FACTORY, 0));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(NULL, 5));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 0));
ESP_LOGI(TAG, "2. Test write operation");
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6));
TEST_ASSERT_EQUAL_INT(0, test3_len_6);
TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 1));
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6));
TEST_ASSERT_EQUAL_INT(1, test3_len_6);
TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 1));
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6));
TEST_ASSERT_EQUAL_INT(2, test3_len_6);
TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 3));
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6));
TEST_ASSERT_EQUAL_INT(5, test3_len_6);
esp_efuse_utility_debug_dump_blocks();
ESP_LOGI(TAG, "3. Test field is full set");
int max_bits = esp_efuse_get_field_size(ESP_EFUSE_TEST4_LEN_182);
size_t test4_len_182;
esp_efuse_utility_debug_dump_blocks();
for (int i = 0; i < max_bits / 26; ++i) {
ESP_LOGD(TAG, "# %d", i);
TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST4_LEN_182, 26));
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST4_LEN_182, &test4_len_182));
esp_efuse_utility_debug_dump_blocks();
TEST_ASSERT_EQUAL_INT((i + 1) * 26, test4_len_182);
}
esp_efuse_utility_debug_dump_blocks();
ESP_LOGI(TAG, "4. Test field ESP_EFUSE_TEST4_LEN_182 is full");
TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_write_field_cnt(ESP_EFUSE_TEST4_LEN_182, 1));
ESP_LOGI(TAG, "3. Test field with one bit");
size_t test5_len_1;
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST5_LEN_1, &test5_len_1));
TEST_ASSERT_EQUAL_HEX8(0, test5_len_1);
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1));
TEST_ASSERT_EQUAL_HEX8(0, test5_len_1);
test5_len_1 = 1;
TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST5_LEN_1, test5_len_1));
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST5_LEN_1, &test5_len_1));
TEST_ASSERT_EQUAL_HEX8(1, test5_len_1);
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1));
TEST_ASSERT_EQUAL_HEX8(1, test5_len_1);
test5_len_1 = 1;
TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_write_field_cnt(ESP_EFUSE_TEST5_LEN_1, test5_len_1));
esp_efuse_utility_debug_dump_blocks();
ESP_LOGI(TAG, "4. Test field test2_len_16");
size_t test2_len_16 = 11;
TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST2_LEN_16, test2_len_16));
TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST2_LEN_16, &test2_len_16));
TEST_ASSERT_EQUAL_HEX16(11, test2_len_16);
TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST2_LEN_16, &test2_len_16, 16));
TEST_ASSERT_EQUAL_HEX16(0x07FF, test2_len_16);
esp_efuse_utility_debug_dump_blocks();
}
TEST_CASE("efuse test write_field_cnt", "[efuse]")
{
test_write_cnt();
}
void cut_tail_arr(uint8_t *arr, int num_used_bits, size_t count_bits)
{
if ((num_used_bits + count_bits) % 8) {
int start_used_item = (num_used_bits - 1) / 8;
int last_used_item = ((num_used_bits + count_bits) - 1) / 8;
int shift = 0;
int mask = num_used_bits + count_bits;
if (last_used_item == start_used_item) {
shift = (num_used_bits) % 8;
mask = count_bits;
}
arr[last_used_item] &= ((1 << (mask % 8)) - 1) << shift;
}
}
void cut_start_arr(uint8_t *arr, size_t num_used_bits)
{
if (num_used_bits % 8) {
int start_used_item = (num_used_bits - 1) / 8;
arr[start_used_item] &= ~((1 << (num_used_bits % 8)) - 1);
}
}
void get_part_arr(uint8_t *arr_in, uint8_t *arr_out, int num_used_bits, int count_bits)
{
int num_items = esp_efuse_utility_get_number_of_items(num_used_bits + count_bits, 8);
memcpy(arr_out, arr_in, num_items);
memset(arr_out, 0, num_used_bits / 8);
cut_start_arr(arr_out, num_used_bits);
cut_tail_arr(arr_out, num_used_bits, count_bits);
}
void fill_part_arr(uint8_t *arr_in, uint8_t *arr_out, int count_bits)
{
int num_items = esp_efuse_utility_get_number_of_items(count_bits, 8);
memcpy(arr_out, arr_in, num_items);
cut_tail_arr(arr_out, 0, count_bits);
}
// Writes a random array to efuse, then reads and compares it.
void test_blob(const esp_efuse_desc_t* field[], uint8_t *arr_w, uint8_t *arr_r, uint8_t *arr_temp, int arr_size, size_t field_size)
{
ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_w, arr_size, ESP_LOG_INFO);
TEST_ESP_OK(esp_efuse_write_field_blob(field, arr_w, field_size));
memset(arr_r, 0, arr_size);
TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size));
ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_r, arr_size, ESP_LOG_INFO);
esp_efuse_utility_debug_dump_blocks();
TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_w, arr_r, arr_size) == 0, "Operation write/read blob is not success");
int count_once = 0;
for (int i = 0; i < arr_size; ++i) {
count_once += __builtin_popcount(arr_w[i]);
}
size_t num_bits_r = 0;
TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r));
TEST_ASSERT_EQUAL_INT(count_once, num_bits_r);
size_t num_bits_w = field_size - count_once;
if (num_bits_w == 0) {
esp_efuse_utility_erase_virt_blocks();
num_bits_w = field_size;
}
TEST_ESP_OK(esp_efuse_write_field_cnt(field, num_bits_w));
TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r));
esp_efuse_utility_debug_dump_blocks();
TEST_ASSERT_EQUAL_INT(field_size, num_bits_r);
memset(arr_r, 0, arr_size);
TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size));
memset(arr_temp, 0xFF, arr_size);
cut_tail_arr(arr_temp, 0, field_size);
esp_efuse_utility_debug_dump_blocks();
TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_temp, arr_r, arr_size) == 0, "Operation write/read blob is not success");
}
// Records a random number of bits (as "1") in the efuse field, then reads and compares.
void test_cnt_part(const esp_efuse_desc_t* field[], uint8_t *arr_r, int arr_size, size_t field_size)
{
size_t num_bits_r = 0;
TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r));
TEST_ASSERT_EQUAL_INT(0, num_bits_r);
TEST_ESP_OK(esp_efuse_write_field_cnt(field, field_size));
TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r));
TEST_ASSERT_EQUAL_INT(field_size, num_bits_r);
esp_efuse_utility_erase_virt_blocks();
int num_bits_summ_r = 0;
int num_bits_w = 0;
while(field_size > num_bits_summ_r) {
num_bits_w = 0;
while(num_bits_w == 0 || (num_bits_summ_r + num_bits_w) > field_size) {
bootloader_random_enable();
bootloader_fill_random(&num_bits_w, 1);
bootloader_random_disable();
num_bits_w = num_bits_w * field_size / 255;
if (num_bits_w != 0 && (num_bits_summ_r + num_bits_w) <= field_size) {
break;
}
}
TEST_ESP_OK(esp_efuse_write_field_cnt(field, num_bits_w));
TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r));
num_bits_summ_r += num_bits_w;
TEST_ASSERT_EQUAL_INT(num_bits_summ_r, num_bits_r);
memset(arr_r, 0, arr_size);
TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size));
int count_once = 0;
for (int i = 0; i < arr_size; ++i) {
count_once += __builtin_popcount(arr_r[i]);
}
TEST_ASSERT_EQUAL_INT(num_bits_summ_r, count_once);
ESP_LOGI(TAG, "Once bits=%d, step=%d", num_bits_summ_r, num_bits_w);
}
esp_efuse_utility_debug_dump_blocks();
}
// From a random array takes a random number of bits and write to efuse, it repeats until the entire length of the field is written down.
void test_blob_part(const esp_efuse_desc_t* field[], uint8_t *arr_w, uint8_t *arr_r, uint8_t *arr_temp, int arr_size, size_t field_size)
{
esp_efuse_utility_debug_dump_blocks();
int num_bits_summ_r = 0;
int num_bits_w = 0;
memset(arr_w, 0, arr_size);
bootloader_random_enable();
bootloader_fill_random(arr_w, arr_size);
bootloader_random_disable();
ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_w, arr_size, ESP_LOG_INFO);
while(field_size > num_bits_summ_r) {
num_bits_w = 0;
while(num_bits_w == 0 || (num_bits_summ_r + num_bits_w) > field_size) {
bootloader_random_enable();
bootloader_fill_random(&num_bits_w, 1);
bootloader_random_disable();
num_bits_w = num_bits_w * field_size / 255;
if (num_bits_w != 0 && (num_bits_summ_r + num_bits_w) <= field_size) {
break;
}
}
ESP_LOGI(TAG, "Summ bits=%d, step=%d", num_bits_summ_r, num_bits_w);
memset(arr_temp, 0, arr_size);
get_part_arr(arr_w, arr_temp, num_bits_summ_r, num_bits_w);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_temp, arr_size, ESP_LOG_INFO);
TEST_ESP_OK(esp_efuse_write_field_blob(field, arr_temp, field_size));
memset(arr_r, 0, arr_size);
TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size));
ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_r, arr_size, ESP_LOG_INFO);
esp_efuse_utility_debug_dump_blocks();
num_bits_summ_r += num_bits_w;
memset(arr_temp, 0, arr_size);
fill_part_arr(arr_w, arr_temp, num_bits_summ_r);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_temp, arr_size, ESP_LOG_INFO);
TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_temp, arr_r, arr_size) == 0, "Operation write/read blob is not success");
}
}
void check_efuse_table_test(int cycle)
{
int num_test = 0;
while(1) {
const esp_efuse_desc_t** field;
switch (num_test++) {
case 0: field = ESP_EFUSE_TEST1_LEN_8; break;
case 1: field = ESP_EFUSE_TEST2_LEN_16; break;
case 2: field = ESP_EFUSE_TEST3_LEN_6; break;
case 3: field = ESP_EFUSE_TEST4_LEN_182; break;
case 4: field = ESP_EFUSE_TEST5_LEN_1; break;
case 5: field = ESP_EFUSE_TEST6_LEN_17; break;
default:
return;
break;
}
size_t field_size = esp_efuse_get_field_size(field);
int arr_size = esp_efuse_utility_get_number_of_items(field_size, 8);
uint8_t *arr_w = (uint8_t *) malloc(arr_size);
uint8_t *arr_r = (uint8_t *) malloc(arr_size);
uint8_t *arr_temp = (uint8_t *) malloc(arr_size);
ESP_LOGI(TAG, "Test#%d", num_test);
for (int c = 1; c <= cycle; ++c) {
ESP_LOGI(TAG, "Cycle#%d/%d", c, cycle);
memset(arr_w, 0, arr_size);
bootloader_random_enable();
bootloader_fill_random(arr_w, arr_size);
bootloader_random_disable();
cut_tail_arr(arr_w, 0, field_size);
esp_efuse_utility_erase_virt_blocks();
ESP_LOGI(TAG, "1) blob write/read");
test_blob(field, arr_w, arr_r, arr_temp, arr_size, field_size);
esp_efuse_utility_erase_virt_blocks();
ESP_LOGI(TAG, "2) cnt part write/read");
test_cnt_part(field, arr_r, arr_size, field_size);
esp_efuse_utility_erase_virt_blocks();
ESP_LOGI(TAG, "3) blob part write/read");
test_blob_part(field, arr_w, arr_r, arr_temp, arr_size, field_size);
}
free(arr_temp);
free(arr_r);
free(arr_w);
}
}
TEST_CASE("efuse esp_efuse_table_test", "[efuse]")
{
check_efuse_table_test(2);
}
TEST_CASE("Test esp_efuse_read_block esp_efuse_write_block functions", "[efuse]")
{
int count_useful_reg = 0;
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2);
if (coding_scheme == EFUSE_CODING_SCHEME_NONE) {
printf("EFUSE_CODING_SCHEME_NONE\n");
count_useful_reg = 8;
} else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
printf("EFUSE_CODING_SCHEME_3_4\n");
count_useful_reg = 6;
} else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) {
printf("EFUSE_CODING_SCHEME_REPEAT\n");
count_useful_reg = 4;
}
esp_efuse_utility_reset();
esp_efuse_utility_erase_virt_blocks();
uint8_t src_key[32] = { 0 };
uint8_t dst_key[32] = { 0 };
int offset_in_bits = 0;
for (int i = 0; i < count_useful_reg * 4; ++i) {
src_key[i] = 0xAB + i;
}
TEST_ESP_OK(esp_efuse_write_block(EFUSE_BLK2, src_key, offset_in_bits, count_useful_reg * 32));
TEST_ESP_OK(esp_efuse_read_block(EFUSE_BLK2, dst_key, offset_in_bits, count_useful_reg * 32));
esp_efuse_utility_debug_dump_blocks();
TEST_ASSERT_EQUAL_HEX8_ARRAY(src_key, dst_key, sizeof(src_key));
esp_efuse_utility_erase_virt_blocks();
memset(src_key, 0, sizeof(src_key));
memset(dst_key, 0, sizeof(dst_key));
offset_in_bits = count_useful_reg * 32 / 2;
for (int i = 0; i < count_useful_reg * 4 / 2; ++i) {
src_key[i] = 0xCD + i;
}
TEST_ESP_OK(esp_efuse_write_block(EFUSE_BLK2, src_key, offset_in_bits, count_useful_reg * 32 / 2));
TEST_ESP_OK(esp_efuse_read_block(EFUSE_BLK2, dst_key, offset_in_bits, count_useful_reg * 32 / 2));
esp_efuse_utility_debug_dump_blocks();
TEST_ASSERT_EQUAL_HEX8_ARRAY(src_key, dst_key, count_useful_reg * 4 / 2);
esp_efuse_utility_erase_virt_blocks();
}
TEST_CASE("Test Bits are not empty. Write operation is forbidden", "[efuse]")
{
esp_efuse_utility_update_virt_blocks();
esp_efuse_utility_debug_dump_blocks();
int count_useful_reg = 0;
uint8_t r_buff[32];
int st_offset = -1;
int num_block;
for (num_block = EFUSE_BLK1; num_block < 4; ++num_block) {
memset(r_buff, 0, sizeof(r_buff));
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(num_block);
if (coding_scheme == EFUSE_CODING_SCHEME_NONE) {
printf("EFUSE_CODING_SCHEME_NONE. The test is not applicable.\n");
count_useful_reg = 8;
return;
} else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
printf("EFUSE_CODING_SCHEME_3_4\n");
count_useful_reg = 6;
} else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) {
printf("EFUSE_CODING_SCHEME_REPEAT\n");
count_useful_reg = 4;
}
TEST_ESP_OK(esp_efuse_read_block(num_block, r_buff, 0, count_useful_reg * 32));
for (int i = 0; i < count_useful_reg * 4; ++i) {
if (r_buff[i] != 0) {
// found used byte
for (int j = 0; j < 8; ++j) {
if ((r_buff[i] & (1 << j)) == 0) {
// found empty bit into this byte
st_offset = i * 8 + j;
printf("Byte = 0x%02x. offset is = %d\n", r_buff[i], st_offset);
break;
}
}
if (st_offset != -1) {
break;
}
}
}
if (st_offset != -1) {
break;
}
}
if (st_offset != -1) {
// write 1 bit to empty place.
uint8_t val = 1;
TEST_ESP_ERR(ESP_ERR_CODING, esp_efuse_write_block(num_block, &val, st_offset, 1));
} else {
printf("Test skipped. It is not applicable, the device has no written bits.");
}
}
TEST_CASE("Test a write/read protection", "[efuse]")
{
esp_efuse_utility_reset();
esp_efuse_utility_erase_virt_blocks();
esp_efuse_utility_debug_dump_blocks();
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_efuse_set_write_protect(EFUSE_BLK0));
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_efuse_set_read_protect(EFUSE_BLK0));
size_t out_cnt;
esp_efuse_read_field_cnt(ESP_EFUSE_WR_DIS_BLK1, &out_cnt);
TEST_ASSERT_EQUAL_INT(0, out_cnt);
TEST_ESP_OK(esp_efuse_set_write_protect(EFUSE_BLK1));
esp_efuse_read_field_cnt(ESP_EFUSE_WR_DIS_BLK1, &out_cnt);
TEST_ASSERT_EQUAL_INT(1, out_cnt);
TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_set_write_protect(EFUSE_BLK1));
TEST_ESP_OK(esp_efuse_set_write_protect(EFUSE_BLK2));
esp_efuse_read_field_cnt(ESP_EFUSE_WR_DIS_BLK2, &out_cnt);
TEST_ASSERT_EQUAL_INT(1, out_cnt);
TEST_ESP_OK(esp_efuse_set_write_protect(EFUSE_BLK3));
esp_efuse_read_field_cnt(ESP_EFUSE_WR_DIS_BLK3, &out_cnt);
TEST_ASSERT_EQUAL_INT(1, out_cnt);
esp_efuse_utility_debug_dump_blocks();
esp_efuse_read_field_cnt(ESP_EFUSE_RD_DIS_BLK1, &out_cnt);
TEST_ASSERT_EQUAL_INT(0, out_cnt);
TEST_ESP_OK(esp_efuse_set_read_protect(EFUSE_BLK1));
esp_efuse_read_field_cnt(ESP_EFUSE_RD_DIS_BLK1, &out_cnt);
TEST_ASSERT_EQUAL_INT(1, out_cnt);
TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_set_read_protect(EFUSE_BLK1));
TEST_ESP_OK(esp_efuse_set_read_protect(EFUSE_BLK2));
esp_efuse_read_field_cnt(ESP_EFUSE_RD_DIS_BLK2, &out_cnt);
TEST_ASSERT_EQUAL_INT(1, out_cnt);
TEST_ESP_OK(esp_efuse_set_read_protect(EFUSE_BLK3));
esp_efuse_read_field_cnt(ESP_EFUSE_RD_DIS_BLK3, &out_cnt);
TEST_ASSERT_EQUAL_INT(1, out_cnt);
esp_efuse_utility_debug_dump_blocks();
esp_efuse_utility_reset();
esp_efuse_utility_erase_virt_blocks();
}
#endif // #ifdef CONFIG_EFUSE_VIRTUAL

View File

@@ -1,7 +1,10 @@
#include <stdint.h>
#include <strings.h>
#include "esp_efuse.h"
#include "../src/esp_efuse_utility.h"
#include "soc/efuse_reg.h"
#include "unity.h"
#include "bootloader_random.h"
typedef struct {
uint8_t unencoded[24];
@@ -71,7 +74,7 @@ static const coding_scheme_test_t coding_scheme_data[] = {
},
};
TEST_CASE("Test 3/4 Coding Scheme Algorithm", "[bootloader_support]")
TEST_CASE("Test 3/4 Coding Scheme Algorithm", "[efuse]")
{
const int num_tests = sizeof(coding_scheme_data)/sizeof(coding_scheme_test_t);
for (int i = 0; i < num_tests; i++) {
@@ -92,3 +95,110 @@ TEST_CASE("Test 3/4 Coding Scheme Algorithm", "[bootloader_support]")
}
}
}
TEST_CASE("Test Coding Scheme for efuse manager", "[efuse]")
{
int count_useful_reg = 0;
int useful_data_in_byte;
uint8_t buf[32];
uint32_t encoded[8];
bootloader_random_enable();
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2);
if (coding_scheme == EFUSE_CODING_SCHEME_NONE) {
printf("EFUSE_CODING_SCHEME_NONE\n");
count_useful_reg = 8;
} else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
printf("EFUSE_CODING_SCHEME_3_4\n");
count_useful_reg = 6;
} else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) {
printf("EFUSE_CODING_SCHEME_REPEAT\n");
count_useful_reg = 4;
}
useful_data_in_byte = count_useful_reg * 4;
for (int i = 0; i < 10; ++i) {
printf("Test case %d...\n", i);
memset(buf, 0, sizeof(buf));
memset(encoded, 0, sizeof(encoded));
// get test data
bootloader_fill_random(buf, useful_data_in_byte);
memset(buf, 0, i);
esp_efuse_utility_reset();
for (int j = 0; j < count_useful_reg; ++j) {
REG_WRITE(EFUSE_BLK2_WDATA0_REG + j * 4, *((uint32_t*)buf + j));
}
TEST_ESP_OK(esp_efuse_utility_apply_new_coding_scheme());
uint32_t w_data_after_coding[8] = { 0 };
for (int j = 0; j < 8; ++j) {
w_data_after_coding[j] = REG_READ(EFUSE_BLK2_WDATA0_REG + j * 4);
}
if (coding_scheme == EFUSE_CODING_SCHEME_NONE) {
memcpy((uint8_t*)encoded, buf, sizeof(buf));
} else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
TEST_ESP_OK(esp_efuse_apply_34_encoding(buf, encoded, useful_data_in_byte));
} else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) {
for (int j = 0; j < count_useful_reg; ++j) {
encoded[j] = *((uint32_t*)buf + j);
encoded[j + 4] = encoded[j];
}
}
#ifdef CONFIG_EFUSE_VIRTUAL
printf("Data from W reg\n");
esp_efuse_utility_erase_virt_blocks();
esp_efuse_utility_burn_efuses();
esp_efuse_utility_debug_dump_blocks();
printf("Data from encoded\n");
for (int j = 0; j < 8; ++j) {
printf("0x%08x ", encoded[j]);
}
printf("\nData from w_data_after_coding\n");
for (int j = 0; j < 8; ++j) {
printf("0x%08x ", w_data_after_coding[j]);
}
printf("\nData from buf\n");
for (int j = 0; j < 8; ++j) {
printf("0x%08x ", *((uint32_t*)buf + j));
}
printf("\n");
#endif
TEST_ASSERT_EQUAL_HEX32_ARRAY(encoded, w_data_after_coding, 8);
}
esp_efuse_utility_reset();
bootloader_random_disable();
}
TEST_CASE("Test data does not match the coding scheme", "[efuse]")
{
int count_useful_reg = 0;
esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2);
if (coding_scheme == EFUSE_CODING_SCHEME_NONE) {
printf("EFUSE_CODING_SCHEME_NONE\n");
count_useful_reg = 8;
} else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
printf("EFUSE_CODING_SCHEME_3_4\n");
count_useful_reg = 6 + 1;
} else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) {
printf("EFUSE_CODING_SCHEME_REPEAT\n");
count_useful_reg = 4 + 1;
}
esp_efuse_utility_reset();
for (int i = 0; i < count_useful_reg; ++i) {
REG_WRITE(EFUSE_BLK2_WDATA0_REG + i * 4, 0xABCDEF01 + i);
}
if (coding_scheme == EFUSE_CODING_SCHEME_NONE) {
TEST_ESP_OK(esp_efuse_utility_apply_new_coding_scheme());
} else {
TEST_ESP_ERR(ESP_ERR_CODING, esp_efuse_utility_apply_new_coding_scheme());
}
esp_efuse_utility_reset();
}

View File

@@ -0,0 +1,341 @@
#!/usr/bin/env python
from __future__ import print_function, division
import unittest
import sys
try:
import efuse_table_gen
except ImportError:
sys.path.append("..")
import efuse_table_gen
'''
To run the test on local PC:
cd ~/esp/esp-idf/components/efuse/test_efuse_host/
./efuse_tests.py
'''
class Py23TestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(Py23TestCase, self).__init__(*args, **kwargs)
try:
self.assertRaisesRegex
except AttributeError:
# assertRaisesRegexp is deprecated in Python3 but assertRaisesRegex doesn't exist in Python2
# This fix is used in order to avoid using the alias from the six library
self.assertRaisesRegex = self.assertRaisesRegexp
class CSVParserTests(Py23TestCase):
def test_general(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, 0, 5, Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
t.verify()
self.assertEqual(t[0].field_name, 'name1')
self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3')
self.assertEqual(t[0].bit_start, 0)
self.assertEqual(t[0].bit_count, 5)
self.assertEqual(t[0].comment, 'Use for test name 1')
self.assertEqual(t[1].field_name, 'name2')
self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3')
self.assertEqual(t[1].bit_start, 5)
self.assertEqual(t[1].bit_count, 4)
self.assertEqual(t[1].comment, 'Use for test name 2')
def test_seq_bit_start1_fill(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, , 5,
name2, EFUSE_BLK3, , 4,
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
t.verify()
self.assertEqual(t[0].field_name, 'name1')
self.assertEqual(t[0].bit_start, 0)
self.assertEqual(t[0].bit_count, 5)
self.assertEqual(t[1].field_name, 'name2')
self.assertEqual(t[1].bit_start, 5)
self.assertEqual(t[1].bit_count, 4)
def test_seq_bit_start2_fill(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, , 5,
name2, EFUSE_BLK2, , 4,
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
t.verify()
self.assertEqual(t[0].field_name, 'name1')
self.assertEqual(t[0].bit_start, 0)
self.assertEqual(t[0].bit_count, 5)
self.assertEqual(t[1].field_name, 'name2')
self.assertEqual(t[1].bit_start, 0)
self.assertEqual(t[1].bit_count, 4)
def test_seq_bit_start3_fill(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, , 5,
name2, EFUSE_BLK2, , 4,
name3, EFUSE_BLK2, 5, 4,
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
t.verify()
self.assertEqual(t[0].field_name, 'name1')
self.assertEqual(t[0].bit_start, 0)
self.assertEqual(t[0].bit_count, 5)
self.assertEqual(t[1].field_name, 'name2')
self.assertEqual(t[1].bit_start, 0)
self.assertEqual(t[1].bit_count, 4)
self.assertEqual(t[2].field_name, 'name3')
self.assertEqual(t[2].bit_start, 5)
self.assertEqual(t[2].bit_count, 4)
def test_seq_bit_start4_fill(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, , 5,
name2, EFUSE_BLK2, , 4,
, EFUSE_BLK2, , 4,
name1, EFUSE_BLK3, , 5,
"""
with self.assertRaisesRegex(efuse_table_gen.InputError, "Field names must be unique"):
efuse_table_gen.FuseTable.from_csv(csv)
def test_seq_bit_start5_fill(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, , 5,
name2, EFUSE_BLK2, , 4,
, EFUSE_BLK2, , 4,
name3, EFUSE_BLK3, 5, 5,
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
t.verify()
self.assertEqual(t[0].field_name, 'name1')
self.assertEqual(t[0].bit_start, 0)
self.assertEqual(t[0].bit_count, 5)
self.assertEqual(t[1].field_name, 'name2')
self.assertEqual(t[1].bit_start, 0)
self.assertEqual(t[1].bit_count, 4)
self.assertEqual(t[2].field_name, 'name2')
self.assertEqual(t[2].bit_start, 4)
self.assertEqual(t[2].bit_count, 4)
self.assertEqual(t[3].field_name, 'name3')
self.assertEqual(t[3].bit_start, 5)
self.assertEqual(t[3].bit_count, 5)
def test_overlapping_bit_start_fail(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, 1, 5, Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
with self.assertRaisesRegex(efuse_table_gen.InputError, "overlap"):
t.verify()
def test_empty_field_name_fail(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
, EFUSE_BLK3, , 5,
name2, EFUSE_BLK2, , 4,
"""
with self.assertRaisesRegex(efuse_table_gen.InputError, "missing field name"):
efuse_table_gen.FuseTable.from_csv(csv)
def test_unique_field_name_fail(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, 0, 5, Use for test name 1
name1, EFUSE_BLK3, 5, 4, Use for test name 2
"""
with self.assertRaisesRegex(efuse_table_gen.InputError, "Field names must be unique"):
efuse_table_gen.FuseTable.from_csv(csv)
def test_bit_count_empty_fail(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, 0, , Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2
"""
with self.assertRaisesRegex(efuse_table_gen.InputError, "empty"):
efuse_table_gen.FuseTable.from_csv(csv)
def test_bit_start_num_fail(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, k, 5, Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2
"""
with self.assertRaisesRegex(efuse_table_gen.InputError, "Invalid field value"):
efuse_table_gen.FuseTable.from_csv(csv)
def test_join_entry(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK2, 0, 6, Use for test name 1
name2, EFUSE_BLK2, 6, 5, Use for test name 2
name3, EFUSE_BLK3, 20, 5, Use for test name 3
, EFUSE_BLK3, 30, 5, Use for test name 3
name4, EFUSE_BLK2, 30, 5, Use for test name 4
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
t.verify()
self.assertEqual(t[0].field_name, 'name1')
self.assertEqual(t[0].efuse_block, 'EFUSE_BLK2')
self.assertEqual(t[0].bit_start, 0)
self.assertEqual(t[0].bit_count, 6)
self.assertEqual(t[1].field_name, 'name2')
self.assertEqual(t[1].efuse_block, 'EFUSE_BLK2')
self.assertEqual(t[1].bit_start, 6)
self.assertEqual(t[1].bit_count, 5)
self.assertEqual(t[2].field_name, 'name3')
self.assertEqual(t[2].efuse_block, 'EFUSE_BLK3')
self.assertEqual(t[2].bit_start, 20)
self.assertEqual(t[2].bit_count, 5)
self.assertEqual(t[3].field_name, 'name3')
self.assertEqual(t[3].efuse_block, 'EFUSE_BLK3')
self.assertEqual(t[3].bit_start, 30)
self.assertEqual(t[3].bit_count, 5)
self.assertEqual(t[4].field_name, 'name4')
self.assertEqual(t[4].efuse_block, 'EFUSE_BLK2')
self.assertEqual(t[4].bit_start, 30)
self.assertEqual(t[4].bit_count, 5)
def test_block_fail(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK5, 0, 5, Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2
"""
with self.assertRaisesRegex(efuse_table_gen.InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"):
efuse_table_gen.FuseTable.from_csv(csv)
def test_field_size_is_ok(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK0, 0, 224, Use for test name 1
name2, EFUSE_BLK1, 0, 256, Use for test name 2
"""
efuse_table_gen.max_blk_len = 256
t = efuse_table_gen.FuseTable.from_csv(csv)
t.verify()
def test_field_blk3_size_is_more(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, 190, 1, Use for test name 1
name2, EFUSE_BLK3, 191, 5, Use for test name 2
"""
efuse_table_gen.max_blk_len = 192
t = efuse_table_gen.FuseTable.from_csv(csv)
with self.assertRaisesRegex(efuse_table_gen.InputError, "The field is outside the boundaries"):
t.verify()
def test_field_blk1_size_is_more(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK0, 0, 224, Use for test name 1
name2, EFUSE_BLK1, 1, 256, Use for test name 2
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
with self.assertRaisesRegex(efuse_table_gen.InputError, "The field is outside the boundaries"):
t.verify()
class VerificationTests(Py23TestCase):
def test_general(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, 0, 5, Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2
name1_1, EFUSE_BLK2, 0, 5, Use for test name 1_1
name2_1, EFUSE_BLK2, 5, 4, Use for test name 2_1
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
t.verify()
self.assertEqual(t[0].field_name, 'name1')
self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3')
self.assertEqual(t[0].bit_start, 0)
self.assertEqual(t[0].bit_count, 5)
self.assertEqual(t[1].field_name, 'name2')
self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3')
self.assertEqual(t[1].bit_start, 5)
self.assertEqual(t[1].bit_count, 4)
self.assertEqual(t[2].field_name, 'name1_1')
self.assertEqual(t[2].efuse_block, 'EFUSE_BLK2')
self.assertEqual(t[2].bit_start, 0)
self.assertEqual(t[2].bit_count, 5)
self.assertEqual(t[3].field_name, 'name2_1')
self.assertEqual(t[3].efuse_block, 'EFUSE_BLK2')
self.assertEqual(t[3].bit_start, 5)
self.assertEqual(t[3].bit_count, 4)
def test_custom_use_only_BLK3(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, 0, 5, Use for test name 1
name2, EFUSE_BLK2, 5, 4, Use for test name 2
"""
t = efuse_table_gen.FuseTable.from_csv(csv)
with self.assertRaisesRegex(efuse_table_gen.ValidationError, "custom_table should use only EFUSE_BLK3"):
t.verify("custom_table")
def test_common_and_custom_table_use_the_same_bits(self):
csv_common = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK3, 0, 5, Use for test name 1
name2, EFUSE_BLK2, 5, 4, Use for test name 2
"""
common_table = efuse_table_gen.FuseTable.from_csv(csv_common)
common_table.verify("common_table")
two_tables = common_table
csv_custom = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name3, EFUSE_BLK3, 20, 5, Use for test name 1
name4, EFUSE_BLK3, 4, 1, Use for test name 2
"""
custom_table = efuse_table_gen.FuseTable.from_csv(csv_custom)
custom_table.verify("custom_table")
two_tables += custom_table
with self.assertRaisesRegex(efuse_table_gen.InputError, "overlaps"):
two_tables.verify()
if __name__ == "__main__":
unittest.main()

View File

@@ -53,7 +53,7 @@ else()
"hwcrypto/sha.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES driver tcpip_adapter esp_event)
set(COMPONENT_REQUIRES driver tcpip_adapter esp_event efuse)
# driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t
# tcpip_adapter is a public requirement because esp_event.h uses tcpip_adapter types
# app_update is added here because cpu_start.c uses esp_ota_get_app_description() function.

View File

@@ -7,6 +7,9 @@
#if __has_include("esp32/ulp.h")
#include "esp32/ulp.h"
#endif
#if __has_include("esp_efuse.h")
#include "esp_efuse.h"
#endif
#if __has_include("esp_err.h")
#include "esp_err.h"
#endif
@@ -240,6 +243,23 @@ static const esp_err_msg_t esp_err_msg_table[] = {
(ESP_OTA_IMG_PENDING_VERIFY), essentially
first boot of firmware image post upgrade
and hence firmware upgrade is not possible */
# endif
// components/efuse/include/esp_efuse.h
# ifdef ESP_ERR_EFUSE
ERR_TBL_IT(ESP_ERR_EFUSE), /* 5632 0x1600 Base error code for efuse api. */
# endif
# ifdef ESP_OK_EFUSE_CNT
ERR_TBL_IT(ESP_OK_EFUSE_CNT), /* 5633 0x1601 OK the required number of bits is set. */
# endif
# ifdef ESP_ERR_EFUSE_CNT_IS_FULL
ERR_TBL_IT(ESP_ERR_EFUSE_CNT_IS_FULL), /* 5634 0x1602 Error field is full. */
# endif
# ifdef ESP_ERR_EFUSE_REPEATED_PROG
ERR_TBL_IT(ESP_ERR_EFUSE_REPEATED_PROG), /* 5635 0x1603 Error repeated programming of programmed
bits is strictly forbidden. */
# endif
# ifdef ESP_ERR_CODING
ERR_TBL_IT(ESP_ERR_CODING), /* 5636 0x1604 Error while a encoding operation. */
# endif
// components/bootloader_support/include/esp_image_format.h
# ifdef ESP_ERR_IMAGE_BASE

View File

@@ -37,6 +37,8 @@
#include "freertos/xtensa_api.h"
#include "esp_heap_caps.h"
#include "esp_system_internal.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
static const char* TAG = "system_api";
@@ -77,31 +79,17 @@ esp_err_t esp_base_mac_addr_get(uint8_t *mac)
esp_err_t esp_efuse_mac_get_custom(uint8_t *mac)
{
uint32_t mac_low;
uint32_t mac_high;
uint8_t efuse_crc;
uint8_t calc_crc;
uint8_t version = REG_READ(EFUSE_BLK3_RDATA5_REG) >> 24;
uint8_t version;
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM_VER, &version, 8);
if (version != 1) {
ESP_LOGE(TAG, "Base MAC address from BLK3 of EFUSE version error, version = %d", version);
return ESP_ERR_INVALID_VERSION;
}
mac_low = REG_READ(EFUSE_BLK3_RDATA1_REG);
mac_high = REG_READ(EFUSE_BLK3_RDATA0_REG);
mac[0] = mac_high >> 8;
mac[1] = mac_high >> 16;
mac[2] = mac_high >> 24;
mac[3] = mac_low;
mac[4] = mac_low >> 8;
mac[5] = mac_low >> 16;
efuse_crc = mac_high;
calc_crc = esp_crc8(mac, 6);
uint8_t efuse_crc;
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48);
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM_CRC, &efuse_crc, 8);
uint8_t calc_crc = esp_crc8(mac, 6);
if (efuse_crc != calc_crc) {
ESP_LOGE(TAG, "Base MAC address from BLK3 of EFUSE CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc);
@@ -112,29 +100,17 @@ esp_err_t esp_efuse_mac_get_custom(uint8_t *mac)
esp_err_t esp_efuse_mac_get_default(uint8_t* mac)
{
uint32_t mac_low;
uint32_t mac_high;
uint8_t efuse_crc;
uint8_t calc_crc;
mac_low = REG_READ(EFUSE_BLK0_RDATA1_REG);
mac_high = REG_READ(EFUSE_BLK0_RDATA2_REG);
mac[0] = mac_high >> 8;
mac[1] = mac_high;
mac[2] = mac_low >> 24;
mac[3] = mac_low >> 16;
mac[4] = mac_low >> 8;
mac[5] = mac_low;
efuse_crc = mac_high >> 16;
calc_crc = esp_crc8(mac, 6);
esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, 48);
esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY_CRC, &efuse_crc, 8);
uint8_t calc_crc = esp_crc8(mac, 6);
if (efuse_crc != calc_crc) {
// Small range of MAC addresses are accepted even if CRC is invalid.
// These addresses are reserved for Espressif internal use.
uint32_t mac_high = ((uint32_t)mac[0] << 8) | mac[1];
if ((mac_high & 0xFFFF) == 0x18fe) {
uint32_t mac_low = ((uint32_t)mac[2] << 24) | ((uint32_t)mac[3] << 16) | ((uint32_t)mac[4] << 8) | mac[5];
if ((mac_low >= 0x346a85c7) && (mac_low <= 0x346a85f8)) {
return ESP_OK;
}

View File

@@ -316,6 +316,7 @@
#define EFUSE_CODING_SCHEME_VAL_NONE 0x0
#define EFUSE_CODING_SCHEME_VAL_34 0x1
#define EFUSE_CODING_SCHEME_VAL_REPEAT 0x2
#define EFUSE_BLK0_WDATA0_REG (DR_REG_EFUSE_BASE + 0x01c)
/* EFUSE_FLASH_CRYPT_CNT : R/W ;bitpos:[27:20] ;default: 8'b0 ; */

View File

@@ -191,6 +191,8 @@ INPUT = \
### esp_event, Event Loop Library
../../components/esp_event/include/esp_event.h \
../../components/esp_event/include/esp_event_base.h \
### eFuse Manager
../../components/efuse/include/esp_efuse.h \
### ESP Pthread parameters
../../components/pthread/include/esp_pthread.h \
###

View File

@@ -0,0 +1,331 @@
eFuse Manager
=============
Introduction
------------
The eFuse Manager library is designed to structure access to eFuse bits and make using these easy. This library operates eFuse bits by a structure name wich assigned in eFuse table. This sections introduces some concepts used by eFuse Manager.
Hardware description
--------------------
The ESP32 has a number of eFuses which can store system and user parameters. Each eFuse is a one-bit field which can be programmed to 1 after which it cannot be reverted back to 0.
Some of system parameters are using these eFuse bits directly by hardware modules and have special place (for example EFUSE_BLK0). For more details see `ESP32 Technical Reference Manual <https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_ in part 20 eFuse controller. Some eFuse bits are available for user applications.
ESP32 has 4 eFuse blocks each of the size of 256 bits (not all bits are available):
* EFUSE_BLK0 is used entirely for system purposes;
* EFUSE_BLK1 is used for flash encrypt key. If not using that Flash Encryption feature, they can be used for another purpose;
* EFUSE_BLK2 is used for security boot key. If not using that Secure Boot feature, they can be used for another purpose;
* EFUSE_BLK3 can be partially reserved for the custom MAC address, or used entirely for user application. Note that some bits are already used in IDF.
Each block is divided into 8 32-bits registers.
eFuse Manager component
-----------------------
The component has API functions for reading and writing fields. Access to the fields is carried out through the structures that describe the location of the eFuse bits in the blocks. The component provides the ability to form fields of any length and from any number of individual bits. The description of the fields is made in a CSV file in a table form. To generate from a tabular form (CSV file) in the C-source uses the tool `efuse_table_gen.py`. The tool checks the CSV file for uniqueness of field names and bit intersection, in case of using a `custom` file from the user's project directory, the utility will check with the `common` CSV file.
CSV files:
* common (`esp_efuse_table.csv`) - contains eFuse fields which are used inside the IDF. C-source generation should be done manually when changing this file (run command 'make efuse_common_table' or `idf.py efuse_common_table`). Note that changes in this file can lead to incorrect operation.
* custom - (optional and can be enabled by :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains eFuse fields that are used by the user in their application. C-source generation should be done manually when changing this file (run command 'make efuse_custom_table' or `idf.py efuse_custom_table`).
Description CSV file
--------------------
The CSV file contains a description of the eFuse fields. In the simple case, one field has one line of description.
Table header:
::
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count(1..256), comment
Individual params in CSV file the following meanings:
field_name
Name of field. The prefix `ESP_EFUSE_` will be added to the name, and this field name will be available in the code. This name will be used to access the fields. The name must be unique for all fields. If the line has an empty name, then this line is combined with the previous field. This allows you to set an arbitrary order of bits in the field, and expand the field as well (see ``MAC_FACTORY`` field in the common table).
efuse_block
Block number. It determines where the eFuse bits will be placed for this field. Available EFUSE_BLK0..EFUSE_BLK3.
bit_start
Start bit number (0..255). The bit_start field can be omitted. In this case, it will be set to bit_start + bit_count from the previous record, if it has the same efuse_block. Otherwise (if efuse_block is different, or this is the first entry), an error will be generated.
bit_count
The number of bits to use in this field (1..-). This parameter can not be omitted. This field also may be ``MAX_BLK_LEN`` in this case, the field length will have the maximum block length, taking into account the coding scheme (applicable for ``ESP_EFUSE_SECURE_BOOT_KEY`` and ``ESP_EFUSE_ENCRYPT_FLASH_KEY`` fields). The value ``MAX_BLK_LEN`` depends on :envvar:`CONFIG_EFUSE_MAX_BLK_LEN`, will be replaced with "None" - 256, "3/4" - 192, "REPEAT" - 128.
comment
This param is using for comment field, it also move to C-header file. The comment field can be omitted.
If a non-sequential bit order is required to describe a field, then the field description in the following lines should be continued without specifying a name, this will indicate that it belongs to one field. For example two fields MAC_FACTORY and MAC_FACTORY_CRC:
::
# Factory MAC address #
#######################
MAC_FACTORY, EFUSE_BLK0, 72, 8, Factory MAC addr [0]
, EFUSE_BLK0, 64, 8, Factory MAC addr [1]
, EFUSE_BLK0, 56, 8, Factory MAC addr [2]
, EFUSE_BLK0, 48, 8, Factory MAC addr [3]
, EFUSE_BLK0, 40, 8, Factory MAC addr [4]
, EFUSE_BLK0, 32, 8, Factory MAC addr [5]
MAC_FACTORY_CRC, EFUSE_BLK0, 80, 8, CRC8 for factory MAC address
This field will available in code as ESP_EFUSE_MAC_FACTORY and ESP_EFUSE_MAC_FACTORY_CRC.
efuse_table_gen.py tool
-----------------------
The tool is designed to generate C-source files from CSV file and validate fields. First of all, the check is carried out on the uniqueness of the names and overlaps of the field bits. If an additional `custom` file is used, it will be checked with the existing `common` file (esp_efuse_table.csv). In case of errors, a message will be displayed and the string that caused the error. C-source files contain structures of type `esp_efuse_desc_t`.
To generate a `common` files, use the following command 'make efuse_common_table' or `idf.py efuse_common_table` or:
::
cd $IDF_PATH/components/efuse/
./efuse_table_gen.py esp32/esp_efuse_table.csv
After generation in the folder `esp32` create:
* `esp_efuse_table.c` file.
* In `include` folder `esp_efuse_table.c` file.
To generate a `custom` files, use the following command 'make efuse_custom_table' or `idf.py efuse_custom_table` or:
::
cd $IDF_PATH/components/efuse/
./efuse_table_gen.py esp32/esp_efuse_table.csv PROJECT_PATH/main/esp_efuse_custom_table.csv
After generation in the folder PROJECT_PATH/main create:
* `esp_efuse_custom_table.c` file.
* In `include` folder `esp_efuse_custom_table.c` file.
To use the generated fields, you need to include two files:
::
#include "esp_efuse.h"
#include "esp_efuse_table.h" or "esp_efuse_custom_table.h"
Support coding scheme
---------------------
eFuse have three coding schemes:
* ``None`` (value 0).
* ``3/4`` (value 1).
* ``Repeat`` (value 2).
The coding scheme affects only EFUSE_BLK1, EFUSE_BLK2 and EFUSE_BLK3 blocks. EUSE_BLK0 block always has a coding scheme ``None``.
Coding changes the number of bits that can be written into a block, the block length is constant 256, some of these bits are used for encoding and are not used.
When using a coding scheme, the length of the payload that can be written is limited (for more details ``20.3.1.3 System Parameter coding_scheme``):
* None 256 bits.
* 3/4 192 bits.
* Repeat 128 bits.
You can find out the coding scheme of your chip:
* run a ``espefuse.py -p COM4 summary`` command.
* from ``esptool`` utility logs (during flashing).
* calling the function in the code :cpp:func:`esp_efuse_get_coding_scheme` for the EFUSE_BLK3 block.
eFuse tables must always comply with the coding scheme in the chip. There is an :envvar:`EFUSE_CODE_SCHEME_SELECTOR` option to select the coding type for tables in a Kconfig. When generating source files, if your tables do not follow the coding scheme, an error message will be displayed. Adjust the length or offset fields.
If your program was compiled with ``None`` encoding and ``3/4`` is used in the chip, then the ``ESP_ERR_CODING`` error may occur when calling the eFuse API (the field is outside the block boundaries). If the field matches the new block boundaries, then the API will work without errors.
Also, 3/4 coding scheme imposes restrictions on writing bits belonging to one coding unit. The whole block with a length of 256 bits is divided into 4 coding units, and in each coding unit there are 6 bytes of useful data and 2 service bytes. These 2 service bytes contain the checksum of the previous 6 data bytes.
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.
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
---------
Access to the fields is via a pointer to the description structure. API functions have some basic operation:
* :cpp:func:`esp_efuse_read_field_blob` - returns an array of read eFuse bits.
* :cpp:func:`esp_efuse_read_field_cnt` - returns the number of bits programmed as "1".
* :cpp:func:`esp_efuse_write_field_blob` - writes an array.
* :cpp:func:`esp_efuse_write_field_cnt` - writes a required count of bits as "1".
* :cpp:func:`esp_efuse_get_field_size` - returns the number of bits by the field name.
* :cpp:func:`esp_efuse_read_reg` - returns value of eFuse register.
* :cpp:func:`esp_efuse_write_reg` - writes value to eFuse register.
* :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.
For frequently used fields, special functions are made, like this :cpp:func:`esp_efuse_get_chip_ver`, :cpp:func:`esp_efuse_get_pkg_ver`.
How add a new field
-------------------
1. Find a free bits for field. Show `esp_efuse_table.csv` file or run ``make show_efuse_table`` or ``idf.py show_efuse_table`` or the next command:
::
$ ./efuse_table_gen.py esp32/esp_efuse_table.csv --info
eFuse coding scheme: NONE
# field_name efuse_block bit_start bit_count
1 WR_DIS_FLASH_CRYPT_CNT EFUSE_BLK0 2 1
2 WR_DIS_BLK1 EFUSE_BLK0 7 1
3 WR_DIS_BLK2 EFUSE_BLK0 8 1
4 WR_DIS_BLK3 EFUSE_BLK0 9 1
5 RD_DIS_BLK1 EFUSE_BLK0 16 1
6 RD_DIS_BLK2 EFUSE_BLK0 17 1
7 RD_DIS_BLK3 EFUSE_BLK0 18 1
8 FLASH_CRYPT_CNT EFUSE_BLK0 20 8
9 MAC_FACTORY EFUSE_BLK0 32 8
10 MAC_FACTORY EFUSE_BLK0 40 8
11 MAC_FACTORY EFUSE_BLK0 48 8
12 MAC_FACTORY EFUSE_BLK0 56 8
13 MAC_FACTORY EFUSE_BLK0 64 8
14 MAC_FACTORY EFUSE_BLK0 72 8
15 MAC_FACTORY_CRC EFUSE_BLK0 80 8
16 CHIP_VER_DIS_APP_CPU EFUSE_BLK0 96 1
17 CHIP_VER_DIS_BT EFUSE_BLK0 97 1
18 CHIP_VER_PKG EFUSE_BLK0 105 3
19 CHIP_CPU_FREQ_LOW EFUSE_BLK0 108 1
20 CHIP_CPU_FREQ_RATED EFUSE_BLK0 109 1
21 CHIP_VER_REV1 EFUSE_BLK0 111 1
22 ADC_VREF_AND_SDIO_DREF EFUSE_BLK0 136 6
23 XPD_SDIO_REG EFUSE_BLK0 142 1
24 SDIO_TIEH EFUSE_BLK0 143 1
25 SDIO_FORCE EFUSE_BLK0 144 1
26 ENCRYPT_CONFIG EFUSE_BLK0 188 4
27 CONSOLE_DEBUG_DISABLE EFUSE_BLK0 194 1
28 ABS_DONE_0 EFUSE_BLK0 196 1
29 DISABLE_JTAG EFUSE_BLK0 198 1
30 DISABLE_DL_ENCRYPT EFUSE_BLK0 199 1
31 DISABLE_DL_DECRYPT EFUSE_BLK0 200 1
32 DISABLE_DL_CACHE EFUSE_BLK0 201 1
33 ENCRYPT_FLASH_KEY EFUSE_BLK1 0 256
34 SECURE_BOOT_KEY EFUSE_BLK2 0 256
35 MAC_CUSTOM_CRC EFUSE_BLK3 0 8
36 MAC_CUSTOM EFUSE_BLK3 8 48
37 ADC1_TP_LOW EFUSE_BLK3 96 7
38 ADC1_TP_HIGH EFUSE_BLK3 103 9
39 ADC2_TP_LOW EFUSE_BLK3 112 7
40 ADC2_TP_HIGH EFUSE_BLK3 119 9
41 SECURE_VERSION EFUSE_BLK3 128 32
42 MAC_CUSTOM_VER EFUSE_BLK3 184 8
Used bits in eFuse table:
EFUSE_BLK0
[2 2] [7 9] [16 18] [20 27] [32 87] [96 97] [105 109] [111 111] [136 144] [188 191] [194 194] [196 196] [198 201]
EFUSE_BLK1
[0 255]
EFUSE_BLK2
[0 255]
EFUSE_BLK3
[0 55] [96 159] [184 191]
Note: Not printed ranges are free for using. (bits in EFUSE_BLK0 are reserved for Espressif)
Parsing eFuse CSV input file $IDF_PATH/components/efuse/esp32/esp_efuse_table.csv ...
Verifying eFuse table...
The number of bits not included in square brackets is free (bits in EFUSE_BLK0 are reserved for Espressif). All fields are checked for overlapping.
2. Fill a line for field: field_name, efuse_block, bit_start, bit_count, comment.
3. Run a ``show_efuse_table`` command to check eFuse table. To generate source files run ``efuse_common_table`` or ``efuse_custom_table`` command.
Debug eFuse & Unit tests
------------------------
eFuse manager have option :envvar:`CONFIG_EFUSE_VIRTUAL` in Kconfig which will make an operation write is virtual. It can help to debug app and unit tests.
esptool have an useful tool for reading/writing ESP32 eFuse bits - `espefuse.py <https://github.com/espressif/esptool/wiki/espefuse>`_.
::
espefuse.py -p COM4 summary
espefuse.py v2.3.1
Connecting........_
Security fuses:
FLASH_CRYPT_CNT Flash encryption mode counter = 0 R/W (0x0)
FLASH_CRYPT_CONFIG Flash encryption config (key tweak bits) = 0 R/W (0x0)
CONSOLE_DEBUG_DISABLE Disable ROM BASIC interpreter fallback = 1 R/W (0x1)
ABS_DONE_0 secure boot enabled for bootloader = 0 R/W (0x0)
ABS_DONE_1 secure boot abstract 1 locked = 0 R/W (0x0)
JTAG_DISABLE Disable JTAG = 0 R/W (0x0)
DISABLE_DL_ENCRYPT Disable flash encryption in UART bootloader = 0 R/W (0x0)
DISABLE_DL_DECRYPT Disable flash decryption in UART bootloader = 0 R/W (0x0)
DISABLE_DL_CACHE Disable flash cache in UART bootloader = 0 R/W (0x0)
BLK1 Flash encryption key
= 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLK2 Secure boot key
= 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLK3 Variable Block 3
= 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa 87 02 91 00 00 00 00 00 00 00 00 00 00 00 00 R/W
Efuse fuses:
WR_DIS Efuse write disable mask = 0 R/W (0x0)
RD_DIS Efuse read disablemask = 0 R/W (0x0)
CODING_SCHEME Efuse variable block length scheme = 1 R/W (0x1) (3/4)
KEY_STATUS Usage of efuse block 3 (reserved) = 0 R/W (0x0)
Config fuses:
XPD_SDIO_FORCE Ignore MTDI pin (GPIO12) for VDD_SDIO on reset = 0 R/W (0x0)
XPD_SDIO_REG If XPD_SDIO_FORCE, enable VDD_SDIO reg on reset = 0 R/W (0x0)
XPD_SDIO_TIEH If XPD_SDIO_FORCE & XPD_SDIO_REG, 1=3.3V 0=1.8V = 0 R/W (0x0)
SPI_PAD_CONFIG_CLK Override SD_CLK pad (GPIO6/SPICLK) = 0 R/W (0x0)
SPI_PAD_CONFIG_Q Override SD_DATA_0 pad (GPIO7/SPIQ) = 0 R/W (0x0)
SPI_PAD_CONFIG_D Override SD_DATA_1 pad (GPIO8/SPID) = 0 R/W (0x0)
SPI_PAD_CONFIG_HD Override SD_DATA_2 pad (GPIO9/SPIHD) = 0 R/W (0x0)
SPI_PAD_CONFIG_CS0 Override SD_CMD pad (GPIO11/SPICS0) = 0 R/W (0x0)
DISABLE_SDIO_HOST Disable SDIO host = 0 R/W (0x0)
Identity fuses:
MAC MAC Address
= 84:0d:8e:18:8e:44 (CRC ad OK) R/W
CHIP_VER_REV1 Silicon Revision 1 = 1 R/W (0x1)
CHIP_VERSION Reserved for future chip versions = 2 R/W (0x2)
CHIP_PACKAGE Chip package identifier = 0 R/W (0x0)
Calibration fuses:
BLK3_PART_RESERVE BLOCK3 partially served for ADC calibration data = 1 R/W (0x1)
ADC_VREF Voltage reference calibration = 1114 R/W (0x2)
ADC1_TP_LOW ADC1 150mV reading = 346 R/W (0x11)
ADC1_TP_HIGH ADC1 850mV reading = 3285 R/W (0x5)
ADC2_TP_LOW ADC2 150mV reading = 449 R/W (0x7)
ADC2_TP_HIGH ADC2 850mV reading = 3362 R/W (0x1f5)
Flash voltage (VDD_SDIO) determined by GPIO12 on reset (High for 1.8V, Low/NC for 3.3V).
To get a dump for all eFuse registers.
::
espefuse.py -p COM4 dump
$ espefuse.py -p COM4 dump
espefuse.py v2.3.1
Connecting........__
EFUSE block 0:
00000000 c403bb68 0082240a 00000000 00000035 00000000 00000000
EFUSE block 1:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
EFUSE block 2:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
EFUSE block 3:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
.. include:: /_build/inc/esp_efuse.inc

View File

@@ -11,6 +11,7 @@ System API
Himem (large external SPI RAM) API <himem>
Interrupt Allocation <intr_alloc>
Watchdogs <wdts>
eFuse Manager <efuse>
Inter-Processor Call <ipc>
High Resolution Timer <esp_timer>
Logging <log>

View File

@@ -0,0 +1 @@
.. include:: ../../../en/api-reference/system/efuse.rst

View File

@@ -5,6 +5,8 @@ components/espcoredump/espcoredump.py
components/heap/test_multi_heap_host/test_all_configs.sh
components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py
components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py
components/efuse/efuse_table_gen.py
components/efuse/test_efuse_host/efuse_tests.py
components/partition_table/gen_esp32part.py
components/partition_table/parttool.py
components/app_update/gen_empty_partition.py

View File

@@ -422,6 +422,9 @@ ACTIONS = {
"bootloader-flash": (flash, ["bootloader"], ["erase_flash"]),
"app": (build_target, [], ["clean", "fullclean", "reconfigure"]),
"app-flash": (flash, ["app"], ["erase_flash"]),
"efuse_common_table": (build_target, [], ["reconfigure"]),
"efuse_custom_table": (build_target, [], ["reconfigure"]),
"show_efuse_table": (build_target, [], ["reconfigure"]),
"partition_table": (build_target, [], ["reconfigure"]),
"partition_table-flash": (flash, ["partition_table"], ["erase_flash"]),
"flash": (flash, ["all"], ["erase_flash"]),

View File

@@ -28,5 +28,6 @@ CONFIG_ESP_TIMER_PROFILING=y
CONFIG_ADC2_DISABLE_DAC=n
CONFIG_WARN_WRITE_STRINGS=y
CONFIG_SPI_MASTER_IN_IRAM=y
CONFIG_EFUSE_VIRTUAL=y
CONFIG_SPIRAM_BANKSWITCH_ENABLE=n
CONFIG_FATFS_ALLOC_EXTRAM_FIRST=y