efuse: Add API efuse

Added support 3/4 coding scheme
This commit is contained in:
Konstantin Kondrashov 2018-11-19 11:46:21 +08:00 committed by bot
parent 91676b8620
commit 693a5c209b
23 changed files with 3579 additions and 0 deletions

View file

@ -0,0 +1,54 @@
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()
###################
# Make common files esp_efuse_table.c and include/esp_efuse_table.h files.
# The generated files are used in the bootloader and application space.
# To generate new *.c/*.h files run the command manually "make efuse_common_table".
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})
# custom gen header 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 "${PROJECT_PATH}")
add_custom_target(efuse_custom_table ALL
COMMAND ${CMAKE_COMMAND} -E echo "Efuse CSV ${EFUSE_CUSTOM_TABLE_CSV_PATH} does not exist. Either change efuse table file in menuconfig or create this input file."
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt"
COMMAND ${CMAKE_COMMAND} -P ${IDF_PATH}/tools/cmake/scripts/fail.cmake)
string(REPLACE ".csv" ".c" HEADER_CUSTOM ${EFUSE_CUSTOM_TABLE_CSV_PATH})
add_custom_command(OUTPUT ${HEADER_CUSTOM}
COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py"
${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH}
DEPENDS ${EFUSE_CUSTOM_TABLE_CSV_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py"
VERBATIM)
if(EXISTS ${EFUSE_CUSTOM_TABLE_CSV_PATH})
add_custom_target(efuse_custom_table ALL DEPENDS ${HEADER_CUSTOM} ${EFUSE_CUSTOM_TABLE_CSV_PATH})
endif()
endif()#if(${CONFIG_EFUSE_CUSTOM_TABLE})
###################
# 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})

37
components/efuse/Kconfig Normal file
View file

@ -0,0 +1,37 @@
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" if 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 "Emulate eFuse work"
default n
help
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
prompt "eFuse Code Scheme"
default EFUSE_CODE_SCHEME_NONE
help
Selector eFuse code scheme.
config EFUSE_CODE_SCHEME_NONE
bool "None"
config EFUSE_CODE_SCHEME_3_4
bool "3/4"
config EFUSE_CODE_SCHEME_REPEAT
bool "Repeat"
endchoice
endmenu

View file

@ -0,0 +1,48 @@
#
# eFuse Manager ganeretes header file.
#
# .PHONY: efuse_table efuse_custom_table efuse_common_table efuse_test_table show_efuse_table
GEN_EFUSE_TABLE := $(PYTHON) $(COMPONENT_PATH)/efuse_table_gen.py
efuse_table: efuse_custom_table
###################
# Make common files esp_efuse_table.c and include/esp_efuse_table.h files.
# The generated files are used in the bootloader and application space.
# To generate new *.c/*.h files run the command manually "make efuse_common_table".
SOC_NAME := $(IDF_TARGET)
EFUSE_COMMON_TABLE_CSV_PATH := $(COMPONENT_PATH)/$(SOC_NAME)/esp_efuse_table.csv
efuse_common_table:
$(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH)
###################
# Make custom files
# Changes in esp_efuse_custom_table.csv file lead to regeneration of esp_efuse_custom_table.c and include/esp_efuse_custom_table.h files.
# The generated files are used only in the application.
ifdef IS_BOOTLOADER_BUILD
efuse_custom_table:
else
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_OUT_PATH := $(call dequote,$(abspath $(call dequote, $(BUILD_DIR_BASE))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME))))
efuse_custom_table: $(EFUSE_CUSTOM_TABLE_OUT_PATH:.csv=.o)
$(EFUSE_CUSTOM_TABLE_OUT_PATH:.csv=.o): $(EFUSE_CUSTOM_TABLE_CSV_PATH)
@echo "$(EFUSE_CUSTOM_TABLE_OUT_PATH)"
@echo "$(EFUSE_CUSTOM_TABLE_CSV_PATH)"
$(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH)
else
efuse_custom_table:
endif
endif
###################
# 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)

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,415 @@
#!/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 struct
import sys
import hashlib
import binascii
import ntpath
__version__ = '1.0'
quiet = False
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 = ""
@classmethod
def from_csv(cls, csv_contents):
res = FuseTable()
res.md5_digest = res.calc_md5(csv_contents)
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_enfl_error = 0
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()
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 == True:
raise InputError("Field names must be unique")
def verify(self):
'''list_field_names = []'''
for p in self:
p.verify()
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, csv_contents):
return hashlib.md5(csv_contents).hexdigest()
def show_range_used_bits(self):
# print used and free bits
rows = ''
rows += 'Sorted efuse table:\n'
num = 1
for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)):
rows += "#%d \t%s \t\t%s \t\t%d \t\t%d" % (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.\n'
return rows
def to_header(self, file_name):
rows = [ copyright ]
rows += [ "#ifdef __cplusplus",
'extern "C" {',
"#endif",
"",
"",
"// md5_digest " + self.md5_digest,
"// This file was generated automatically 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 build system will generate this header file",
"// To show efuse_table run the command 'make 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 "esp_efuse.h"',
'#include "' + file_name + '.h"',
"",
"// md5_digest " + self.md5_digest,
"// This file was generated automatically 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 build system will generate this header file",
"// To show efuse_table run the command 'make show_efuse_table'.",
"",
""]
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.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_num(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_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 != "EFUSE_BLK0" and strval != "EFUSE_BLK1" and strval != "EFUSE_BLK2" and strval != "EFUSE_BLK3":
raise InputError("Field 'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3")
return strval
def verify(self):
'''if self.field_name is None:
raise ValidationError(self, "field_name field is not set")'''
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")
max_bits = 256
if self.efuse_block == "EFUSE_BLK0":
max_bits = 224
if self.bit_start + self.bit_count > max_bits:
raise ValidationError(self, "The field is outside the boundaries of the %s block" % (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 to_struct(self, debug):
start = " {"
if (debug == True):
start = " {" + '"' + self.field_name + '" ,'
return ", ".join([start + self.efuse_block,
str(self.bit_start),
str(self.bit_count) + "}, \t // " + self.comment])
def process_input_file(file):
status("Parsing efuse CSV input file " + file.name + " ...")
input = file.read()
table = FuseTable.from_csv(input)
status("Verifying efuse table...")
table.verify()
return table
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:
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")
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)
f.close()
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)
f.close()
def main():
global quiet
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('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('rb'))
parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('rb'), nargs='?', default=None)
args = parser.parse_args()
quiet = args.quiet
debug = args.debug
info = args.info
common_table = process_input_file(args.common_input)
if args.custom_input is not None:
custom_table = process_input_file(args.custom_input)
common_table += custom_table
common_table.verify()
if info == True:
output_table = common_table
else:
output_table = custom_table
name = args.custom_input.name
else:
output_table = common_table
name = args.common_input.name
output_table.verify()
# save files.
if info == False:
create_output_files(name, output_table, debug)
else:
print(output_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,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
#include "esp_efuse.h"
#include "esp_efuse_table.h"
// md5_digest 963d6d14dc4bd997fd5d4b9de351745d
// This file was generated automatically 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 build system will generate this header file
// To show efuse_table run the command 'make show_efuse_table'.
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, 256}, // Security boot. Key.,
};
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, 256}, // Flash encrypt. Key.,
};
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,
};
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.
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.
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
};

View file

@ -0,0 +1,80 @@
# field_name, | efuse_block, | bit_start, | bit_count, |comment #
# | (EFUSE_BLK0 | (0..255) | (1..256) | #
# | EFUSE_BLK1 | | | #
# | EFUSE_BLK2 | | | #
# | EFUSE_BLK3) | | | #
##########################################################################
# !!!!!!!!!!! #
# 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, 256, Security boot. Key.
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, 256, Flash encrypt. Key.
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
Can't render this file because it contains an unexpected character in line 8 and column 53.

View file

@ -0,0 +1,66 @@
// 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 963d6d14dc4bd997fd5d4b9de351745d
// This file was generated automatically 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 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_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[];
#ifdef __cplusplus
}
#endif

View file

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

View file

@ -0,0 +1,294 @@
// 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; /**< Block of eFuse */
uint16_t bit_start; /**< Start bit [0..255] */
uint16_t bit_count; /**< Length of bit field [1..256]*/
} 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 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.
*/
esp_err_t 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.
*
* @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);
#ifdef __cplusplus
}
#endif
#endif // _ESP_EFUSE_MANAGER_H_

View file

@ -0,0 +1,214 @@
// 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"
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;
}
// get the length of the field in bits
int esp_efuse_get_field_size(const esp_efuse_desc_t* field[])
{
assert(field != NULL);
int bits_counter = 0;
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

@ -0,0 +1,117 @@
// 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 "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 "soc/efuse_reg.h"
#include "bootloader_random.h"
const static char *TAG = "efuse";
// Contains functions that provide access to efuse fields which are often used in IDF.
// 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)
{
esp_efuse_utility_burn_efuses();
}
// Reset efuse write registers
void esp_efuse_reset(void)
{
esp_efuse_utility_reset();
}
// Disable BASIC ROM Console via efuse
void esp_efuse_disable_basic_rom_console(void)
{
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_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len)
{
if (in_bytes == NULL || out_words == NULL || in_bytes_len % 6 != 0) {
return ESP_ERR_INVALID_ARG;
}
while (in_bytes_len > 0) {
uint8_t out[8];
uint8_t xor = 0;
uint8_t mul = 0;
for (int i = 0; i < 6; i++) {
xor ^= in_bytes[i];
mul += (i + 1) * __builtin_popcount(in_bytes[i]);
}
memcpy(out, in_bytes, 6); // Data bytes
out[6] = xor;
out[7] = mul;
memcpy(out_words, out, 8);
in_bytes_len -= 6;
in_bytes += 6;
out_words += 2;
}
return ESP_OK;
}
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
{
uint32_t buf[8];
uint8_t raw[24];
uint32_t coding_scheme = REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M;
if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE) {
bootloader_fill_random(buf, sizeof(buf));
} else { // 3/4 Coding Scheme
bootloader_fill_random(raw, sizeof(raw));
esp_err_t r = esp_efuse_apply_34_encoding(raw, buf, sizeof(raw));
assert(r == ESP_OK);
}
ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg);
for (int i = 0; i < 8; i++) {
ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]);
REG_WRITE(blk_wdata0_reg + 4*i, buf[i]);
}
bzero(buf, sizeof(buf));
bzero(raw, sizeof(raw));
}

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 dac4d84347dab29412b8b8713b4b0065
// 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 dac4d84347dab29412b8b8713b4b0065
// 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,546 @@
#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.");
}
}
#endif // #ifdef CONFIG_EFUSE_VIRTUAL

View file

@ -0,0 +1,204 @@
#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];
uint32_t encoded[8];
} coding_scheme_test_t;
/* Randomly generated byte strings, encoded and written to ESP32
using espefuse algorithm, then verified to have no encoding errors
and correct readback.
*/
static const coding_scheme_test_t coding_scheme_data[] = {
{
.unencoded = { 0x96, 0xa9, 0xab, 0xb2, 0xda, 0xdd, 0x21, 0xd2, 0x35, 0x22, 0xd3, 0x30, 0x3b, 0xf8, 0xcb, 0x77, 0x8d, 0x8d, 0xf4, 0x96, 0x25, 0xc4, 0xb9, 0x94 },
.encoded = { 0xb2aba996, 0x6821ddda, 0x2235d221, 0x430730d3, 0x77cbf83b, 0x627f8d8d, 0xc42596f4, 0x4dae94b9 },
},
{
.unencoded = { 0x0e, 0x6b, 0x1a, 0x1d, 0xa5, 0x9f, 0x24, 0xcf, 0x91, 0x5b, 0xe7, 0xe1, 0x7c, 0x0a, 0x6e, 0xdc, 0x5e, 0x8e, 0xb1, 0xec, 0xd1, 0xf3, 0x75, 0x48 },
.encoded = { 0x1d1a6b0e, 0x5e589fa5, 0x5b91cf24, 0x6127e1e7, 0xdc6e0a7c, 0x5d148e5e, 0xf3d1ecb1, 0x57424875 },
},
{
.unencoded = { 0x0a, 0x79, 0x5a, 0x1c, 0xb1, 0x45, 0x71, 0x2c, 0xb3, 0xda, 0x9e, 0xdc, 0x76, 0x27, 0xf5, 0xca, 0xe7, 0x00, 0x39, 0x95, 0x6c, 0x53, 0xc2, 0x07 },
.encoded = { 0x1c5a790a, 0x4ac145b1, 0xdab32c71, 0x6476dc9e, 0xcaf52776, 0x4d8900e7, 0x536c9539, 0x495607c2 },
},
{
.unencoded = { 0x76, 0x46, 0x88, 0x2d, 0x4c, 0xe1, 0x50, 0x5d, 0xd6, 0x7c, 0x41, 0x15, 0xc6, 0x1f, 0xd4, 0x60, 0x10, 0x15, 0x2a, 0x72, 0x2d, 0x89, 0x93, 0x13 },
.encoded = { 0x2d884676, 0x4838e14c, 0x7cd65d50, 0x4bf31541, 0x60d41fc6, 0x39681510, 0x892d722a, 0x497c1393 },
},
{
.unencoded = { 0x32, 0xbc, 0x40, 0x92, 0x13, 0x37, 0x1a, 0xae, 0xb6, 0x00, 0xed, 0x30, 0xb8, 0x82, 0xee, 0xfc, 0xcf, 0x6d, 0x7f, 0xc5, 0xfa, 0x0e, 0xdd, 0x84 },
.encoded = { 0x9240bc32, 0x49783713, 0x00b6ae1a, 0x46df30ed, 0xfcee82b8, 0x6e8a6dcf, 0x0efac57f, 0x571784dd },
},
{
.unencoded = { 0x29, 0xb3, 0x04, 0x95, 0xf2, 0x3c, 0x81, 0xe6, 0x5a, 0xf3, 0x42, 0x82, 0xd1, 0x79, 0xe2, 0x12, 0xbe, 0xc3, 0xd4, 0x10, 0x63, 0x66, 0x9f, 0xe3 },
.encoded = { 0x9504b329, 0x51c53cf2, 0xf35ae681, 0x460e8242, 0x12e279d1, 0x5825c3be, 0x666310d4, 0x5ebde39f },
},
{
.unencoded = { 0xda, 0xda, 0x71, 0x4a, 0x62, 0x33, 0xdd, 0x31, 0x87, 0xf3, 0x70, 0x12, 0x33, 0x3b, 0x3b, 0xe9, 0xed, 0xc4, 0x6e, 0x6a, 0xc7, 0xd5, 0x85, 0xfc },
.encoded = { 0x4a71dada, 0x4e6a3362, 0xf38731dd, 0x4bfa1270, 0xe93b3b33, 0x61f3c4ed, 0xd5c76a6e, 0x636ffc85 },
},
{
.unencoded = { 0x45, 0x64, 0x51, 0x34, 0x1c, 0x82, 0x81, 0x77, 0xf8, 0x89, 0xb1, 0x15, 0x82, 0x94, 0xdd, 0x64, 0xa2, 0x46, 0x0e, 0xfb, 0x1a, 0x70, 0x4b, 0x9f },
.encoded = { 0x34516445, 0x39da821c, 0x89f87781, 0x4f2315b1, 0x64dd9482, 0x474b46a2, 0x701afb0e, 0x5e4b9f4b },
},
{
.unencoded = { 0x89, 0x87, 0x15, 0xb6, 0x66, 0x34, 0x49, 0x18, 0x8b, 0x7b, 0xb2, 0xf6, 0x96, 0x1e, 0x2e, 0xf1, 0x03, 0x9d, 0x4e, 0x16, 0x32, 0xd6, 0x23, 0x22 },
.encoded = { 0xb6158789, 0x4eff3466, 0x7b8b1849, 0x63e5f6b2, 0xf12e1e96, 0x54c99d03, 0xd632164e, 0x42bd2223 },
},
{
.unencoded = { 0xa7, 0xa0, 0xb5, 0x21, 0xd2, 0xa3, 0x9f, 0x65, 0xa9, 0xeb, 0x72, 0xa2, 0x2e, 0xa6, 0xfb, 0x9c, 0x48, 0x7e, 0x68, 0x08, 0x7a, 0xb1, 0x4f, 0xbc },
.encoded = { 0x21b5a0a7, 0x4ce2a3d2, 0xeba9659f, 0x5868a272, 0x9cfba62e, 0x5fd97e48, 0xb17a0868, 0x5b58bc4f },
},
{
.unencoded = { 0xf7, 0x05, 0xe3, 0x6c, 0xb1, 0x55, 0xcb, 0x2f, 0x8d, 0x3e, 0x0b, 0x2e, 0x3e, 0xb7, 0x02, 0xf5, 0x91, 0xb1, 0xfe, 0x8b, 0x58, 0x50, 0xb2, 0x40 },
.encoded = { 0x6ce305f7, 0x569955b1, 0x3e8d2fcb, 0x56722e0b, 0xf502b73e, 0x535eb191, 0x50588bfe, 0x3a8f40b2 },
},
{
.unencoded = { 0x0f, 0x93, 0xb0, 0xd5, 0x60, 0xba, 0x40, 0x2a, 0x62, 0xa6, 0x92, 0x82, 0xb8, 0x91, 0x2c, 0xd7, 0x23, 0xdc, 0x6f, 0x7f, 0x2f, 0xbe, 0x41, 0xf5 },
.encoded = { 0xd5b0930f, 0x5123ba60, 0xa6622a40, 0x3bbe8292, 0xd72c91b8, 0x582ddc23, 0xbe2f7f6f, 0x6935f541 },
},
{
.unencoded = { 0x7f, 0x0c, 0x99, 0xde, 0xff, 0x2e, 0xd2, 0x1c, 0x48, 0x98, 0x70, 0x85, 0x15, 0x01, 0x2a, 0xfb, 0xcd, 0xf2, 0xa0, 0xf9, 0x0e, 0xbc, 0x9f, 0x0c },
.encoded = { 0xde990c7f, 0x6fe52eff, 0x98481cd2, 0x3deb8570, 0xfb2a0115, 0x61faf2cd, 0xbc0ef9a0, 0x55780c9f },
},
{
.unencoded = { 0x9a, 0x10, 0x92, 0x03, 0x81, 0xfe, 0x41, 0x57, 0x77, 0x02, 0xcb, 0x20, 0x67, 0xa4, 0x97, 0xf3, 0xf8, 0xc7, 0x0d, 0x65, 0xcd, 0xfc, 0x15, 0xef },
.encoded = { 0x0392109a, 0x4b64fe81, 0x02775741, 0x418820cb, 0xf397a467, 0x6998c7f8, 0xfccd650d, 0x6ba3ef15 },
},
};
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++) {
uint32_t result[8];
const coding_scheme_test_t *t = &coding_scheme_data[i];
printf("Test case %d...\n", i);
esp_err_t r = esp_efuse_apply_34_encoding(t->unencoded, result, sizeof(t->unencoded));
TEST_ASSERT_EQUAL_HEX(ESP_OK, r);
TEST_ASSERT_EQUAL_HEX32_ARRAY(t->encoded, result, 8);
// Do the same, 6 bytes at a time
for (int offs = 0; offs < sizeof(t->unencoded); offs += 6) {
bzero(result, sizeof(result));
r = esp_efuse_apply_34_encoding(t->unencoded + offs, result, 6);
TEST_ASSERT_EQUAL_HEX(ESP_OK, r);
TEST_ASSERT_EQUAL_HEX32_ARRAY(t->encoded + (offs / 6 * 2), result, 2);
}
}
}
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,295 @@
#!/usr/bin/env python
from __future__ import print_function, division
import unittest
import struct
import csv
import sys
import subprocess
import tempfile
import os
import StringIO
sys.path.append("..")
from efuse import *
'''
To run the test on local PC:
cd ~/esp/esp-idf/components/efuse/test_efuse_host/
./efuse_tests.py
'''
class CSVParserTests(unittest.TestCase):
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 = 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 = 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 = 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 = 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.assertRaisesRegexp(InputError, "Field names must be unique"):
t = 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 = 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 = FuseTable.from_csv(csv)
with self.assertRaisesRegexp(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.assertRaisesRegexp(InputError, "missing field name"):
t = 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.assertRaisesRegexp(InputError, "Field names must be unique"):
t = 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.assertRaisesRegexp(InputError, "empty"):
t = 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.assertRaisesRegexp(InputError, "Invalid field value"):
t = 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 = 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.assertRaisesRegexp(InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"):
t = 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
"""
t = FuseTable.from_csv(csv)
t.verify()
def test_field_blk0_size_is_more(self):
csv = """
# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment
name1, EFUSE_BLK0, 1, 224, Use for test name 1
name2, EFUSE_BLK1, 0, 256, Use for test name 2
"""
t = FuseTable.from_csv(csv)
with self.assertRaisesRegexp(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 = FuseTable.from_csv(csv)
with self.assertRaisesRegexp(InputError, "The field is outside the boundaries"):
t.verify()
class VerificationTests(unittest.TestCase):
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, 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 = 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)
if __name__ =="__main__":
unittest.main()