From bd219609556b8ee016d2ae27c25c9fb2acb92adf Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 16 Jul 2019 16:39:12 +0200 Subject: [PATCH 01/46] tools: Support sdkconfig.rename files from outside IDF in confgen.py --- docs/conf_common.py | 3 ++ make/project_config.mk | 5 +++ tools/cmake/kconfig.cmake | 11 ++++++ tools/kconfig_new/confgen.py | 59 +++++++++++++++------------------ tools/kconfig_new/config.env.in | 1 + tools/kconfig_new/confserver.py | 12 +++++-- 6 files changed, 56 insertions(+), 35 deletions(-) diff --git a/docs/conf_common.py b/docs/conf_common.py index 8fd13cbaf..505dab8a0 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -93,13 +93,16 @@ temp_sdkconfig_path = '{}/sdkconfig.tmp'.format(builddir) kconfigs = find_component_files("../../components", "Kconfig") kconfig_projbuilds = find_component_files("../../components", "Kconfig.projbuild") +sdkconfig_renames = find_component_files("../../components", "sdkconfig.rename") confgen_args = [sys.executable, "../../tools/kconfig_new/confgen.py", "--kconfig", "../../Kconfig", + "--sdkconfig-rename", "../../sdkconfig.rename", "--config", temp_sdkconfig_path, "--env", "COMPONENT_KCONFIGS={}".format(" ".join(kconfigs)), "--env", "COMPONENT_KCONFIGS_PROJBUILD={}".format(" ".join(kconfig_projbuilds)), + "--env", "COMPONENT_SDKCONFIG_RENAMES={}".format(" ".join(sdkconfig_renames)), "--env", "IDF_PATH={}".format(idf_path), "--output", "docs", kconfig_inc_path + '.in' ] diff --git a/make/project_config.mk b/make/project_config.mk index e590b401f..7eede5ebb 100644 --- a/make/project_config.mk +++ b/make/project_config.mk @@ -3,6 +3,7 @@ #Find all Kconfig files for all components COMPONENT_KCONFIGS := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/Kconfig)) COMPONENT_KCONFIGS_PROJBUILD := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/Kconfig.projbuild)) +COMPONENT_SDKCONFIG_RENAMES := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/sdkconfig.rename)) ifeq ($(OS),Windows_NT) # kconfiglib requires Windows-style paths for kconfig files @@ -17,6 +18,8 @@ KCONFIG_TOOL_DIR=$(IDF_PATH)/tools/kconfig # unless it's overriden (happens for bootloader) SDKCONFIG ?= $(PROJECT_PATH)/sdkconfig +SDKCONFIG_RENAME ?= $(IDF_PATH)/sdkconfig.rename + # SDKCONFIG_DEFAULTS is an optional file containing default # overrides (usually used for esp-idf examples) SDKCONFIG_DEFAULTS ?= $(PROJECT_PATH)/sdkconfig.defaults @@ -48,8 +51,10 @@ define RunConfGen $(PYTHON) $(IDF_PATH)/tools/kconfig_new/confgen.py \ --kconfig $(IDF_PATH)/Kconfig \ --config $(SDKCONFIG) \ + --sdkconfig-rename $(SDKCONFIG_RENAME) \ --env "COMPONENT_KCONFIGS=$(strip $(COMPONENT_KCONFIGS))" \ --env "COMPONENT_KCONFIGS_PROJBUILD=$(strip $(COMPONENT_KCONFIGS_PROJBUILD))" \ + --env "COMPONENT_SDKCONFIG_RENAMES=$(strip $(COMPONENT_SDKCONFIG_RENAMES))" \ --env "IDF_CMAKE=n" \ --output config ${SDKCONFIG} \ --output makefile $(SDKCONFIG_MAKEFILE) \ diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index 561c95ccd..d1d34234d 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -72,6 +72,7 @@ function(__kconfig_init) idf_build_get_property(idf_path IDF_PATH) idf_build_set_property(__ROOT_KCONFIG ${idf_path}/Kconfig) + idf_build_set_property(__ROOT_SDKCONFIG_RENAME ${idf_path}/sdkconfig.rename) idf_build_set_property(__OUTPUT_SDKCONFIG 1) endfunction() @@ -86,6 +87,8 @@ function(__kconfig_component_init component_target) __component_set_property(${component_target} KCONFIG "${kconfig}") file(GLOB kconfig "${component_dir}/Kconfig.projbuild") __component_set_property(${component_target} KCONFIG_PROJBUILD "${kconfig}") + file(GLOB sdkconfig_rename "${component_dir}/sdkconfig.rename") + __component_set_property(${component_target} SDKCONFIG_RENAME "${sdkconfig_rename}") endfunction() # @@ -100,12 +103,16 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) if(component_target IN_LIST build_component_targets) __component_get_property(kconfig ${component_target} KCONFIG) __component_get_property(kconfig_projbuild ${component_target} KCONFIG_PROJBUILD) + __component_get_property(sdkconfig_rename ${component_target} SDKCONFIG_RENAME) if(kconfig) list(APPEND kconfigs ${kconfig}) endif() if(kconfig_projbuild) list(APPEND kconfig_projbuilds ${kconfig_projbuild}) endif() + if(sdkconfig_rename) + list(APPEND sdkconfig_renames ${sdkconfig_rename}) + endif() endif() endforeach() @@ -118,6 +125,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) string(REPLACE ";" " " kconfigs "${kconfigs}") string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}") + string(REPLACE ";" " " sdkconfig_renames "${sdkconfig_renames}") # Place config-related environment arguments into config.env file # to work around command line length limits for execute_process @@ -135,11 +143,13 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) endif() idf_build_get_property(root_kconfig __ROOT_KCONFIG) + idf_build_get_property(root_sdkconfig_rename __ROOT_SDKCONFIG_RENAME) idf_build_get_property(python PYTHON) set(confgen_basecommand ${python} ${idf_path}/tools/kconfig_new/confgen.py --kconfig ${root_kconfig} + --sdkconfig-rename ${root_sdkconfig_rename} --config ${sdkconfig} ${defaults_arg} --env-file ${config_env_path}) @@ -231,6 +241,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) COMMAND ${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py --env-file ${config_env_path} --kconfig ${IDF_PATH}/Kconfig + --sdkconfig-rename ${root_sdkconfig_rename} --config ${sdkconfig} VERBATIM USES_TERMINAL) diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index e58f55efb..0af2be1bc 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -22,7 +22,6 @@ # limitations under the License. from __future__ import print_function import argparse -import fnmatch import json import os import os.path @@ -46,15 +45,15 @@ class DeprecatedOptions(object): _RE_DEP_OP_BEGIN = re.compile(_DEP_OP_BEGIN) _RE_DEP_OP_END = re.compile(_DEP_OP_END) - def __init__(self, config_prefix, path_rename_files, ignore_dirs=()): + def __init__(self, config_prefix, path_rename_files=[]): self.config_prefix = config_prefix # r_dic maps deprecated options to new options; rev_r_dic maps in the opposite direction - self.r_dic, self.rev_r_dic = self._parse_replacements(path_rename_files, ignore_dirs) + self.r_dic, self.rev_r_dic = self._parse_replacements(path_rename_files) # note the '=' at the end of regex for not getting partial match of configs self._RE_CONFIG = re.compile(r'{}(\w+)='.format(self.config_prefix)) - def _parse_replacements(self, repl_dir, ignore_dirs): + def _parse_replacements(self, repl_paths): rep_dic = {} rev_rep_dic = {} @@ -64,31 +63,24 @@ class DeprecatedOptions(object): raise RuntimeError('Error in {} (line {}): Config {} is not prefixed with {}' ''.format(rep_path, line_number, string, self.config_prefix)) - for root, dirnames, filenames in os.walk(repl_dir): - for filename in fnmatch.filter(filenames, self._REN_FILE): - rep_path = os.path.join(root, filename) + for rep_path in repl_paths: + with open(rep_path) as f_rep: + for line_number, line in enumerate(f_rep, start=1): + sp_line = line.split() + if len(sp_line) == 0 or sp_line[0].startswith('#'): + # empty line or comment + continue + if len(sp_line) != 2 or not all(x.startswith(self.config_prefix) for x in sp_line): + raise RuntimeError('Syntax error in {} (line {})'.format(rep_path, line_number)) + if sp_line[0] in rep_dic: + raise RuntimeError('Error in {} (line {}): Replacement {} exist for {} and new ' + 'replacement {} is defined'.format(rep_path, line_number, + rep_dic[sp_line[0]], sp_line[0], + sp_line[1])) - if rep_path.startswith(ignore_dirs): - print('Ignoring: {}'.format(rep_path)) - continue - - with open(rep_path) as f_rep: - for line_number, line in enumerate(f_rep, start=1): - sp_line = line.split() - if len(sp_line) == 0 or sp_line[0].startswith('#'): - # empty line or comment - continue - if len(sp_line) != 2 or not all(x.startswith(self.config_prefix) for x in sp_line): - raise RuntimeError('Syntax error in {} (line {})'.format(rep_path, line_number)) - if sp_line[0] in rep_dic: - raise RuntimeError('Error in {} (line {}): Replacement {} exist for {} and new ' - 'replacement {} is defined'.format(rep_path, line_number, - rep_dic[sp_line[0]], sp_line[0], - sp_line[1])) - - (dep_opt, new_opt) = (remove_config_prefix(x) for x in sp_line) - rep_dic[dep_opt] = new_opt - rev_rep_dic[new_opt] = dep_opt + (dep_opt, new_opt) = (remove_config_prefix(x) for x in sp_line) + rep_dic[dep_opt] = new_opt + rev_rep_dic[new_opt] = dep_opt return rep_dic, rev_rep_dic def get_deprecated_option(self, new_option): @@ -190,6 +182,10 @@ def main(): help='KConfig file with config item definitions', required=True) + parser.add_argument('--sdkconfig-rename', + help='File with deprecated Kconfig options', + required=False) + parser.add_argument('--output', nargs=2, action='append', help='Write output file (format and output filename)', metavar=('FORMAT', 'FILENAME'), @@ -235,10 +231,9 @@ def main(): raise RuntimeError("Defaults file not found: %s" % name) config.load_config(name, replace=False) - # don't collect rename options from examples because those are separate projects and no need to "stay compatible" - # with example projects - deprecated_options = DeprecatedOptions(config.config_prefix, path_rename_files=os.environ["IDF_PATH"], - ignore_dirs=(os.path.join(os.environ["IDF_PATH"], 'examples'))) + sdkconfig_renames = [args.sdkconfig_rename] if args.sdkconfig_rename else [] + sdkconfig_renames += os.environ.get("COMPONENT_SDKCONFIG_RENAMES", "").split() + deprecated_options = DeprecatedOptions(config.config_prefix, path_rename_files=sdkconfig_renames) # If config file previously exists, load it if args.config and os.path.exists(args.config): diff --git a/tools/kconfig_new/config.env.in b/tools/kconfig_new/config.env.in index d685c85d0..a066b4743 100644 --- a/tools/kconfig_new/config.env.in +++ b/tools/kconfig_new/config.env.in @@ -1,6 +1,7 @@ { "COMPONENT_KCONFIGS": "${kconfigs}", "COMPONENT_KCONFIGS_PROJBUILD": "${kconfig_projbuilds}", + "COMPONENT_SDKCONFIG_RENAMES": "${sdkconfig_renames}", "IDF_CMAKE": "y", "IDF_TARGET": "${idf_target}", "IDF_PATH": "${idf_path}" diff --git a/tools/kconfig_new/confserver.py b/tools/kconfig_new/confserver.py index 914a2dd73..2e0d24ad7 100755 --- a/tools/kconfig_new/confserver.py +++ b/tools/kconfig_new/confserver.py @@ -29,6 +29,10 @@ def main(): help='KConfig file with config item definitions', required=True) + parser.add_argument('--sdkconfig-rename', + help='File with deprecated Kconfig options', + required=False) + parser.add_argument('--env', action='append', default=[], help='Environment to set when evaluating the config file', metavar='NAME=VAL') @@ -62,12 +66,14 @@ def main(): env = json.load(args.env_file) os.environ.update(env) - run_server(args.kconfig, args.config) + run_server(args.kconfig, args.config, args.sdkconfig_rename) -def run_server(kconfig, sdkconfig, default_version=MAX_PROTOCOL_VERSION): +def run_server(kconfig, sdkconfig, sdkconfig_rename, default_version=MAX_PROTOCOL_VERSION): config = kconfiglib.Kconfig(kconfig) - deprecated_options = confgen.DeprecatedOptions(config.config_prefix, path_rename_files=os.environ["IDF_PATH"]) + sdkconfig_renames = [sdkconfig_rename] if sdkconfig_rename else [] + sdkconfig_renames += os.environ.get("COMPONENT_SDKCONFIG_RENAMES", "").split() + deprecated_options = confgen.DeprecatedOptions(config.config_prefix, path_rename_files=sdkconfig_renames) with tempfile.NamedTemporaryFile(mode='w+b') as f_o: with open(sdkconfig, mode='rb') as f_i: f_o.write(f_i.read()) From 4a0733c33c3fc7d4203a0a7c3f0982307472bc4a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 17 Jul 2019 12:24:29 +1000 Subject: [PATCH 02/46] test: Set timeout of libsodium ed25519_convert test to 60s Test takes 28s-29s to run in some configs, can fail in CI. --- components/libsodium/test/test_sodium.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/libsodium/test/test_sodium.c b/components/libsodium/test/test_sodium.c index 7a9f096da..5ab4b0edc 100644 --- a/components/libsodium/test/test_sodium.c +++ b/components/libsodium/test/test_sodium.c @@ -39,7 +39,7 @@ TEST_CASE("box tests", "[libsodium]") extern int ed25519_convert_xmain(); -TEST_CASE("ed25519_convert tests", "[libsodium]") +TEST_CASE("ed25519_convert tests", "[libsodium][timeout=60]") { printf("Running ed25519_convert\n"); TEST_ASSERT_EQUAL(0, ed25519_convert_xmain() ); From 8cd04c80f6c524119c373688a14e272c410d3ead Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 11 Apr 2019 21:06:15 +0800 Subject: [PATCH 03/46] efuse: set timing configuration before writing --- components/efuse/src/esp_efuse_utility.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/components/efuse/src/esp_efuse_utility.c b/components/efuse/src/esp_efuse_utility.c index 03ea26084..a4a4d6d87 100644 --- a/components/efuse/src/esp_efuse_utility.c +++ b/components/efuse/src/esp_efuse_utility.c @@ -15,6 +15,7 @@ #include "esp_efuse_utility.h" #include "soc/efuse_periph.h" +#include "esp32/clk.h" #include "esp_log.h" #include "assert.h" #include "sdkconfig.h" @@ -209,6 +210,25 @@ void esp_efuse_utility_burn_efuses(void) } } #else + // Update Efuse timing configuration + uint32_t apb_freq_mhz = esp_clk_apb_freq() / 1000000; + uint32_t clk_sel0, clk_sel1, dac_clk_div; + if (apb_freq_mhz <= 26) { + clk_sel0 = 250; + clk_sel1 = 255; + dac_clk_div = 52; + } else if (apb_freq_mhz <= 40) { + clk_sel0 = 160; + clk_sel1 = 255; + dac_clk_div = 80; + } else { + clk_sel0 = 80; + clk_sel1 = 128; + dac_clk_div = 100; + } + REG_SET_FIELD(EFUSE_DAC_CONF_REG, EFUSE_DAC_CLK_DIV, dac_clk_div); + REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL0, clk_sel0); + REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL1, clk_sel1); // 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); From e1ef0faccd97c4c38685152c76915b784828e066 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 18 Jul 2019 15:09:17 +1000 Subject: [PATCH 04/46] esptool: Bump to v2.7 https://github.com/espressif/esptool/releases/tag/v2.7 --- components/esptool_py/esptool | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index b4c418a5d..1319c49ad 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit b4c418a5d90c94863b44c8661b9332cf229b08b7 +Subproject commit 1319c49adb2fe99d2981151ff781930d6ed62729 From 91ce5db1727972ec793eccc0182cce10e6f5213c Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Wed, 10 Jul 2019 14:08:21 +0200 Subject: [PATCH 05/46] VFS: Support concurrent VFS select calls Closes https://github.com/espressif/esp-idf/issues/3392 --- components/vfs/include/esp_vfs.h | 4 +- components/vfs/test/test_vfs_select.c | 148 ++++++++++++----- components/vfs/vfs.c | 25 ++- components/vfs/vfs_uart.c | 231 ++++++++++++++------------ 4 files changed, 253 insertions(+), 155 deletions(-) diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index e4eafb417..2f39ca62f 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -236,7 +236,7 @@ typedef struct #endif // CONFIG_VFS_SUPPORT_TERMIOS /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */ - esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem); + esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args); /** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */ int (*socket_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); /** called by VFS to interrupt the socket_select call when select is activated from a non-socket VFS driver; set only for the socket driver */ @@ -246,7 +246,7 @@ typedef struct /** end_select is called to stop the I/O multiplexing and deinitialize the environment created by start_select for the given VFS */ void* (*get_socket_select_semaphore)(void); /** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */ - void (*end_select)(void); + esp_err_t (*end_select)(void *end_select_args); } esp_vfs_t; diff --git a/components/vfs/test/test_vfs_select.c b/components/vfs/test/test_vfs_select.c index bea17242e..2ce2270b8 100644 --- a/components/vfs/test/test_vfs_select.c +++ b/components/vfs/test/test_vfs_select.c @@ -31,6 +31,16 @@ typedef struct { xSemaphoreHandle sem; } test_task_param_t; +typedef struct { + fd_set *rdfds; + fd_set *wrfds; + fd_set *errfds; + int maxfds; + struct timeval *tv; + int select_ret; + xSemaphoreHandle sem; +} test_select_task_param_t; + static const char message[] = "Hello world!"; static int open_dummy_socket(void) @@ -420,73 +430,121 @@ TEST_CASE("poll() timeout", "[vfs]") deinit(uart_fd, socket_fd); } -static void select_task(void *param) +static void select_task(void *task_param) { - const test_task_param_t *test_task_param = param; - struct timeval tv = { - .tv_sec = 0, - .tv_usec = 100000, - }; + const test_select_task_param_t *param = task_param; - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(test_task_param->fd, &rfds); + int s = select(param->maxfds, param->rdfds, param->wrfds, param->errfds, param->tv); + TEST_ASSERT_EQUAL(param->select_ret, s); - int s = select(test_task_param->fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(0, s); //timeout - - if (test_task_param->sem) { - xSemaphoreGive(test_task_param->sem); + if (param->sem) { + xSemaphoreGive(param->sem); } vTaskDelete(NULL); } -TEST_CASE("concurent selects work", "[vfs]") +static void inline start_select_task(test_select_task_param_t *param) { - struct timeval tv = { - .tv_sec = 0, - .tv_usec = 100000,//irrelevant - }; + xTaskCreate(select_task, "select_task", 4*1024, (void *) param, 5, NULL); +} +TEST_CASE("concurrent selects work", "[vfs]") +{ int uart_fd, socket_fd; init(&uart_fd, &socket_fd); - const int dummy_socket_fd = open_dummy_socket(); - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(uart_fd, &rfds); + { + // Two tasks will wait for the same UART FD for reading and they will time-out - test_task_param_t test_task_param = { - .fd = uart_fd, - .sem = xSemaphoreCreateBinary(), - }; - TEST_ASSERT_NOT_NULL(test_task_param.sem); + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 100000, + }; - xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL); - vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() + fd_set rdfds1; + FD_ZERO(&rdfds1); + FD_SET(uart_fd, &rdfds1); - int s = select(uart_fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(-1, s); //this select should fail because two selects are accessing UART - //(the other one is waiting for the timeout) - TEST_ASSERT_EQUAL(EINTR, errno); + test_select_task_param_t param = { + .rdfds = &rdfds1, + .wrfds = NULL, + .errfds = NULL, + .maxfds = uart_fd + 1, + .tv = &tv, + .select_ret = 0, // expected timeout + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(param.sem); - TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS)); + fd_set rdfds2; + FD_ZERO(&rdfds2); + FD_SET(uart_fd, &rdfds2); + FD_SET(socket_fd, &rdfds2); + FD_SET(dummy_socket_fd, &rdfds2); - FD_ZERO(&rfds); - FD_SET(socket_fd, &rfds); + start_select_task(¶m); + vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() - test_task_param.fd = dummy_socket_fd; + int s = select(MAX(MAX(uart_fd, dummy_socket_fd), socket_fd) + 1, &rdfds2, NULL, NULL, &tv); + TEST_ASSERT_EQUAL(0, s); // timeout here as well - xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL); - vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(param.sem); + } - s = select(socket_fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(0, s); //this select should timeout as well as the concurrent one because - //concurrent socket select should work + { + // One tasks waits for UART reading and one for writing. The former will be successful and latter will + // time-out. - TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS)); - vSemaphoreDelete(test_task_param.sem); + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 100000, + }; + + fd_set wrfds1; + FD_ZERO(&wrfds1); + FD_SET(uart_fd, &wrfds1); + + test_select_task_param_t param = { + .rdfds = NULL, + .wrfds = &wrfds1, + .errfds = NULL, + .maxfds = uart_fd + 1, + .tv = &tv, + .select_ret = 0, // expected timeout + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(param.sem); + + start_select_task(¶m); + + fd_set rdfds2; + FD_ZERO(&rdfds2); + FD_SET(uart_fd, &rdfds2); + FD_SET(socket_fd, &rdfds2); + FD_SET(dummy_socket_fd, &rdfds2); + + const test_task_param_t send_param = { + .fd = uart_fd, + .delay_ms = 50, + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(send_param.sem); + start_task(&send_param); // This task will write to UART which will be detected by select() + + int s = select(MAX(MAX(uart_fd, dummy_socket_fd), socket_fd) + 1, &rdfds2, NULL, NULL, &tv); + TEST_ASSERT_EQUAL(1, s); + TEST_ASSERT(FD_ISSET(uart_fd, &rdfds2)); + TEST_ASSERT_UNLESS(FD_ISSET(socket_fd, &rdfds2)); + TEST_ASSERT_UNLESS(FD_ISSET(dummy_socket_fd, &rdfds2)); + + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(param.sem); + + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(send_param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(send_param.sem); + } deinit(uart_fd, socket_fd); close(dummy_socket_fd); diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index c604b0973..ed4db5e7e 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -794,13 +794,16 @@ int truncate(const char *path, off_t length) return ret; } -static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple) +static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, void **driver_args) { for (int i = 0; i < end_index; ++i) { const vfs_entry_t *vfs = get_vfs_for_index(i); const fds_triple_t *item = &vfs_fds_triple[i]; if (vfs && vfs->vfs.end_select && item->isset) { - vfs->vfs.end_select(); + esp_err_t err = vfs->vfs.end_select(driver_args[i]); + if (err != ESP_OK) { + ESP_LOGD(TAG, "end_select failed: %s", esp_err_to_name(err)); + } } } } @@ -947,6 +950,15 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds } } + void **driver_args = calloc(s_vfs_count, sizeof(void *)); + + if (driver_args == NULL) { + free(vfs_fds_triple); + __errno_r(r) = ENOMEM; + ESP_LOGD(TAG, "calloc is unsuccessful for driver args"); + return -1; + } + for (int i = 0; i < s_vfs_count; ++i) { const vfs_entry_t *vfs = get_vfs_for_index(i); fds_triple_t *item = &vfs_fds_triple[i]; @@ -958,16 +970,18 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds esp_vfs_log_fd_set("readfds", &item->readfds); esp_vfs_log_fd_set("writefds", &item->writefds); esp_vfs_log_fd_set("errorfds", &item->errorfds); - esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem); + esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem, + driver_args + i); if (err != ESP_OK) { - call_end_selects(i, vfs_fds_triple); + call_end_selects(i, vfs_fds_triple, driver_args); (void) set_global_fd_sets(vfs_fds_triple, s_vfs_count, readfds, writefds, errorfds); if (sel_sem.is_sem_local && sel_sem.sem) { vSemaphoreDelete(sel_sem.sem); sel_sem.sem = NULL; } free(vfs_fds_triple); + free(driver_args); __errno_r(r) = EINTR; ESP_LOGD(TAG, "start_select failed: %s", esp_err_to_name(err)); return -1; @@ -1006,7 +1020,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds xSemaphoreTake(sel_sem.sem, ticks_to_wait); } - call_end_selects(s_vfs_count, vfs_fds_triple); // for VFSs for start_select was called before + call_end_selects(s_vfs_count, vfs_fds_triple, driver_args); // for VFSs for start_select was called before if (ret >= 0) { ret += set_global_fd_sets(vfs_fds_triple, s_vfs_count, readfds, writefds, errorfds); } @@ -1015,6 +1029,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds sel_sem.sem = NULL; } free(vfs_fds_triple); + free(driver_args); ESP_LOGD(TAG, "esp_vfs_select returns %d", ret); esp_vfs_log_fd_set("readfds", readfds); diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index d996e9eeb..f1513ae1d 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -111,20 +111,21 @@ static vfs_uart_context_t* s_ctx[UART_NUM] = { #endif }; -/* Lock ensuring that uart_select is used from only one task at the time */ -static _lock_t s_one_select_lock; +typedef struct { + esp_vfs_select_sem_t select_sem; + fd_set *readfds; + fd_set *writefds; + fd_set *errorfds; + fd_set readfds_orig; + fd_set writefds_orig; + fd_set errorfds_orig; +} uart_select_args_t; -static esp_vfs_select_sem_t _select_sem = {.sem = NULL}; -static fd_set *_readfds = NULL; -static fd_set *_writefds = NULL; -static fd_set *_errorfds = NULL; -static fd_set *_readfds_orig = NULL; -static fd_set *_writefds_orig = NULL; -static fd_set *_errorfds_orig = NULL; - - -static void uart_end_select(void); +static uart_select_args_t **s_registered_selects = NULL; +static int s_registered_select_num = 0; +static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED; +static esp_err_t uart_end_select(void *end_select_args); static int uart_open(const char * path, int flags, int mode) { @@ -335,132 +336,156 @@ static int uart_fsync(int fd) return 0; } -static void select_notif_callback(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken) +static esp_err_t register_select(uart_select_args_t *args) { - switch (uart_select_notif) { - case UART_SELECT_READ_NOTIF: - if (FD_ISSET(uart_num, _readfds_orig)) { - FD_SET(uart_num, _readfds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; - case UART_SELECT_WRITE_NOTIF: - if (FD_ISSET(uart_num, _writefds_orig)) { - FD_SET(uart_num, _writefds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; - case UART_SELECT_ERROR_NOTIF: - if (FD_ISSET(uart_num, _errorfds_orig)) { - FD_SET(uart_num, _errorfds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; + esp_err_t ret = ESP_ERR_INVALID_ARG; + + if (args) { + portENTER_CRITICAL(&s_registered_select_lock); + const int new_size = s_registered_select_num + 1; + if ((s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *))) == NULL) { + ret = ESP_ERR_NO_MEM; + } else { + s_registered_selects[s_registered_select_num] = args; + s_registered_select_num = new_size; + ret = ESP_OK; + } + portEXIT_CRITICAL(&s_registered_select_lock); } + + return ret; } -static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t select_sem) +static esp_err_t unregister_select(uart_select_args_t *args) { - if (_lock_try_acquire(&s_one_select_lock)) { - return ESP_ERR_INVALID_STATE; + esp_err_t ret = ESP_OK; + if (args) { + ret = ESP_ERR_INVALID_STATE; + portENTER_CRITICAL(&s_registered_select_lock); + for (int i = 0; i < s_registered_select_num; ++i) { + if (s_registered_selects[i] == args) { + const int new_size = s_registered_select_num - 1; + // The item is removed by overwriting it with the last item. The subsequent rellocation will drop the + // last item. + s_registered_selects[i] = s_registered_selects[new_size]; + s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *)); + if (s_registered_selects || new_size == 0) { + s_registered_select_num = new_size; + ret = ESP_OK; + } else { + ret = ESP_ERR_NO_MEM; + } + break; + } + } + portEXIT_CRITICAL(&s_registered_select_lock); } + return ret; +} - const int max_fds = MIN(nfds, UART_NUM); - - portENTER_CRITICAL(uart_get_selectlock()); - - if (_readfds || _writefds || _errorfds || _readfds_orig || _writefds_orig || _errorfds_orig || _select_sem.sem) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_INVALID_STATE; - } - - if ((_readfds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - if ((_writefds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - if ((_errorfds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - //uart_set_select_notif_callback set the callbacks in UART ISR - for (int i = 0; i < max_fds; ++i) { - if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) { - uart_set_select_notif_callback(i, select_notif_callback); +static void select_notif_callback_isr(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken) +{ + portENTER_CRITICAL_ISR(&s_registered_select_lock); + for (int i = 0; i < s_registered_select_num; ++i) { + uart_select_args_t *args = s_registered_selects[i]; + if (args) { + switch (uart_select_notif) { + case UART_SELECT_READ_NOTIF: + if (FD_ISSET(uart_num, &args->readfds_orig)) { + FD_SET(uart_num, args->readfds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + case UART_SELECT_WRITE_NOTIF: + if (FD_ISSET(uart_num, &args->writefds_orig)) { + FD_SET(uart_num, args->writefds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + case UART_SELECT_ERROR_NOTIF: + if (FD_ISSET(uart_num, &args->errorfds_orig)) { + FD_SET(uart_num, args->errorfds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + } } } + portEXIT_CRITICAL_ISR(&s_registered_select_lock); +} - _select_sem = select_sem; +static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + esp_vfs_select_sem_t select_sem, void **end_select_args) +{ + const int max_fds = MIN(nfds, UART_NUM); + *end_select_args = NULL; - _readfds = readfds; - _writefds = writefds; - _errorfds = exceptfds; + uart_select_args_t *args = malloc(sizeof(uart_select_args_t)); - *_readfds_orig = *readfds; - *_writefds_orig = *writefds; - *_errorfds_orig = *exceptfds; + if (args == NULL) { + return ESP_ERR_NO_MEM; + } + args->select_sem = select_sem; + args->readfds = readfds; + args->writefds = writefds; + args->errorfds = exceptfds; + args->readfds_orig = *readfds; // store the original values because they will be set to zero + args->writefds_orig = *writefds; + args->errorfds_orig = *exceptfds; FD_ZERO(readfds); FD_ZERO(writefds); FD_ZERO(exceptfds); + portENTER_CRITICAL(uart_get_selectlock()); + + //uart_set_select_notif_callback sets the callbacks in UART ISR for (int i = 0; i < max_fds; ++i) { - if (FD_ISSET(i, _readfds_orig)) { + if (FD_ISSET(i, &args->readfds_orig) || FD_ISSET(i, &args->writefds_orig) || FD_ISSET(i, &args->errorfds_orig)) { + uart_set_select_notif_callback(i, select_notif_callback_isr); + } + } + + for (int i = 0; i < max_fds; ++i) { + if (FD_ISSET(i, &args->readfds_orig)) { size_t buffered_size; if (uart_get_buffered_data_len(i, &buffered_size) == ESP_OK && buffered_size > 0) { // signalize immediately when data is buffered - FD_SET(i, _readfds); - esp_vfs_select_triggered(_select_sem); + FD_SET(i, readfds); + esp_vfs_select_triggered(args->select_sem); } } } - portEXIT_CRITICAL(uart_get_selectlock()); - // s_one_select_lock is not released on successfull exit - will be - // released in uart_end_select() + esp_err_t ret = register_select(args); + if (ret != ESP_OK) { + portEXIT_CRITICAL(uart_get_selectlock()); + free(args); + return ret; + } + portEXIT_CRITICAL(uart_get_selectlock()); + + *end_select_args = args; return ESP_OK; } -static void uart_end_select(void) +static esp_err_t uart_end_select(void *end_select_args) { + uart_select_args_t *args = end_select_args; + + if (args) { + free(args); + } + portENTER_CRITICAL(uart_get_selectlock()); + esp_err_t ret = unregister_select(args); for (int i = 0; i < UART_NUM; ++i) { uart_set_select_notif_callback(i, NULL); } - - _select_sem.sem = NULL; - - _readfds = NULL; - _writefds = NULL; - _errorfds = NULL; - - if (_readfds_orig) { - free(_readfds_orig); - _readfds_orig = NULL; - } - - if (_writefds_orig) { - free(_writefds_orig); - _writefds_orig = NULL; - } - - if (_errorfds_orig) { - free(_errorfds_orig); - _errorfds_orig = NULL; - } portEXIT_CRITICAL(uart_get_selectlock()); - _lock_release(&s_one_select_lock); + + return ret; } #ifdef CONFIG_VFS_SUPPORT_TERMIOS From 2211039b6d243e6c124d807b15f49443c9001764 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Wed, 17 Jul 2019 09:59:21 +0200 Subject: [PATCH 06/46] docs: Correct and extend the documentation about VFS select() --- components/vfs/README.rst | 82 ++++++++++++++++++++++++++++++++------- components/vfs/vfs.c | 2 + 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/components/vfs/README.rst b/components/vfs/README.rst index 20bc9770e..c296e81a6 100644 --- a/components/vfs/README.rst +++ b/components/vfs/README.rst @@ -66,9 +66,29 @@ Case 2: API functions are declared with an extra context pointer (the FS driver Synchronous input/output multiplexing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you want to use synchronous input/output multiplexing by :cpp:func:`select` -then you need to register VFS with the functions :cpp:func:`start_select` and -:cpp:func:`end_select` similar to the following example: +Synchronous input/output multiplexing by :cpp:func:`select` is supported in the VFS component. The implementation +works in the following way. + +1. :cpp:func:`select` is called with file descriptors which could belong to various VFS drivers. +2. The file descriptors are divided into groups each belonging to one VFS driver. +3. The file descriptors belonging to non-socket VFS drivers are handed over to the given VFS drivers by :cpp:func:`start_select` + described later on this page. This function represents the driver-specific implementation of :cpp:func:`select` for + the given driver. This should be a non-blocking call which means the function should immediately return after setting up + the environment for checking events related to the given file descriptors. +4. The file descriptors belonging to the socket VFS driver are handed over to the socket driver by + :cpp:func:`socket_select` described later on this page. This is a blocking call which means that it will return only + if there is an event related to socket file descriptors or a non-socket driver signals :cpp:func:`socket_select` + to exit. +5. Results are collected from each VFS driver and all drivers are stopped by deinitiazation + of the environment for checking events. +6. The :cpp:func:`select` call ends and returns the appropriate results. + +Non-socket VFS drivers +"""""""""""""""""""""" + +If you want to use :cpp:func:`select` with a file descriptor belonging to a non-socket VFS driver +then you need to register the driver with functions :cpp:func:`start_select` and +:cpp:func:`end_select` similarly to the following example: .. highlight:: c @@ -81,25 +101,57 @@ then you need to register VFS with the functions :cpp:func:`start_select` and :cpp:func:`start_select` is called for setting up the environment for detection of read/write/error conditions on file descriptors belonging to the -given VFS. :cpp:func:`end_select` is called to stop/deinitialize/free the -environment which was setup by :cpp:func:`start_select`. Please refer to the +given VFS driver. + +:cpp:func:`end_select` is called to stop/deinitialize/free the +environment which was setup by :cpp:func:`start_select`. + +Please refer to the reference implementation for the UART peripheral in :component_file:`vfs/vfs_uart.c` and most particularly to the functions :cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select`, and -:cpp:func:`uart_end_select`. +:cpp:func:`uart_end_select` for more information. Please check the following examples that demonstrate the use of :cpp:func:`select` with VFS file descriptors: -- :example:`peripherals/uart_select` -- :example:`system/select` + - :example:`peripherals/uart/uart_select` + - :example:`system/select` -<<<<<<< HEAD -If :cpp:func:`select` is used for socket file descriptors only then one can -enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option which can reduce the code -======= -If you use :cpp:func:`select` for socket file descriptors, you can enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code ->>>>>>> afc2fdf27... Review all the files in the esp-idf's api_ref/storage directory -size and improve performance. +Socket VFS drivers +"""""""""""""""""" +A socket VFS driver is using its own internal implementation of :cpp:func:`select` and non-socket VFS drivers notify +it upon read/write/error conditions. + +A socket VFS driver needs to be registered with the following functions defined: + +.. highlight:: c + +:: + + // In definition of esp_vfs_t: + .socket_select = &lwip_select, + .get_socket_select_semaphore = &lwip_get_socket_select_semaphore, + .stop_socket_select = &lwip_stop_socket_select, + .stop_socket_select_isr = &lwip_stop_socket_select_isr, + // ... other members initialized + +:cpp:func:`socket_select` is the internal implementation of :cpp:func:`select` for the socket driver. It works only +with file descriptors belonging to the socket VFS. + +:cpp:func:`get_socket_select_semaphore` returns the signalization object (semaphore) which will be used in non-socket +drivers to stop the waiting in :cpp:func:`socket_select`. + +:cpp:func:`stop_socket_select` call is used to stop the waiting in :cpp:func:`socket_select` by passing the object +returned by :cpp:func:`get_socket_select_semaphore`. + +:cpp:func:`stop_socket_select_isr` has the same functionality as :cpp:func:`stop_socket_select` but it can be used +from ISR. + +Please see :component_file:`lwip/port/esp32/vfs_lwip.c` for a reference socket driver implementation using LWIP. + +.. note:: + If you use :cpp:func:`select` for socket file descriptors only then you can enable the + :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code size and improve performance. Paths ----- diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index ed4db5e7e..681a9ec61 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -858,6 +858,8 @@ static void esp_vfs_log_fd_set(const char *fds_name, const fd_set *fds) int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout) { + // NOTE: Please see the "Synchronous input/output multiplexing" section of the ESP-IDF Programming Guide + // (API Reference -> Storage -> Virtual Filesystem) for a general overview of the implementation of VFS select(). int ret = 0; struct _reent* r = __getreent(); From 40e808c63b7c944faf81f85c6b2ae35981f1c447 Mon Sep 17 00:00:00 2001 From: xueyunfei Date: Mon, 5 Aug 2019 17:33:37 +0800 Subject: [PATCH 07/46] Try to allocate some LWIP memories in SPIRAM first. If failed, try to allocate in internal RAM then --- components/lwip/lwip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lwip/lwip b/components/lwip/lwip index 61d840ff4..663b2fdb4 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit 61d840ff4778f4946c8743f7e412345abcd537f1 +Subproject commit 663b2fdb41177c82f2aa5939e41aef54427d15cd From 2e8c85d8fff823232af46cc0f353ac170d0971e9 Mon Sep 17 00:00:00 2001 From: kooho <2229179028@qq.com> Date: Thu, 1 Nov 2018 12:23:11 +0800 Subject: [PATCH 08/46] driver(ledc): fixed ledc clock selection bug. --- components/driver/include/driver/ledc.h | 10 ++ components/driver/ledc.c | 111 +++++++++++++----- components/driver/test/test_ledc.c | 9 ++ components/driver/test/test_pcnt.c | 2 + .../internal_communication/main/mesh_light.c | 3 +- .../mesh/manual_networking/main/mesh_light.c | 3 +- .../peripherals/ledc/main/ledc_example_main.c | 3 +- .../peripherals/pcnt/main/pcnt_example_main.c | 1 + 8 files changed, 107 insertions(+), 35 deletions(-) diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index 17875783f..4d5593abb 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -51,6 +51,13 @@ typedef enum { LEDC_APB_CLK, /*!< LEDC timer clock divided from APB clock (80Mhz) */ } ledc_clk_src_t; +typedef enum { + LEDC_AUTO_CLK, /*!< The driver will automatically select the source clock(REF_TICK or APB) based on the giving resolution and duty parameter when init the timer*/ + LEDC_USE_REF_TICK, /*!< LEDC timer select REF_TICK clock as source clock*/ + LEDC_USE_APB_CLK, /*!< LEDC timer select APB clock as source clock*/ + LEDC_USE_RTC8M_CLK, /*!< LEDC timer select RTC8M_CLK as source clock. Only for low speed channels and this parameter must be the same for all low speed channels*/ +} ledc_clk_cfg_t; + typedef enum { LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */ LEDC_TIMER_1, /*!< LEDC timer 1 */ @@ -125,6 +132,9 @@ typedef struct { }; ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3) */ uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */ + ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock. + For low speed channels and high speed channels, you can specify the source clock using LEDC_USE_REF_TICK, LEDC_USE_APB_CLK or LEDC_AUTO_CLK. + For low speed channels, you can also specify the source clock using LEDC_USE_RTC8M_CLK, in this case, all low speed channel's source clock must be RTC8M_CLK*/ } ledc_timer_config_t; typedef intr_handle_t ledc_isr_handle_t; diff --git a/components/driver/ledc.c b/components/driver/ledc.c index ff992d147..f82efaf5e 100644 --- a/components/driver/ledc.c +++ b/components/driver/ledc.c @@ -19,6 +19,7 @@ #include "soc/gpio_periph.h" #include "driver/ledc.h" #include "soc/ledc_periph.h" +#include "soc/rtc.h" #include "esp_log.h" static const char* LEDC_TAG = "ledc"; @@ -51,12 +52,17 @@ static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL; #define LEDC_VAL_NO_CHANGE (-1) #define LEDC_STEP_NUM_MAX (1023) #define LEDC_DUTY_DECIMAL_BIT_NUM (4) +#define DELAY_CLK8M_CLK_SWITCH (5) +#define SLOW_CLK_CYC_CALIBRATE (13) #define LEDC_HPOINT_VAL_MAX (LEDC_HPOINT_HSCH1_V) #define LEDC_FADE_TOO_SLOW_STR "LEDC FADE TOO SLOW" #define LEDC_FADE_TOO_FAST_STR "LEDC FADE TOO FAST" static const char *LEDC_FADE_SERVICE_ERR_STR = "LEDC fade service not installed"; static const char *LEDC_FADE_INIT_ERROR_STR = "LEDC fade channel init error, not enough memory or service not installed"; +//This value will be calibrated when in use. +static uint32_t s_ledc_slow_clk_8M = 0; + static void ledc_ls_timer_update(ledc_mode_t speed_mode, ledc_timer_t timer_sel) { if (speed_mode == LEDC_LOW_SPEED_MODE) { @@ -71,6 +77,23 @@ static IRAM_ATTR void ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channe } } +//We know that CLK8M is about 8M, but don't know the actual value. So we need to do a calibration. +static bool ledc_slow_clk_calibrate(void) +{ + //Enable CLK8M for LEDC + SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M); + //Waiting for CLK8M to turn on + ets_delay_us(DELAY_CLK8M_CLK_SWITCH); + uint32_t cal_val = rtc_clk_cal(RTC_CAL_8MD256, SLOW_CLK_CYC_CALIBRATE); + if(cal_val == 0) { + ESP_LOGE(LEDC_TAG, "CLK8M_CLK calibration failed"); + return false; + } + s_ledc_slow_clk_8M = 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / cal_val; + ESP_LOGD(LEDC_TAG, "Calibrate CLK8M_CLK : %d Hz", s_ledc_slow_clk_8M); + return true; +} + static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type) { LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode"); @@ -219,6 +242,60 @@ esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, return ret; } +// Setting the LEDC timer divisor with the given source clock, frequency and resolution. +static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_num, ledc_clk_cfg_t clk_cfg, int freq_hz, int duty_resolution) +{ + uint32_t div_param = 0; + uint32_t precision = ( 0x1 << duty_resolution ); + ledc_clk_src_t timer_clk_src = LEDC_APB_CLK; + + // Calculate the divisor + // User specified source clock(RTC8M_CLK) for low speed channel + if ((speed_mode == LEDC_LOW_SPEED_MODE) && (clk_cfg == LEDC_USE_RTC8M_CLK)) { + if(s_ledc_slow_clk_8M == 0) { + if (ledc_slow_clk_calibrate() == false) { + goto error; + } + } + div_param = ( (uint64_t) s_ledc_slow_clk_8M << 8 ) / freq_hz / precision; + } else { + // Automatically select APB or REF_TICK as the source clock. + if (clk_cfg == LEDC_AUTO_CLK) { + // Try calculating divisor based on LEDC_APB_CLK + div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision; + if (div_param > LEDC_DIV_NUM_HSTIMER0_V) { + // APB_CLK results in divisor which too high. Try using REF_TICK as clock source. + timer_clk_src = LEDC_REF_TICK; + div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision; + } else if (div_param < 256) { + // divisor is too low + goto error; + } + // User specified source clock(LEDC_APB_CLK_HZ or LEDC_REF_TICK) + } else { + timer_clk_src = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK : LEDC_REF_TICK; + uint32_t sclk_freq = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK_HZ : LEDC_REF_CLK_HZ; + div_param = ( (uint64_t) sclk_freq << 8 ) / freq_hz / precision; + } + } + if (div_param < 256 || div_param > LEDC_DIV_NUM_LSTIMER0_V) { + goto error; + } + // For low speed channels, if RTC_8MCLK is used as the source clock, the `slow_clk_sel` register should be cleared, otherwise it should be set. + if (speed_mode == LEDC_LOW_SPEED_MODE) { + LEDC.conf.slow_clk_sel = (clk_cfg == LEDC_USE_RTC8M_CLK) ? 0 : 1; + } + //Set the divisor + ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src); + // reset the timer + ledc_timer_rst(speed_mode, timer_num); + return ESP_OK; +error: + ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=%d", + (uint32_t ) div_param); + return ESP_FAIL; +} + esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf) { LEDC_ARG_CHECK(timer_conf != NULL, "timer_conf"); @@ -227,6 +304,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf) uint32_t timer_num = timer_conf->timer_num; uint32_t speed_mode = timer_conf->speed_mode; LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode"); + LEDC_ARG_CHECK(!((timer_conf->clk_cfg == LEDC_USE_RTC8M_CLK) && (speed_mode != LEDC_LOW_SPEED_MODE)), "Only low speed channel support RTC8M_CLK"); periph_module_enable(PERIPH_LEDC_MODULE); if (freq_hz == 0 || duty_resolution == 0 || duty_resolution >= LEDC_TIMER_BIT_MAX) { ESP_LOGE(LEDC_TAG, "freq_hz=%u duty_resolution=%u", freq_hz, duty_resolution); @@ -236,38 +314,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf) ESP_LOGE(LEDC_TAG, "invalid timer #%u", timer_num); return ESP_ERR_INVALID_ARG; } - esp_err_t ret = ESP_OK; - uint32_t precision = ( 0x1 << duty_resolution ); // 2**depth - // Try calculating divisor based on LEDC_APB_CLK - ledc_clk_src_t timer_clk_src = LEDC_APB_CLK; - // div_param is a Q10.8 fixed point value - uint64_t div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision; - if (div_param < 256) { - // divisor is too low - ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=%d", - (uint32_t ) div_param); - ret = ESP_FAIL; - } - if (div_param > LEDC_DIV_NUM_HSTIMER0_V) { - // APB_CLK results in divisor which too high. Try using REF_TICK as clock source. - timer_clk_src = LEDC_REF_TICK; - div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision; - if (div_param < 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) { - ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try increasing freq_hz or duty_resolution. div_param=%d", - (uint32_t ) div_param); - ret = ESP_FAIL; - } - } else { - if (speed_mode == LEDC_LOW_SPEED_MODE) { - //for now, we only select 80mhz for slow clk of LEDC low speed channels. - LEDC.conf.slow_clk_sel = 1; - } - } - // set timer parameters - ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src); - // reset timer - ledc_timer_rst(speed_mode, timer_num); - return ret; + return ledc_set_timer_div(timer_num, timer_num, timer_conf->clk_cfg, freq_hz, duty_resolution); } esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel) diff --git a/components/driver/test/test_ledc.c b/components/driver/test/test_ledc.c index d0e35851d..b676c4232 100644 --- a/components/driver/test/test_ledc.c +++ b/components/driver/test/test_ledc.c @@ -86,6 +86,7 @@ static void timer_frequency_test(ledc_channel_t channel, ledc_timer_bit_t timer_ .bit_num = timer_bit, .timer_num = timer, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_channel_config(&ledc_ch_config)); TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -126,6 +127,7 @@ static void timer_duty_test(ledc_channel_t channel, ledc_timer_bit_t timer_bit, .bit_num = timer_bit, .timer_num = timer, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_channel_config(&ledc_ch_config)); TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -188,6 +190,7 @@ TEST_CASE("LEDC error log channel and timer config", "[ledc][test_env=UT_T1_LEDC ledc_time_config.duty_resolution = LEDC_TIMER_13_BIT; ledc_time_config.timer_num = LEDC_TIMER_0; ledc_time_config.freq_hz = 5000; + ledc_time_config.clk_cfg = LEDC_AUTO_CLK; ledc_timer_config_t temp_timer_config = ledc_time_config; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -228,6 +231,7 @@ TEST_CASE("LEDC normal channel and timer config", "[ledc][test_env=UT_T1_LEDC]") .bit_num = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config_t temp_time_config = ledc_time_config; @@ -297,6 +301,7 @@ TEST_CASE("LEDC timer set", "[ledc][test_env=UT_T1_LEDC]") .bit_num = 13, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -347,6 +352,7 @@ TEST_CASE("LEDC timer pause and resume", "[ledc][test_env=UT_T1_LEDC]") .duty_resolution = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -392,6 +398,7 @@ TEST_CASE("LEDC fade with time(logic analyzer)", "[ledc][ignore]") .duty_resolution = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -429,6 +436,7 @@ TEST_CASE("LEDC fade with step(logic analyzer)", "[ledc][ignore]") .duty_resolution = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); @@ -470,6 +478,7 @@ TEST_CASE("LEDC memory test", "[ledc][test_env=UT_T1_LEDC]") .duty_resolution = LEDC_TIMER_13_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, + .clk_cfg = LEDC_AUTO_CLK, }; TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); diff --git a/components/driver/test/test_pcnt.c b/components/driver/test/test_pcnt.c index ae5656a84..af4e58fa6 100644 --- a/components/driver/test/test_pcnt.c +++ b/components/driver/test/test_pcnt.c @@ -55,6 +55,7 @@ static void produce_pulse(void) .timer_num = LEDC_TIMER_1, .duty_resolution = LEDC_TIMER_10_BIT, .freq_hz = 1, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config(&ledc_timer); @@ -160,6 +161,7 @@ static void count_mode_test(gpio_num_t ctl_io) .timer_num = LEDC_TIMER_1, .duty_resolution = LEDC_TIMER_10_BIT, .freq_hz = 100, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config(&ledc_timer); diff --git a/examples/mesh/internal_communication/main/mesh_light.c b/examples/mesh/internal_communication/main/mesh_light.c index 58a66e152..b1f4c6705 100644 --- a/examples/mesh/internal_communication/main/mesh_light.c +++ b/examples/mesh/internal_communication/main/mesh_light.c @@ -42,7 +42,8 @@ esp_err_t mesh_light_init(void) .bit_num = LEDC_TIMER_13_BIT, .freq_hz = 5000, .speed_mode = LEDC_HIGH_SPEED_MODE, - .timer_num = LEDC_TIMER_0 + .timer_num = LEDC_TIMER_0, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config(&ledc_timer); diff --git a/examples/mesh/manual_networking/main/mesh_light.c b/examples/mesh/manual_networking/main/mesh_light.c index 478050381..e181be41b 100644 --- a/examples/mesh/manual_networking/main/mesh_light.c +++ b/examples/mesh/manual_networking/main/mesh_light.c @@ -42,7 +42,8 @@ esp_err_t mesh_light_init(void) .bit_num = LEDC_TIMER_13_BIT, .freq_hz = 5000, .speed_mode = LEDC_HIGH_SPEED_MODE, - .timer_num = LEDC_TIMER_0 + .timer_num = LEDC_TIMER_0, + .clk_cfg = LEDC_AUTO_CLK, }; ledc_timer_config(&ledc_timer); diff --git a/examples/peripherals/ledc/main/ledc_example_main.c b/examples/peripherals/ledc/main/ledc_example_main.c index 3a0cd5e97..88dbe6714 100644 --- a/examples/peripherals/ledc/main/ledc_example_main.c +++ b/examples/peripherals/ledc/main/ledc_example_main.c @@ -63,7 +63,8 @@ void app_main(void) .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty .freq_hz = 5000, // frequency of PWM signal .speed_mode = LEDC_HS_MODE, // timer mode - .timer_num = LEDC_HS_TIMER // timer index + .timer_num = LEDC_HS_TIMER, // timer index + .clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock }; // Set configuration of timer0 for high speed channels ledc_timer_config(&ledc_timer); diff --git a/examples/peripherals/pcnt/main/pcnt_example_main.c b/examples/peripherals/pcnt/main/pcnt_example_main.c index 89a370363..a8d1fb32d 100644 --- a/examples/peripherals/pcnt/main/pcnt_example_main.c +++ b/examples/peripherals/pcnt/main/pcnt_example_main.c @@ -100,6 +100,7 @@ static void ledc_init(void) ledc_timer.timer_num = LEDC_TIMER_1; ledc_timer.duty_resolution = LEDC_TIMER_10_BIT; ledc_timer.freq_hz = 1; // set output frequency at 1 Hz + ledc_timer.clk_cfg = LEDC_AUTO_CLK; ledc_timer_config(&ledc_timer); // Prepare and then apply the LEDC PWM channel configuration From c93cab858ef0ece164312c9973c582e76c5a8c63 Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Tue, 6 Aug 2019 19:30:58 +0530 Subject: [PATCH 09/46] httpd_sess_close: Check for session validity before closing If httpd_sess_trigger_close() gets called twice for the same socket, the first httpd_sess_close() cb closes the correct socket, but the second invocation closes the wrong socket which was just accepted and added to the socket db. Checking for the lru counter will help identify this as the counter is set only for requests actually served. --- components/esp_http_server/src/httpd_sess.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/esp_http_server/src/httpd_sess.c b/components/esp_http_server/src/httpd_sess.c index 8109475b4..9deb6df2f 100644 --- a/components/esp_http_server/src/httpd_sess.c +++ b/components/esp_http_server/src/httpd_sess.c @@ -378,6 +378,10 @@ static void httpd_sess_close(void *arg) { struct sock_db *sock_db = (struct sock_db *)arg; if (sock_db) { + if (sock_db->lru_counter == 0) { + ESP_LOGD(TAG, "Skipping session close for %d as it seems to be a race condition", sock_db->fd); + return; + } int fd = sock_db->fd; struct httpd_data *hd = (struct httpd_data *) sock_db->handle; httpd_sess_delete(hd, fd); From f3d6a34e7d1de1ef3f2fb0b1c8aade7d6882945c Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 23 May 2019 21:48:08 +0200 Subject: [PATCH 10/46] esp_tls: enable psk verification mode, added mqtt example using psk authentication --- components/esp-tls/Kconfig | 11 ++ components/esp-tls/esp_tls.c | 19 ++- components/esp-tls/esp_tls.h | 15 ++ components/mqtt/esp-mqtt | 2 +- .../tcp_transport/include/esp_transport_ssl.h | 15 ++ components/tcp_transport/transport_ssl.c | 8 + .../protocols/mqtt/ssl_psk/CMakeLists.txt | 10 ++ examples/protocols/mqtt/ssl_psk/Makefile | 9 ++ examples/protocols/mqtt/ssl_psk/README.md | 76 ++++++++++ .../mqtt/ssl_psk/main/CMakeLists.txt | 4 + .../protocols/mqtt/ssl_psk/main/app_main.c | 141 ++++++++++++++++++ .../protocols/mqtt/ssl_psk/main/component.mk | 0 .../protocols/mqtt/ssl_psk/sdkconfig.defaults | 1 + 13 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 examples/protocols/mqtt/ssl_psk/CMakeLists.txt create mode 100644 examples/protocols/mqtt/ssl_psk/Makefile create mode 100644 examples/protocols/mqtt/ssl_psk/README.md create mode 100644 examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt create mode 100644 examples/protocols/mqtt/ssl_psk/main/app_main.c create mode 100644 examples/protocols/mqtt/ssl_psk/main/component.mk create mode 100644 examples/protocols/mqtt/ssl_psk/sdkconfig.defaults diff --git a/components/esp-tls/Kconfig b/components/esp-tls/Kconfig index 320894271..e31ac8de7 100644 --- a/components/esp-tls/Kconfig +++ b/components/esp-tls/Kconfig @@ -5,5 +5,16 @@ menu "ESP-TLS" help Enable support for creating server side SSL/TLS session + config ESP_TLS_PSK_VERIFICATION + bool "Enable PSK verification" + select MBEDTLS_PSK_MODES + select MBEDTLS_KEY_EXCHANGE_PSK + select MBEDTLS_KEY_EXCHANGE_DHE_PSK + select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK + select MBEDTLS_KEY_EXCHANGE_RSA_PSK + default n + help + Enable support for pre shared key ciphers + endmenu diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index e527873f7..fc5e76754 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -426,6 +426,23 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls if (esp_ret != ESP_OK) { return esp_ret; } + mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); + } else if (cfg->psk_hint_key) { +#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION) + // + // PSK encryption mode is configured only if no certificate supplied and psk pointer not null + ESP_LOGD(TAG, "ssl psk authentication"); + ret = mbedtls_ssl_conf_psk(&tls->conf, cfg->psk_hint_key->key, cfg->psk_hint_key->key_size, + (const unsigned char *)cfg->psk_hint_key->hint, strlen(cfg->psk_hint_key->hint)); + if (ret != 0) { + ESP_LOGE(TAG, "mbedtls_ssl_conf_psk returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED; + } +#else + ESP_LOGE(TAG, "psk_hint_key configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option"); + return ESP_ERR_INVALID_STATE; +#endif } else { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); } @@ -443,7 +460,7 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls }; esp_err_t esp_ret = set_pki_context(tls, &pki); if (esp_ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to set server pki context"); + ESP_LOGE(TAG, "Failed to set client pki context"); return esp_ret; } } else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) { diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index a026bc4ab..e99770b57 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -48,6 +48,7 @@ extern "C" { #define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */ #define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */ #define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */ typedef struct esp_tls_last_error* esp_tls_error_handle_t; @@ -76,6 +77,15 @@ typedef enum esp_tls_role { ESP_TLS_SERVER, } esp_tls_role_t; +/** + * @brief ESP-TLS preshared key and hint structure + */ +typedef struct psk_key_hint { + const uint8_t* key; /*!< key in PSK authentication mode in binary format */ + const size_t key_size; /*!< length of the key */ + const char* hint; /*!< hint in PSK authentication mode in string format */ +} psk_hint_key_t; + /** * @brief ESP-TLS configuration parameters * @@ -159,6 +169,11 @@ typedef struct esp_tls_cfg { If NULL, server certificate CN must match hostname. */ bool skip_common_name; /*!< Skip any validation of server certificate CN field */ + + const psk_hint_key_t* psk_hint_key; /*!< Pointer to PSK hint and key. if not NULL (and certificates are NULL) + then PSK authentication is enabled with configured setup. + Important note: the pointer must be valid for connection */ + } esp_tls_cfg_t; #ifdef CONFIG_ESP_TLS_SERVER diff --git a/components/mqtt/esp-mqtt b/components/mqtt/esp-mqtt index dc37d3a06..117eef2da 160000 --- a/components/mqtt/esp-mqtt +++ b/components/mqtt/esp-mqtt @@ -1 +1 @@ -Subproject commit dc37d3a065f345a7358b8ff4553db0baceeb8ad6 +Subproject commit 117eef2dad54e0f9e25b3005fcfc18e7695ff29e diff --git a/components/tcp_transport/include/esp_transport_ssl.h b/components/tcp_transport/include/esp_transport_ssl.h index c69749b4b..a83e93882 100644 --- a/components/tcp_transport/include/esp_transport_ssl.h +++ b/components/tcp_transport/include/esp_transport_ssl.h @@ -16,6 +16,7 @@ #define _ESP_TRANSPORT_SSL_H_ #include "esp_transport.h" +#include "esp_tls.h" #ifdef __cplusplus extern "C" { @@ -111,6 +112,20 @@ void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const c */ void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t); +/** + * @brief Set PSK key and hint for PSK server/client verification in esp-tls component. + * Important notes: + * - This function stores the pointer to data, rather than making a copy. + * So this data must remain valid until after the connection is cleaned up + * - ESP_TLS_PSK_VERIFICATION config option must be enabled in menuconfig + * - certificate verification takes priority so it must not be configured + * to enable PSK method. + * + * @param t ssl transport + * @param[in] psk_hint_key psk key and hint structure defined in esp_tls.h + */ +void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key); + #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index f8543e92e..d5b13490a 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -169,6 +169,14 @@ void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t) } } +void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key) +{ + transport_ssl_t *ssl = esp_transport_get_context_data(t); + if (t && ssl) { + ssl->cfg.psk_hint_key = psk_hint_key; + } +} + void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len) { transport_ssl_t *ssl = esp_transport_get_context_data(t); diff --git a/examples/protocols/mqtt/ssl_psk/CMakeLists.txt b/examples/protocols/mqtt/ssl_psk/CMakeLists.txt new file mode 100644 index 000000000..77934fa67 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following four lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +# (Not part of the boilerplate) +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(mqtt_ssl_psk) diff --git a/examples/protocols/mqtt/ssl_psk/Makefile b/examples/protocols/mqtt/ssl_psk/Makefile new file mode 100644 index 000000000..24bec17e9 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# +PROJECT_NAME := mqtt_ssl_psk + +EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common + +include $(IDF_PATH)/make/project.mk diff --git a/examples/protocols/mqtt/ssl_psk/README.md b/examples/protocols/mqtt/ssl_psk/README.md new file mode 100644 index 000000000..c46688f03 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/README.md @@ -0,0 +1,76 @@ +# ESP-MQTT SSL example with PSK verification + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example connects to a local broker configured to PSK authentication + +## How to use example + +### Hardware Required + +This example can be executed on any ESP32 board, the only required interface is WiFi (or ethernet) to connect to a MQTT +broker with preconfigured PSK verification method. + +#### Mosquitto settings +In case of using mosquitto broker, here is how to enable PSK authentication in `mosquitto.config`, +``` +psk_hint hint +psk_file path_to_your_psk_file +allow_anonymous true +``` +Note: Last line enables anonymous mode, as this example does not use mqtt username and password. + +PSK file then has to contain pairs of hints and keys, as shown below: +``` +hint:BAD123 +``` + +Important note: Keys are stored as text hexadecimal values in PSK file, while the example code stores key as plain binary +as required by MQTT API. (See the example source for details: `"BAD123" -> 0xBA, 0xD1, 0x23`) + +### Configure the project + +* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +* When using Make build system, set `Default serial port` under `Serial flasher config`. + +### Build and Flash + + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +I (2160) example_connect: Ethernet Link Up +I (4650) example_connect: Connected to Ethernet +I (4650) example_connect: IPv4 address: 192.168.0.1 +I (4650) MQTTS_EXAMPLE: [APP] Free memory: 244792 bytes +I (4660) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +D (4670) MQTT_CLIENT: MQTT client_id=ESP32_c6B4F8 +D (4680) MQTT_CLIENT: Core selection disabled +I (4680) MQTTS_EXAMPLE: Other event id:7 +D (4680) esp-tls: host:192.168.0.2: strlen 13 +D (4700) esp-tls: ssl psk authentication +D (4700) esp-tls: handshake in progress... +D (4720) MQTT_CLIENT: Transport connected to mqtts://192.168.0.2:8883 +I (4720) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000 +D (4720) MQTT_CLIENT: mqtt_message_receive: first byte: 0x20 +D (4730) MQTT_CLIENT: mqtt_message_receive: read "remaining length" byte: 0x2 +D (4730) MQTT_CLIENT: mqtt_message_receive: total message length: 4 (already read: 2) +D (4740) MQTT_CLIENT: mqtt_message_receive: read_len=2 +D (4750) MQTT_CLIENT: mqtt_message_receive: transport_read():4 4 +D (4750) MQTT_CLIENT: Connected +I (4760) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED +D (4760) MQTT_CLIENT: mqtt_enqueue id: 4837, type=8 successful +D (4770) OUTBOX: ENQUEUE msgid=4837, msg_type=8, len=18, size=18 +D (4770) MQTT_CLIENT: Sent subscribe topic=/topic/qos0, id: 4837, type=8 successful +I (4780) MQTTS_EXAMPLE: sent subscribe successful, msg_id=4837 +D (4790) MQTT_CLIENT: mqtt_enqueue id: 58982, type=8 successful +D (4790) OUTBOX: ENQUEUE msgid=58982, msg_type=8, len=18, size=36 +D (4800) MQTT_CLIENT: Sent subscribe topic=/topic/qos1, id: 58982, type=8 successful +I (4810) MQTTS_EXAMPLE: sent subscribe successful, msg_id=58982 +``` + diff --git a/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt b/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt new file mode 100644 index 000000000..6b0350063 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(COMPONENT_SRCS "app_main.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/protocols/mqtt/ssl_psk/main/app_main.c b/examples/protocols/mqtt/ssl_psk/main/app_main.c new file mode 100644 index 000000000..7a08d1772 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/main/app_main.c @@ -0,0 +1,141 @@ +/* MQTT over SSL Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "esp_wifi.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "tcpip_adapter.h" +#include "protocol_examples_common.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" + +#include "lwip/sockets.h" +#include "lwip/dns.h" +#include "lwip/netdb.h" + +#include "esp_log.h" +#include "mqtt_client.h" +#include "esp_tls.h" + +/* + * Add here URI of mqtt broker which supports PSK authentication + */ +#define EXAMPLE_BROKER_URI "mqtts://192.168.0.2" + +static const char *TAG = "MQTTS_EXAMPLE"; + +/* + * Define psk key and hint as defined in mqtt broker + * example for mosquitto server, content of psk_file: + * hint:BAD123 + * + */ +static const uint8_t s_key[] = { 0xBA, 0xD1, 0x23 }; + +static const psk_hint_key_t psk_hint_key = { + .key = s_key, + .key_size = sizeof(s_key), + .hint = "hint" + }; + +static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) +{ + esp_mqtt_client_handle_t client = event->client; + int msg_id; + // your_context_t *context = event->context; + switch (event->event_id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + break; + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } + return ESP_OK; +} + + +static void mqtt_app_start(void) +{ + const esp_mqtt_client_config_t mqtt_cfg = { + .uri = EXAMPLE_BROKER_URI, + .event_handle = mqtt_event_handler, + .psk_hint_key = &psk_hint_key, + }; + + ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); + esp_mqtt_client_start(client); +} + +void app_main(void) +{ + ESP_LOGI(TAG, "[APP] Startup.."); + ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); + ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); + + esp_log_level_set("*", ESP_LOG_INFO); + esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); + esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); + + ESP_ERROR_CHECK(nvs_flash_init()); + tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + mqtt_app_start(); +} diff --git a/examples/protocols/mqtt/ssl_psk/main/component.mk b/examples/protocols/mqtt/ssl_psk/main/component.mk new file mode 100644 index 000000000..e69de29bb diff --git a/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults b/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults new file mode 100644 index 000000000..1df83e8f3 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_TLS_PSK_VERIFICATION=y From 5203a1543996e5ad9aacd33672dda9103c0c8aad Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Wed, 7 Aug 2019 11:49:55 +0530 Subject: [PATCH 11/46] esp32_gdbstub: fix build error with esp32-2019r1 toolchain Fixes https://github.com/espressif/esp-idf/issues/3866 --- components/esp32/panic.c | 2 ++ components/esp_gdbstub/src/gdbstub.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esp32/panic.c b/components/esp32/panic.c index 4a104f029..9b5693862 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -429,6 +429,7 @@ static inline void disableAllWdts(void) TIMERG1.wdt_wprotect = 0; } +#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT static void esp_panic_dig_reset(void) __attribute__((noreturn)); static void esp_panic_dig_reset(void) @@ -444,6 +445,7 @@ static void esp_panic_dig_reset(void) ; } } +#endif static void putEntry(uint32_t pc, uint32_t sp) { diff --git a/components/esp_gdbstub/src/gdbstub.c b/components/esp_gdbstub/src/gdbstub.c index fbb3d26bf..f15be617f 100644 --- a/components/esp_gdbstub/src/gdbstub.c +++ b/components/esp_gdbstub/src/gdbstub.c @@ -205,12 +205,14 @@ static void handle_H_command(const unsigned char* cmd, int len) } else if (requested_task_index > s_scratch.task_count) { ret = "E00"; } else { - TaskHandle_t handle; + TaskHandle_t handle = NULL; get_task_handle(requested_task_index, &handle); /* FIXME: for the task currently running on the other CPU, extracting the registers from TCB * isn't valid. Need to use some IPC mechanism to obtain the registers of the other CPU */ - esp_gdbstub_tcb_to_regfile(handle, &s_scratch.regfile); + if (handle != NULL) { + esp_gdbstub_tcb_to_regfile(handle, &s_scratch.regfile); + } } esp_gdbstub_send_str_packet(ret); } else { From 80a5bd8e5400b8f3446ba857c786850f257dd37d Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Fri, 2 Aug 2019 14:28:33 +0530 Subject: [PATCH 12/46] wpa_supplicant: Port more crypto functions to use mbedtls Use mbedtls PBKDF2 and SHA1 for faster calculations during four-way handshake. Closes WIFI-1590 --- .../wpa_supplicant/src/crypto/sha1-internal.c | 49 +++++++++++++++- .../wpa_supplicant/src/crypto/sha1-pbkdf2.c | 58 ++++++++++++++++++- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/components/wpa_supplicant/src/crypto/sha1-internal.c b/components/wpa_supplicant/src/crypto/sha1-internal.c index 9eb190039..3bcd88116 100644 --- a/components/wpa_supplicant/src/crypto/sha1-internal.c +++ b/components/wpa_supplicant/src/crypto/sha1-internal.c @@ -20,11 +20,17 @@ #include "crypto/md5.h" #include "crypto/crypto.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/sha1.h" +#endif + typedef struct SHA1Context SHA1_CTX; void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + +#ifndef USE_MBEDTLS_CRYPTO /** * sha1_vector - SHA-1 hash for data vector * @num_elem: Number of elements in the data vector @@ -45,7 +51,49 @@ sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) SHA1Final(mac, &ctx); return 0; } +#else +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + mbedtls_sha1_context ctx; + size_t i; + int ret; + mbedtls_sha1_init( &ctx ); + + if ((ret = mbedtls_sha1_starts_ret( &ctx)) != 0) { + goto exit; + } + + + for (i = 0; i < num_elem; i++) { + if ((ret = mbedtls_sha1_update_ret(&ctx, addr[i], len[i])) != 0) { + goto exit; + } + } + + if ((ret = mbedtls_sha1_finish_ret( &ctx, mac)) != 0) { + goto exit; + } + +exit: + mbedtls_sha1_free( &ctx ); + + if (ret) { + return -1; + } + + return 0; +} +#endif /* ===== start - public domain SHA1 implementation ===== */ @@ -309,5 +357,4 @@ SHA1Final(unsigned char digest[20], SHA1_CTX* context) os_memset(context->count, 0, 8); os_memset(finalcount, 0, 8); } - /* ===== end - public domain SHA1 implementation ===== */ diff --git a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c index ec7100142..b842a57d4 100644 --- a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c +++ b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -18,10 +18,63 @@ #include "crypto/md5.h" #include "crypto/crypto.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/pkcs5.h" + +/** + * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * @passphrase: ASCII passphrase + * @ssid: SSID + * @ssid_len: SSID length in bytes + * @iterations: Number of iterations to run + * @buf: Buffer for the generated key + * @buflen: Length of the buffer in bytes + * Returns: 0 on success, -1 of failure + * + * This function is used to derive PSK for WPA-PSK. For this protocol, + * iterations is set to 4096 and buflen to 32. This function is described in + * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. + */ +int +pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + + mbedtls_md_context_t sha1_ctx; + const mbedtls_md_info_t *info_sha1; + int ret; + + mbedtls_md_init( &sha1_ctx ); + + info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + if (info_sha1 == NULL) { + ret = -1; + goto exit; + } + + if ((ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0) { + ret = -1; + goto exit; + } + + ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, (const unsigned char*) passphrase, os_strlen(passphrase) , (const unsigned char*) ssid, + ssid_len, iterations, 32, buf ); + if (ret != 0) { + ret = -1; + goto exit; + } + +exit: + mbedtls_md_free( &sha1_ctx ); + + return ret; +} +#else + static int pbkdf2_sha1_f(const char *passphrase, const char *ssid, - size_t ssid_len, int iterations, unsigned int count, - u8 *digest) + size_t ssid_len, int iterations, unsigned int count, + u8 *digest) { unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; int i, j; @@ -99,3 +152,4 @@ pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, return 0; } +#endif From 07166a6b18003a350d384f421e983a610ecb2a6c Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Tue, 9 Apr 2019 13:20:22 +0800 Subject: [PATCH 13/46] sdio_slave: rewrite the doc and highlight efuse-burning as the default option for 3.3V modules --- .../peripherals/sd_pullup_requirements.rst | 351 ++++++++++++------ .../api-reference/peripherals/sdio_slave.rst | 84 +++-- .../sdio/slave/main/Kconfig.projbuild | 2 +- 3 files changed, 291 insertions(+), 146 deletions(-) diff --git a/docs/en/api-reference/peripherals/sd_pullup_requirements.rst b/docs/en/api-reference/peripherals/sd_pullup_requirements.rst index 3fd76b0a0..658d94ea9 100644 --- a/docs/en/api-reference/peripherals/sd_pullup_requirements.rst +++ b/docs/en/api-reference/peripherals/sd_pullup_requirements.rst @@ -1,153 +1,268 @@ SD Pullup Requirements ====================== -CMD and DATA lines D0-D3 of the slave should be pulled up by 50KOhm resistor +CMD and DATA lines D0-D3 of the slave should be pulled up by 10 kOhm resistor even in 1-bit mode or SPI mode. The pullups of the slave cards should be connected even if they're not connected to the host. -The MTDI strapping pin is incompatible with DAT2 line pull-up by default -when the code flash is 3.3V. See :ref:`mtdi_strapping_pin` below. +The MTDI strapping pin by default is incompatible with DAT2 line pullup when +the flash is 3.3 V. See :ref:`technical_detail_sdio` below. -Pullup inside Official Modules ------------------------------- +.. _existing_issues_official_modules_sdio: -For Espressif official modules, different weak pullups / pulldowns are -connected to CMD, and DATA pins as below. To use these modules, -these pins are required to be pulled up by 50KOhm resistors, since internal -weak pullups are insufficient. +Possible Issues +--------------- -+-----------------------+-----+--------------------------+------+----------------------+------+ -| GPIO | 15 | 2 | 4 | 12 | 13 | -+=======================+=====+==========================+======+======================+======+ -| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | -+-----------------------+-----+--------------------------+------+----------------------+------+ -| At startup | WPU | WPD | WPD | PU for 1.8v flash; | WPU | -| | | | | WPD for 3.3v flash | | -+-----------------------+-----+--------------------------+------+----------------------+------+ -| Strapping requirement | | Low to download to flash | | High for 1.8v flash; | | -| | | | | Low for 3.3v flash | | -+-----------------------+-----+--------------------------+------+----------------------+------+ +Here is a list of Espressif chips, official modules and development kits and +the issues they may have during SDIO development. Since the requirements are +for the pullups on the SD bus, the issues should be resolved no matter if it +is a host or slave. Each issue is linked to its solution. The solution for a +specific issue may be different for host and slave. -- WPU: Weak pullup -- WPD: Weak pulldown -- PU: Pullup inside the module +Official modules are usually without the sufficient pullups on all 6 pins, it +is suggested to select one of the development kits for either host or slave +to provide such pullups. -For Wrover modules, they use 1.8v flash, and have pullup on GPIO12 inside. -For Wroom-32 Series, PICO-D4 modules, they use 3.3v flash, and is weakly -pulled down internally. See :ref:`mtdi_strapping_pin` below. +Chips +^^^^^ -Pullup on Official Devkit (WroverKit) --------------------------------------- + - ESP32 (except D2WD, see `ESP32 datasheet `_): + :ref:`sd_pullup_no_pullups`, whether the strapping conflicts with DAT2 is determined + by the flash you are using. Please see :ref:`strapping_conflicts_dat2` if + your flash chip is 3.3 V. -For official Wrover Kit (till version 3), some of the pullups are provided on -the board as the table below. For other devkits that don't have pullups, -please connect them yourselves. + - ESP32-D2WD: + :ref:`sd_pullup_no_pullups`, :ref:`no_pullup_on_gpio12` -+-----------------------+-----+------+------+------+---------+ -| GPIO | 15 | 2 | 4 | 12 | 13 | -+=======================+=====+======+======+======+=========+ -| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | -+-----------------------+-----+------+------+------+---------+ -| Pullup on the Kit | PU | PU | PU | | PU & PD | -+-----------------------+-----+------+------+------+---------+ + - ESP32-PICO-D4: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2` -- PU: Pullup -- PD: Pulldown +Modules +^^^^^^^ -The DAT3 pullup conflicts with JTAG pulldown in WroverKit v3 and earlier, please -either: + - ESP32-WROOM-32 Series: + Including ESP32-WROOM-32, ESP32-WROOM-32D, ESP32-WROOM-32U and + ESP32-SOLO-1. -1. pull it up by resistor less than 5KOhm (2kOhm suggested) in 4-bit mode. -2. pull it up or drive it high by host or VDD3.3V in 1-bit mode. + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`. -.. _mtdi_strapping_pin: + - ESP32-WROVER Series: + Including ESP32-WROVER and ESP32-WROVER-I. -MTDI strapping pin ------------------- + :ref:`sd_pullup_no_pullups`. -MTDI (GPIO12) is used as a bootstrapping pin to select output voltage of an -internal regulator which powers the flash chip (VDD_SDIO). This pin has an -internal pulldown so if left unconnected it will read low at reset (selecting -default 3.3V operation). When adding a pullup to this pin for SD card -operation, consider the following: + - ESP32-WROVER-B Series: + Including ESP32-WROVER-B and ESP32-WROVER-IB. -- For boards which don't use the internal regulator (VDD_SDIO) to power the - flash, GPIO12 can be pulled high. -- For boards which use 1.8V flash chip, GPIO12 needs to be pulled high at - reset. This is fully compatible with SD card operation. -- On boards which use the internal regulator and a 3.3V flash chip, GPIO12 - must be low at reset. This is incompatible with SD card operation. Please - check the table below to see whether your modules/kits use 3.3v flash. + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`. -+-----------------+---------------+--------------------------------------+ -| Module | Flash voltage | DAT2 connections | -+=================+===============+======================================+ -| PICO-D4 | 3.3V | Internal PD, change EFUSE and pullup | -+-----------------+ + or disable DAT2 line* + -| Wroom-32 Series | | | -+-----------------+---------------+--------------------------------------+ -| Wrover | 1.8V | Internal PU, pullup suggested | -+-----------------+---------------+--------------------------------------+ +.. _sdio_dev_kits: -Official devkits of different types and version mount different types of -modules, please refer to the table below to see whether your devkit can -support SDIO slave without steps above. +Development Boards +^^^^^^^^^^^^^^^^^^ -+--------------------------+-----------------+---------------+ -| Devkit | Module | Flash voltage | -+==========================+=================+===============+ -| PICO Kit | PICO-D4 | 3.3V | -+--------------------------+-----------------+ (see steps + -| DevKitC | Wroom-32 Series | below) | -+--------------------------+ + + -| WroverKit v2 and earlier | | | -+--------------------------+-----------------+---------------+ -| WroverKit v3 | Wrover | 1.8V | -+--------------------------+-----------------+---------------+ + - ESP32-PICO-KIT: + Including PICO-KIT v4.1, v4.0 and v3. -If your board requires internal regulator with 3.3v output, to make it -compatible with SD pullup, you can either: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`, + :ref:`gpio2_strapping_pin`. - - **In the case using ESP32 host only**, external pullup can be omitted and an - internal pullup can be enabled using a ``gpio_pullup_en(GPIO_NUM_12);`` call. - Most SD cards work fine when an internal pullup on GPIO12 line is enabled. - Note that if ESP32 experiences a power-on reset while the SD card is - sending data, high level on GPIO12 can be latched into the bootstrapping - register, and ESP32 will enter a boot loop until external reset with - correct GPIO12 level is applied. - - **In the case using ESP32 slave in 1-bit mode**, speicfy - ``SDIO_SLAVE_FLAG_DAT2_DISABLED`` in the slave to avoid slave detecting on - DAT2 line. Note the host will not know 4-bit mode is not supported any more - by the standard CCCR register. You have to tell the host use 1-bit only. - - **For ESP32 host or slave**, another option is to burn the flash voltage - selection efuses. This will permanently select 3.3V output voltage for the - internal regulator, and GPIO12 will not be used as a bootstrapping pin. - Then it is safe to connect a pullup resistor to GPIO12. This option is - suggested for production use. NOTE this cannot be reverted once the EFUSE - is burnt. + - ESP32-DevKitC: + Including ESP32-DevKitC v4 and v2. - The following command can be used to program flash voltage selection efuses **to 3.3V**: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`, + :ref:`gpio2_strapping_pin`. - components/esptool_py/esptool/espefuse.py set_flash_voltage 3.3V + - ESP-WROVER-KIT: + v4.1: Have pullups, but :ref:`pullup_conflicts_on_gpio13` , + :ref:`strapping_conflicts_dat2`. - This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and - `XPD_SDIO_REG` efuses. With all three burned to value 1, the internal - VDD_SDIO flash voltage regulator is permanently enabled at 3.3V. See - the technical reference manual for more details. + v3: Have pullups, but :ref:`pullup_conflicts_on_gpio13`. - `espefuse.py` has a `--do-not-confirm` option if running from an automated flashing script. + v2 and v1: Have pullups, but :ref:`pullup_conflicts_on_gpio13`, + :ref:`strapping_conflicts_dat2`, :ref:`gpio2_strapping_pin`. -GPIO2 Strapping pin -------------------- + You can tell the version of your ESP23-WROVER-KIT version from the module + on it: v4.1 are with ESP32-WROVER-B modules, v3 are with ESP32-WROVER + modules, while v2 and v1 are with ESP32-WROOM-32 modules. + + - ESP32-LyraTD-MSC: + :ref:`strapping_conflicts_dat2`. Have pullups. + + - ESP32-LyraT: + Have pullups, but :ref:`pullup_conflicts_on_gpio13` + +Non-Espressif Hosts +^^^^^^^^^^^^^^^^^^^ + +Please make sure that your 3rd party SDIO host has correct pullups for all +the signals. + +Solutions +--------- + +.. _sd_pullup_no_pullups: + +No Pullups +^^^^^^^^^^ + +When developing on boards without pullups, you can either: + +1. If your host and slave are on seperated boards, you can change one of them + to a board with pullups. Please see :ref:`sdio_dev_kits` to find Espressif + official boards with pullups. +2. Connect external pullups to VDD by yourself. Connect these pins without + pullups to the VDD through a 10 kOhm resistor. + +.. _pullup_conflicts_on_gpio13: + +Pullup Conflicts on GPIO13 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The DAT3 of slave may not be properly pulled up. You can either: + +1. Use 1-bit mode, and tie DAT3 of slave to VDD. +2. Use SPI mode. +3. Remove the pulldown resistors on GPIO13; or pull it up by resistor less + than 5 kOhm (2 kOhm suggested); or pull it up or drive it high by host or + VDD3.3V in 1-bit mode. + +.. _strapping_conflicts_dat2: + +Conflicts Between Bootstrap and SDIO on DAT2 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The strapping requirements conflict with SDIO protocol. See +:ref:`mtdi_strapping_pin` for the details of this issue. You can either: + +1. (Recomended) Burn the flash voltage selection eFuses. This will + permanently select 3.3 V output voltage for the internal regulator, and GPIO12 + will not be used as a bootstrapping pin. Then connect a pullup resistor + to GPIO12. + + .. warning:: Burning eFuse is irreversible. The issue list above may be + out of date. Do make sure the module you are burning is using a 3.3 V flash + according to the information on http://www.espressif.com/. If you burn the + 3.3 V eFuses on an 1.8 V module, the module will get broken. + + Run the command below under your IDF folder: + :: + + components/esptool_py/esptool/espefuse.py set_flash_voltage 3.3V + + This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and + `XPD_SDIO_REG` eFuses. With all three burned to value 1, the internal + VDD_SDIO flash voltage regulator is permanently set to 3.3 V. You will + see the following log if the burning succeeds: + :: + + espefuse.py v2.6 + Connecting.... + + Enable internal flash voltage regulator (VDD_SDIO) to 3.3 V. + The following eFuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG, XPD_SDIO_TIEH. + This is an irreversible operation. + Type 'BURN' (all capitals) to continue. + BURN + VDD_SDIO setting complete. + + You can also run ``components/esptool_py/esptool/espefuse.py summary`` to + check the status of the eFuses above. + + `espefuse.py` has a ``--do-not-confirm`` option if running from an + automated flashing script. + + See the ESP32 Technical Reference Manual for more details. + +2. **When using 1-bit mode or SPI mode**, DAT2 signal is not needed (though it + still has to be pulled up). If the device works as the host, you can leave + the DAT2 of host floating, and directly connect DAT2 of slave to VDD; or if + the device works as the slave, specify ``SDIO_SLAVE_FLAG_DAT2_DISABLED`` in + the slave app to avoid slave detecting on DAT2 line. Note the host will + not know that 4-bit mode is not supported any more by the standard CCCR + register. You have to forbid the host from using 4-bit mode. + +.. _no_pullup_on_gpio12: + +No Pullup on GPIO12 +^^^^^^^^^^^^^^^^^^^ + +Your module is compatible with the SDIO protocol. Just connect GPIO12 to the +VDD through a 10 kOhm resistor. + +.. _gpio2_strapping_pin: + +Auto-program Not Working (minor issue) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART download mode. You may find it unable to enter the UART download mode if you -correctly connect the pullup of SD on GPIO2. For WroverKit v3, there are -dedicated circuits to pulldown the GPIO2 when downloading. For other boards, -one way to do this is to connect GPIO0 and GPIO2 using a jumper, and then the -auto-reset circuit on most development boards will pull GPIO2 low along with -GPIO0, when entering download mode. +correctly connect the pullup of SD on GPIO2. -- Some boards have pulldown and/or LED on GPIO2. LED is usually ok, but - pulldown will interfere with D0 signals and must be removed. Check the - schematic of your development board for anything connected to GPIO2. +Some official kits pull down GPIO2 when downloading. For other boards, you +may try to connect GPIO0 and GPIO2 using a jumper, and then the auto-reset +circuit on most development boards will pull GPIO2 low along with GPIO0, when +entering download mode. (Some boards have pulldown and/or LED on GPIO2. LED +is usually ok, but the pulldown resistor will interfere with D0 signals and +must be removed. Check the schematic of your development board for anything +connected to GPIO2.) + +If the above way is not working, please just turn off the other device and +remove the pullups on GPIO2 when you are programming the slave. + + +.. _technical_detail_sdio: + +Technical Details +----------------- + +.. _mtdi_strapping_pin: + +MTDI Strapping Pin +^^^^^^^^^^^^^^^^^^ + +MTDI (GPIO12) is used as a bootstrapping pin to select output voltage of an +internal regulator which powers the flash chip (VDD_SDIO). This pin has an +internal pulldown so if left unconnected it will read low at startup +(selecting default 3.3 V operation). + +For ESP32-WROVER modules, excluding ESP32-WROVER-B, they use 1.8 V flash, and +have pullup on GPIO12 inside. For other modules, which use 3.3 V flash, have +no pullups on GPIO12, and GPIO12 is weakly pulled down internally. + +When adding a pullup to this pin for SD card operation, consider the +following: + +- For boards which don't use the internal regulator (VDD_SDIO) to power the + flash, GPIO12 can be pulled high. +- For boards which use 1.8 V flash chip, GPIO12 needs to be pulled high at + reset. This is fully compatible with SD card operation. +- On boards which use the internal regulator and a 3.3 V flash chip, GPIO12 + must be low at reset. This is incompatible with SD card operation. Please + check :ref:`existing_issues_official_modules_sdio` to see whether your board + has this issue, and how to solve it. + +Internal Pullups and Strapping Requirements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is never recommended to rely on internal weak pullups for SDIO +communications, since internal weak pullups are insufficient. But information +of the strapping requirements and internal pullups may be useful. For +Espressif official modules, different weak pullups / pulldowns are connected +to CMD, and DATA pins as below. + ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| GPIO | 15 | 2 | 4 | 12 | 13 | ++=======================+=====+==========================+======+=======================+======+ +| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| At startup | WPU | WPD | WPD | PU for 1.8 V flash; | WPU | +| | | | | WPD for 3.3 V flash | | ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| Strapping requirement | | Low to download to flash | | High for 1.8 V flash; | | +| | | | | Low for 3.3 V flash | | ++-----------------------+-----+--------------------------+------+-----------------------+------+ + +- WPU: Weak pullup +- WPD: Weak pulldown +- PU: Pullup inside the module \ No newline at end of file diff --git a/docs/en/api-reference/peripherals/sdio_slave.rst b/docs/en/api-reference/peripherals/sdio_slave.rst index 163cf1168..cd01a51d7 100644 --- a/docs/en/api-reference/peripherals/sdio_slave.rst +++ b/docs/en/api-reference/peripherals/sdio_slave.rst @@ -8,42 +8,72 @@ The ESP32 SDIO Card peripherals (Host, Slave) shares two sets of pins as below t The first set is usually occupied by SPI0 bus which is responsible for the SPI flash holding the code to run. This means SDIO slave driver can only runs on the second set of pins while SDIO host is not using it. -+----------+-------+-------+ -| Pin Name | Slot1 | Slot2 | -+ +-------+-------+ -| | GPIO Number | -+==========+=======+=======+ -| CLK | 6 | 14 | -+----------+-------+-------+ -| CMD | 11 | 15 | -+----------+-------+-------+ -| DAT0 | 7 | 2 | -+----------+-------+-------+ -| DAT1 | 8 | 4 | -+----------+-------+-------+ -| DAT2 | 9 | 12 | -+----------+-------+-------+ -| DAT3 | 10 | 13 | -+----------+-------+-------+ - The SDIO slave can run under 3 modes: SPI, 1-bit SD and 4-bit SD modes, which is detected automatically by the hardware. According to the SDIO specification, CMD and DAT0-3 lines should be pulled up no matter in 1-bit, -4-bit or SPI mode. Then the host initialize the slave into SD mode by first -sending CMD0 with DAT3 pin high, while initialize the slave into SPI mode by -sending CMD0 with CS pin (the same pin as DAT3) low. +4-bit or SPI mode. -.. note:: CMD and DATA lines D0-D3 of the card should be pulled up by 50KOhm resistor - even in 1-bit mode or SPI mode. Most official devkits don't meet the pullup - requirements by default, and there are conflicts on strapping pins as well. - Please refer to :doc:`sd_pullup_requirements` to see how to setup your - system correctly. +Connections +^^^^^^^^^^^ + ++----------+---------------+-------+-------+ +| Pin Name | Corresponding | Slot1 | Slot2 | ++ + pins in SPI +-------+-------+ +| | mode | GPIO Number | ++==========+===============+=======+=======+ +| CLK | SCLK | 6 | 14 | ++----------+---------------+-------+-------+ +| CMD | MOSI | 11 | 15 | ++----------+---------------+-------+-------+ +| DAT0 | MISO | 7 | 2 | ++----------+---------------+-------+-------+ +| DAT1 | Interrupt | 8 | 4 | ++----------+---------------+-------+-------+ +| DAT2 | N.C. (pullup) | 9 | 12 | ++----------+---------------+-------+-------+ +| DAT3 | #CS | 10 | 13 | ++----------+---------------+-------+-------+ + +- 1-bit SD mode: Connect CLK, CMD, DAT0, DAT1 pins and the ground. +- 4-bit SD mode: Connect all pins and the ground. +- SPI mode: Connect SCLK, MOSI, MISO, Interrupt, #CS pins and the ground. + +.. note:: Please check if CMD and DATA lines D0-D3 of the card are properly + pulled up by 10 KOhm resistors. This should be ensured even in 1-bit mode + or SPI mode. Most official modules don't offer these pullups internally. + If you are using official development boards, check + :ref:`existing_issues_official_modules_sdio` to see whether your + development boards have such pullups. + +.. note:: Most official modules have conflicts on strapping pins with the + SDIO slave function. If you are using a ESP32 module with 3.3 V flash + inside, you have to burn the EFUSE when you are developing on the module + for the first time. See :ref:`existing_issues_official_modules_sdio` to + see how to make your modules compatible with the SDIO. + + Here is a list for modules/kits with 3.3 V flash: + + - Modules: ESP32-PICO-D4, ESP32-WROOM-32 series (including ESP32-SOLO-1), + ESP32-WROVER-B and ESP32-WROVER-IB + - Kits: ESP32-PICO-KIT, ESP32-DevKitC (till v4), ESP32-WROVER-KIT + (v4.1 (also known as ESP32-WROVER-KIT-VB), v2, v1 (also known as DevKitJ + v1)) + + You can tell the version of your ESP23-WROVER-KIT version from the module + on it: v4.1 are with ESP32-WROVER-B modules, v3 are with ESP32-WROVER + modules, while v2 and v1 are with ESP32-WROOM-32 modules. + +Refer to :doc:`sd_pullup_requirements` for more technical details of the pullups. .. toctree:: :hidden: sd_pullup_requirements +The host initialize the slave into SD mode by first sending CMD0 with DAT3 +pin high, or in SPI mode by sending CMD0 with CS pin (the same pin as DAT3) +low. + After the initialization, the host can enable the 4-bit SD mode by writing CCCR register 0x07 by CMD52. All the bus detection process are handled by the slave peripheral. @@ -97,7 +127,7 @@ SDIO initialization process (Sector 3.1.2 of `SDIO Simplified Specification `_), which is described briefly in :ref:`esp_slave_init`. -However, there's an ESP32-specific upper-level communication protocol upon +Furthermore, there's an ESP32-specific upper-level communication protocol upon the CMD52/CMD53 to Func 1. Please refer to :ref:`esp_slave_protocol_layer`, or example :example:`peripherals/sdio` when programming your host. diff --git a/examples/peripherals/sdio/slave/main/Kconfig.projbuild b/examples/peripherals/sdio/slave/main/Kconfig.projbuild index 82a44877a..b3485bd3c 100644 --- a/examples/peripherals/sdio/slave/main/Kconfig.projbuild +++ b/examples/peripherals/sdio/slave/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" config SDIO_DAT2_DISABLED bool "Disable the DAT2 in SDIO slave" - default y + default n help SDIO slave DAT pin is unfortunately the same pin as MTDI, which controls the flash power voltage. For 3.3v flash devkits / modules / From 3fd896fe64fabd72530b2140c4cf19d51111e806 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Wed, 17 Apr 2019 12:40:49 +0800 Subject: [PATCH 14/46] sdio_slave: update version read from CCCR to 2.0 --- components/driver/sdio_slave.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/driver/sdio_slave.c b/components/driver/sdio_slave.c index 0d639d802..98e4f4ae4 100644 --- a/components/driver/sdio_slave.c +++ b/components/driver/sdio_slave.c @@ -533,6 +533,7 @@ static inline esp_err_t sdio_slave_hw_init(sdio_slave_config_t *config) SLC.rx_dscr_conf.slc0_token_no_replace = 1; HINF.cfg_data1.highspeed_enable = 1; + HINF.cfg_data1.sdio_ver = 0x232; switch(config->timing) { case SDIO_SLAVE_TIMING_PSEND_PSAMPLE: From ab6ad844b152594d7df7d4e23df3ec8397acc176 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Thu, 8 Aug 2019 13:42:47 +0530 Subject: [PATCH 15/46] mbedtls: use `errno` instead of `SO_ERROR` for getting socket errors As per upgrade notes of lwIP v2.1.0: socket API: according to the standard, SO_ERROR now only returns asynchronous errors. All other/normal/synchronous errors are (and always were) available via 'errno'. LWIP_SOCKET_SET_ERRNO has been removed - 'errno' is always set - and required! Refer: https://www.nongnu.org/lwip/2_1_x/upgrading.html Fixes https://github.com/espressif/esp-azure/issues/51 --- components/mbedtls/port/net_sockets.c | 38 ++++++++------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/components/mbedtls/port/net_sockets.c b/components/mbedtls/port/net_sockets.c index 6d8a1cc55..e64510071 100644 --- a/components/mbedtls/port/net_sockets.c +++ b/components/mbedtls/port/net_sockets.c @@ -59,16 +59,6 @@ static int net_prepare( void ) return ( 0 ); } -static int mbedtls_net_errno(int fd) -{ - int sock_errno = 0; - u32_t optlen = sizeof(sock_errno); - - getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen); - - return sock_errno; -} - /* * Initialize a context */ @@ -204,22 +194,19 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char * * Note: on a blocking socket this function always returns 0! */ -static int net_would_block( const mbedtls_net_context *ctx, int *errout ) +static int net_would_block( const mbedtls_net_context *ctx ) { - int error = mbedtls_net_errno(ctx->fd); - - if ( errout ) { - *errout = error; - } + int error = errno; /* * Never return 'WOULD BLOCK' on a non-blocking socket */ if ( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK ) { + errno = error; return ( 0 ); } - switch ( error ) { + switch ( errno = error ) { #if defined EAGAIN case EAGAIN: #endif @@ -267,7 +254,7 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx, } if ( ret < 0 ) { - if ( net_would_block( bind_ctx, NULL ) != 0 ) { + if ( net_would_block( bind_ctx ) != 0 ) { return ( MBEDTLS_ERR_SSL_WANT_READ ); } @@ -347,7 +334,6 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) { int ret; int fd = ((mbedtls_net_context *) ctx)->fd; - int error = 0; if ( fd < 0 ) { return ( MBEDTLS_ERR_NET_INVALID_CONTEXT ); @@ -356,15 +342,15 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) ret = (int) read( fd, buf, len ); if ( ret < 0 ) { - if ( net_would_block( ctx, &error ) != 0 ) { + if ( net_would_block( ctx ) != 0 ) { return ( MBEDTLS_ERR_SSL_WANT_READ ); } - if ( error == EPIPE || error == ECONNRESET ) { + if ( errno == EPIPE || errno == ECONNRESET ) { return ( MBEDTLS_ERR_NET_CONN_RESET ); } - if ( error == EINTR ) { + if ( errno == EINTR ) { return ( MBEDTLS_ERR_SSL_WANT_READ ); } @@ -422,8 +408,6 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) int ret; int fd = ((mbedtls_net_context *) ctx)->fd; - int error = 0; - if ( fd < 0 ) { return ( MBEDTLS_ERR_NET_INVALID_CONTEXT ); } @@ -431,15 +415,15 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) ret = (int) write( fd, buf, len ); if ( ret < 0 ) { - if ( net_would_block( ctx, &error ) != 0 ) { + if ( net_would_block( ctx ) != 0 ) { return ( MBEDTLS_ERR_SSL_WANT_WRITE ); } - if ( error == EPIPE || error == ECONNRESET ) { + if ( errno == EPIPE || errno == ECONNRESET ) { return ( MBEDTLS_ERR_NET_CONN_RESET ); } - if ( error == EINTR ) { + if ( errno == EINTR ) { return ( MBEDTLS_ERR_SSL_WANT_WRITE ); } From e5704ab1a8a5a3b95faaed9256c3c3f6fc179a05 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 2 Aug 2019 13:04:48 +0800 Subject: [PATCH 16/46] esp_flash: fix the set/get write protection functions Add support for get write protection support, fixed the duplicated set_write_protection link. All the write_protection check in the top layer are removed. The lower levels (chip) should ensure to disable write protection before the operation start. --- components/spi_flash/esp_flash_api.c | 30 +++------------ components/spi_flash/include/esp_flash.h | 2 - .../spi_flash/include/spi_flash_chip_driver.h | 7 +--- .../include/spi_flash_chip_generic.h | 14 ++++++- components/spi_flash/spi_flash_chip_generic.c | 38 +++++++++++-------- components/spi_flash/spi_flash_chip_issi.c | 5 +-- components/spi_flash/test/test_esp_flash.c | 33 +++++++++++++++- 7 files changed, 77 insertions(+), 52 deletions(-) diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index f064bcbdb..0e16fc80d 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -265,23 +265,13 @@ esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip) { VERIFY_OP(erase_chip); CHECK_WRITE_ADDRESS(chip, 0, chip->size); - bool write_protect = false; esp_err_t err = spiflash_start(chip); if (err != ESP_OK) { return err; } - err = esp_flash_get_chip_write_protect(chip, &write_protect); - - if (err == ESP_OK && write_protect) { - err = ESP_ERR_FLASH_PROTECTED; - } - - if (err == ESP_OK) { - err = chip->chip_drv->erase_chip(chip); - } - + err = chip->chip_drv->erase_chip(chip); return spiflash_end(chip, err); } @@ -292,7 +282,6 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui CHECK_WRITE_ADDRESS(chip, start, len); uint32_t block_erase_size = chip->chip_drv->erase_block == NULL ? 0 : chip->chip_drv->block_erase_size; uint32_t sector_size = chip->chip_drv->sector_size; - bool write_protect = false; if (sector_size == 0 || (block_erase_size % sector_size) != 0) { return ESP_ERR_FLASH_NOT_INITIALISED; @@ -310,16 +299,9 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui return err; } - // Check for write protection on whole chip - if (chip->chip_drv->get_chip_write_protect != NULL) { - err = chip->chip_drv->get_chip_write_protect(chip, &write_protect); - if (err == ESP_OK && write_protect) { - err = ESP_ERR_FLASH_PROTECTED; - } - } - // Check for write protected regions overlapping the erase region - if (err == ESP_OK && chip->chip_drv->get_protected_regions != NULL && chip->chip_drv->num_protectable_regions > 0) { + if (chip->chip_drv->get_protected_regions != NULL && + chip->chip_drv->num_protectable_regions > 0) { uint64_t protected = 0; err = chip->chip_drv->get_protected_regions(chip, &protected); if (err == ESP_OK && protected != 0) { @@ -360,10 +342,10 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui return err; } -esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protected) +esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *out_write_protected) { VERIFY_OP(get_chip_write_protect); - if (write_protected == NULL) { + if (out_write_protected == NULL) { return ESP_ERR_INVALID_ARG; } @@ -372,7 +354,7 @@ esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *wr return err; } - err = chip->chip_drv->get_chip_write_protect(chip, write_protected); + err = chip->chip_drv->get_chip_write_protect(chip, out_write_protected); return spiflash_end(chip, err); } diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index efcfccc24..4a7c184de 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -160,8 +160,6 @@ esp_err_t esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protec * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * - * If write protection is enabled, destructive operations will fail with ESP_ERR_FLASH_PROTECTED. - * * Some SPI flash chips may require a power cycle before write protect status can be cleared. Otherwise, * write protection can be removed via a follow-up call to this function. * diff --git a/components/spi_flash/include/spi_flash_chip_driver.h b/components/spi_flash/include/spi_flash_chip_driver.h index fd5c1e4c9..9dd8ffa97 100644 --- a/components/spi_flash/include/spi_flash_chip_driver.h +++ b/components/spi_flash/include/spi_flash_chip_driver.h @@ -90,10 +90,10 @@ struct spi_flash_chip_t { uint32_t block_erase_size; /* Optimal (fastest) block size for multi-sector erases on this chip */ /* Read the write protect status of the entire chip. */ - esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *write_protected); + esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *out_write_protected); /* Set the write protect status of the entire chip. */ - esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool write_protect_chip); + esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool chip_write_protect); /* Number of individually write protectable regions on this chip. Range 0-63. */ uint8_t num_protectable_regions; @@ -135,9 +135,6 @@ struct spi_flash_chip_t { /* Perform an encrypted write to the chip, using internal flash encryption hardware. */ esp_err_t (*write_encrypted)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); - /* Set the write enable flag. This function is called internally by other functions in this structure, before a destructive - operation takes place. */ - esp_err_t (*set_write_protect)(esp_flash_t *chip, bool write_protect); /* Wait for the SPI flash chip to be idle (any write operation to be complete.) This function is both called from the higher-level API functions, and from other functions in this structure. diff --git a/components/spi_flash/include/spi_flash_chip_generic.h b/components/spi_flash/include/spi_flash_chip_generic.h index 676e17311..885bd72e7 100644 --- a/components/spi_flash/include/spi_flash_chip_generic.h +++ b/components/spi_flash/include/spi_flash_chip_generic.h @@ -173,7 +173,19 @@ spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, ui * - ESP_OK if success * - or other error passed from the ``wait_idle``, ``read_status`` or ``set_write_protect`` function of host driver */ -esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect); +esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect); + +/** + * @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR (05h). + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param out_write_protect Output of whether the write protect is set. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``read_status`` function of host driver + */ +esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect); /** * @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c index 0e80e8eb1..8bbb9d137 100644 --- a/components/spi_flash/spi_flash_chip_generic.c +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -82,7 +82,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip) { esp_err_t err; - err = chip->chip_drv->set_write_protect(chip, false); + err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -102,7 +102,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip) esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address) { - esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -122,7 +122,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address) { - esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -185,7 +185,7 @@ esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, ui page_len = page_size - (address % page_size); } - err = chip->chip_drv->set_write_protect(chip, false); + err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->program_page(chip, buffer, address, page_len); @@ -205,7 +205,7 @@ esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void * return ESP_ERR_FLASH_UNSUPPORTED_HOST; // TODO } -esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect) +esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect) { esp_err_t err = ESP_OK; @@ -215,17 +215,26 @@ esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_prot chip->host->set_write_protect(chip->host, write_protect); } + bool wp_read; + err = chip->chip_drv->get_chip_write_protect(chip, &wp_read); + if (err == ESP_OK && wp_read != write_protect) { + // WREN flag has not been set! + err = ESP_ERR_NOT_FOUND; + } + return err; +} + +esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect) +{ + esp_err_t err = ESP_OK; uint8_t status; + assert(out_write_protect!=NULL); err = chip->host->read_status(chip->host, &status); if (err != ESP_OK) { return err; } - if ((status & SR_WREN) == 0) { - // WREN flag has not been set! - err = ESP_ERR_NOT_FOUND; - } - + *out_write_protect = ((status & SR_WREN) == 0); return err; } @@ -329,7 +338,7 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm ESP_EARLY_LOGV(TAG, "set_read_mode: status before 0x%x", sr); if ((sr & qe_sr_bit) == 0) { //some chips needs the write protect to be disabled before writing to Status Register - chip->chip_drv->set_write_protect(chip, false); + chip->chip_drv->set_chip_write_protect(chip, false); sr |= qe_sr_bit; spi_flash_trans_t t = { @@ -354,7 +363,7 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm return ESP_ERR_FLASH_NO_RESPONSE; } - chip->chip_drv->set_write_protect(chip, true); + chip->chip_drv->set_chip_write_protect(chip, true); } } return ESP_OK; @@ -383,8 +392,8 @@ const spi_flash_chip_t esp_flash_chip_generic = { .block_erase_size = 64 * 1024, // TODO: figure out if generic chip-wide protection bits exist across some manufacturers - .get_chip_write_protect = NULL, - .set_chip_write_protect = NULL, + .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, + .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, // Chip write protection regions do not appear to be standardised // at all, this is implemented in chip-specific drivers only. @@ -399,7 +408,6 @@ const spi_flash_chip_t esp_flash_chip_generic = { .page_size = 256, .write_encrypted = spi_flash_chip_generic_write_encrypted, - .set_write_protect = spi_flash_chip_generic_write_enable, .wait_idle = spi_flash_chip_generic_wait_idle, .set_read_mode = spi_flash_chip_generic_set_read_mode, }; diff --git a/components/spi_flash/spi_flash_chip_issi.c b/components/spi_flash/spi_flash_chip_issi.c index d32c3a192..d0b025637 100644 --- a/components/spi_flash/spi_flash_chip_issi.c +++ b/components/spi_flash/spi_flash_chip_issi.c @@ -58,8 +58,8 @@ const spi_flash_chip_t esp_flash_chip_issi = { .block_erase_size = 64 * 1024, // TODO: support get/set chip write protect for ISSI flash - .get_chip_write_protect = NULL, - .set_chip_write_protect = NULL, + .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, + .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, // TODO support protected regions on ISSI flash .num_protectable_regions = 0, @@ -73,7 +73,6 @@ const spi_flash_chip_t esp_flash_chip_issi = { .page_size = 256, .write_encrypted = spi_flash_chip_generic_write_encrypted, - .set_write_protect = spi_flash_chip_generic_write_enable, .wait_idle = spi_flash_chip_generic_wait_idle, .set_read_mode = spi_flash_chip_issi_set_read_mode, }; diff --git a/components/spi_flash/test/test_esp_flash.c b/components/spi_flash/test/test_esp_flash.c index 49d144c9c..19a93c8bf 100644 --- a/components/spi_flash/test/test_esp_flash.c +++ b/components/spi_flash/test/test_esp_flash.c @@ -366,6 +366,36 @@ TEST_CASE("SPI flash erase large region", "[esp_flash]") #endif } +static void test_write_protection(esp_flash_t* chip) +{ + bool wp = true; + esp_err_t ret = ESP_OK; + ret = esp_flash_get_chip_write_protect(chip, &wp); + TEST_ESP_OK(ret); + + for (int i = 0; i < 4; i ++) { + bool wp_write = !wp; + ret = esp_flash_set_chip_write_protect(chip, wp_write); + TEST_ESP_OK(ret); + + bool wp_read; + ret = esp_flash_get_chip_write_protect(chip, &wp_read); + TEST_ESP_OK(ret); + TEST_ASSERT(wp_read == wp_write); + wp = wp_read; + } +} + +TEST_CASE("Test esp_flash can enable/disable write protetion", "[esp_flash]") +{ + test_write_protection(NULL); +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_write_protection(test_chip); + teardown_test_chip(); +#endif +} + static const uint8_t large_const_buffer[16400] = { 203, // first byte 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, @@ -491,5 +521,4 @@ static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, si write_large_buffer(chip, part, source, length); read_and_check(chip, part, source, length); -} - +} \ No newline at end of file From e947522f3875806c61cac46580e35004e049d86a Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Sat, 3 Aug 2019 09:59:10 +0800 Subject: [PATCH 17/46] esp_flash: improve the comments a bit --- components/soc/include/hal/spi_flash_hal.h | 15 +++++--- .../spi_flash/include/memspi_host_driver.h | 2 + .../include/spi_flash_chip_generic.h | 37 +++++++++++-------- components/spi_flash/spi_flash_chip_issi.c | 1 - 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/components/soc/include/hal/spi_flash_hal.h b/components/soc/include/hal/spi_flash_hal.h index 3a18e4ca5..bf89c4148 100644 --- a/components/soc/include/hal/spi_flash_hal.h +++ b/components/soc/include/hal/spi_flash_hal.h @@ -88,14 +88,15 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver); esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *driver, spi_flash_trans_t *trans); /** - * Erase whole flash chip. + * Erase whole flash chip by using the erase chip (C7h) command. * * @param driver The driver context. */ void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver); /** - * Erase a specific sector by its start address. + * Erase a specific sector by its start address through the sector erase (20h) + * command. * * @param driver The driver context. * @param start_address Start address of the sector to erase. @@ -103,7 +104,8 @@ void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver); void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address); /** - * Erase a specific block by its start address. + * Erase a specific 64KB block by its start address through the 64KB block + * erase (D8h) command. * * @param driver The driver context. * @param start_address Start address of the block to erase. @@ -111,7 +113,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_ void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address); /** - * Program a page of the flash. + * Program a page of the flash using the page program (02h) command. * * @param driver The driver context. * @param address Address of the page to program @@ -121,7 +123,8 @@ void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_a void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length); /** - * Read from the flash. The read command should be set by ``spi_flash_hal_configure_host_read_mode`` before. + * Read from the flash. Call ``spi_flash_hal_configure_host_read_mode`` to + * configure the read command before calling this function. * * @param driver The driver context. * @param buffer Buffer to store the read data @@ -133,7 +136,7 @@ void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buf esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); /** - * Enable or disable the write protection of the flash chip. + * @brief Send the write enable (06h) or write disable (04h) command to the flash chip. * * @param driver The driver context. * @param wp true to enable the write protection, otherwise false. diff --git a/components/spi_flash/include/memspi_host_driver.h b/components/spi_flash/include/memspi_host_driver.h index 2347398aa..434361d97 100644 --- a/components/spi_flash/include/memspi_host_driver.h +++ b/components/spi_flash/include/memspi_host_driver.h @@ -62,6 +62,8 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d ******************************************************************************/ /** + * @brief Read the Status Register read from RDSR (05h). + * * High speed implementation of RDID through memspi interface relying on the * ``common_command``. * diff --git a/components/spi_flash/include/spi_flash_chip_generic.h b/components/spi_flash/include/spi_flash_chip_generic.h index 885bd72e7..672ca6550 100644 --- a/components/spi_flash/include/spi_flash_chip_generic.h +++ b/components/spi_flash/include/spi_flash_chip_generic.h @@ -66,7 +66,7 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip); esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size); /** - * @brief Erase chip by using the generic erase chip (C7h) command. + * @brief Erase chip by using the generic erase chip command. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @@ -77,7 +77,7 @@ esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size); esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip); /** - * @brief Erase sector by using the generic sector erase (20h) command. + * @brief Erase sector by using the generic sector erase command. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param start_address Start address of the sector to erase @@ -89,7 +89,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip); esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address); /** - * @brief Erase block by using the generic 64KB block erase (D8h) command + * @brief Erase block by the generic 64KB block erase command * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param start_address Start address of the block to erase @@ -114,7 +114,7 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length); /** - * @brief Perform a page program using the page program (02h) command. + * @brief Perform a page program using the page program command. * * @note Length of each call should not excced the limitation in * ``chip->host->max_write_bytes``. This function is called in @@ -163,7 +163,7 @@ esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); /** - * @brief Send the write enable (06h) command and verify the expected bit (1) in + * @brief Send the write enable or write disable command and verify the expected bit (1) in * the status register is set. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. @@ -171,12 +171,13 @@ spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, ui * * @return * - ESP_OK if success - * - or other error passed from the ``wait_idle``, ``read_status`` or ``set_write_protect`` function of host driver + * - or other error passed from the ``wait_idle``, ``read_status`` or + * ``set_write_protect`` function of host driver */ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect); /** - * @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR (05h). + * @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param out_write_protect Output of whether the write protect is set. @@ -188,8 +189,8 @@ esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect); /** - * @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write - * in progress bit) to be cleared. + * @brief Read flash status via the RDSR command and wait for bit 0 (write in + * progress bit) to be cleared. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param timeout_ms Time to wait before timeout, in ms. @@ -244,13 +245,15 @@ extern const spi_flash_chip_t esp_flash_chip_generic; esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms); /** - * @brief Utility function for set_read_mode chip_drv function + * @brief Utility function for set_read_mode chip_drv function. If required, + * set and check the QE bit in the flash chip to enable the QIO/QOUT mode. * - * Most setting of read mode follows a common pattern, except for how to enable Quad I/O modes (QIO/QOUT). - * These use different commands to read/write the status register, and a different bit is set/cleared. + * Most chip QE enable follows a common pattern, though commands to read/write + * the status register may be different, as well as the position of QE bit. * - * This is a generic utility function to implement set_read_mode() for this pattern. Also configures host - * registers via spi_flash_common_configure_host_read_mode(). + * Registers to actually do Quad transtions and command to be sent in reading + * should also be configured via + * spi_flash_chip_generic_config_host_read_mode(). * * @param qe_rdsr_command SPI flash command to read status register * @param qe_wrsr_command SPI flash command to write status register @@ -262,7 +265,11 @@ esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit); /** - * @brief Configure the host to use the specified read mode set in the ``chip->read_mode``. + * @brief Configure the host registers to use the specified read mode set in + * the ``chip->read_mode``. + * + * Usually called in chip_drv read() functions before actual reading + * transactions. Also prepare the command to be sent in read functions. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * diff --git a/components/spi_flash/spi_flash_chip_issi.c b/components/spi_flash/spi_flash_chip_issi.c index d0b025637..71684ec19 100644 --- a/components/spi_flash/spi_flash_chip_issi.c +++ b/components/spi_flash/spi_flash_chip_issi.c @@ -57,7 +57,6 @@ const spi_flash_chip_t esp_flash_chip_issi = { .sector_size = 4 * 1024, .block_erase_size = 64 * 1024, - // TODO: support get/set chip write protect for ISSI flash .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, From 08de39c226a85647207e9bf1a87e44ea79e9da26 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 6 Aug 2019 10:59:48 +0800 Subject: [PATCH 18/46] cmake: check include directories --- tools/cmake/component.cmake | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 6959af26c..8de4cc4c1 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -232,10 +232,10 @@ function(__component_get_requirements) file(REMOVE ${component_requires_file}) endfunction() -# __component_add_sources, __component_check_target +# __component_add_sources, __component_check_target, __component_add_include_dirs # -# Utility macros for component registration. Adds source files and checks target requirements -# respectively. +# Utility macros for component registration. Adds source files and checks target requirements, +# and adds include directories respectively. macro(__component_add_sources sources) set(sources "") if(__SRCS) @@ -279,6 +279,16 @@ macro(__component_add_sources sources) list(REMOVE_DUPLICATES sources) endmacro() +macro(__component_add_include_dirs lib dirs type) + foreach(dir ${dirs}) + get_filename_component(_dir ${dir} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_LIST_DIR}) + if(NOT IS_DIRECTORY ${_dir}) + message(FATAL_ERROR "Include directory '${_dir}' is not a directory.") + endif() + target_include_directories(${lib} ${type} ${_dir}) + endforeach() +endmacro() + macro(__component_check_target) if(__REQUIRED_IDF_TARGETS) idf_build_get_property(idf_target IDF_TARGET) @@ -324,6 +334,7 @@ macro(__component_set_all_dependencies) endif() endmacro() + # idf_component_get_property # # @brief Retrieve the value of the specified component property @@ -436,16 +447,16 @@ function(idf_component_register) if(sources OR __EMBED_FILES OR __EMBED_TXTFILES) add_library(${component_lib} STATIC ${sources}) __component_set_property(${component_target} COMPONENT_TYPE LIBRARY) - target_include_directories(${component_lib} PUBLIC ${__INCLUDE_DIRS}) - target_include_directories(${component_lib} PRIVATE ${__PRIV_INCLUDE_DIRS}) - target_include_directories(${component_lib} PUBLIC ${config_dir}) + __component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" PUBLIC) + __component_add_include_dirs(${component_lib} "${__PRIV_INCLUDE_DIRS}" PRIVATE) + __component_add_include_dirs(${component_lib} "${config_dir}" PUBLIC) set_target_properties(${component_lib} PROPERTIES OUTPUT_NAME ${COMPONENT_NAME}) __ldgen_add_component(${component_lib}) else() add_library(${component_lib} INTERFACE) __component_set_property(${component_target} COMPONENT_TYPE CONFIG_ONLY) - target_include_directories(${component_lib} INTERFACE ${__INCLUDE_DIRS}) - target_include_directories(${component_lib} INTERFACE ${config_dir}) + __component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" INTERFACE) + __component_add_include_dirs(${component_lib} "${config_dir}" INTERFACE) endif() # Alias the static/interface library created for linking to external targets. From 4dd2b9edb15246cde9e37ea3d69de6d2fac39483 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Tue, 6 Aug 2019 11:00:37 +0800 Subject: [PATCH 19/46] components: fix incorrect include dir args --- components/esp-tls/CMakeLists.txt | 2 +- components/tcp_transport/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index f6cc17c80..ea6b61216 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRCS "esp_tls.c" INCLUDE_DIRS "." - PRIVATE_INCLUDE_DIRS "private_include" + PRIV_INCLUDE_DIRS "private_include" REQUIRES mbedtls PRIV_REQUIRES lwip nghttp) diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index 9d5028a1b..fe7e71bf3 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -5,5 +5,5 @@ idf_component_register(SRCS "transport.c" "transport_utils.c" "transport_strcasestr.c" INCLUDE_DIRS "include" - PRIVATE_INCLUDE_DIRS "private_include" + PRIV_INCLUDE_DIRS "private_include" REQUIRES lwip esp-tls) From d47288d9db9de027bf77774cce4acbd531244f9d Mon Sep 17 00:00:00 2001 From: Soumesh Banerjee Date: Fri, 9 Aug 2019 10:07:22 +0800 Subject: [PATCH 20/46] :bug: Fix the white space bug in docs Fix only the visual rendering the issue for selection of text still remains and have to be solved by updating the html generator Closes #3208 --- docs/_static/theme_overrides.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css index df1cdd442..011488e79 100644 --- a/docs/_static/theme_overrides.css +++ b/docs/_static/theme_overrides.css @@ -40,3 +40,7 @@ a:hover { .logo { width: 240px !important; } + +a.internal::after{ + content: ' '; +} From b413a240cb70c1b9dfa946a368684276a44bd37e Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Mon, 29 Jul 2019 14:31:30 +0800 Subject: [PATCH 21/46] esp_attr: support force_inline --- components/esp32/include/esp_attr.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/esp32/include/esp_attr.h b/components/esp32/include/esp_attr.h index 7a3ec771d..58fef76c7 100644 --- a/components/esp32/include/esp_attr.h +++ b/components/esp32/include/esp_attr.h @@ -34,6 +34,9 @@ // Forces data to be placed to DMA-capable places #define DMA_ATTR WORD_ALIGNED_ATTR DRAM_ATTR +// Forces a function to be inlined +#define FORCE_INLINE_ATTR static inline __attribute__((always_inline)) + // Forces a string into DRAM instead of flash // Use as ets_printf(DRAM_STR("Hello world!\n")); #define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;})) @@ -45,7 +48,7 @@ // Forces bss variable into external memory. " #define EXT_RAM_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__) #else -#define EXT_RAM_ATTR +#define EXT_RAM_ATTR #endif // Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst" From a97fe5615f7e76b194c3d9328cf66f722b5e3b13 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Mon, 15 Jul 2019 14:21:36 +0800 Subject: [PATCH 22/46] feat(timer): refator timer group driver (partly pick) --- components/driver/include/driver/timer.h | 18 +-- components/soc/esp32/include/hal/timer_ll.h | 133 ++++++++++++++++++++ components/soc/include/hal/timer_types.h | 44 +++++++ 3 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 components/soc/esp32/include/hal/timer_ll.h create mode 100644 components/soc/include/hal/timer_types.h diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index cbf2a5bd2..cdff8a1b4 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -19,6 +19,7 @@ #include "soc/soc.h" #include "soc/timer_periph.h" #include "esp_intr_alloc.h" +#include "hal/timer_types.h" #ifdef __cplusplus extern "C" { @@ -36,15 +37,6 @@ typedef enum { TIMER_GROUP_MAX, } timer_group_t; -/** - * @brief Select a hardware timer from timer groups - */ -typedef enum { - TIMER_0 = 0, /*! Date: Thu, 25 Jul 2019 09:52:36 +0800 Subject: [PATCH 23/46] timer_group: support interrupt LL and some utility functions in ISR --- components/driver/include/driver/timer.h | 72 +++++++++++++++++---- components/driver/timer.c | 53 +++++++++++++-- components/soc/esp32/include/hal/timer_ll.h | 62 +++++++++++++++++- components/soc/include/hal/timer_types.h | 12 ++++ 4 files changed, 178 insertions(+), 21 deletions(-) diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index cdff8a1b4..6ab7e1095 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -246,9 +246,9 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will * be returned here. * - * @note If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, - * the handler function must be declared with IRAM_ATTR attribute - * and can only call functions in IRAM or ROM. It cannot call other timer APIs. + * @note If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, + * the handler function must be declared with IRAM_ATTR attribute + * and can only call functions in IRAM or ROM. It cannot call other timer APIs. * Use direct register access to configure timers from inside the ISR in this case. * * @return @@ -258,7 +258,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void*), void * arg, int intr_alloc_flags, timer_isr_handle_t *handle); /** @brief Initializes and configure the timer. - * + * * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1] * @param config Pointer to timer initialization parameters. @@ -284,28 +284,30 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer /** @brief Enable timer group interrupt, by enable mask * * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param en_mask Timer interrupt enable mask. - * Use TIMG_T0_INT_ENA_M to enable t0 interrupt - * Use TIMG_T1_INT_ENA_M to enable t1 interrupt + * @param intr_mask Timer interrupt enable mask. + * - TIMER_INTR_T0: t0 interrupt + * - TIMER_INTR_T1: t1 interrupt + * - TIMER_INTR_WDT: watchdog interrupt * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask); +esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask); /** @brief Disable timer group interrupt, by disable mask * * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 - * @param disable_mask Timer interrupt disable mask. - * Use TIMG_T0_INT_ENA_M to disable t0 interrupt - * Use TIMG_T1_INT_ENA_M to disable t1 interrupt + * @param intr_mask Timer interrupt disable mask. + * - TIMER_INTR_T0: t0 interrupt + * - TIMER_INTR_T1: t1 interrupt + * - TIMER_INTR_WDT: watchdog interrupt * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask); +esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask); /** @brief Enable timer interrupt * @@ -329,6 +331,52 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num); */ esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num); +/** @cond */ +/* Utilities functions that can be used in the ISR */ +/* Preview, don't treat them as stable API. */ + +/** + * Clear interrupt status bit. + */ +void timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Enable alarm. + */ +void timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Get the current counter value. + */ +uint64_t timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** + * Set the alarm threshold for the timer. + */ +void timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val); + +/** + * Enable/disable a counter. + */ +void timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en); + +/** + * Get the masked interrupt status. + */ +timer_intr_t timer_group_intr_get_in_isr(timer_group_t group_num); + +/** + * Clear interrupt. + */ +void timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask); + +/** + * Get auto reload enable status. + */ +bool timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num); + +/** @endcond */ + #ifdef __cplusplus } #endif diff --git a/components/driver/timer.c b/components/driver/timer.c index 6a82d87fa..67f0fffb3 100644 --- a/components/driver/timer.c +++ b/components/driver/timer.c @@ -19,6 +19,7 @@ #include "freertos/xtensa_api.h" #include "driver/timer.h" #include "driver/periph_ctrl.h" +#include "hal/timer_ll.h" static const char* TIMER_TAG = "timer_group"; #define TIMER_CHECK(a, str, ret_val) \ @@ -35,7 +36,7 @@ static const char* TIMER_TAG = "timer_group"; #define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR" #define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR" #define DIVIDER_RANGE_ERROR "HW TIMER divider outside of [2, 65536] range error" -static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1}; +DRAM_ATTR static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1}; static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; #define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux); @@ -171,7 +172,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_ return ESP_OK; } -esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, +esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void*), void * arg, int intr_alloc_flags, timer_isr_handle_t *handle) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); @@ -253,7 +254,7 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer return ESP_OK; } -esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask) +esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t en_mask) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&timer_spinlock[group_num]); @@ -262,7 +263,7 @@ esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask) return ESP_OK; } -esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask) +esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t disable_mask) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&timer_spinlock[group_num]); @@ -275,14 +276,54 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG); - return timer_group_intr_enable(group_num, BIT(timer_num)); + return timer_group_intr_enable(group_num, TIMER_LL_GET_INTR(timer_num)); } esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG); - return timer_group_intr_disable(group_num, BIT(timer_num)); + return timer_group_intr_disable(group_num, TIMER_LL_GET_INTR(timer_num)); } +timer_intr_t IRAM_ATTR timer_group_intr_get_in_isr(timer_group_t group_num) +{ + return timer_ll_intr_status_get(TG[group_num]); +} +void IRAM_ATTR timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + timer_ll_intr_status_clear(TG[group_num], TIMER_LL_GET_INTR(timer_num)); +} + +void IRAM_ATTR timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + timer_ll_set_alarm_enable(TG[group_num], timer_num, true); +} + +uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + uint64_t val; + timer_ll_get_counter_value(TG[group_num], timer_num, &val); + return val; +} + +void IRAM_ATTR timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val) +{ + timer_ll_set_alarm_value(TG[group_num], timer_num, alarm_val); +} + +void IRAM_ATTR timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en) +{ + timer_ll_set_counter_enable(TG[group_num], timer_num, counter_en); +} + +void IRAM_ATTR timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask) +{ + timer_ll_intr_status_clear(TG[group_num], intr_mask); +} + +bool IRAM_ATTR timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num) +{ + return timer_ll_get_auto_reload(TG[group_num], timer_num); +} diff --git a/components/soc/esp32/include/hal/timer_ll.h b/components/soc/esp32/include/hal/timer_ll.h index cc0cd69c5..d74c00ee7 100644 --- a/components/soc/esp32/include/hal/timer_ll.h +++ b/components/soc/esp32/include/hal/timer_ll.h @@ -24,6 +24,65 @@ extern "C" { #include "hal/timer_types.h" #include "soc/timer_periph.h" +//Helper macro to get corresponding interrupt of a timer +#define TIMER_LL_GET_INTR(TIMER_IDX) ((TIMER_IDX)==TIMER_0? TIMER_INTR_T0: TIMER_INTR_T1) + +#define TIMER_LL_GET_HW(TIMER_GROUP) ((TIMER_GROUP)==0? &TIMERG0: &TIMERG1) + +_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); +_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); +_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t"); + +/** + * @brief Enable timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt enable mask + * + * @return None + */ +static inline void timer_ll_intr_enable(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_ena.val |= intr_mask; +} + +/** + * @brief Disable timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt disable mask + * + * @return None + */ +static inline void timer_ll_intr_disable(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_ena.val &= (~intr_mask); +} + +/** + * @brief Get timer interrupt status. + * + * @param hw Beginning address of the peripheral registers. + * + * @return Masked interrupt status + */ +static inline timer_intr_t timer_ll_intr_status_get(timg_dev_t *hw) +{ + return hw->int_raw.val; +} + +/** + * @brief Clear timer interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param intr_mask Interrupt mask to clear + * + * @return None + */ +static inline void timer_ll_intr_status_clear(timg_dev_t *hw, timer_intr_t intr_mask) +{ + hw->int_clr_timers.val = intr_mask; +} /** * @brief Get counter vaule from time-base counter @@ -40,8 +99,6 @@ static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_ *timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low); } - - /** * @brief Set counter status, enable or disable counter. * @@ -56,7 +113,6 @@ static inline void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer hw->hw_timer[timer_num].config.enable = counter_en; } - /** * @brief Get auto reload mode. * diff --git a/components/soc/include/hal/timer_types.h b/components/soc/include/hal/timer_types.h index d555a2115..f1564eee9 100644 --- a/components/soc/include/hal/timer_types.h +++ b/components/soc/include/hal/timer_types.h @@ -20,6 +20,8 @@ extern "C" { #include #include +#include + /** * @brief Select a hardware timer from timer groups @@ -39,6 +41,16 @@ typedef enum { } timer_start_t; +/** + * @brief Interrupt types of the timer. + */ +//this is compatible with the value of esp32. +typedef enum { + TIMER_INTR_T0 = BIT(0), /*!< interrupt of timer 0 */ + TIMER_INTR_T1 = BIT(1), /*!< interrupt of timer 1 */ + TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */ +} timer_intr_t; + #ifdef __cplusplus } #endif From feea477023ccaa2ae05014ce083a7350fd04b1ae Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Tue, 30 Jul 2019 17:22:51 +0800 Subject: [PATCH 24/46] timer_group: add LL functions for WDT --- components/soc/esp32/include/hal/timer_ll.h | 96 +++++++++++++++++++++ components/soc/include/hal/timer_types.h | 11 +++ 2 files changed, 107 insertions(+) diff --git a/components/soc/esp32/include/hal/timer_ll.h b/components/soc/esp32/include/hal/timer_ll.h index d74c00ee7..f4fa09d94 100644 --- a/components/soc/esp32/include/hal/timer_ll.h +++ b/components/soc/esp32/include/hal/timer_ll.h @@ -184,6 +184,102 @@ static inline void timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_n *alarm_en = hw->hw_timer[timer_num].config.alarm_en; } +/* WDT operations */ + +/** + * Unlock/lock the WDT register in case of mis-operations. + * + * @param hw Beginning address of the peripheral registers. + * @param protect true to lock, false to unlock before operations. + */ + +FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect) +{ + hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE); +} + +/** + * Initialize WDT. + * + * @param hw Beginning address of the peripheral registers. + * + * @note Call ``timer_ll_wdt_set_protect first`` + */ +FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw) +{ + hw->wdt_config0.sys_reset_length=7; //3.2uS + hw->wdt_config0.cpu_reset_length=7; //3.2uS + //currently only level interrupt is supported + hw->wdt_config0.level_int_en = 1; + hw->wdt_config0.edge_int_en = 0; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us) +{ + hw->wdt_config1.clk_prescale=80*tick_time_us; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw) +{ + hw->wdt_feed = 1; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick) +{ + switch (stage) { + case 0: + hw->wdt_config2=timeout_tick; + break; + case 1: + hw->wdt_config3=timeout_tick; + break; + case 2: + hw->wdt_config4=timeout_tick; + break; + case 3: + hw->wdt_config5=timeout_tick; + break; + default: + abort(); + } +} + +_Static_assert(TIMER_WDT_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); +_Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); + +FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior) +{ + switch (stage) { + case 0: + hw->wdt_config0.stg0 = behavior; + break; + case 1: + hw->wdt_config0.stg1 = behavior; + break; + case 2: + hw->wdt_config0.stg2 = behavior; + break; + case 3: + hw->wdt_config0.stg3 = behavior; + break; + default: + abort(); + } +} + +FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable) +{ + hw->wdt_config0.en = enable; +} + +FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable) +{ + hw->wdt_config0.flashboot_mod_en = enable; +} + + #ifdef __cplusplus } #endif diff --git a/components/soc/include/hal/timer_types.h b/components/soc/include/hal/timer_types.h index f1564eee9..8ab5757f2 100644 --- a/components/soc/include/hal/timer_types.h +++ b/components/soc/include/hal/timer_types.h @@ -51,6 +51,17 @@ typedef enum { TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */ } timer_intr_t; +/** + * @brief Behavior of the watchdog if a stage times out. + */ +//this is compatible with the value of esp32. +typedef enum { + TIMER_WDT_OFF = 0, ///< The stage is turned off + TIMER_WDT_INT = 1, ///< The stage will trigger an interrupt + TIMER_WDT_RESET_CPU = 2, ///< The stage will reset the CPU + TIMER_WDT_RESET_SYSTEM = 3, ///< The stage will reset the whole system +} timer_wdt_behavior_t; + #ifdef __cplusplus } #endif From 264ffbeb14106ae32c7e156e9c3ad0eff737b503 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Wed, 24 Jul 2019 23:18:19 +0800 Subject: [PATCH 25/46] timer_group: use the LL --- components/app_trace/gcov/gcov_rtio.c | 13 +- components/app_trace/test/test_trace.c | 72 +---------- .../bootloader_support/src/bootloader_init.c | 5 +- components/driver/test/test_timer.c | 112 +++++++----------- components/esp32/int_wdt.c | 58 +++++---- components/esp32/panic.c | 43 ++++--- components/esp32/system_api.c | 22 ++-- components/esp32/task_wdt.c | 65 +++++----- components/esp32/test/test_intr_alloc.c | 22 ++-- components/esp32/test/test_reset_reason.c | 5 +- .../include/esp_private/system_internal.h | 2 + components/esp_event/test/test_event.c | 16 +-- components/esp_ringbuf/test/test_ringbuf.c | 4 +- components/freemodbus/port/porttimer.c | 18 ++- components/freemodbus/port/porttimer_m.c | 20 ++-- .../freertos/test/test_freertos_eventgroups.c | 4 +- .../freertos/test/test_freertos_task_notify.c | 12 +- .../freertos/test/test_suspend_scheduler.c | 5 +- .../freertos/test/test_task_suspend_resume.c | 2 +- components/spi_flash/test/test_spi_flash.c | 4 +- .../main/timer_group_example_main.c | 24 ++-- .../sysview_tracing/main/sysview_tracing.c | 29 +---- 22 files changed, 217 insertions(+), 340 deletions(-) diff --git a/components/app_trace/gcov/gcov_rtio.c b/components/app_trace/gcov/gcov_rtio.c index d01d7c6b6..a6008b463 100644 --- a/components/app_trace/gcov/gcov_rtio.c +++ b/components/app_trace/gcov/gcov_rtio.c @@ -21,6 +21,7 @@ #include "soc/timer_periph.h" #include "esp_app_trace.h" #include "esp_private/dbg_stubs.h" +#include "hal/timer_ll.h" #if CONFIG_ESP32_GCOV_ENABLE @@ -124,13 +125,13 @@ void esp_gcov_dump(void) #endif while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) { // to avoid complains that task watchdog got triggered for other tasks - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); // to avoid reboot on INT_WDT - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); } esp_dbg_stub_gcov_dump_do(); diff --git a/components/app_trace/test/test_trace.c b/components/app_trace/test/test_trace.c index 3037ab431..2e19e5808 100644 --- a/components/app_trace/test/test_trace.c +++ b/components/app_trace/test/test_trace.c @@ -145,56 +145,16 @@ static void esp_apptrace_test_timer_isr(void *arg) } tim_arg->data.wr_cnt++; - if (tim_arg->group == 0) { - if (tim_arg->id == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->id == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); } static void esp_apptrace_test_timer_isr_crash(void *arg) { esp_apptrace_test_timer_arg_t *tim_arg = (esp_apptrace_test_timer_arg_t *)arg; - if (tim_arg->group == 0) { - if (tim_arg->id == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->id == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); if (tim_arg->data.wr_cnt < ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH) { uint32_t *ts = (uint32_t *)(tim_arg->data.buf + sizeof(uint32_t)); *ts = (uint32_t)esp_apptrace_test_ts_get();//xthal_get_ccount();//xTaskGetTickCount(); @@ -850,28 +810,8 @@ static void esp_sysview_test_timer_isr(void *arg) //ESP_APPTRACE_TEST_LOGI("tim-%d: IRQ %d/%d\n", tim_arg->id, tim_arg->group, tim_arg->timer); - if (tim_arg->group == 0) { - if (tim_arg->timer == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->timer == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); } static void esp_sysviewtrace_test_task(void *p) diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 26b8fd0b3..d3196dd85 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -53,6 +53,7 @@ #include "bootloader_flash_config.h" #include "flash_qio_mode.h" +#include "hal/timer_ll.h" extern int _bss_start; extern int _bss_end; @@ -158,8 +159,8 @@ static esp_err_t bootloader_main(void) /* disable watch dog here */ rtc_wdt_disable(); #endif - REG_SET_FIELD(TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY, TIMG_WDT_WKEY_VALUE); - REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_flashboot_en(&TIMERG0, false); #ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH const uint32_t spiconfig = ets_efuse_get_spiconfig(); diff --git a/components/driver/test/test_timer.c b/components/driver/test/test_timer.c index bc5f3ae75..7aae242eb 100644 --- a/components/driver/test/test_timer.c +++ b/components/driver/test/test_timer.c @@ -11,68 +11,44 @@ #define TIMER_DELTA 0.001 static bool alarm_flag; -// group0 interruption -static void test_timer_group0_isr(void *para) -{ - int timer_idx = (int) para; - uint64_t timer_val; - double time; - uint64_t alarm_value; - alarm_flag = true; - if (TIMERG0.hw_timer[timer_idx].config.autoreload == 1) { - if (timer_idx == 0) { - TIMERG0.int_clr_timers.t0 = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - } - ets_printf("This is TG0 timer[%d] reload-timer alarm!\n", timer_idx); - timer_get_counter_value(TIMER_GROUP_0, timer_idx, &timer_val); - timer_get_counter_time_sec(TIMER_GROUP_0, timer_idx, &time); - ets_printf("time: %.8f S\n", time); - } else { - if (timer_idx == 0) { - TIMERG0.int_clr_timers.t0 = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - } - ets_printf("This is TG0 timer[%d] count-up-timer alarm!\n", timer_idx); - timer_get_counter_value(TIMER_GROUP_0, timer_idx, &timer_val); - timer_get_counter_time_sec(TIMER_GROUP_0, timer_idx, &time); - timer_get_alarm_value(TIMER_GROUP_0, timer_idx, &alarm_value); - ets_printf("time: %.8f S\n", time); - double alarm_time = (double) alarm_value / TIMER_SCALE; - ets_printf("alarm_time: %.8f S\n", alarm_time); - } -} +typedef struct { + timer_group_t timer_group; + timer_idx_t timer_idx; +} timer_info_t; -// group1 interruption -static void test_timer_group1_isr(void *para) +#define TIMER_INFO_INIT(TG, TID) {.timer_group = (TG), .timer_idx = (TID),} + +static timer_info_t timer_info[4] = { + TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_0), + TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_1), + TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_0), + TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_1), +}; + +#define GET_TIMER_INFO(TG, TID) (&timer_info[(TG)*2+(TID)]) + +// timer group interruption +static void test_timer_group_isr(void *para) { - int timer_idx = (int) para; + timer_info_t* info = (timer_info_t*) para; + const timer_group_t timer_group = info->timer_group; + const timer_idx_t timer_idx = info->timer_idx; uint64_t timer_val; double time; uint64_t alarm_value; alarm_flag = true; - if (TIMERG1.hw_timer[timer_idx].config.autoreload == 1) { - if (timer_idx == 0) { - TIMERG1.int_clr_timers.t0 = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - } - ets_printf("This is TG1 timer[%d] reload-timer alarm!\n", timer_idx); - timer_get_counter_value(TIMER_GROUP_1, timer_idx, &timer_val); - timer_get_counter_time_sec(TIMER_GROUP_1, timer_idx, &time); + if (timer_group_get_auto_reload_in_isr(timer_group, timer_idx)) { + timer_group_intr_clr_in_isr(timer_group, timer_idx); + ets_printf("This is TG%d timer[%d] reload-timer alarm!\n", timer_group, timer_idx); + timer_get_counter_value(timer_group, timer_idx, &timer_val); + timer_get_counter_time_sec(timer_group, timer_idx, &time); ets_printf("time: %.8f S\n", time); } else { - if (timer_idx == 0) { - TIMERG1.int_clr_timers.t0 = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - } - ets_printf("This is TG1 timer[%d] count-up-timer alarm!\n", timer_idx); - timer_get_counter_value(TIMER_GROUP_1, timer_idx, &timer_val); - timer_get_counter_time_sec(TIMER_GROUP_1, timer_idx, &time); - timer_get_alarm_value(TIMER_GROUP_1, timer_idx, &alarm_value); + timer_group_intr_clr_in_isr(timer_group, timer_idx); + ets_printf("This is TG%d timer[%d] count-up-timer alarm!\n", timer_group, timer_idx); + timer_get_counter_value(timer_group, timer_idx, &timer_val); + timer_get_counter_time_sec(timer_group, timer_idx, &time); + timer_get_alarm_value(timer_group, timer_idx, &alarm_value); ets_printf("time: %.8f S\n", time); double alarm_time = (double) alarm_value / TIMER_SCALE; ets_printf("alarm_time: %.8f S\n", alarm_time); @@ -86,13 +62,7 @@ static void tg_timer_init(int timer_group, int timer_idx, double alarm_time) timer_set_counter_value(timer_group, timer_idx, 0x0); timer_set_alarm_value(timer_group, timer_idx, alarm_time * TIMER_SCALE); timer_enable_intr(timer_group, timer_idx); - if (timer_group == 0) { - timer_isr_register(timer_group, timer_idx, test_timer_group0_isr, - (void *) timer_idx, ESP_INTR_FLAG_LOWMED, NULL); - } else { - timer_isr_register(timer_group, timer_idx, test_timer_group1_isr, - (void *) timer_idx, ESP_INTR_FLAG_LOWMED, NULL); - } + timer_isr_register(timer_group, timer_idx, test_timer_group_isr, GET_TIMER_INFO(timer_group, timer_idx), ESP_INTR_FLAG_LOWMED, NULL); timer_start(timer_group, timer_idx); } @@ -747,8 +717,8 @@ TEST_CASE("Timer enable timer interrupt", "[hw_timer]") // enable timer_intr0 timer_set_counter_value(TIMER_GROUP_0, TIMER_0, set_timer_val); timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1.2 * TIMER_SCALE); - timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr, - (void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL); + timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, + GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL); timer_start(TIMER_GROUP_0, TIMER_0); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == true) @@ -765,8 +735,8 @@ TEST_CASE("Timer enable timer interrupt", "[hw_timer]") // enable timer_intr1 timer_set_counter_value(TIMER_GROUP_1, TIMER_1, set_timer_val); timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, 1.2 * TIMER_SCALE); - timer_isr_register(TIMER_GROUP_1, TIMER_1, test_timer_group1_isr, - (void *) TIMER_1, ESP_INTR_FLAG_LOWMED, NULL); + timer_isr_register(TIMER_GROUP_1, TIMER_1, test_timer_group_isr, + GET_TIMER_INFO(TIMER_GROUP_1, TIMER_1), ESP_INTR_FLAG_LOWMED, NULL); timer_start(TIMER_GROUP_1, TIMER_1); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == true) @@ -813,23 +783,21 @@ TEST_CASE("Timer enable timer group interrupt", "[hw_timer][ignore]") all_timer_set_alarm_value(1.2); // enable timer group - timer_group_intr_enable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M); - timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr, - (void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL); + timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0); + timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL); timer_start(TIMER_GROUP_0, TIMER_0); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == true); //test enable auto_reload alarm_flag = false; - timer_group_intr_disable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M); + timer_group_intr_disable(TIMER_GROUP_0, TIMER_INTR_T0); timer_start(TIMER_GROUP_0, TIMER_0); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == false); - timer_group_intr_enable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M); - timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr, - (void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL); + timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0); + timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL); timer_start(TIMER_GROUP_0, TIMER_0); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT(alarm_flag == true); diff --git a/components/esp32/int_wdt.c b/components/esp32/int_wdt.c index 8f18f7157..2bfff8078 100644 --- a/components/esp32/int_wdt.c +++ b/components/esp32/int_wdt.c @@ -30,10 +30,11 @@ #include "driver/timer.h" #include "driver/periph_ctrl.h" #include "esp_int_wdt.h" +#include "hal/timer_ll.h" #if CONFIG_ESP_INT_WDT - +#define TG1_WDT_TICK_US 500 #define WDT_INT_NUM 24 @@ -48,11 +49,15 @@ static void IRAM_ATTR tick_hook(void) { } else { //Only feed wdt if app cpu also ticked. if (int_wdt_app_cpu_ticked) { - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt - TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG1, false); + //Set timeout before interrupt + timer_ll_wdt_set_timeout(&TIMERG1, 0, + CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); + //Set timeout before reset + timer_ll_wdt_set_timeout(&TIMERG1, 1, + 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); int_wdt_app_cpu_ticked=false; } } @@ -60,33 +65,36 @@ static void IRAM_ATTR tick_hook(void) { #else static void IRAM_ATTR tick_hook(void) { if (xPortGetCoreID()!=0) return; - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt - TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG1, false); + //Set timeout before interrupt + timer_ll_wdt_set_timeout(&TIMERG1, 0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); + //Set timeout before reset + timer_ll_wdt_set_timeout(&TIMERG1, 1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); } #endif void esp_int_wdt_init(void) { periph_module_enable(PERIPH_TIMG1_MODULE); - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS - TIMERG1.wdt_config0.cpu_reset_length=7; //3.2uS - TIMERG1.wdt_config0.level_int_en=1; - TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt - TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system - TIMERG1.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets //it to their actual value. - TIMERG1.wdt_config2=10000; - TIMERG1.wdt_config3=10000; - TIMERG1.wdt_config0.en=1; - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; - TIMERG1.int_clr_timers.wdt=1; - timer_group_intr_enable(TIMER_GROUP_1, TIMG_WDT_INT_ENA_M); + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_init(&TIMERG1); + timer_ll_wdt_set_tick(&TIMERG1, TG1_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG1_WDT_TICK_US + //1st stage timeout: interrupt + timer_ll_wdt_set_timeout_behavior(&TIMERG1, 0, TIMER_WDT_INT); + timer_ll_wdt_set_timeout(&TIMERG1, 0, 5*1000*1000/TG1_WDT_TICK_US); + //2nd stage timeout: reset system + timer_ll_wdt_set_timeout_behavior(&TIMERG1, 1, TIMER_WDT_RESET_SYSTEM); + timer_ll_wdt_set_timeout(&TIMERG1, 1, 5*1000*1000/TG1_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG1, true); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); + + timer_ll_intr_status_clear(&TIMERG1, TIMER_INTR_WDT); + timer_group_intr_enable(TIMER_GROUP_1, TIMER_INTR_WDT); } void esp_int_wdt_cpu_init(void) diff --git a/components/esp32/panic.c b/components/esp32/panic.c index 4a104f029..b0c6401de 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -44,6 +44,8 @@ #include "esp_private/system_internal.h" #include "sdkconfig.h" #include "esp_ota_ops.h" +#include "driver/timer.h" +#include "hal/timer_ll.h" #if CONFIG_SYSVIEW_ENABLE #include "SEGGER_RTT.h" #endif @@ -311,7 +313,7 @@ void panicHandler(XtExcFrame *frame) disableAllWdts(); if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || frame->exccause == PANIC_RSN_INTWDT_CPU1) { - TIMERG1.int_clr_timers.wdt = 1; + timer_group_clr_intr_sta_in_isr(TIMER_GROUP_1, TIMER_INTR_WDT); } #if CONFIG_ESP32_APPTRACE_ENABLE #if CONFIG_SYSVIEW_ENABLE @@ -401,19 +403,21 @@ static void illegal_instruction_helper(XtExcFrame *frame) */ static void reconfigureAllWdts(void) { - TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed = 1; - TIMERG0.wdt_config0.sys_reset_length = 7; //3.2uS - TIMERG0.wdt_config0.cpu_reset_length = 7; //3.2uS - TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system - TIMERG0.wdt_config1.clk_prescale = 80 * 500; //Prescaler: wdt counts in ticks of 0.5mS - TIMERG0.wdt_config2 = 2000; //1 second before reset - TIMERG0.wdt_config0.en = 1; - TIMERG0.wdt_wprotect = 0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_init(&TIMERG0); + timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US + //1st stage timeout: reset system + timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_RESET_SYSTEM); + //1 second before reset + timer_ll_wdt_set_timeout(&TIMERG0, 0, 1000*1000/TG0_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG0, true); + timer_ll_wdt_set_protect(&TIMERG0, true); + //Disable wdt 1 - TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.en = 0; - TIMERG1.wdt_wprotect = 0; + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_set_enable(&TIMERG1, false); + timer_ll_wdt_set_protect(&TIMERG1, true); } /* @@ -421,12 +425,13 @@ static void reconfigureAllWdts(void) */ static inline void disableAllWdts(void) { - TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_config0.en = 0; - TIMERG0.wdt_wprotect = 0; - TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.en = 0; - TIMERG1.wdt_wprotect = 0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_set_enable(&TIMERG0, false); + timer_ll_wdt_set_protect(&TIMERG0, true); + + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_set_enable(&TIMERG1, false); + timer_ll_wdt_set_protect(&TIMERG1, true); } static void esp_panic_dig_reset(void) __attribute__((noreturn)); diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index 570c0997a..7d3f1a90b 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -38,6 +38,7 @@ #include "esp_private/system_internal.h" #include "esp_efuse.h" #include "esp_efuse_table.h" +#include "hal/timer_ll.h" static const char* TAG = "system_api"; @@ -204,7 +205,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type) ESP_LOGW(TAG, "incorrect mac type"); break; } - + return ESP_OK; } @@ -281,12 +282,13 @@ void IRAM_ATTR esp_restart_noos(void) esp_dport_access_int_abort(); // Disable TG0/TG1 watchdogs - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_config0.en = 0; - TIMERG0.wdt_wprotect=0; - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.en = 0; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_set_enable(&TIMERG0, false); + timer_ll_wdt_set_protect(&TIMERG0, true); + + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_set_enable(&TIMERG1, false); + timer_ll_wdt_set_protect(&TIMERG1, true); // Flush any data left in UART FIFOs uart_tx_wait_idle(0); @@ -307,10 +309,10 @@ void IRAM_ATTR esp_restart_noos(void) WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); // Reset wifi/bluetooth/ethernet/sdio (bb/mac) - DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, + DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST | - DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | + DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0); @@ -370,7 +372,7 @@ static void get_chip_info_esp32(esp_chip_info_t* out_info) { uint32_t reg = REG_READ(EFUSE_BLK0_RDATA3_REG); memset(out_info, 0, sizeof(*out_info)); - + out_info->model = CHIP_ESP32; if ((reg & EFUSE_RD_CHIP_VER_REV1_M) != 0) { out_info->revision = 1; diff --git a/components/esp32/task_wdt.c b/components/esp32/task_wdt.c index 6675a1a98..c1aa4e976 100644 --- a/components/esp32/task_wdt.c +++ b/components/esp32/task_wdt.c @@ -34,6 +34,8 @@ #include "driver/periph_ctrl.h" #include "esp_task_wdt.h" #include "esp_private/system_internal.h" +#include "hal/timer_ll.h" + static const char *TAG = "task_wdt"; @@ -107,9 +109,9 @@ static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset) static void reset_hw_timer(void) { //All tasks have reset; time to reset the hardware timer. - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); //Clear all has_reset flags in list for (twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){ task->has_reset=false; @@ -137,11 +139,11 @@ static void task_wdt_isr(void *arg) twdt_task_t *twdttask; const char *cpu; //Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset) - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); //Acknowledge interrupt - TIMERG0.int_clr_timers.wdt=1; + timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_INTR_WDT); //We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty //bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case, //something bad already happened and reporting this is considered more important @@ -198,32 +200,33 @@ esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic) //Configure hardware timer periph_module_enable(PERIPH_TIMG0_MODULE); - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS - TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS - TIMERG0.wdt_config0.level_int_en=1; - TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt - TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system - TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS - TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt - TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset - TIMERG0.wdt_config0.en=1; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; //Enable write protection - - }else{ //twdt_config previously initialized + timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection + timer_ll_wdt_init(&TIMERG0); + timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US + //1st stage timeout: interrupt + timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_INT); + timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); + //2nd stage timeout: reset system + timer_ll_wdt_set_timeout_behavior(&TIMERG0, 1, TIMER_WDT_RESET_SYSTEM); + timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG0, true); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection + } else { //twdt_config previously initialized //Reconfigure task wdt twdt_config->panic = panic; twdt_config->timeout = timeout; //Reconfigure hardware timer - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.en=0; //Disable timer - TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt - TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset - TIMERG0.wdt_config0.en=1; //Renable timer - TIMERG0.wdt_feed=1; //Reset timer - TIMERG0.wdt_wprotect=0; //Enable write protection + timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection + timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer + //Set timeout before interrupt + timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); + //Set timeout before reset + timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG0, true); //Renable timer + timer_ll_wdt_feed(&TIMERG0); //Reset timer + timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection } portEXIT_CRITICAL(&twdt_spinlock); return ESP_OK; @@ -238,9 +241,9 @@ esp_err_t esp_task_wdt_deinit(void) ASSERT_EXIT_CRIT_RETURN((twdt_config->list == NULL), ESP_ERR_INVALID_STATE); //Disable hardware timer - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.en=0; //Disable timer - TIMERG0.wdt_wprotect=0; //Enable write protection + timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection + timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer + timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection ESP_ERROR_CHECK(esp_intr_free(twdt_config->intr_handle)); //Unregister interrupt free(twdt_config); //Free twdt_config diff --git a/components/esp32/test/test_intr_alloc.c b/components/esp32/test/test_intr_alloc.c index 85654c1ae..b17fb9e83 100644 --- a/components/esp32/test/test_intr_alloc.c +++ b/components/esp32/test/test_intr_alloc.c @@ -55,24 +55,20 @@ static void timer_isr(void *arg) int timer_idx = (int)arg; count[timer_idx]++; if (timer_idx==0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update=1; - TIMERG0.hw_timer[0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0); } if (timer_idx==1) { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update=1; - TIMERG0.hw_timer[1].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_1); } if (timer_idx==2) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update=1; - TIMERG1.hw_timer[0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_0); } if (timer_idx==3) { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update=1; - TIMERG1.hw_timer[1].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_1); + timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_1); } // ets_printf("int %d\n", timer_idx); } @@ -280,7 +276,7 @@ TEST_CASE("allocate 2 handlers for a same source and remove the later one","[esp r=esp_intr_alloc(ETS_SPI2_INTR_SOURCE, ESP_INTR_FLAG_SHARED, int_handler2, &ctx, &handle2); TEST_ESP_OK(r); SPI2.slave.trans_inten = 1; - + printf("trigger first time.\n"); SPI2.slave.trans_done = 1; diff --git a/components/esp32/test/test_reset_reason.c b/components/esp32/test/test_reset_reason.c index da03e8c1e..1aed30039 100644 --- a/components/esp32/test/test_reset_reason.c +++ b/components/esp32/test/test_reset_reason.c @@ -280,11 +280,12 @@ static void timer_group_test_first_stage(void) //Start timer timer_start(TIMER_GROUP_0, TIMER_0); //Waiting for timer_group to generate an interrupt - while( !TIMERG0.int_raw.t0 && loop_cnt++ < 100) { + while( !(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0) && + loop_cnt++ < 100) { vTaskDelay(200); } //TIMERG0.int_raw.t0 == 1 means an interruption has occurred - TEST_ASSERT_EQUAL(1, TIMERG0.int_raw.t0); + TEST_ASSERT(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0); esp_restart(); } diff --git a/components/esp_common/include/esp_private/system_internal.h b/components/esp_common/include/esp_private/system_internal.h index e0d95d2f7..8ecef8da9 100644 --- a/components/esp_common/include/esp_private/system_internal.h +++ b/components/esp_common/include/esp_private/system_internal.h @@ -20,6 +20,8 @@ extern "C" { #include "esp_system.h" +#define TG0_WDT_TICK_US 500 + /** * @brief Internal function to restart PRO and APP CPUs. * diff --git a/components/esp_event/test/test_event.c b/components/esp_event/test/test_event.c index 6560bdc5f..b375d3f90 100644 --- a/components/esp_event/test/test_event.c +++ b/components/esp_event/test/test_event.c @@ -30,14 +30,14 @@ static const char* TAG = "test_event"; #define TEST_CONFIG_WAIT_MULTIPLIER 5 -// The initial logging "initializing test" is to ensure mutex allocation is not counted against memory not being freed -// during teardown. +// The initial logging "initializing test" is to ensure mutex allocation is not counted against memory not being freed +// during teardown. #define TEST_SETUP() \ ESP_LOGI(TAG, "initializing test"); \ size_t free_mem_before = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); \ test_setup(); \ s_test_core_id = xPortGetCoreID(); \ - s_test_priority = uxTaskPriorityGet(NULL); + s_test_priority = uxTaskPriorityGet(NULL); #define TEST_TEARDOWN() \ test_teardown(); \ @@ -294,15 +294,11 @@ void IRAM_ATTR test_event_on_timer_alarm(void* para) { /* Retrieve the interrupt status and the counter value from the timer that reported the interrupt */ - TIMERG0.hw_timer[TIMER_0].update = 1; uint64_t timer_counter_value = - ((uint64_t) TIMERG0.hw_timer[TIMER_0].cnt_high) << 32 - | TIMERG0.hw_timer[TIMER_0].cnt_low; - - TIMERG0.int_clr_timers.t0 = 1; + timer_group_get_counter_value_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE); - TIMERG0.hw_timer[TIMER_0].alarm_high = (uint32_t) (timer_counter_value >> 32); - TIMERG0.hw_timer[TIMER_0].alarm_low = (uint32_t) timer_counter_value; + timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, TIMER_0, timer_counter_value); int data = (int) para; // Posting events with data more than 4 bytes should fail. diff --git a/components/esp_ringbuf/test/test_ringbuf.c b/components/esp_ringbuf/test/test_ringbuf.c index 62ca3c9b1..476283a0b 100644 --- a/components/esp_ringbuf/test/test_ringbuf.c +++ b/components/esp_ringbuf/test/test_ringbuf.c @@ -356,8 +356,8 @@ static int iterations; static void ringbuffer_isr(void *arg) { //Clear timer interrupt - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID()); //Test sending to buffer from ISR from ISR if (buf_type < NO_OF_RB_TYPES) { diff --git a/components/freemodbus/port/porttimer.c b/components/freemodbus/port/porttimer.c index 4e832ef73..709031d66 100644 --- a/components/freemodbus/port/porttimer.c +++ b/components/freemodbus/port/porttimer.c @@ -64,19 +64,15 @@ static const USHORT usTimerIndex = CONFIG_FMB_TIMER_INDEX; // Modbus Timer index used by stack static const USHORT usTimerGroupIndex = CONFIG_FMB_TIMER_GROUP; // Modbus Timer group index used by stack -static timg_dev_t *MB_TG[2] = {&TIMERG0, &TIMERG1}; - /* ----------------------- Start implementation -----------------------------*/ static void IRAM_ATTR vTimerGroupIsr(void *param) { - // Retrieve the interrupt status and the counter value - // from the timer that reported the interrupt - uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st_timers.val; - if (intr_status & BIT(usTimerIndex)) { - MB_TG[usTimerGroupIndex]->int_clr_timers.val |= BIT(usTimerIndex); - (void)pxMBPortCBTimerExpired(); // Timer callback function - MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].config.alarm_en = TIMER_ALARM_EN; - } + assert((int)param == usTimerIndex); + // Retrieve the counter value from the timer that reported the interrupt + timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex); + (void)pxMBPortCBTimerExpired(); // Timer callback function + // Enable alarm + timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex); } #endif @@ -113,7 +109,7 @@ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us) "failure to set alarm failure, timer_set_alarm_value() returned (0x%x).", (uint32_t)xErr); // Register ISR for timer - xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, NULL, ESP_INTR_FLAG_IRAM, NULL); + xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_IRAM, NULL); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "timer set value failure, timer_isr_register() returned (0x%x).", (uint32_t)xErr); diff --git a/components/freemodbus/port/porttimer_m.c b/components/freemodbus/port/porttimer_m.c index 9ba9f52cd..c2d52281b 100644 --- a/components/freemodbus/port/porttimer_m.c +++ b/components/freemodbus/port/porttimer_m.c @@ -61,22 +61,16 @@ static USHORT usT35TimeOut50us; static const USHORT usTimerIndex = MB_TIMER_INDEX; // Initialize Modbus Timer index used by stack, static const USHORT usTimerGroupIndex = MB_TIMER_GROUP; // Timer group index used by stack -static timg_dev_t *MB_TG[2] = { &TIMERG0, &TIMERG1 }; - /* ----------------------- static functions ---------------------------------*/ static void IRAM_ATTR vTimerGroupIsr(void *param) { - // Retrieve the interrupt status and the counter value - // from the timer that reported the interrupt - uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st_timers.val; - if (intr_status & BIT(usTimerIndex)) { - MB_TG[usTimerGroupIndex]->int_clr_timers.val |= BIT(usTimerIndex); - MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].update = 1; - (void)pxMBMasterPortCBTimerExpired(); // Timer expired callback function - // Enable alarm - MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].config.alarm_en = TIMER_ALARM_EN; - } + assert((int)param == usTimerIndex); + // Retrieve the the counter value from the timer that reported the interrupt + timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex); + (void)pxMBMasterPortCBTimerExpired(); // Timer expired callback function + // Enable alarm + timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex); } /* ----------------------- Start implementation -----------------------------*/ @@ -115,7 +109,7 @@ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us) (uint32_t)xErr); // Register ISR for timer xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, - vTimerGroupIsr, NULL, ESP_INTR_FLAG_IRAM, NULL); + vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_IRAM, NULL); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "timer set value failure, timer_isr_register() returned (0x%x).", (uint32_t)xErr); diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index 9b86f759f..1a245e2fb 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -138,8 +138,8 @@ static bool test_clear_bits; static void IRAM_ATTR event_group_isr(void *arg) { portBASE_TYPE task_woken = pdFALSE; - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID()); if(test_set_bits){ xEventGroupSetBitsFromISR(eg, BITS, &task_woken); diff --git a/components/freertos/test/test_freertos_task_notify.c b/components/freertos/test/test_freertos_task_notify.c index 8179cef9b..226180d8a 100644 --- a/components/freertos/test/test_freertos_task_notify.c +++ b/components/freertos/test/test_freertos_task_notify.c @@ -97,16 +97,10 @@ static void receiver_task (void* arg){ static void IRAM_ATTR sender_ISR (void *arg) { int curcore = xPortGetCoreID(); - if(curcore == 0){ //Clear timer interrupt - //Clear intr and pause via direct reg access as IRAM ISR cannot access timer APIs - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].config.enable = 0; - }else{ - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].config.enable = 0; - } + timer_group_intr_clr_in_isr(TIMER_GROUP_0, curcore); + timer_group_set_counter_enable_in_isr(TIMER_GROUP_0, curcore, TIMER_PAUSE); //Re-enable alarm - TIMERG0.hw_timer[curcore].config.alarm_en = 1; + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, curcore); if(isr_give){ //Test vTaskNotifyGiveFromISR() on same core notifs_sent++; diff --git a/components/freertos/test/test_suspend_scheduler.c b/components/freertos/test/test_suspend_scheduler.c index 9aef2ce7e..9e7b039ed 100644 --- a/components/freertos/test/test_suspend_scheduler.c +++ b/components/freertos/test/test_suspend_scheduler.c @@ -20,9 +20,8 @@ static volatile unsigned isr_count; mutex semaphore to wake up another counter task */ static void timer_group0_isr(void *vp_arg) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[TIMER_0].update = 1; - TIMERG0.hw_timer[TIMER_0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0); portBASE_TYPE higher_awoken = pdFALSE; isr_count++; xSemaphoreGiveFromISR(isr_semaphore, &higher_awoken); diff --git a/components/freertos/test/test_task_suspend_resume.c b/components/freertos/test/test_task_suspend_resume.c index 7d60de366..9b7c47cd4 100644 --- a/components/freertos/test/test_task_suspend_resume.c +++ b/components/freertos/test/test_task_suspend_resume.c @@ -118,7 +118,7 @@ volatile bool timer_isr_fired; void IRAM_ATTR timer_group0_isr(void *vp_arg) { // Clear interrupt - TIMERG0.int_clr_timers.val = TIMERG0.int_st_timers.val; + timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_0|TIMER_1); timer_isr_fired = true; TaskHandle_t handle = vp_arg; diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index 0010f86d8..f94372374 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -108,8 +108,8 @@ typedef struct { static void IRAM_ATTR timer_isr(void* varg) { block_task_arg_t* arg = (block_task_arg_t*) varg; - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0); ets_delay_us(arg->delay_time_us); arg->repeat_count++; } diff --git a/examples/peripherals/timer_group/main/timer_group_example_main.c b/examples/peripherals/timer_group/main/timer_group_example_main.c index 403f9c0a0..cd1e8cdee 100644 --- a/examples/peripherals/timer_group/main/timer_group_example_main.c +++ b/examples/peripherals/timer_group/main/timer_group_example_main.c @@ -60,11 +60,8 @@ void IRAM_ATTR timer_group0_isr(void *para) /* Retrieve the interrupt status and the counter value from the timer that reported the interrupt */ - uint32_t intr_status = TIMERG0.int_st_timers.val; - TIMERG0.hw_timer[timer_idx].update = 1; - uint64_t timer_counter_value = - ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32 - | TIMERG0.hw_timer[timer_idx].cnt_low; + timer_intr_t timer_intr = timer_group_intr_get_in_isr(TIMER_GROUP_0); + uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(TIMER_GROUP_0, timer_idx); /* Prepare basic event data that will be then sent back to the main program task */ @@ -75,22 +72,21 @@ void IRAM_ATTR timer_group0_isr(void *para) /* Clear the interrupt and update the alarm time for the timer with without reload */ - if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) { + if (timer_intr & TIMER_INTR_T0) { evt.type = TEST_WITHOUT_RELOAD; - TIMERG0.int_clr_timers.t0 = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE); - TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_counter_value >> 32); - TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_counter_value; - } else if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) { + timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value); + } else if (timer_intr & TIMER_INTR_T1) { evt.type = TEST_WITH_RELOAD; - TIMERG0.int_clr_timers.t1 = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1); } else { evt.type = -1; // not supported even type } /* After the alarm has been triggered we need enable it again, so it is triggered the next time */ - TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN; + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, timer_idx); /* Now just send the event data back to the main program task */ xQueueSendFromISR(timer_queue, &evt, NULL); @@ -103,7 +99,7 @@ void IRAM_ATTR timer_group0_isr(void *para) * auto_reload - should the timer auto reload on alarm? * timer_interval_sec - the interval of alarm to set */ -static void example_tg0_timer_init(int timer_idx, +static void example_tg0_timer_init(int timer_idx, bool auto_reload, double timer_interval_sec) { /* Select and initialize basic parameters of the timer */ @@ -123,7 +119,7 @@ static void example_tg0_timer_init(int timer_idx, /* Configure the alarm value and the interrupt on alarm. */ timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE); timer_enable_intr(TIMER_GROUP_0, timer_idx); - timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr, + timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr, (void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL); timer_start(TIMER_GROUP_0, timer_idx); diff --git a/examples/system/sysview_tracing/main/sysview_tracing.c b/examples/system/sysview_tracing/main/sysview_tracing.c index 3436b4cbc..32c4562e1 100644 --- a/examples/system/sysview_tracing/main/sysview_tracing.c +++ b/examples/system/sysview_tracing/main/sysview_tracing.c @@ -107,32 +107,6 @@ static void example_timer_init(int timer_group, int timer_idx, uint32_t period) timer_enable_intr(timer_group, timer_idx); } -static void example_timer_rearm(int timer_group, int timer_idx) -{ - if (timer_group == 0) { - if (timer_idx == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (timer_group == 1) { - if (timer_idx == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } -} - static void example_timer_isr(void *arg) { example_event_data_t *tim_arg = (example_event_data_t *)arg; @@ -152,7 +126,8 @@ static void example_timer_isr(void *arg) } } // re-start timer - example_timer_rearm(tim_arg->group, tim_arg->timer); + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->timer); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->timer); } static void example_task(void *p) From d850a0bd1c7fd96ec7dcf58a13f140124eba3a65 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 8 Aug 2019 17:49:12 +0800 Subject: [PATCH 26/46] esp_attr: add flag_attr to support enums used as flags --- components/cxx/test/test_cxx.cpp | 28 ++++++++++++++++++++++++ components/esp32/include/esp_attr.h | 24 ++++++++++++++++++++ components/soc/include/hal/timer_types.h | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/components/cxx/test/test_cxx.cpp b/components/cxx/test/test_cxx.cpp index 0f5cce331..0bf92f324 100644 --- a/components/cxx/test/test_cxx.cpp +++ b/components/cxx/test/test_cxx.cpp @@ -319,3 +319,31 @@ TEST_CASE("can call std::function and bind", "[cxx]") #endif +/* Tests below are done in the compile time, don't actually get run. */ +/* Check whether a enumerator flag can be used in C++ */ + + +template __attribute__((unused)) static void test_binary_operators() +{ + T flag1 = (T)0; + T flag2 = (T)0; + flag1 = ~flag1; + flag1 = flag1 | flag2; + flag1 = flag1 & flag2; + flag1 = flag1 ^ flag2; + flag1 = flag1 >> 2; + flag1 = flag1 << 2; + flag1 |= flag2; + flag1 &= flag2; + flag1 ^= flag2; + flag1 >>= 2; + flag1 <<= 2; +} + +//Add more types here. If any flags cannot pass the build, use FLAG_ATTR in esp_attr.h +#include "hal/timer_types.h" +template void test_binary_operators(); + + + + diff --git a/components/esp32/include/esp_attr.h b/components/esp32/include/esp_attr.h index 58fef76c7..34458948a 100644 --- a/components/esp32/include/esp_attr.h +++ b/components/esp32/include/esp_attr.h @@ -76,6 +76,30 @@ // Forces to not inline function #define NOINLINE_ATTR __attribute__((noinline)) +// This allows using enum as flags in C++ +// Format: FLAG_ATTR(flag_enum_t) +#ifdef __cplusplus + +#define FLAG_ATTR_IMPL(TYPE, INT_TYPE) \ +constexpr TYPE operator~ (TYPE a) { return (TYPE)~(INT_TYPE)a; } \ +constexpr TYPE operator| (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a | (INT_TYPE)b); } \ +constexpr TYPE operator& (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a & (INT_TYPE)b); } \ +constexpr TYPE operator^ (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a ^ (INT_TYPE)b); } \ +constexpr TYPE operator>> (TYPE a, int b) { return (TYPE)((INT_TYPE)a >> b); } \ +constexpr TYPE operator<< (TYPE a, int b) { return (TYPE)((INT_TYPE)a << b); } \ +TYPE& operator|=(TYPE& a, TYPE b) { a = a | b; return a; } \ +TYPE& operator&=(TYPE& a, TYPE b) { a = a & b; return a; } \ +TYPE& operator^=(TYPE& a, TYPE b) { a = a ^ b; return a; } \ +TYPE& operator>>=(TYPE& a, int b) { a >>= b; return a; } \ +TYPE& operator<<=(TYPE& a, int b) { a <<= b; return a; } + +#define FLAG_ATTR_U32(TYPE) FLAG_ATTR_IMPL(TYPE, uint32_t) +#define FLAG_ATTR FLAG_ATTR_U32 + +#else +#define FLAG_ATTR(TYPE) +#endif + // Implementation for a unique custom section // // This prevents gcc producing "x causes a section type conflict with y" diff --git a/components/soc/include/hal/timer_types.h b/components/soc/include/hal/timer_types.h index 8ab5757f2..e9bcc9985 100644 --- a/components/soc/include/hal/timer_types.h +++ b/components/soc/include/hal/timer_types.h @@ -40,7 +40,6 @@ typedef enum { TIMER_START = 1, /*! Date: Fri, 9 Aug 2019 16:35:31 +0800 Subject: [PATCH 27/46] cmake: fix encrypted project flash arg file generation --- components/esptool_py/flash_encrypted_project_args.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esptool_py/flash_encrypted_project_args.in b/components/esptool_py/flash_encrypted_project_args.in index db16bc6cd..a1875e69e 100644 --- a/components/esptool_py/flash_encrypted_project_args.in +++ b/components/esptool_py/flash_encrypted_project_args.in @@ -1,3 +1,3 @@ --encrypt ${ESPTOOLPY_FLASH_PROJECT_OPTIONS} -$, +$ From b1f657fc656f1784c1d237a4476e8e0db0a19236 Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Thu, 8 Aug 2019 16:02:33 +0530 Subject: [PATCH 28/46] wifi: Avoid recalculating PMK when esp_wifi_set_config is not called Scenarios where this fix is applicable. 1) Every time the system is powered-on/restarted without calling esp_wifi_set_config. 2) esp_wifi_init()/connect()/stop()/deinit() is called multiple times without esp_wifi_set_config. Closes IDFGH-1520 --- components/esp_wifi/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index 8e2ed075d..09ed80c2b 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit 8e2ed075db7f4d5f942b5ea354070d6273c01638 +Subproject commit 09ed80c2b047ae5bb41ddbfb9be44ec2bc71fedd From 87ebdaa74e84966ed297fa977cd2ed1e70e65ddf Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 9 Aug 2019 12:30:23 +0800 Subject: [PATCH 29/46] cmake: set component properties --- tools/ci/test_build_system_cmake.sh | 8 ++++++++ tools/cmake/component.cmake | 2 ++ 2 files changed, 10 insertions(+) diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 5b2828d84..bbe299b92 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -510,6 +510,14 @@ endmenu\n" >> ${IDF_PATH}/Kconfig; mv CMakeLists.txt.bak CMakeLists.txt rm -rf CMakeLists.txt.bak + print_status "Component properties are set" + clean_build_dir + cp CMakeLists.txt CMakeLists.txt.bak + printf "\nidf_component_get_property(srcs main SRCS)\nmessage(STATUS SRCS:\${srcs})" >> CMakeLists.txt + (idf.py reconfigure | grep "SRCS:$(realpath main/main.c)") || failure "Component properties should be set" + rm -rf CMakeLists.txt + mv CMakeLists.txt.bak CMakeLists.txt + rm -rf CMakeLists.txt.bak print_status "All tests completed" if [ -n "${FAILURES}" ]; then diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 6959af26c..21950dee9 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -479,6 +479,8 @@ function(idf_component_register) # COMPONENT_TARGET is deprecated but is made available with same function # as COMPONENT_LIB for compatibility. set(COMPONENT_TARGET ${component_lib} PARENT_SCOPE) + + __component_set_properties() endfunction() # From caea2889c808e3844f73388fda7c5cb254c9501e Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 May 2019 18:12:42 +1000 Subject: [PATCH 30/46] aes: Add fault injection checks when writing key to hardware Vulnerability reported by LimitedResults under Espressif Bug Bounty Program. --- components/idf_test/include/idf_performance.h | 2 +- components/mbedtls/port/esp32/aes.c | 108 +++++++++++++++--- components/mbedtls/port/include/esp32/aes.h | 6 +- 3 files changed, 92 insertions(+), 24 deletions(-) diff --git a/components/idf_test/include/idf_performance.h b/components/idf_test/include/idf_performance.h index 137c1b74b..8a952c406 100644 --- a/components/idf_test/include/idf_performance.h +++ b/components/idf_test/include/idf_performance.h @@ -26,7 +26,7 @@ #define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA1_32KB 5000 #define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA512_32KB 4500 // AES-CBC hardware throughput (accounts for worst-case performance with PSRAM workaround) -#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.5 +#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.2 // floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround) #define IDF_PERFORMANCE_MAX_ESP32_CYCLES_PER_DIV 70 #define IDF_PERFORMANCE_MAX_ESP32_CYCLES_PER_SQRT 140 diff --git a/components/mbedtls/port/esp32/aes.c b/components/mbedtls/port/esp32/aes.c index 3925f13e4..db8f1bf57 100644 --- a/components/mbedtls/port/esp32/aes.c +++ b/components/mbedtls/port/esp32/aes.c @@ -49,6 +49,11 @@ */ static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED; +static inline bool valid_key_length(const esp_aes_context *ctx) +{ + return ctx->key_bytes == 128/8 || ctx->key_bytes == 192/8 || ctx->key_bytes == 256/8; +} + void esp_aes_acquire_hardware( void ) { portENTER_CRITICAL(&aes_spinlock); @@ -93,6 +98,7 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, } ctx->key_bytes = keybits / 8; memcpy(ctx->key, key, ctx->key_bytes); + ctx->key_in_hardware = 0; return 0; } @@ -102,28 +108,47 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, * * Call only while holding esp_aes_acquire_hardware(). */ -static inline void esp_aes_setkey_hardware( esp_aes_context *ctx, int mode) +static void esp_aes_setkey_hardware(esp_aes_context *ctx, int mode) { const uint32_t MODE_DECRYPT_BIT = 4; unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; + ctx->key_in_hardware = 0; + for (int i = 0; i < ctx->key_bytes/4; ++i) { DPORT_REG_WRITE(AES_KEY_BASE + i * 4, *(((uint32_t *)ctx->key) + i)); + ctx->key_in_hardware += 4; } DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2)); + + /* Fault injection check: all words of key data should have been written to hardware */ + if (ctx->key_in_hardware < 16 + || ctx->key_in_hardware != ctx->key_bytes) { + abort(); + } } /* Run a single 16 byte block of AES, using the hardware engine. * * Call only while holding esp_aes_acquire_hardware(). */ -static void esp_aes_block(const void *input, void *output) +static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output) { const uint32_t *input_words = (const uint32_t *)input; uint32_t i0, i1, i2, i3; uint32_t *output_words = (uint32_t *)output; + /* If no key is written to hardware yet, either the user hasn't called + mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec - meaning we also don't + know which mode to use - or a fault skipped the + key write to hardware. Treat this as a fatal error and zero the output block. + */ + if (ctx->key_in_hardware != ctx->key_bytes) { + bzero(output, 16); + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + } + /* Storing i0,i1,i2,i3 in registers not an array helps a lot with optimisations at -Os level */ i0 = input_words[0]; @@ -152,11 +177,14 @@ static void esp_aes_block(const void *input, void *output) Bypassing this check requires at least one additional fault. */ if(i0 == output_words[0] && i1 == output_words[1] && i2 == output_words[2] && i3 == output_words[3]) { - // calling two zeroing functions to narrow the - // window for a double-fault here + // calling zeroing functions to narrow the + // window for a double-fault of the abort step, here memset(output, 0, 16); mbedtls_platform_zeroize(output, 16); + abort(); } + + return 0; } /* @@ -166,11 +194,18 @@ int esp_internal_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { + int r; + + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); - esp_aes_block(input, output); + r = esp_aes_block(ctx, input, output); esp_aes_release_hardware(); - return 0; + return r; } void esp_aes_encrypt( esp_aes_context *ctx, @@ -188,11 +223,18 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { + int r; + + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); - esp_aes_block(input, output); + r = esp_aes_block(ctx, input, output); esp_aes_release_hardware(); - return 0; + return r; } void esp_aes_decrypt( esp_aes_context *ctx, @@ -202,7 +244,6 @@ void esp_aes_decrypt( esp_aes_context *ctx, esp_internal_aes_decrypt(ctx, input, output); } - /* * AES-ECB block encryption/decryption */ @@ -211,12 +252,19 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) { + int r; + + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, mode); - esp_aes_block(input, output); + r = esp_aes_block(ctx, input, output); esp_aes_release_hardware(); - return 0; + return r; } @@ -240,14 +288,19 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, return ( ERR_ESP_AES_INVALID_INPUT_LENGTH ); } + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, mode); if ( mode == ESP_AES_DECRYPT ) { while ( length > 0 ) { memcpy(temp, input_words, 16); - esp_aes_block(input_words, output_words); + esp_aes_block(ctx, input_words, output_words); for ( i = 0; i < 4; i++ ) { output_words[i] = output_words[i] ^ iv_words[i]; @@ -266,7 +319,7 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, output_words[i] = input_words[i] ^ iv_words[i]; } - esp_aes_block(output_words, output_words); + esp_aes_block(ctx, output_words, output_words); memcpy( iv_words, output_words, 16 ); input_words += 4; @@ -294,14 +347,19 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, int c; size_t n = *iv_off; + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); if ( mode == ESP_AES_DECRYPT ) { while ( length-- ) { if ( n == 0 ) { - esp_aes_block(iv, iv ); + esp_aes_block(ctx, iv, iv); } c = *input++; @@ -313,7 +371,7 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, } else { while ( length-- ) { if ( n == 0 ) { - esp_aes_block(iv, iv ); + esp_aes_block(ctx, iv, iv); } iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); @@ -342,13 +400,18 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx, unsigned char c; unsigned char ov[17]; + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); while ( length-- ) { memcpy( ov, iv, 16 ); - esp_aes_block(iv, iv); + esp_aes_block(ctx, iv, iv); if ( mode == ESP_AES_DECRYPT ) { ov[16] = *input; @@ -382,13 +445,18 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx, int c, i; size_t n = *nc_off; + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); while ( length-- ) { if ( n == 0 ) { - esp_aes_block(nonce_counter, stream_block); + esp_aes_block(ctx, nonce_counter, stream_block); for ( i = 16; i > 0; i-- ) if ( ++nonce_counter[i - 1] != 0 ) { @@ -432,13 +500,17 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx, return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); } + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + esp_aes_acquire_hardware(); esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); while( length-- ) { if( n == 0 ) { - esp_aes_block( iv, iv ); + esp_aes_block(ctx, iv, iv); } *output++ = *input++ ^ iv[n]; diff --git a/components/mbedtls/port/include/esp32/aes.h b/components/mbedtls/port/include/esp32/aes.h index 962e14806..107193015 100644 --- a/components/mbedtls/port/include/esp32/aes.h +++ b/components/mbedtls/port/include/esp32/aes.h @@ -41,17 +41,13 @@ extern "C" { /** * \brief AES context structure * - * \note buf is able to hold 32 extra bytes, which can be used: - * - for alignment purposes if VIA padlock is used, and/or - * - to simplify key expansion in the 256-bit case by - * generating an extra round key */ typedef struct { uint8_t key_bytes; + volatile uint8_t key_in_hardware; /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */ uint8_t key[32]; } esp_aes_context; - /** * \brief The AES XTS context-type definition. */ From aa3c988c17b40286734030151f7940ef30f9dcac Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 May 2019 10:18:55 +1000 Subject: [PATCH 31/46] sha: Add fault injection checks reading hash digest state Vulnerability reported by LimitedResults under Espressif Bug Bounty Program. --- components/mbedtls/port/esp32/sha.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/mbedtls/port/esp32/sha.c b/components/mbedtls/port/esp32/sha.c index 7b7a0f415..35c52eee3 100644 --- a/components/mbedtls/port/esp32/sha.c +++ b/components/mbedtls/port/esp32/sha.c @@ -228,6 +228,7 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state) { uint32_t *digest_state_words = NULL; uint32_t *reg_addr_buf = NULL; + uint32_t word_len = sha_length(sha_type)/4; #ifndef NDEBUG { SemaphoreHandle_t *engine_state = sha_get_engine_state(sha_type); @@ -250,15 +251,25 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state) if(sha_type == SHA2_384 || sha_type == SHA2_512) { /* for these ciphers using 64-bit states, swap each pair of words */ DPORT_INTERRUPT_DISABLE(); // Disable interrupt only on current CPU. - for(int i = 0; i < sha_length(sha_type)/4; i += 2) { + for(int i = 0; i < word_len; i += 2) { digest_state_words[i+1] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i]); digest_state_words[i] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i+1]); } DPORT_INTERRUPT_RESTORE(); // restore the previous interrupt level } else { - esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], sha_length(sha_type)/4); + esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], word_len); } esp_sha_unlock_memory_block(); + + /* Fault injection check: verify SHA engine actually ran, + state is not all zeroes. + */ + for (int i = 0; i < word_len; i++) { + if (digest_state_words[i] != 0) { + return; + } + } + abort(); // SHA peripheral returned all zero state, probably due to fault injection } void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block) From 8658b1633c5bc43f50ba4de22b74f84541fa3ae6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 09:38:44 +1000 Subject: [PATCH 32/46] ci: Temporarily disable NimBLE tests in CI --- .../nimble/blecent/{blecent_test.py => blecent_test_noci.py} | 0 .../bluetooth/nimble/blehr/{blehr_test.py => blehr_test_noci.py} | 0 .../nimble/bleprph/{bleprph_test.py => bleprph_test_noci.py} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename examples/bluetooth/nimble/blecent/{blecent_test.py => blecent_test_noci.py} (100%) rename examples/bluetooth/nimble/blehr/{blehr_test.py => blehr_test_noci.py} (100%) rename examples/bluetooth/nimble/bleprph/{bleprph_test.py => bleprph_test_noci.py} (100%) diff --git a/examples/bluetooth/nimble/blecent/blecent_test.py b/examples/bluetooth/nimble/blecent/blecent_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/blecent/blecent_test.py rename to examples/bluetooth/nimble/blecent/blecent_test_noci.py diff --git a/examples/bluetooth/nimble/blehr/blehr_test.py b/examples/bluetooth/nimble/blehr/blehr_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/blehr/blehr_test.py rename to examples/bluetooth/nimble/blehr/blehr_test_noci.py diff --git a/examples/bluetooth/nimble/bleprph/bleprph_test.py b/examples/bluetooth/nimble/bleprph/bleprph_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/bleprph/bleprph_test.py rename to examples/bluetooth/nimble/bleprph/bleprph_test_noci.py From a40e164988ccc5301c3f525867fa1d5f6ed2fc16 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 31 Jul 2019 11:07:23 +0800 Subject: [PATCH 33/46] doc: Add clarifications Xtensa Core ID and "Core ID" used in FreeRTOS are different Closes https://github.com/espressif/esp-idf/issues/2567 --- components/freertos/include/freertos/portmacro.h | 6 +++++- components/freertos/include/freertos/task.h | 6 +++--- components/freertos/include/freertos/xtensa_context.h | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index d5df0b274..6b09a2ce8 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -136,10 +136,14 @@ typedef unsigned portBASE_TYPE UBaseType_t; /* "mux" data structure (spinlock) */ typedef struct { /* owner field values: - * 0 - Uninitialized (invalid) + * 0 - Uninitialized (invalid) * portMUX_FREE_VAL - Mux is free, can be locked by either CPU * CORE_ID_PRO / CORE_ID_APP - Mux is locked to the particular core * + * Note that for performance reasons we use the full Xtensa CORE ID values + * (CORE_ID_PRO, CORE_ID_APP) and not the 0,1 values which are used in most + * other FreeRTOS code. + * * Any value other than portMUX_FREE_VAL, CORE_ID_PRO, CORE_ID_APP indicates corruption */ uint32_t owner; diff --git a/components/freertos/include/freertos/task.h b/components/freertos/include/freertos/task.h index 3fc06d9e3..8fb6ee22f 100644 --- a/components/freertos/include/freertos/task.h +++ b/components/freertos/include/freertos/task.h @@ -185,7 +185,7 @@ typedef struct xTASK_STATUS StackType_t *pxStackBase; /*!< Points to the lowest address of the task's stack area. */ uint32_t usStackHighWaterMark; /*!< The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ #if configTASKLIST_INCLUDE_COREID - BaseType_t xCoreID; /*!< Core this task is pinned to. This field is present if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set. */ + BaseType_t xCoreID; /*!< Core this task is pinned to (0, 1, or -1 for tskNO_AFFINITY). This field is present if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set. */ #endif } TaskStatus_t; @@ -324,7 +324,7 @@ is used in assert() statements. */ * * @param xCoreID If the value is tskNO_AFFINITY, the created task is not * pinned to any CPU, and the scheduler can run it on any core available. - * Other values indicate the index number of the CPU which the task should + * Values 0 or 1 indicate the index number of the CPU which the task should * be pinned to. Specifying values larger than (portNUM_PROCESSORS - 1) will * cause the function to fail. * @@ -476,7 +476,7 @@ is used in assert() statements. */ * * @param xCoreID If the value is tskNO_AFFINITY, the created task is not * pinned to any CPU, and the scheduler can run it on any core available. - * Other values indicate the index number of the CPU which the task should + * Values 0 or 1 indicate the index number of the CPU which the task should * be pinned to. Specifying values larger than (portNUM_PROCESSORS - 1) will * cause the function to fail. * diff --git a/components/freertos/include/freertos/xtensa_context.h b/components/freertos/include/freertos/xtensa_context.h index 9e6fe558f..073a137bc 100644 --- a/components/freertos/include/freertos/xtensa_context.h +++ b/components/freertos/include/freertos/xtensa_context.h @@ -325,6 +325,9 @@ STRUCT_END(XtSolFrame) .endm #endif +/* Note: These are different to xCoreID used in ESP-IDF FreeRTOS, we just use + 0 and 1 which are determined by checking bit 13 (see previous comment) +*/ #define CORE_ID_PRO 0xCDCD #define CORE_ID_APP 0xABAB From 4fe74b8f6471d302cd0f7fa812ce53e2dfa01134 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 12 Aug 2019 11:12:34 +1000 Subject: [PATCH 34/46] freertos: Rename CORE_ID_PRO/CORE_ID_APP macros to CORE_ID_REGVAL_xxx Old values remain for compatibility. As suggested in https://github.com/espressif/esp-idf/issues/2567 --- components/freertos/include/freertos/portmacro.h | 6 +++--- .../freertos/include/freertos/xtensa_context.h | 12 +++++++++--- components/freertos/portmux_impl.h | 2 +- components/freertos/portmux_impl.inc.h | 12 ++++++------ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index 6b09a2ce8..d6b218465 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -138,13 +138,13 @@ typedef struct { /* owner field values: * 0 - Uninitialized (invalid) * portMUX_FREE_VAL - Mux is free, can be locked by either CPU - * CORE_ID_PRO / CORE_ID_APP - Mux is locked to the particular core + * CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core * * Note that for performance reasons we use the full Xtensa CORE ID values - * (CORE_ID_PRO, CORE_ID_APP) and not the 0,1 values which are used in most + * (CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP) and not the 0,1 values which are used in most * other FreeRTOS code. * - * Any value other than portMUX_FREE_VAL, CORE_ID_PRO, CORE_ID_APP indicates corruption + * Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption */ uint32_t owner; /* count field: diff --git a/components/freertos/include/freertos/xtensa_context.h b/components/freertos/include/freertos/xtensa_context.h index 073a137bc..120676dad 100644 --- a/components/freertos/include/freertos/xtensa_context.h +++ b/components/freertos/include/freertos/xtensa_context.h @@ -325,11 +325,17 @@ STRUCT_END(XtSolFrame) .endm #endif -/* Note: These are different to xCoreID used in ESP-IDF FreeRTOS, we just use +/* Note: These are different to xCoreID used in ESP-IDF FreeRTOS, most places use 0 and 1 which are determined by checking bit 13 (see previous comment) */ -#define CORE_ID_PRO 0xCDCD -#define CORE_ID_APP 0xABAB +#define CORE_ID_REGVAL_PRO 0xCDCD +#define CORE_ID_REGVAL_APP 0xABAB + +/* Included for compatibility, recommend using CORE_ID_REGVAL_PRO instead */ +#define CORE_ID_PRO CORE_ID_REGVAL_PRO + +/* Included for compatibility, recommend using CORE_ID_REGVAL_APP instead */ +#define CORE_ID_APP CORE_ID_REGVAL_APP /* ------------------------------------------------------------------------------- diff --git a/components/freertos/portmux_impl.h b/components/freertos/portmux_impl.h index 5aef351b6..691ad01e2 100644 --- a/components/freertos/portmux_impl.h +++ b/components/freertos/portmux_impl.h @@ -49,7 +49,7 @@ #include "soc/soc_memory_layout.h" /* XOR one core ID with this value to get the other core ID */ -#define CORE_ID_XOR_SWAP (CORE_ID_PRO ^ CORE_ID_APP) +#define CORE_ID_REGVAL_XOR_SWAP (CORE_ID_REGVAL_PRO ^ CORE_ID_REGVAL_APP) diff --git a/components/freertos/portmux_impl.inc.h b/components/freertos/portmux_impl.inc.h index 07a7ce9fe..908fec153 100644 --- a/components/freertos/portmux_impl.inc.h +++ b/components/freertos/portmux_impl.inc.h @@ -61,7 +61,7 @@ PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) { #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG uint32_t owner = mux->owner; - if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) { + if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP) { ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line); mux->owner=portMUX_FREE_VAL; } @@ -70,13 +70,13 @@ PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) { /* Spin until we own the core */ RSR(PRID, coreID); - /* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP), + /* Note: coreID is the full 32 bit core ID (CORE_ID_REGVAL_PRO/CORE_ID_REGVAL_APP), not the 0/1 value returned by xPortGetCoreID() */ - otherCoreID = CORE_ID_XOR_SWAP ^ coreID; + otherCoreID = CORE_ID_REGVAL_XOR_SWAP ^ coreID; do { - /* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO, - CORE_ID_APP: + /* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, + CORE_ID_REGVAL_APP: - If portMUX_FREE_VAL, we want to atomically set to 'coreID'. - If "our" coreID, we can drop through immediately. @@ -138,7 +138,7 @@ static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux) { mux->lastLockedFn=fnName; mux->lastLockedLine=line; uint32_t owner = mux->owner; - if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) { + if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP) { ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner); } #endif From b64551718c3b7ae3776e156943f228e80f57c1c9 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Mon, 12 Aug 2019 19:45:48 +0800 Subject: [PATCH 35/46] gh_action: converted main.workflow to Actions V2 yml files --- .github/main.workflow | 22 ---------------------- .github/workflows/issue_comment.yml | 16 ++++++++++++++++ .github/workflows/issues.yml | 16 ++++++++++++++++ .github/workflows/pull_request.yml | 16 ++++++++++++++++ 4 files changed, 48 insertions(+), 22 deletions(-) delete mode 100644 .github/main.workflow create mode 100644 .github/workflows/issue_comment.yml create mode 100644 .github/workflows/issues.yml create mode 100644 .github/workflows/pull_request.yml diff --git a/.github/main.workflow b/.github/main.workflow deleted file mode 100644 index d23b686c5..000000000 --- a/.github/main.workflow +++ /dev/null @@ -1,22 +0,0 @@ -workflow "Sync issues to JIRA" { - on = "issues" - resolves = ["Sync to JIRA"] -} - -workflow "Sync issue and PR comments to JIRA" { - on = "issue_comment" - resolves = ["Sync to JIRA"] -} - -workflow "Sync PRs to JIRA" { - on = "pull_request" - resolves = ["Sync to JIRA"] -} - -action "Sync to JIRA" { - uses = "espressif/github-actions/sync_issues_to_jira@master" - secrets = ["GITHUB_TOKEN", "JIRA_URL", "JIRA_USER", "JIRA_PASS"] - env = { - JIRA_PROJECT = "IDFGH" - } -} diff --git a/.github/workflows/issue_comment.yml b/.github/workflows/issue_comment.yml new file mode 100644 index 000000000..16069f1f1 --- /dev/null +++ b/.github/workflows/issue_comment.yml @@ -0,0 +1,16 @@ +on: issue_comment +name: Sync issue and PR comments to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml new file mode 100644 index 000000000..3ead59688 --- /dev/null +++ b/.github/workflows/issues.yml @@ -0,0 +1,16 @@ +on: issues +name: Sync issues to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 000000000..324639e08 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,16 @@ +on: pull_request +name: Sync PRs to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} From 0addc0aef1c09bd3b2c6b955e179c44fc144f5f2 Mon Sep 17 00:00:00 2001 From: Luke Bayes Date: Sun, 4 Aug 2019 17:05:03 -0400 Subject: [PATCH 36/46] Added -r flag to pip install command from file Closes https://github.com/espressif/esp-idf/pull/3874 Closes https://github.com/espressif/esp-idf/issues/3915 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19c9980dd..4be36b48d 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ See the Getting Started guide links above for a detailed setup guide. This is a * Install host build dependencies mentioned in Getting Started guide. * Add `tools/` directory to the PATH -* Run `python -m pip install requirements.txt` to install Python dependencies +* Run `python -m pip install -r requirements.txt` to install Python dependencies ## Configuring the Project From f86e82cb63ec820982bc0b8e47a44813773b364a Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Mon, 29 Jul 2019 11:35:00 +0800 Subject: [PATCH 37/46] efuse: update the scheme of getting chip revision --- components/efuse/esp32/esp_efuse_table.c | 11 ++++++- components/efuse/esp32/esp_efuse_table.csv | 15 +++++----- .../efuse/esp32/include/esp_efuse_table.h | 3 +- components/efuse/src/esp_efuse_fields.c | 28 +++++++++++++++-- components/esp32/Kconfig | 28 +++++++++++++++++ components/esp32/cpu_start.c | 12 +++++++- components/esp32/dport_access.c | 8 ++--- components/esp32/include/esp32/dport_access.h | 2 +- components/esp32/system_api.c | 30 +++++++------------ components/esptool_py/esptool | 2 +- .../soc/esp32/include/soc/dport_access.h | 8 ++--- components/soc/esp32/include/soc/soc.h | 2 +- 12 files changed, 106 insertions(+), 43 deletions(-) diff --git a/components/efuse/esp32/esp_efuse_table.c b/components/efuse/esp32/esp_efuse_table.c index 36b54b50b..e0d4e2d10 100644 --- a/components/efuse/esp32/esp_efuse_table.c +++ b/components/efuse/esp32/esp_efuse_table.c @@ -17,7 +17,7 @@ #include #include "esp_efuse_table.h" -// md5_digest_table 544d434da010ce22f7db1b14d38e1d66 +// md5_digest_table 2e23344575b3d07f01ecb695294e9770 // This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. // If you want to change some fields, you need to change esp_efuse_table.csv file // then run `efuse_common_table` or `efuse_custom_table` command it will generate this file. @@ -151,6 +151,10 @@ static const esp_efuse_desc_t CHIP_VER_REV1[] = { {EFUSE_BLK0, 111, 1}, // EFUSE_RD_CHIP_VER_REV1, }; +static const esp_efuse_desc_t CHIP_VER_REV2[] = { + {EFUSE_BLK0, 180, 1}, // EFUSE_RD_CHIP_VER_REV2, +}; + static const esp_efuse_desc_t XPD_SDIO_REG[] = { {EFUSE_BLK0, 142, 1}, // EFUSE_RD_XPD_SDIO_REG, }; @@ -336,6 +340,11 @@ const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[] = { NULL }; +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[] = { + &CHIP_VER_REV2[0], // EFUSE_RD_CHIP_VER_REV2 + NULL +}; + const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[] = { &XPD_SDIO_REG[0], // EFUSE_RD_XPD_SDIO_REG NULL diff --git a/components/efuse/esp32/esp_efuse_table.csv b/components/efuse/esp32/esp_efuse_table.csv index 23b28ec47..1445ac8ae 100644 --- a/components/efuse/esp32/esp_efuse_table.csv +++ b/components/efuse/esp32/esp_efuse_table.csv @@ -6,7 +6,7 @@ ########################################################################## # *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_MAX_BLK_LEN, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128. # !!!!!!!!!!! # -# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table" +# 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. # !!!!!!!!!!! # @@ -36,11 +36,11 @@ ABS_DONE_0, EFUSE_BLK0, 196, 1, Secure boot is enabled for ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, MAX_BLK_LEN, Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128) ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M -DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT. -DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT. -DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE. -DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG. -CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE. +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, 7, Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT. # Write protection # @@ -53,7 +53,7 @@ WR_DIS_BLK3, EFUSE_BLK0, 9, 1, Write protection for EFUSE_B # 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_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 # @@ -64,6 +64,7 @@ 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 +CHIP_VER_REV2, EFUSE_BLK0, 180, 1, EFUSE_RD_CHIP_VER_REV2 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 diff --git a/components/efuse/esp32/include/esp_efuse_table.h b/components/efuse/esp32/include/esp_efuse_table.h index 807fb0888..a0137c012 100644 --- a/components/efuse/esp32/include/esp_efuse_table.h +++ b/components/efuse/esp32/include/esp_efuse_table.h @@ -17,7 +17,7 @@ extern "C" { #endif -// md5_digest_table 544d434da010ce22f7db1b14d38e1d66 +// md5_digest_table 2e23344575b3d07f01ecb695294e9770 // This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. // If you want to change some fields, you need to change esp_efuse_table.csv file // then run `efuse_common_table` or `efuse_custom_table` command it will generate this file. @@ -52,6 +52,7 @@ 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_CHIP_VER_REV2[]; 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[]; diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c index 01ed585d8..313bbc611 100644 --- a/components/efuse/src/esp_efuse_fields.c +++ b/components/efuse/src/esp_efuse_fields.c @@ -23,6 +23,7 @@ #include "esp_log.h" #include "soc/efuse_periph.h" #include "bootloader_random.h" +#include "soc/apb_ctrl_reg.h" const static char *TAG = "efuse"; @@ -31,8 +32,29 @@ const static char *TAG = "efuse"; // Returns chip version from efuse uint8_t esp_efuse_get_chip_ver(void) { - uint8_t chip_ver; - esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &chip_ver, 1); + uint8_t eco_bit0, eco_bit1, eco_bit2; + esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &eco_bit0, 1); + esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV2, &eco_bit1, 1); + eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 80000000) >> 31; + uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0; + uint8_t chip_ver = 0; + switch (combine_value) { + case 0: + chip_ver = 0; + break; + case 1: + chip_ver = 1; + break; + case 3: + chip_ver = 2; + break; + case 7: + chip_ver = 3; + break; + default: + chip_ver = 0; + break; + } return chip_ver; } @@ -111,7 +133,7 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg) 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]); + REG_WRITE(blk_wdata0_reg + 4 * i, buf[i]); } bzero(buf, sizeof(buf)); bzero(raw, sizeof(raw)); diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 847560fe0..d0e9b5da0 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -1,5 +1,33 @@ menu "ESP32-specific" + choice ESP32_REV_MIN + prompt "Minimum Supported ESP32 Revision" + default ESP32_REV_MIN_0 + help + Minimum revision that ESP-IDF would support. + ESP-IDF performs different strategy on different esp32 revision. + + config ESP32_REV_MIN_0 + bool "Rev 0" + config ESP32_REV_MIN_1 + bool "Rev 1" + config ESP32_REV_MIN_2 + bool "Rev 2" + config ESP32_REV_MIN_3 + bool "Rev 3" + endchoice + + config ESP32_REV_MIN + int + default 0 if ESP32_REV_MIN_0 + default 1 if ESP32_REV_MIN_1 + default 2 if ESP32_REV_MIN_2 + default 3 if ESP32_REV_MIN_3 + + config ESP32_DPORT_WORKAROUND + bool + default "y" if !FREERTOS_UNICORE && ESP32_REV_MIN < 2 + choice ESP32_DEFAULT_CPU_FREQ_MHZ prompt "CPU frequency" default ESP32_DEFAULT_CPU_FREQ_160 diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 1dfa5c246..7f06aff56 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -204,7 +204,7 @@ void IRAM_ATTR call_start_cpu0(void) abort(); } ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); - + esp_flash_enc_mode_t mode; mode = esp_get_flash_encryption_mode(); if (mode == ESP_FLASH_ENC_MODE_DEVELOPMENT) { @@ -408,6 +408,16 @@ void start_cpu0_default(void) esp_flash_app_init(); esp_err_t flash_ret = esp_flash_init_default_chip(); assert(flash_ret == ESP_OK); + + uint8_t revision = esp_efuse_get_chip_ver(); + ESP_LOGI(TAG, "Chip Revision: %d", revision); + if (revision > CONFIG_ESP32_REV_MIN) { + ESP_LOGW(TAG, "Chip revision is higher than the one configured in menuconfig. Suggest to upgrade it."); + } else if(revision != CONFIG_ESP32_REV_MIN) { + ESP_LOGE(TAG, "ESP-IDF can't support this chip revision. Modify minimum supported revision in menuconfig"); + abort(); + } + #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO diff --git a/components/esp32/dport_access.c b/components/esp32/dport_access.c index 2c8358335..f2fea2d35 100644 --- a/components/esp32/dport_access.c +++ b/components/esp32/dport_access.c @@ -16,7 +16,7 @@ * DPORT access is used for do protection when dual core access DPORT internal register and APB register via DPORT simultaneously * This function will be initialize after FreeRTOS startup. * When cpu0 want to access DPORT register, it should notify cpu1 enter in high-priority interrupt for be mute. When cpu1 already in high-priority interrupt, - * cpu0 can access DPORT register. Currently, cpu1 will wait for cpu0 finish access and exit high-priority interrupt. + * cpu0 can access DPORT register. Currently, cpu1 will wait for cpu0 finish access and exit high-priority interrupt. */ #include @@ -116,7 +116,7 @@ void IRAM_ATTR esp_dport_access_stall_other_cpu_end(void) { #ifndef CONFIG_FREERTOS_UNICORE int cpu_id = xPortGetCoreID(); - + if (dport_core_state[0] == DPORT_CORE_STATE_IDLE || dport_core_state[1] == DPORT_CORE_STATE_IDLE) { return; @@ -249,7 +249,7 @@ void IRAM_ATTR esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address */ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else uint32_t apb; @@ -295,7 +295,7 @@ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg) */ uint32_t IRAM_ATTR esp_dport_access_sequence_reg_read(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else uint32_t apb; diff --git a/components/esp32/include/esp32/dport_access.h b/components/esp32/include/esp32/dport_access.h index f91c563e6..8ea60c4cd 100644 --- a/components/esp32/include/esp32/dport_access.h +++ b/components/esp32/include/esp32/dport_access.h @@ -33,7 +33,7 @@ uint32_t esp_dport_access_sequence_reg_read(uint32_t reg); //only call in case of panic(). void esp_dport_access_int_abort(void); -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) #define DPORT_STALL_OTHER_CPU_START() #define DPORT_STALL_OTHER_CPU_END() #define DPORT_INTERRUPT_DISABLE() diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index 570c0997a..e5f6649b7 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -204,7 +204,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type) ESP_LOGW(TAG, "incorrect mac type"); break; } - + return ESP_OK; } @@ -307,10 +307,10 @@ void IRAM_ATTR esp_restart_noos(void) WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); // Reset wifi/bluetooth/ethernet/sdio (bb/mac) - DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, + DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST | - DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | + DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0); @@ -366,35 +366,27 @@ const char* esp_get_idf_version(void) return IDF_VER; } -static void get_chip_info_esp32(esp_chip_info_t* out_info) +void esp_chip_info(esp_chip_info_t* out_info) { - uint32_t reg = REG_READ(EFUSE_BLK0_RDATA3_REG); + uint32_t efuse_rd3 = REG_READ(EFUSE_BLK0_RDATA3_REG); memset(out_info, 0, sizeof(*out_info)); - + out_info->model = CHIP_ESP32; - if ((reg & EFUSE_RD_CHIP_VER_REV1_M) != 0) { - out_info->revision = 1; - } - if ((reg & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) { + out_info->revision = esp_efuse_get_chip_ver(); + + if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) { out_info->cores = 2; } else { out_info->cores = 1; } out_info->features = CHIP_FEATURE_WIFI_BGN; - if ((reg & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) { + if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) { out_info->features |= CHIP_FEATURE_BT | CHIP_FEATURE_BLE; } - int package = (reg & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S; + int package = (efuse_rd3 & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S; if (package == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 || package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) { out_info->features |= CHIP_FEATURE_EMB_FLASH; } } - -void esp_chip_info(esp_chip_info_t* out_info) -{ - // Only ESP32 is supported now, in the future call one of the - // chip-specific functions based on sdkconfig choice - return get_chip_info_esp32(out_info); -} diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool index 1319c49ad..1a7dbf787 160000 --- a/components/esptool_py/esptool +++ b/components/esptool_py/esptool @@ -1 +1 @@ -Subproject commit 1319c49adb2fe99d2981151ff781930d6ed62729 +Subproject commit 1a7dbf787e7e504acdeaea074d15a5ccaf87e9e8 diff --git a/components/soc/esp32/include/soc/dport_access.h b/components/soc/esp32/include/soc/dport_access.h index 544560fdf..fe7e70ebc 100644 --- a/components/soc/esp32/include/soc/dport_access.h +++ b/components/soc/esp32/include/soc/dport_access.h @@ -48,7 +48,7 @@ extern "C" { // After completing read operations, use DPORT_STALL_OTHER_CPU_END(). // This method uses stall other CPU while reading DPORT registers. // Useful for compatibility, as well as for large consecutive readings. -// This method is slower, but must be used if ROM functions or +// This method is slower, but must be used if ROM functions or // other code is called which accesses DPORT without any other workaround. // *) The pre-readable APB register before reading the DPORT register // helps synchronize the operation of the two CPUs, @@ -73,7 +73,7 @@ extern "C" { */ static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else return esp_dport_access_reg_read(reg); @@ -106,7 +106,7 @@ static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg) */ static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else return esp_dport_access_sequence_reg_read(reg); @@ -166,7 +166,7 @@ static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg) */ static inline uint32_t IRAM_ATTR DPORT_READ_PERI_REG(uint32_t reg) { -#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM) +#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM) return _DPORT_REG_READ(reg); #else return esp_dport_access_reg_read(reg); diff --git a/components/soc/esp32/include/soc/soc.h b/components/soc/esp32/include/soc/soc.h index 5901abca2..419cf49b7 100644 --- a/components/soc/esp32/include/soc/soc.h +++ b/components/soc/esp32/include/soc/soc.h @@ -108,7 +108,7 @@ #define IS_DPORT_REG(_r) (((_r) >= DR_REG_DPORT_BASE) && (_r) <= DR_REG_DPORT_END) -#if !defined( BOOTLOADER_BUILD ) && !defined( CONFIG_FREERTOS_UNICORE ) && defined( ESP_PLATFORM ) +#if !defined( BOOTLOADER_BUILD ) && defined( CONFIG_ESP32_DPORT_WORKAROUND ) && defined( ESP_PLATFORM ) #define ASSERT_IF_DPORT_REG(_r, OP) TRY_STATIC_ASSERT(!IS_DPORT_REG(_r), (Cannot use OP for DPORT registers use DPORT_##OP)); #else #define ASSERT_IF_DPORT_REG(_r, OP) From b1497f21874dfcc1d6dbadab2132e582fb92cb33 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Wed, 22 May 2019 20:21:11 +0800 Subject: [PATCH 38/46] exclude rom headers in examples 1. avoid including rom headers directly in examples 2. add common API interface for CRC calculation in esp_common component --- components/driver/include/driver/uart.h | 8 + components/driver/uart.c | 29 +- components/esp_common/include/esp_crc.h | 113 +++ .../bluedroid/ble/blufi/main/blufi_security.c | 6 +- .../peripherals/sdio/slave/main/app_main.c | 1 - .../components/tjpgd/CMakeLists.txt | 4 + .../spi_master/components/tjpgd/component.mk | 3 + .../components/tjpgd/include/tjpgd.h | 88 ++ .../spi_master/components/tjpgd/src/tjpgd.c | 960 ++++++++++++++++++ .../spi_master/main/decode_image.c | 124 ++- .../spi_slave/receiver/main/app_main.c | 1 - .../spi_slave/sender/main/app_main.c | 7 +- .../components/cmd_system/cmd_system.c | 3 +- examples/system/himem/main/himem_test_main.c | 1 - .../main/light_sleep_example_main.c | 4 +- .../wifi/espnow/main/espnow_example_main.c | 7 +- tools/ci/check_examples_rom_header.sh | 19 + tools/ci/config/check.yml | 5 + tools/ci/executable-list.txt | 1 + 19 files changed, 1292 insertions(+), 92 deletions(-) create mode 100644 components/esp_common/include/esp_crc.h create mode 100644 examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt create mode 100644 examples/peripherals/spi_master/components/tjpgd/component.mk create mode 100644 examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h create mode 100644 examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c create mode 100755 tools/ci/check_examples_rom_header.sh diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 4bf855c18..f25e21776 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -841,6 +841,14 @@ esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold); */ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_threshold); +/** + * @brief Wait until UART tx memory empty and the last char send ok (polling mode). + * + * @param uart_num UART number + * + */ +void uart_wait_tx_idle_polling(uart_port_t uart_num); + #ifdef __cplusplus } #endif diff --git a/components/driver/uart.c b/components/driver/uart.c index 3367d1d04..da215dde0 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -81,7 +81,7 @@ typedef struct { intr_handle_t intr_handle; /*!< UART interrupt handle*/ uart_mode_t uart_mode; /*!< UART controller actual mode set by uart_set_mode() */ bool coll_det_flg; /*!< UART collision detection flag */ - + //rx parameters int rx_buffered_len; /*!< UART cached data length */ SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/ @@ -1007,13 +1007,13 @@ static void uart_rx_intr_handler_default(void *param) UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); uart_reset_rx_fifo(uart_num); // Set collision detection flag - p_uart_obj[uart_num]->coll_det_flg = true; + p_uart_obj[uart_num]->coll_det_flg = true; UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); uart_event.type = UART_EVENT_MAX; } else if(uart_intr_status & UART_TX_DONE_INT_ST_M) { uart_disable_intr_mask_from_isr(uart_num, UART_TX_DONE_INT_ENA_M); uart_clear_intr_status(uart_num, UART_TX_DONE_INT_CLR_M); - // If RS485 half duplex mode is enable then reset FIFO and + // If RS485 half duplex mode is enable then reset FIFO and // reset RTS pin to start receiver driver if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); @@ -1489,11 +1489,11 @@ portMUX_TYPE *uart_get_selectlock(void) return &uart_selectlock; } // Set UART mode -esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode) +esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode) { UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_ERR_INVALID_STATE); UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); - if ((mode == UART_MODE_RS485_COLLISION_DETECT) || (mode == UART_MODE_RS485_APP_CTRL) + if ((mode == UART_MODE_RS485_COLLISION_DETECT) || (mode == UART_MODE_RS485_APP_CTRL) || (mode == UART_MODE_RS485_HALF_DUPLEX)) { UART_CHECK((UART[uart_num]->conf1.rx_flow_en != 1), "disable hw flowctrl before using RS485 mode", ESP_ERR_INVALID_ARG); @@ -1548,13 +1548,13 @@ esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode) return ESP_OK; } -esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh) +esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); UART_CHECK((tout_thresh < 127), "tout_thresh max value is 126", ESP_ERR_INVALID_ARG); UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - // The tout_thresh = 1, defines TOUT interrupt timeout equal to - // transmission time of one symbol (~11 bit) on current baudrate + // The tout_thresh = 1, defines TOUT interrupt timeout equal to + // transmission time of one symbol (~11 bit) on current baudrate if (tout_thresh > 0) { //Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) @@ -1575,8 +1575,8 @@ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); UART_CHECK((collision_flag != NULL), "wrong parameter pointer", ESP_ERR_INVALID_ARG); - UART_CHECK((UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX) - || UART_IS_MODE_SET(uart_num, UART_MODE_RS485_COLLISION_DETECT)), + UART_CHECK((UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX) + || UART_IS_MODE_SET(uart_num, UART_MODE_RS485_COLLISION_DETECT)), "wrong mode", ESP_ERR_INVALID_ARG); *collision_flag = p_uart_obj[uart_num]->coll_det_flg; return ESP_OK; @@ -1601,3 +1601,12 @@ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_thresh *out_wakeup_threshold = UART[uart_num]->sleep_conf.active_threshold + UART_MIN_WAKEUP_THRESH; return ESP_OK; } + +void uart_wait_tx_idle_polling(uart_port_t uart_num) +{ + uint32_t status; + do { + status = READ_PERI_REG(UART_STATUS_REG(uart_num)); + /* either tx count or state is non-zero */ + } while ((status & (UART_ST_UTX_OUT_M | UART_TXFIFO_CNT_M)) != 0); +} diff --git a/components/esp_common/include/esp_crc.h b/components/esp_common/include/esp_crc.h new file mode 100644 index 000000000..23a04876a --- /dev/null +++ b/components/esp_common/include/esp_crc.h @@ -0,0 +1,113 @@ +// Copyright 2015-2019 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. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "sdkconfig.h" + +#if defined(CONFIG_IDF_TARGET_ESP32) +#include "esp32/rom/crc.h" +#endif + +/******************* Polynomials Used in the CRC APIs **************************** +* CRC-8 x8+x2+x1+1 0x07 +* CRC16-CCITT x16+x12+x5+1 0x1021 +* CRC32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x1+1 0x04c11db7 +********************************************************************************/ + +/** +* @brief CRC32 value in little endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC32 value +*/ +static inline uint32_t esp_crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len) +{ + return crc32_le(crc, buf, len); +} + +/** +* @brief CRC32 value in big endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC32 value +*/ +static inline uint32_t esp_crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len) +{ + return crc32_be(crc, buf, len); +} + +/** +* @brief CRC16 value in little endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC16 value +*/ +static inline uint16_t esp_crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len) +{ + return crc16_le(crc, buf, len); +} + +/** +* @brief CRC16 value in big endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC16 value +*/ +static inline uint16_t esp_crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len) +{ + return crc16_be(crc, buf, len); +} + +/** +* @brief CRC8 value in little endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC8 value +*/ +static inline uint8_t esp_crc8_le(uint8_t crc, uint8_t const *buf, uint32_t len) +{ + return crc8_le(crc, buf, len); +} + +/** +* @brief CRC8 value in big endian. +* +* @param crc: Initial CRC value (result of last calculation or 0 for the first time) +* @param buf: Data buffer that used to calculate the CRC value +* @param len: Length of the data buffer +* @return CRC8 value +*/ +static inline uint8_t esp_crc8_be(uint8_t crc, uint8_t const *buf, uint32_t len) +{ + return crc8_be(crc, buf, len); +} + +#ifdef __cplusplus +} +#endif diff --git a/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c index 64b989e74..f790e58e5 100644 --- a/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c +++ b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c @@ -28,7 +28,7 @@ #include "mbedtls/aes.h" #include "mbedtls/dhm.h" #include "mbedtls/md5.h" -#include "esp32/rom/crc.h" +#include "esp_crc.h" /* The SEC_TYPE_xxx is for self-defined packet data type in the procedure of "BLUFI negotiate key" @@ -124,7 +124,7 @@ void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_da mbedtls_md5(blufi_sec->share_key, blufi_sec->share_len, blufi_sec->psk); mbedtls_aes_setkey_enc(&blufi_sec->aes, blufi_sec->psk, 128); - + /* alloc output data */ *output_data = &blufi_sec->self_public_key[0]; *output_len = blufi_sec->dhm.len; @@ -178,7 +178,7 @@ int blufi_aes_decrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len) uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t *data, int len) { /* This iv8 ignore, not used */ - return crc16_be(0, data, len); + return esp_crc16_be(0, data, len); } esp_err_t blufi_security_init(void) diff --git a/examples/peripherals/sdio/slave/main/app_main.c b/examples/peripherals/sdio/slave/main/app_main.c index 147f4aba4..3a6a7c759 100644 --- a/examples/peripherals/sdio/slave/main/app_main.c +++ b/examples/peripherals/sdio/slave/main/app_main.c @@ -8,7 +8,6 @@ */ #include "driver/sdio_slave.h" #include "esp_log.h" -#include "esp32/rom/lldesc.h" #include "sys/queue.h" #include "soc/soc.h" #include "freertos/task.h" diff --git a/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt b/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt new file mode 100644 index 000000000..cde4d0eed --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt @@ -0,0 +1,4 @@ +set(tjpgd_srcs "src/tjpgd.c") + +idf_component_register(SRCS "${tjpgd_srcs}" + INCLUDE_DIRS "include") diff --git a/examples/peripherals/spi_master/components/tjpgd/component.mk b/examples/peripherals/spi_master/components/tjpgd/component.mk new file mode 100644 index 000000000..24cab8b63 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/component.mk @@ -0,0 +1,3 @@ +COMPONENT_ADD_INCLUDEDIRS := include + +COMPONENT_SRCDIRS := src diff --git a/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h b/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h new file mode 100644 index 000000000..abb9dd480 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h @@ -0,0 +1,88 @@ +/*----------------------------------------------------------------------------/ +/ TJpgDec - Tiny JPEG Decompressor include file (C)ChaN, 2019 +/----------------------------------------------------------------------------*/ +#ifndef DEF_TJPGDEC +#define DEF_TJPGDEC +/*---------------------------------------------------------------------------*/ +/* System Configurations */ + +#define JD_SZBUF 512 /* Size of stream input buffer */ +#define JD_FORMAT 0 /* Output pixel format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ +#define JD_USE_SCALE 1 /* Use descaling feature for output */ +#define JD_TBLCLIP 1 /* Use table for saturation (might be a bit faster but increases 1K bytes of code size) */ + +/*---------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) /* Main development platform */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned long uint32_t; +typedef long int32_t; +#else +#include "stdint.h" +#endif + +/* Error code */ +typedef enum { + JDR_OK = 0, /* 0: Succeeded */ + JDR_INTR, /* 1: Interrupted by output function */ + JDR_INP, /* 2: Device error or wrong termination of input stream */ + JDR_MEM1, /* 3: Insufficient memory pool for the image */ + JDR_MEM2, /* 4: Insufficient stream input buffer */ + JDR_PAR, /* 5: Parameter error */ + JDR_FMT1, /* 6: Data format error (may be damaged data) */ + JDR_FMT2, /* 7: Right format but not supported */ + JDR_FMT3 /* 8: Not supported JPEG standard */ +} JRESULT; + + + +/* Rectangular structure */ +typedef struct { + uint16_t left, right, top, bottom; +} JRECT; + + + +/* Decompressor object structure */ +typedef struct JDEC JDEC; +struct JDEC { + uint16_t dctr; /* Number of bytes available in the input buffer */ + uint8_t* dptr; /* Current data read ptr */ + uint8_t* inbuf; /* Bit stream input buffer */ + uint8_t dmsk; /* Current bit in the current read byte */ + uint8_t scale; /* Output scaling ratio */ + uint8_t msx, msy; /* MCU size in unit of block (width, height) */ + uint8_t qtid[3]; /* Quantization table ID of each component */ + int16_t dcv[3]; /* Previous DC element of each component */ + uint16_t nrst; /* Restart inverval */ + uint16_t width, height; /* Size of the input image (pixel) */ + uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ + uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ + uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ + int32_t* qttbl[4]; /* Dequantizer tables [id] */ + void* workbuf; /* Working buffer for IDCT and RGB output */ + uint8_t* mcubuf; /* Working buffer for the MCU */ + void* pool; /* Pointer to available memory pool */ + uint16_t sz_pool; /* Size of momory pool (bytes available) */ + uint16_t (*infunc)(JDEC*, uint8_t*, uint16_t);/* Pointer to jpeg stream input function */ + void* device; /* Pointer to I/O device identifiler for the session */ +}; + + + +/* TJpgDec API functions */ +JRESULT jd_prepare (JDEC*, uint16_t(*)(JDEC*,uint8_t*,uint16_t), void*, uint16_t, void*); +JRESULT jd_decomp (JDEC*, uint16_t(*)(JDEC*,void*,JRECT*), uint8_t); + + +#ifdef __cplusplus +} +#endif + +#endif /* _TJPGDEC */ diff --git a/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c b/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c new file mode 100644 index 000000000..dc87fe08e --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c @@ -0,0 +1,960 @@ +/*----------------------------------------------------------------------------/ +/ TJpgDec - Tiny JPEG Decompressor R0.01c (C)ChaN, 2019 +/-----------------------------------------------------------------------------/ +/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. +/ This is a free software that opened for education, research and commercial +/ developments under license policy of following terms. +/ +/ Copyright (C) 2019, ChaN, all right reserved. +/ +/ * The TJpgDec module is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/-----------------------------------------------------------------------------/ +/ Oct 04, 2011 R0.01 First release. +/ Feb 19, 2012 R0.01a Fixed decompression fails when scan starts with an escape seq. +/ Sep 03, 2012 R0.01b Added JD_TBLCLIP option. +/ Mar 16, 2019 R0.01c Supprted stdint.h. +/----------------------------------------------------------------------------*/ + +#include "tjpgd.h" + + +/*-----------------------------------------------*/ +/* Zigzag-order to raster-order conversion table */ +/*-----------------------------------------------*/ + +#define ZIG(n) Zig[n] + +static const uint8_t Zig[64] = { /* Zigzag-order to raster-order conversion table */ + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + + + +/*-------------------------------------------------*/ +/* Input scale factor of Arai algorithm */ +/* (scaled up 16 bits for fixed point operations) */ +/*-------------------------------------------------*/ + +#define IPSF(n) Ipsf[n] + +static const uint16_t Ipsf[64] = { /* See also aa_idct.png */ + (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), + (uint16_t)(1.38704*8192), (uint16_t)(1.92388*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.08979*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.38268*8192), + (uint16_t)(1.30656*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.70711*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.36048*8192), + (uint16_t)(1.17588*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.38268*8192), (uint16_t)(1.17588*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.32442*8192), + (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), + (uint16_t)(0.78570*8192), (uint16_t)(1.08979*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.61732*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.21677*8192), + (uint16_t)(0.54120*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.29290*8192), (uint16_t)(0.14932*8192), + (uint16_t)(0.27590*8192), (uint16_t)(0.38268*8192), (uint16_t)(0.36048*8192), (uint16_t)(0.32442*8192), (uint16_t)(0.27590*8192), (uint16_t)(0.21678*8192), (uint16_t)(0.14932*8192), (uint16_t)(0.07612*8192) +}; + + + +/*---------------------------------------------*/ +/* Conversion table for fast clipping process */ +/*---------------------------------------------*/ + +#if JD_TBLCLIP + +#define BYTECLIP(v) Clip8[(uint16_t)(v) & 0x3FF] + +static const uint8_t Clip8[1024] = { + /* 0..255 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + /* 256..511 */ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + /* -512..-257 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* -256..-1 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#else /* JD_TBLCLIP */ + +inline uint8_t BYTECLIP ( + int16_t val +) +{ + if (val < 0) val = 0; + if (val > 255) val = 255; + + return (uint8_t)val; +} + +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Allocate a memory block from memory pool */ +/*-----------------------------------------------------------------------*/ + +static void* alloc_pool ( /* Pointer to allocated memory block (NULL:no memory available) */ + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t nd /* Number of bytes to allocate */ +) +{ + char *rp = 0; + + + nd = (nd + 3) & ~3; /* Align block size to the word boundary */ + + if (jd->sz_pool >= nd) { + jd->sz_pool -= nd; + rp = (char*)jd->pool; /* Get start of available memory pool */ + jd->pool = (void*)(rp + nd); /* Allocate requierd bytes */ + } + + return (void*)rp; /* Return allocated memory block (NULL:no memory to allocate) */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create de-quantization and prescaling tables with a DQT segment */ +/*-----------------------------------------------------------------------*/ + +static int create_qt_tbl ( /* 0:OK, !0:Failed */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* data, /* Pointer to the quantizer tables */ + uint16_t ndata /* Size of input data */ +) +{ + uint16_t i; + uint8_t d, z; + int32_t *pb; + + + while (ndata) { /* Process all tables in the segment */ + if (ndata < 65) return JDR_FMT1; /* Err: table size is unaligned */ + ndata -= 65; + d = *data++; /* Get table property */ + if (d & 0xF0) return JDR_FMT1; /* Err: not 8-bit resolution */ + i = d & 3; /* Get table ID */ + pb = alloc_pool(jd, 64 * sizeof (int32_t));/* Allocate a memory block for the table */ + if (!pb) return JDR_MEM1; /* Err: not enough memory */ + jd->qttbl[i] = pb; /* Register the table */ + for (i = 0; i < 64; i++) { /* Load the table */ + z = ZIG(i); /* Zigzag-order to raster-order conversion */ + pb[z] = (int32_t)((uint32_t)*data++ * IPSF(z)); /* Apply scale factor of Arai algorithm to the de-quantizers */ + } + } + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create huffman code tables with a DHT segment */ +/*-----------------------------------------------------------------------*/ + +static int create_huffman_tbl ( /* 0:OK, !0:Failed */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* data, /* Pointer to the packed huffman tables */ + uint16_t ndata /* Size of input data */ +) +{ + uint16_t i, j, b, np, cls, num; + uint8_t d, *pb, *pd; + uint16_t hc, *ph; + + + while (ndata) { /* Process all tables in the segment */ + if (ndata < 17) return JDR_FMT1; /* Err: wrong data size */ + ndata -= 17; + d = *data++; /* Get table number and class */ + if (d & 0xEE) return JDR_FMT1; /* Err: invalid class/number */ + cls = d >> 4; num = d & 0x0F; /* class = dc(0)/ac(1), table number = 0/1 */ + pb = alloc_pool(jd, 16); /* Allocate a memory block for the bit distribution table */ + if (!pb) return JDR_MEM1; /* Err: not enough memory */ + jd->huffbits[num][cls] = pb; + for (np = i = 0; i < 16; i++) { /* Load number of patterns for 1 to 16-bit code */ + np += (pb[i] = *data++); /* Get sum of code words for each code */ + } + ph = alloc_pool(jd, (uint16_t)(np * sizeof (uint16_t)));/* Allocate a memory block for the code word table */ + if (!ph) return JDR_MEM1; /* Err: not enough memory */ + jd->huffcode[num][cls] = ph; + hc = 0; + for (j = i = 0; i < 16; i++) { /* Re-build huffman code word table */ + b = pb[i]; + while (b--) ph[j++] = hc++; + hc <<= 1; + } + + if (ndata < np) return JDR_FMT1; /* Err: wrong data size */ + ndata -= np; + pd = alloc_pool(jd, np); /* Allocate a memory block for the decoded data */ + if (!pd) return JDR_MEM1; /* Err: not enough memory */ + jd->huffdata[num][cls] = pd; + for (i = 0; i < np; i++) { /* Load decoded data corresponds to each code ward */ + d = *data++; + if (!cls && d > 11) return JDR_FMT1; + *pd++ = d; + } + } + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Extract N bits from input stream */ +/*-----------------------------------------------------------------------*/ + +static int bitext ( /* >=0: extracted data, <0: error code */ + JDEC* jd, /* Pointer to the decompressor object */ + int nbit /* Number of bits to extract (1 to 11) */ +) +{ + uint8_t msk, s, *dp; + uint16_t dc, v, f; + + + msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ + s = *dp; v = f = 0; + do { + if (!msk) { /* Next byte? */ + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; /* Top of input buffer */ + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return 0 - (int16_t)JDR_INP; /* Err: read error or wrong stream termination */ + } else { + dp++; /* Next data ptr */ + } + dc--; /* Decrement number of available bytes */ + if (f) { /* In flag sequence? */ + f = 0; /* Exit flag sequence */ + if (*dp != 0) return 0 - (int16_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ + *dp = s = 0xFF; /* The flag is a data 0xFF */ + } else { + s = *dp; /* Get next data byte */ + if (s == 0xFF) { /* Is start of flag sequence? */ + f = 1; continue; /* Enter flag sequence */ + } + } + msk = 0x80; /* Read from MSB */ + } + v <<= 1; /* Get a bit */ + if (s & msk) v++; + msk >>= 1; + nbit--; + } while (nbit); + jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; + + return (int)v; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Extract a huffman decoded data from input stream */ +/*-----------------------------------------------------------------------*/ + +static int16_t huffext ( /* >=0: decoded data, <0: error code */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* hbits, /* Pointer to the bit distribution table */ + const uint16_t* hcode, /* Pointer to the code word table */ + const uint8_t* hdata /* Pointer to the data table */ +) +{ + uint8_t msk, s, *dp; + uint16_t dc, v, f, bl, nd; + + + msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ + s = *dp; v = f = 0; + bl = 16; /* Max code length */ + do { + if (!msk) { /* Next byte? */ + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; /* Top of input buffer */ + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return 0 - (int16_t)JDR_INP; /* Err: read error or wrong stream termination */ + } else { + dp++; /* Next data ptr */ + } + dc--; /* Decrement number of available bytes */ + if (f) { /* In flag sequence? */ + f = 0; /* Exit flag sequence */ + if (*dp != 0) return 0 - (int16_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ + *dp = s = 0xFF; /* The flag is a data 0xFF */ + } else { + s = *dp; /* Get next data byte */ + if (s == 0xFF) { /* Is start of flag sequence? */ + f = 1; continue; /* Enter flag sequence, get trailing byte */ + } + } + msk = 0x80; /* Read from MSB */ + } + v <<= 1; /* Get a bit */ + if (s & msk) v++; + msk >>= 1; + + for (nd = *hbits++; nd; nd--) { /* Search the code word in this bit length */ + if (v == *hcode++) { /* Matched? */ + jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; + return *hdata; /* Return the decoded data */ + } + hdata++; + } + bl--; + } while (bl); + + return 0 - (int16_t)JDR_FMT1; /* Err: code not found (may be collapted data) */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png) */ +/*-----------------------------------------------------------------------*/ + +static void block_idct ( + int32_t* src, /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */ + uint8_t* dst /* Pointer to the destination to store the block as byte array */ +) +{ + const int32_t M13 = (int32_t)(1.41421*4096), M2 = (int32_t)(1.08239*4096), M4 = (int32_t)(2.61313*4096), M5 = (int32_t)(1.84776*4096); + int32_t v0, v1, v2, v3, v4, v5, v6, v7; + int32_t t10, t11, t12, t13; + uint16_t i; + + /* Process columns */ + for (i = 0; i < 8; i++) { + v0 = src[8 * 0]; /* Get even elements */ + v1 = src[8 * 2]; + v2 = src[8 * 4]; + v3 = src[8 * 6]; + + t10 = v0 + v2; /* Process the even elements */ + t12 = v0 - v2; + t11 = (v1 - v3) * M13 >> 12; + v3 += v1; + t11 -= v3; + v0 = t10 + v3; + v3 = t10 - v3; + v1 = t11 + t12; + v2 = t12 - t11; + + v4 = src[8 * 7]; /* Get odd elements */ + v5 = src[8 * 1]; + v6 = src[8 * 5]; + v7 = src[8 * 3]; + + t10 = v5 - v4; /* Process the odd elements */ + t11 = v5 + v4; + t12 = v6 - v7; + v7 += v6; + v5 = (t11 - v7) * M13 >> 12; + v7 += t11; + t13 = (t10 + t12) * M5 >> 12; + v4 = t13 - (t10 * M2 >> 12); + v6 = t13 - (t12 * M4 >> 12) - v7; + v5 -= v6; + v4 -= v5; + + src[8 * 0] = v0 + v7; /* Write-back transformed values */ + src[8 * 7] = v0 - v7; + src[8 * 1] = v1 + v6; + src[8 * 6] = v1 - v6; + src[8 * 2] = v2 + v5; + src[8 * 5] = v2 - v5; + src[8 * 3] = v3 + v4; + src[8 * 4] = v3 - v4; + + src++; /* Next column */ + } + + /* Process rows */ + src -= 8; + for (i = 0; i < 8; i++) { + v0 = src[0] + (128L << 8); /* Get even elements (remove DC offset (-128) here) */ + v1 = src[2]; + v2 = src[4]; + v3 = src[6]; + + t10 = v0 + v2; /* Process the even elements */ + t12 = v0 - v2; + t11 = (v1 - v3) * M13 >> 12; + v3 += v1; + t11 -= v3; + v0 = t10 + v3; + v3 = t10 - v3; + v1 = t11 + t12; + v2 = t12 - t11; + + v4 = src[7]; /* Get odd elements */ + v5 = src[1]; + v6 = src[5]; + v7 = src[3]; + + t10 = v5 - v4; /* Process the odd elements */ + t11 = v5 + v4; + t12 = v6 - v7; + v7 += v6; + v5 = (t11 - v7) * M13 >> 12; + v7 += t11; + t13 = (t10 + t12) * M5 >> 12; + v4 = t13 - (t10 * M2 >> 12); + v6 = t13 - (t12 * M4 >> 12) - v7; + v5 -= v6; + v4 -= v5; + + dst[0] = BYTECLIP((v0 + v7) >> 8); /* Descale the transformed values 8 bits and output */ + dst[7] = BYTECLIP((v0 - v7) >> 8); + dst[1] = BYTECLIP((v1 + v6) >> 8); + dst[6] = BYTECLIP((v1 - v6) >> 8); + dst[2] = BYTECLIP((v2 + v5) >> 8); + dst[5] = BYTECLIP((v2 - v5) >> 8); + dst[3] = BYTECLIP((v3 + v4) >> 8); + dst[4] = BYTECLIP((v3 - v4) >> 8); + dst += 8; + + src += 8; /* Next row */ + } +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load all blocks in the MCU into working buffer */ +/*-----------------------------------------------------------------------*/ + +static JRESULT mcu_load ( + JDEC* jd /* Pointer to the decompressor object */ +) +{ + int32_t *tmp = (int32_t*)jd->workbuf; /* Block working buffer for de-quantize and IDCT */ + int b, d, e; + uint16_t blk, nby, nbc, i, z, id, cmp; + uint8_t *bp; + const uint8_t *hb, *hd; + const uint16_t *hc; + const int32_t *dqf; + + + nby = jd->msx * jd->msy; /* Number of Y blocks (1, 2 or 4) */ + nbc = 2; /* Number of C blocks (2) */ + bp = jd->mcubuf; /* Pointer to the first block */ + + for (blk = 0; blk < nby + nbc; blk++) { + cmp = (blk < nby) ? 0 : blk - nby + 1; /* Component number 0:Y, 1:Cb, 2:Cr */ + id = cmp ? 1 : 0; /* Huffman table ID of the component */ + + /* Extract a DC element from input stream */ + hb = jd->huffbits[id][0]; /* Huffman table for the DC element */ + hc = jd->huffcode[id][0]; + hd = jd->huffdata[id][0]; + b = huffext(jd, hb, hc, hd); /* Extract a huffman coded data (bit length) */ + if (b < 0) return 0 - b; /* Err: invalid code or input */ + d = jd->dcv[cmp]; /* DC value of previous block */ + if (b) { /* If there is any difference from previous block */ + e = bitext(jd, b); /* Extract data bits */ + if (e < 0) return 0 - e; /* Err: input */ + b = 1 << (b - 1); /* MSB position */ + if (!(e & b)) e -= (b << 1) - 1; /* Restore sign if needed */ + d += e; /* Get current value */ + jd->dcv[cmp] = (int16_t)d; /* Save current DC value for next block */ + } + dqf = jd->qttbl[jd->qtid[cmp]]; /* De-quantizer table ID for this component */ + tmp[0] = d * dqf[0] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ + + /* Extract following 63 AC elements from input stream */ + for (i = 1; i < 64; tmp[i++] = 0) ; /* Clear rest of elements */ + hb = jd->huffbits[id][1]; /* Huffman table for the AC elements */ + hc = jd->huffcode[id][1]; + hd = jd->huffdata[id][1]; + i = 1; /* Top of the AC elements */ + do { + b = huffext(jd, hb, hc, hd); /* Extract a huffman coded value (zero runs and bit length) */ + if (b == 0) break; /* EOB? */ + if (b < 0) return 0 - b; /* Err: invalid code or input error */ + z = (uint16_t)b >> 4; /* Number of leading zero elements */ + if (z) { + i += z; /* Skip zero elements */ + if (i >= 64) return JDR_FMT1; /* Too long zero run */ + } + if (b &= 0x0F) { /* Bit length */ + d = bitext(jd, b); /* Extract data bits */ + if (d < 0) return 0 - d; /* Err: input device */ + b = 1 << (b - 1); /* MSB position */ + if (!(d & b)) d -= (b << 1) - 1;/* Restore negative value if needed */ + z = ZIG(i); /* Zigzag-order to raster-order converted index */ + tmp[z] = d * dqf[z] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ + } + } while (++i < 64); /* Next AC element */ + + if (JD_USE_SCALE && jd->scale == 3) { + *bp = (uint8_t)((*tmp / 256) + 128); /* If scale ratio is 1/8, IDCT can be ommited and only DC element is used */ + } else { + block_idct(tmp, bp); /* Apply IDCT and store the block to the MCU buffer */ + } + + bp += 64; /* Next block */ + } + + return JDR_OK; /* All blocks have been loaded successfully */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Output an MCU: Convert YCrCb to RGB and output it in RGB form */ +/*-----------------------------------------------------------------------*/ + +static JRESULT mcu_output ( + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ + uint16_t x, /* MCU position in the image (left of the MCU) */ + uint16_t y /* MCU position in the image (top of the MCU) */ +) +{ + const int16_t CVACC = (sizeof (int16_t) > 2) ? 1024 : 128; + uint16_t ix, iy, mx, my, rx, ry; + int16_t yy, cb, cr; + uint8_t *py, *pc, *rgb24; + JRECT rect; + + + mx = jd->msx * 8; my = jd->msy * 8; /* MCU size (pixel) */ + rx = (x + mx <= jd->width) ? mx : jd->width - x; /* Output rectangular size (it may be clipped at right/bottom end) */ + ry = (y + my <= jd->height) ? my : jd->height - y; + if (JD_USE_SCALE) { + rx >>= jd->scale; ry >>= jd->scale; + if (!rx || !ry) return JDR_OK; /* Skip this MCU if all pixel is to be rounded off */ + x >>= jd->scale; y >>= jd->scale; + } + rect.left = x; rect.right = x + rx - 1; /* Rectangular area in the frame buffer */ + rect.top = y; rect.bottom = y + ry - 1; + + + if (!JD_USE_SCALE || jd->scale != 3) { /* Not for 1/8 scaling */ + + /* Build an RGB MCU from discrete comopnents */ + rgb24 = (uint8_t*)jd->workbuf; + for (iy = 0; iy < my; iy++) { + pc = jd->mcubuf; + py = pc + iy * 8; + if (my == 16) { /* Double block height? */ + pc += 64 * 4 + (iy >> 1) * 8; + if (iy >= 8) py += 64; + } else { /* Single block height */ + pc += mx * 8 + iy * 8; + } + for (ix = 0; ix < mx; ix++) { + cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ + cr = pc[64] - 128; + if (mx == 16) { /* Double block width? */ + if (ix == 8) py += 64 - 8; /* Jump to next block if double block heigt */ + pc += ix & 1; /* Increase chroma pointer every two pixels */ + } else { /* Single block width */ + pc++; /* Increase chroma pointer every pixel */ + } + yy = *py++; /* Get Y component */ + + /* Convert YCbCr to RGB */ + *rgb24++ = /* R */ BYTECLIP(yy + ((int16_t)(1.402 * CVACC) * cr) / CVACC); + *rgb24++ = /* G */ BYTECLIP(yy - ((int16_t)(0.344 * CVACC) * cb + (int16_t)(0.714 * CVACC) * cr) / CVACC); + *rgb24++ = /* B */ BYTECLIP(yy + ((int16_t)(1.772 * CVACC) * cb) / CVACC); + } + } + + /* Descale the MCU rectangular if needed */ + if (JD_USE_SCALE && jd->scale) { + uint16_t x, y, r, g, b, s, w, a; + uint8_t *op; + + /* Get averaged RGB value of each square correcponds to a pixel */ + s = jd->scale * 2; /* Bumber of shifts for averaging */ + w = 1 << jd->scale; /* Width of square */ + a = (mx - w) * 3; /* Bytes to skip for next line in the square */ + op = (uint8_t*)jd->workbuf; + for (iy = 0; iy < my; iy += w) { + for (ix = 0; ix < mx; ix += w) { + rgb24 = (uint8_t*)jd->workbuf + (iy * mx + ix) * 3; + r = g = b = 0; + for (y = 0; y < w; y++) { /* Accumulate RGB value in the square */ + for (x = 0; x < w; x++) { + r += *rgb24++; + g += *rgb24++; + b += *rgb24++; + } + rgb24 += a; + } /* Put the averaged RGB value as a pixel */ + *op++ = (uint8_t)(r >> s); + *op++ = (uint8_t)(g >> s); + *op++ = (uint8_t)(b >> s); + } + } + } + + } else { /* For only 1/8 scaling (left-top pixel in each block are the DC value of the block) */ + + /* Build a 1/8 descaled RGB MCU from discrete comopnents */ + rgb24 = (uint8_t*)jd->workbuf; + pc = jd->mcubuf + mx * my; + cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ + cr = pc[64] - 128; + for (iy = 0; iy < my; iy += 8) { + py = jd->mcubuf; + if (iy == 8) py += 64 * 2; + for (ix = 0; ix < mx; ix += 8) { + yy = *py; /* Get Y component */ + py += 64; + + /* Convert YCbCr to RGB */ + *rgb24++ = /* R */ BYTECLIP(yy + ((int16_t)(1.402 * CVACC) * cr / CVACC)); + *rgb24++ = /* G */ BYTECLIP(yy - ((int16_t)(0.344 * CVACC) * cb + (int16_t)(0.714 * CVACC) * cr) / CVACC); + *rgb24++ = /* B */ BYTECLIP(yy + ((int16_t)(1.772 * CVACC) * cb / CVACC)); + } + } + } + + /* Squeeze up pixel table if a part of MCU is to be truncated */ + mx >>= jd->scale; + if (rx < mx) { + uint8_t *s, *d; + uint16_t x, y; + + s = d = (uint8_t*)jd->workbuf; + for (y = 0; y < ry; y++) { + for (x = 0; x < rx; x++) { /* Copy effective pixels */ + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + s += (mx - rx) * 3; /* Skip truncated pixels */ + } + } + + /* Convert RGB888 to RGB565 if needed */ + if (JD_FORMAT == 1) { + uint8_t *s = (uint8_t*)jd->workbuf; + uint16_t w, *d = (uint16_t*)s; + uint16_t n = rx * ry; + + do { + w = (*s++ & 0xF8) << 8; /* RRRRR----------- */ + w |= (*s++ & 0xFC) << 3; /* -----GGGGGG----- */ + w |= *s++ >> 3; /* -----------BBBBB */ + *d++ = w; + } while (--n); + } + + /* Output the RGB rectangular */ + return outfunc(jd, jd->workbuf, &rect) ? JDR_OK : JDR_INTR; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Process restart interval */ +/*-----------------------------------------------------------------------*/ + +static JRESULT restart ( + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t rstn /* Expected restert sequense number */ +) +{ + uint16_t i, dc; + uint16_t d; + uint8_t *dp; + + + /* Discard padding bits and get two bytes from the input stream */ + dp = jd->dptr; dc = jd->dctr; + d = 0; + for (i = 0; i < 2; i++) { + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return JDR_INP; + } else { + dp++; + } + dc--; + d = (d << 8) | *dp; /* Get a byte */ + } + jd->dptr = dp; jd->dctr = dc; jd->dmsk = 0; + + /* Check the marker */ + if ((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) { + return JDR_FMT1; /* Err: expected RSTn marker is not detected (may be collapted data) */ + } + + /* Reset DC offset */ + jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Analyze the JPEG image and Initialize decompressor object */ +/*-----------------------------------------------------------------------*/ + +#define LDB_WORD(ptr) (uint16_t)(((uint16_t)*((uint8_t*)(ptr))<<8)|(uint16_t)*(uint8_t*)((ptr)+1)) + + +JRESULT jd_prepare ( + JDEC* jd, /* Blank decompressor object */ + uint16_t (*infunc)(JDEC*, uint8_t*, uint16_t), /* JPEG strem input function */ + void* pool, /* Working buffer for the decompression session */ + uint16_t sz_pool, /* Size of working buffer */ + void* dev /* I/O device identifier for the session */ +) +{ + uint8_t *seg, b; + uint16_t marker; + uint32_t ofs; + uint16_t n, i, j, len; + JRESULT rc; + + + if (!pool) return JDR_PAR; + + jd->pool = pool; /* Work memroy */ + jd->sz_pool = sz_pool; /* Size of given work memory */ + jd->infunc = infunc; /* Stream input function */ + jd->device = dev; /* I/O device identifier */ + jd->nrst = 0; /* No restart interval (default) */ + + for (i = 0; i < 2; i++) { /* Nulls pointers */ + for (j = 0; j < 2; j++) { + jd->huffbits[i][j] = 0; + jd->huffcode[i][j] = 0; + jd->huffdata[i][j] = 0; + } + } + for (i = 0; i < 4; jd->qttbl[i++] = 0) ; + + jd->inbuf = seg = alloc_pool(jd, JD_SZBUF); /* Allocate stream input buffer */ + if (!seg) return JDR_MEM1; + + if (jd->infunc(jd, seg, 2) != 2) return JDR_INP;/* Check SOI marker */ + if (LDB_WORD(seg) != 0xFFD8) return JDR_FMT1; /* Err: SOI is not detected */ + ofs = 2; + + for (;;) { + /* Get a JPEG marker */ + if (jd->infunc(jd, seg, 4) != 4) return JDR_INP; + marker = LDB_WORD(seg); /* Marker */ + len = LDB_WORD(seg + 2); /* Length field */ + if (len <= 2 || (marker >> 8) != 0xFF) return JDR_FMT1; + len -= 2; /* Content size excluding length field */ + ofs += 4 + len; /* Number of bytes loaded */ + + switch (marker & 0xFF) { + case 0xC0: /* SOF0 (baseline JPEG) */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + jd->width = LDB_WORD(seg+3); /* Image width in unit of pixel */ + jd->height = LDB_WORD(seg+1); /* Image height in unit of pixel */ + if (seg[5] != 3) return JDR_FMT3; /* Err: Supports only Y/Cb/Cr format */ + + /* Check three image components */ + for (i = 0; i < 3; i++) { + b = seg[7 + 3 * i]; /* Get sampling factor */ + if (!i) { /* Y component */ + if (b != 0x11 && b != 0x22 && b != 0x21) { /* Check sampling factor */ + return JDR_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */ + } + jd->msx = b >> 4; jd->msy = b & 15; /* Size of MCU [blocks] */ + } else { /* Cb/Cr component */ + if (b != 0x11) return JDR_FMT3; /* Err: Sampling factor of Cr/Cb must be 1 */ + } + b = seg[8 + 3 * i]; /* Get dequantizer table ID for this component */ + if (b > 3) return JDR_FMT3; /* Err: Invalid ID */ + jd->qtid[i] = b; + } + break; + + case 0xDD: /* DRI */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Get restart interval (MCUs) */ + jd->nrst = LDB_WORD(seg); + break; + + case 0xC4: /* DHT */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Create huffman tables */ + rc = create_huffman_tbl(jd, seg, len); + if (rc) return rc; + break; + + case 0xDB: /* DQT */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Create de-quantizer tables */ + rc = create_qt_tbl(jd, seg, len); + if (rc) return rc; + break; + + case 0xDA: /* SOS */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + if (!jd->width || !jd->height) return JDR_FMT1; /* Err: Invalid image size */ + + if (seg[0] != 3) return JDR_FMT3; /* Err: Supports only three color components format */ + + /* Check if all tables corresponding to each components have been loaded */ + for (i = 0; i < 3; i++) { + b = seg[2 + 2 * i]; /* Get huffman table ID */ + if (b != 0x00 && b != 0x11) return JDR_FMT3; /* Err: Different table number for DC/AC element */ + b = i ? 1 : 0; + if (!jd->huffbits[b][0] || !jd->huffbits[b][1]) { /* Check dc/ac huffman table for this component */ + return JDR_FMT1; /* Err: Nnot loaded */ + } + if (!jd->qttbl[jd->qtid[i]]) { /* Check dequantizer table for this component */ + return JDR_FMT1; /* Err: Not loaded */ + } + } + + /* Allocate working buffer for MCU and RGB */ + n = jd->msy * jd->msx; /* Number of Y blocks in the MCU */ + if (!n) return JDR_FMT1; /* Err: SOF0 has not been loaded */ + len = n * 64 * 2 + 64; /* Allocate buffer for IDCT and RGB output */ + if (len < 256) len = 256; /* but at least 256 byte is required for IDCT */ + jd->workbuf = alloc_pool(jd, len); /* and it may occupy a part of following MCU working buffer for RGB output */ + if (!jd->workbuf) return JDR_MEM1; /* Err: not enough memory */ + jd->mcubuf = (uint8_t*)alloc_pool(jd, (uint16_t)((n + 2) * 64)); /* Allocate MCU working buffer */ + if (!jd->mcubuf) return JDR_MEM1; /* Err: not enough memory */ + + /* Pre-load the JPEG data to extract it from the bit stream */ + jd->dptr = seg; jd->dctr = 0; jd->dmsk = 0; /* Prepare to read bit stream */ + if (ofs %= JD_SZBUF) { /* Align read offset to JD_SZBUF */ + jd->dctr = jd->infunc(jd, seg + ofs, (uint16_t)(JD_SZBUF - ofs)); + jd->dptr = seg + ofs - 1; + } + + return JDR_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */ + + case 0xC1: /* SOF1 */ + case 0xC2: /* SOF2 */ + case 0xC3: /* SOF3 */ + case 0xC5: /* SOF5 */ + case 0xC6: /* SOF6 */ + case 0xC7: /* SOF7 */ + case 0xC9: /* SOF9 */ + case 0xCA: /* SOF10 */ + case 0xCB: /* SOF11 */ + case 0xCD: /* SOF13 */ + case 0xCE: /* SOF14 */ + case 0xCF: /* SOF15 */ + case 0xD9: /* EOI */ + return JDR_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */ + + default: /* Unknown segment (comment, exif or etc..) */ + /* Skip segment data */ + if (jd->infunc(jd, 0, len) != len) { /* Null pointer specifies to skip bytes of stream */ + return JDR_INP; + } + } + } +} + + + + +/*-----------------------------------------------------------------------*/ +/* Start to decompress the JPEG picture */ +/*-----------------------------------------------------------------------*/ + +JRESULT jd_decomp ( + JDEC* jd, /* Initialized decompression object */ + uint16_t (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ + uint8_t scale /* Output de-scaling factor (0 to 3) */ +) +{ + uint16_t x, y, mx, my; + uint16_t rst, rsc; + JRESULT rc; + + + if (scale > (JD_USE_SCALE ? 3 : 0)) return JDR_PAR; + jd->scale = scale; + + mx = jd->msx * 8; my = jd->msy * 8; /* Size of the MCU (pixel) */ + + jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Initialize DC values */ + rst = rsc = 0; + + rc = JDR_OK; + for (y = 0; y < jd->height; y += my) { /* Vertical loop of MCUs */ + for (x = 0; x < jd->width; x += mx) { /* Horizontal loop of MCUs */ + if (jd->nrst && rst++ == jd->nrst) { /* Process restart interval if enabled */ + rc = restart(jd, rsc++); + if (rc != JDR_OK) return rc; + rst = 1; + } + rc = mcu_load(jd); /* Load an MCU (decompress huffman coded stream and apply IDCT) */ + if (rc != JDR_OK) return rc; + rc = mcu_output(jd, outfunc, x, y); /* Output the MCU (color space conversion, scaling and output) */ + if (rc != JDR_OK) return rc; + } + } + + return rc; +} + + + diff --git a/examples/peripherals/spi_master/main/decode_image.c b/examples/peripherals/spi_master/main/decode_image.c index 4a4b4daed..179c3deb7 100644 --- a/examples/peripherals/spi_master/main/decode_image.c +++ b/examples/peripherals/spi_master/main/decode_image.c @@ -7,72 +7,69 @@ CONDITIONS OF ANY KIND, either express or implied. */ - /* -The image used for the effect on the LCD in the SPI master example is stored in flash -as a jpeg file. This file contains the decode_image routine, which uses the tiny JPEG -decoder library in ROM to decode this JPEG into a format that can be sent to the display. +The image used for the effect on the LCD in the SPI master example is stored in flash +as a jpeg file. This file contains the decode_image routine, which uses the tiny JPEG +decoder library to decode this JPEG into a format that can be sent to the display. -Keep in mind that the decoder library cannot handle progressive files (will give +Keep in mind that the decoder library cannot handle progressive files (will give ``Image decoder: jd_prepare failed (8)`` as an error) so make sure to save in the correct format if you want to use a different image file. */ - #include "decode_image.h" -#include "esp32/rom/tjpgd.h" +#include "tjpgd.h" #include "esp_log.h" #include //Reference the binary-included jpeg file -extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); -extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); +extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); +extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); //Define the height and width of the jpeg file. Make sure this matches the actual jpeg //dimensions. #define IMAGE_W 336 #define IMAGE_H 256 - -const char *TAG="ImageDec"; - +const char *TAG = "ImageDec"; //Data that is passed from the decoder function to the infunc/outfunc functions. typedef struct { - const unsigned char *inData; //Pointer to jpeg data - int inPos; //Current position in jpeg data - uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values - int outW; //Width of the resulting file - int outH; //Height of the resulting file + const unsigned char *inData; //Pointer to jpeg data + uint16_t inPos; //Current position in jpeg data + uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values + int outW; //Width of the resulting file + int outH; //Height of the resulting file } JpegDev; - //Input function for jpeg decoder. Just returns bytes from the inData field of the JpegDev structure. -static UINT infunc(JDEC *decoder, BYTE *buf, UINT len) +static uint16_t infunc(JDEC *decoder, uint8_t *buf, uint16_t len) { //Read bytes from input file - JpegDev *jd=(JpegDev*)decoder->device; - if (buf!=NULL) memcpy(buf, jd->inData+jd->inPos, len); - jd->inPos+=len; + JpegDev *jd = (JpegDev *)decoder->device; + if (buf != NULL) { + memcpy(buf, jd->inData + jd->inPos, len); + } + jd->inPos += len; return len; } //Output function. Re-encodes the RGB888 data from the decoder as big-endian RGB565 and //stores it in the outData array of the JpegDev structure. -static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect) +static uint16_t outfunc(JDEC *decoder, void *bitmap, JRECT *rect) { - JpegDev *jd=(JpegDev*)decoder->device; - uint8_t *in=(uint8_t*)bitmap; - for (int y=rect->top; y<=rect->bottom; y++) { - for (int x=rect->left; x<=rect->right; x++) { + JpegDev *jd = (JpegDev *)decoder->device; + uint8_t *in = (uint8_t *)bitmap; + for (int y = rect->top; y <= rect->bottom; y++) { + for (int x = rect->left; x <= rect->right; x++) { //We need to convert the 3 bytes in `in` to a rgb565 value. - uint16_t v=0; - v|=((in[0]>>3)<<11); - v|=((in[1]>>2)<<5); - v|=((in[2]>>3)<<0); + uint16_t v = 0; + v |= ((in[0] >> 3) << 11); + v |= ((in[1] >> 2) << 5); + v |= ((in[2] >> 3) << 0); //The LCD wants the 16-bit value in big-endian, so swap bytes - v=(v>>8)|(v<<8); - jd->outData[y][x]=v; - in+=3; + v = (v >> 8) | (v << 8); + jd->outData[y][x] = v; + in += 3; } } return 1; @@ -82,68 +79,67 @@ static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect) #define WORKSZ 3100 //Decode the embedded image into pixel lines that can be used with the rest of the logic. -esp_err_t decode_image(uint16_t ***pixels) +esp_err_t decode_image(uint16_t ***pixels) { - char *work=NULL; + char *work = NULL; int r; JDEC decoder; JpegDev jd; - *pixels=NULL; - esp_err_t ret=ESP_OK; - + *pixels = NULL; + esp_err_t ret = ESP_OK; //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines. - *pixels=calloc(IMAGE_H, sizeof(uint16_t*)); - if (*pixels==NULL) { + *pixels = calloc(IMAGE_H, sizeof(uint16_t *)); + if (*pixels == NULL) { ESP_LOGE(TAG, "Error allocating memory for lines"); - ret=ESP_ERR_NO_MEM; + ret = ESP_ERR_NO_MEM; goto err; } - for (int i=0; imagic; crc = buf->crc; buf->crc = 0; - crc_cal = crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len); + crc_cal = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len); if (crc_cal == crc) { return buf->type; @@ -146,7 +145,7 @@ void example_espnow_data_prepare(example_espnow_send_param_t *send_param) buf->magic = send_param->magic; /* Fill all remaining bytes after the data with random values */ esp_fill_random(buf->payload, send_param->len - sizeof(example_espnow_data_t)); - buf->crc = crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len); + buf->crc = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len); } static void example_espnow_task(void *pvParameter) diff --git a/tools/ci/check_examples_rom_header.sh b/tools/ci/check_examples_rom_header.sh new file mode 100755 index 000000000..131723e0d --- /dev/null +++ b/tools/ci/check_examples_rom_header.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Examples shouldn't include rom headers directly + +output=$(find ${IDF_PATH}/examples -name "*.[chS]" -o -name "*.cpp" -not -path "**/build/**") +files=$(grep ".*include.*rom.*h" ${output} | cut -d ":" -f 1) +found_rom=0 +for file in ${files} +do + echo "${file} contains rom headers!" + found_rom=`expr $found_rom + 1`; +done + +if [ $found_rom -eq 0 ]; then + echo "No rom headers found in examples" + exit 0 +fi + +exit 1 diff --git a/tools/ci/config/check.yml b/tools/ci/config/check.yml index ad4f71290..7507c47ed 100644 --- a/tools/ci/config/check.yml +++ b/tools/ci/config/check.yml @@ -42,6 +42,11 @@ check_examples_cmake_make: script: - tools/ci/check_examples_cmake_make.sh +check_examples_rom_header: + extends: .check_job_template_with_filter + script: + - tools/ci/check_examples_rom_header.sh + check_python_style: extends: .check_job_template_with_filter artifacts: diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 4e580c5a8..bcc257b3d 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -35,6 +35,7 @@ tools/ci/build_examples_cmake.sh tools/ci/check-executable.sh tools/ci/check-line-endings.sh tools/ci/check_examples_cmake_make.sh +tools/ci/check_examples_rom_header.sh tools/ci/check_idf_version.sh tools/ci/check_ut_cmake_make.sh tools/ci/checkout_project_ref.py From 75adefe437f59b9f1a557164c01fcbbdeadb2b90 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 13 Aug 2019 16:01:50 +0800 Subject: [PATCH 39/46] docs: Alphbetically sort toctree This commit sorts the entries of variuos toctrees alphabetically. Indentation was also fixed. The order of some toctrees were not modified if the existing order had some form of suggested reading order. --- docs/en/api-guides/index.rst | 62 ++++++++++---------- docs/en/api-reference/bluetooth/index.rst | 12 ++-- docs/en/api-reference/index.rst | 20 +++---- docs/en/api-reference/network/index.rst | 10 ++-- docs/en/api-reference/peripherals/index.rst | 40 ++++++------- docs/en/api-reference/protocols/index.rst | 22 +++---- docs/en/api-reference/provisioning/index.rst | 8 +-- docs/en/api-reference/storage/index.rst | 20 +++---- docs/en/api-reference/system/index.rst | 44 +++++++------- 9 files changed, 119 insertions(+), 119 deletions(-) diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index cc762d3b3..fdfd58c98 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -3,35 +3,35 @@ API Guides :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - General Notes - Build System - Build System (Legacy GNU Make) - Error Handling - Fatal Errors - Event Handling - Deep Sleep Wake Stubs - ESP32 Core Dump - Flash Encryption <../security/flash-encryption> - FreeRTOS SMP Changes - Thread Local Storage - High Level Interrupts - JTAG Debugging - Bootloader - Partition Tables - Secure Boot <../security/secure-boot> - ULP Coprocessor - ULP Coprocessor (Legacy GNU Make) - Unit Testing - Unit Testing (Legacy GNU Make) - Application Level Tracing - Console Component - ROM debug console - RF Calibration - WiFi Driver - ESP-MESH - BluFi - External SPI-connected RAM - Linker Script Generation - Tools + Application Level Tracing + BluFi + Bootloader + Build System + Build System (Legacy GNU Make) + Console Component + Deep Sleep Wake Stubs + Error Handling + ESP-MESH + ESP32 Core Dump + Event Handling + External SPI-connected RAM + Fatal Errors + Flash Encryption <../security/flash-encryption> + FreeRTOS SMP Changes + General Notes + High Level Interrupts + JTAG Debugging + Linker Script Generation + Partition Tables + RF Calibration + ROM debug console + Secure Boot <../security/secure-boot> + Thread Local Storage + Tools + ULP Coprocessor (Legacy GNU Make) + ULP Coprocessor + Unit Testing (Legacy GNU Make) + Unit Testing + WiFi Driver diff --git a/docs/en/api-reference/bluetooth/index.rst b/docs/en/api-reference/bluetooth/index.rst index da9f19d65..d25008358 100644 --- a/docs/en/api-reference/bluetooth/index.rst +++ b/docs/en/api-reference/bluetooth/index.rst @@ -4,13 +4,13 @@ Bluetooth API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 2 + :maxdepth: 2 - Bluetooth Controller && VHCI - Bluetooth Common - Bluetooth LE - Bluetooth Classic - NimBLE + Bluetooth Controller && VHCI + Bluetooth Common + Bluetooth LE + Bluetooth Classic + NimBLE ESP-IDF currently supports two host stacks. The Bluedroid based stack (default) supports classic Bluetooth as well as BLE. On the other hand, Apache NimBLE based stack is BLE only. For users to make a choice: * For usecases involving classic Bluetooth as well as BLE, Bluedroid should be used. diff --git a/docs/en/api-reference/index.rst b/docs/en/api-reference/index.rst index a083fe82a..92e57f8cc 100644 --- a/docs/en/api-reference/index.rst +++ b/docs/en/api-reference/index.rst @@ -4,15 +4,15 @@ API Reference :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 2 + :maxdepth: 2 - Bluetooth - Networking - Peripherals - Protocols - Provisioning - Storage - System - Configuration Options - Error Codes Reference + Bluetooth + Networking + Peripherals + Protocols + Provisioning + Storage + System + Configuration Options + Error Codes Reference diff --git a/docs/en/api-reference/network/index.rst b/docs/en/api-reference/network/index.rst index f555a456c..cb5c5801b 100644 --- a/docs/en/api-reference/network/index.rst +++ b/docs/en/api-reference/network/index.rst @@ -7,12 +7,12 @@ Wi-Fi ===== .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - Wi-Fi - Smart Config - ESP-NOW - ESP Mesh + Wi-Fi + Smart Config + ESP-NOW + ESP Mesh Code examples for the Wi-Fi API are provided in the :example:`wifi` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index b9b85c203..73c5b42ed 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -4,26 +4,26 @@ Peripherals API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - ADC - CAN - DAC - GPIO (including RTC low power I/O) - I2C - I2S - LED Control - MCPWM - Pulse Counter - Remote Control - SDMMC Host - SD SPI Host - SDIO Slave - Sigma-delta Modulation - SPI Master - SPI Slave - Timer - Touch Sensor - UART + ADC + CAN + DAC + GPIO (including RTC low power I/O) + I2C + I2S + LED Control + MCPWM + Pulse Counter + Remote Control + SD SPI Host + SDIO Slave + SDMMC Host + Sigma-delta Modulation + SPI Master + SPI Slave + Timer + Touch Sensor + UART Code examples for this API section are provided in the :example:`peripherals` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/protocols/index.rst b/docs/en/api-reference/protocols/index.rst index c35c954f3..36af21989 100644 --- a/docs/en/api-reference/protocols/index.rst +++ b/docs/en/api-reference/protocols/index.rst @@ -3,18 +3,18 @@ Application Protocols :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - mDNS - ESP-TLS - HTTP Client - Websocket Client - HTTP Server - HTTPS Server - ASIO - ESP-MQTT - Modbus - Local Control + ASIO + ESP-MQTT + ESP-TLS + HTTP Client + HTTP Server + HTTPS Server + Local Control + mDNS + Modbus + Websocket Client Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/provisioning/index.rst b/docs/en/api-reference/provisioning/index.rst index 0243ec19f..c2341ad73 100644 --- a/docs/en/api-reference/provisioning/index.rst +++ b/docs/en/api-reference/provisioning/index.rst @@ -4,10 +4,10 @@ Provisioning API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - Unified Provisioning - Protocol Communication - Wi-Fi Provisioning + Protocol Communication + Unified Provisioning + Wi-Fi Provisioning Code examples for this API section are provided in the :example:`provisioning` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/storage/index.rst b/docs/en/api-reference/storage/index.rst index d80e30b56..23cb38b64 100644 --- a/docs/en/api-reference/storage/index.rst +++ b/docs/en/api-reference/storage/index.rst @@ -2,17 +2,17 @@ Storage API *********** .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - SPI Flash and Partition APIs - SD/SDIO/MMC Driver - Non-Volatile Storage - NVS Partition Generation Utility - Virtual Filesystem - FAT Filesystem - Wear Levelling - SPIFFS Filesystem - Mass Manufacturing Utility + FAT Filesystem + Mass Manufacturing Utility + Non-Volatile Storage + NVS Partition Generation Utility + SD/SDIO/MMC Driver + SPI Flash and Partition APIs + SPIFFS Filesystem + Virtual Filesystem + Wear Levelling Code examples for this API section are provided in the :example:`storage` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 1f2c25940..8faac3a0b 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -2,29 +2,29 @@ System API ********** .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - FreeRTOS - FreeRTOS Additions - Heap Memory Allocation - Heap Memory Debugging - Himem (large external SPI RAM) API - Interrupt Allocation - Watchdogs - eFuse Manager - Inter-Processor Call - High Resolution Timer - Logging - Event Loop Library - Application Level Tracing - Power Management - Sleep Modes - Over The Air Updates (OTA) - ESP HTTPS OTA - ESP pthread - Error Codes and Helper Functions - App image format - Miscellaneous System APIs + App image format + Application Level Tracing + eFuse Manager + Error Codes and Helper Functions + ESP HTTPS OTA + ESP pthread + Event Loop Library + FreeRTOS + FreeRTOS Additions + Heap Memory Allocation + Heap Memory Debugging + High Resolution Timer + Himem (large external SPI RAM) API + Inter-Processor Call + Interrupt Allocation + Logging + Miscellaneous System APIs + Over The Air Updates (OTA) + Power Management + Sleep Modes + Watchdogs Code examples for this API section are provided in the :example:`system` directory of ESP-IDF examples. From 0a74227cfa2d6b3a94c75dc05753f91e7d970c10 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 13 Aug 2019 10:09:52 +0200 Subject: [PATCH 40/46] bump version to 4.1 --- components/esp_common/include/esp_idf_version.h | 2 +- make/version.mk | 2 +- tools/cmake/version.cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esp_common/include/esp_idf_version.h b/components/esp_common/include/esp_idf_version.h index 52601ca8f..7f982413c 100644 --- a/components/esp_common/include/esp_idf_version.h +++ b/components/esp_common/include/esp_idf_version.h @@ -21,7 +21,7 @@ extern "C" { /** Major version number (X.x.x) */ #define ESP_IDF_VERSION_MAJOR 4 /** Minor version number (x.X.x) */ -#define ESP_IDF_VERSION_MINOR 0 +#define ESP_IDF_VERSION_MINOR 1 /** Patch version number (x.x.X) */ #define ESP_IDF_VERSION_PATCH 0 diff --git a/make/version.mk b/make/version.mk index 9dcda422a..ce6d88609 100644 --- a/make/version.mk +++ b/make/version.mk @@ -1,3 +1,3 @@ IDF_VERSION_MAJOR := 4 -IDF_VERSION_MINOR := 0 +IDF_VERSION_MINOR := 1 IDF_VERSION_PATCH := 0 diff --git a/tools/cmake/version.cmake b/tools/cmake/version.cmake index 265ab33b7..07ce0b582 100644 --- a/tools/cmake/version.cmake +++ b/tools/cmake/version.cmake @@ -1,3 +1,3 @@ set(IDF_VERSION_MAJOR 4) -set(IDF_VERSION_MINOR 0) +set(IDF_VERSION_MINOR 1) set(IDF_VERSION_PATCH 0) From a001998d5283b29ca9a374adf7cef3357b39a03a Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 20 Jun 2019 17:27:29 +0200 Subject: [PATCH 41/46] mdns: fix missing bye packet if services removed with mdns_service_remove_all() or mdns_free() Closes https://github.com/espressif/esp-idf/issues/3660 --- components/mdns/mdns.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 095651634..4bf5bce4a 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -1676,9 +1676,7 @@ static void _mdns_send_final_bye(bool include_ip) size_t srv_count = 0; mdns_srv_item_t * a = _mdns_server->services; while (a) { - if (!a->service->instance) { - srv_count++; - } + srv_count++; a = a->next; } if (!srv_count) { @@ -1688,9 +1686,7 @@ static void _mdns_send_final_bye(bool include_ip) size_t i = 0; a = _mdns_server->services; while (a) { - if (!a->service->instance) { - services[i++] = a; - } + services[i++] = a; a = a->next; } _mdns_send_bye(services, srv_count, include_ip); @@ -1699,7 +1695,7 @@ static void _mdns_send_final_bye(bool include_ip) /** * @brief Stop the responder on all services without instance */ -static void _mdns_send_bye_all_pcbs_no_instance(void) +static void _mdns_send_bye_all_pcbs_no_instance(bool include_ip) { size_t srv_count = 0; mdns_srv_item_t * a = _mdns_server->services; @@ -1721,7 +1717,7 @@ static void _mdns_send_bye_all_pcbs_no_instance(void) } a = a->next; } - _mdns_send_bye(services, srv_count, false); + _mdns_send_bye(services, srv_count, include_ip); } /** @@ -3728,14 +3724,14 @@ static void _mdns_execute_action(mdns_action_t * action) action->data.sys_event.event_id, action->data.sys_event.interface); break; case ACTION_HOSTNAME_SET: - _mdns_send_final_bye(true); + _mdns_send_bye_all_pcbs_no_instance(true); free((char*)_mdns_server->hostname); _mdns_server->hostname = action->data.hostname; _mdns_restart_all_pcbs(); break; case ACTION_INSTANCE_SET: - _mdns_send_bye_all_pcbs_no_instance(); + _mdns_send_bye_all_pcbs_no_instance(false); free((char*)_mdns_server->instance); _mdns_server->instance = action->data.instance; _mdns_restart_all_pcbs_no_instance(); From 74e2e464029a280e71b71a60394a46b79cb27688 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Wed, 14 Aug 2019 20:57:30 +0800 Subject: [PATCH 42/46] bugfix(flash): add spi dio address bitlen configure in psram init --- components/esp32/spiram_psram.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index 1ac19a97d..a5bd92ded 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -508,6 +508,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; } else if (rd_mode_reg & SPI_FREAD_DIO_M) { spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; + SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S); } else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) { spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; } else { From 4c7b83defc600e4e6d1f7938e92597f494fb9b28 Mon Sep 17 00:00:00 2001 From: Prasad Alatkar Date: Thu, 15 Aug 2019 10:50:30 +0800 Subject: [PATCH 43/46] NimBLE: Fix bug in `protocomm_nimble` chararcteristic access callback Fixes bug in `protocomm_nimble` while writing to characteristic with length greater than MTU value. --- .../src/transports/protocomm_nimble.c | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/components/protocomm/src/transports/protocomm_nimble.c b/components/protocomm/src/transports/protocomm_nimble.c index cbe7bdb8d..bf0697ba5 100644 --- a/components/protocomm/src/transports/protocomm_nimble.c +++ b/components/protocomm/src/transports/protocomm_nimble.c @@ -287,7 +287,7 @@ gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, struct char *temp_outbuf = strdup(ctxt->dsc->arg); if (temp_outbuf == NULL) { ESP_LOGE(TAG, "Error duplicating user description of characteristic"); - return ESP_ERR_NO_MEM; + return BLE_ATT_ERR_INSUFFICIENT_RES; } ssize_t temp_outlen = strlen(temp_outbuf); @@ -308,6 +308,9 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, ssize_t temp_outlen = 0; uint8_t *temp_outbuf = NULL; uint8_t *uuid = NULL; + uint8_t *data_buf = NULL; + uint16_t data_len = 0; + uint16_t data_buf_len = 0; switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: @@ -328,7 +331,7 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, uuid = (uint8_t *) calloc(BLE_UUID128_VAL_LENGTH, sizeof(uint8_t)); if (!uuid) { ESP_LOGE(TAG, "Error allocating memory for 128 bit UUID"); - return ESP_ERR_NO_MEM; + return BLE_ATT_ERR_INSUFFICIENT_RES; } rc = ble_uuid_flat(ctxt->chr->uuid, uuid); @@ -338,16 +341,32 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, return rc; } - ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, om_len = %d", - ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, ctxt->om->om_len); + /* Save the length of entire data */ + data_len = OS_MBUF_PKTLEN(ctxt->om); + ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, data_len = %d", + ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, data_len); + + data_buf = calloc(1, data_len); + if (data_buf == NULL) { + ESP_LOGE(TAG, "Error allocating memory for characteristic value"); + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = ble_hs_mbuf_to_flat(ctxt->om, data_buf, data_len, &data_buf_len); + if (rc != 0) { + ESP_LOGE(TAG, "Error getting data from memory buffers"); + return BLE_ATT_ERR_UNLIKELY; + } + ret = protocomm_req_handle(protoble_internal->pc_ble, uuid128_to_handler(uuid), conn_handle, - ctxt->om->om_data, - ctxt->om->om_len, + data_buf, + data_buf_len, &temp_outbuf, &temp_outlen); /* Release the 16 bytes allocated for uuid*/ free(uuid); + free(data_buf); if (ret == ESP_OK) { /* Save data address and length outbuf and outlen internally */ From 6875080b9bcb65e435c23017286fb1a7480b4c41 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Mon, 12 Aug 2019 20:32:14 +0800 Subject: [PATCH 44/46] mbedtls: add source files to appropriate library --- components/mbedtls/CMakeLists.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index b37269f02..a2d082304 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -19,18 +19,19 @@ set_property(TARGET mbedtls PROPERTY SOURCES ${src_tls}) set(mbedtls_targets mbedtls mbedcrypto mbedx509) # Add port files to mbedtls targets -target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/esp_bignum.c" +target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/mbedtls_debug.c" + "${COMPONENT_DIR}/port/net_sockets.c") + +target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_bignum.c" "${COMPONENT_DIR}/port/esp_hardware.c" - "${COMPONENT_PATH}/port/esp_sha.c" + "${COMPONENT_DIR}/port/esp_mem.c" + "${COMPONENT_DIR}/port/esp_sha.c" "${COMPONENT_DIR}/port/esp_sha1.c" "${COMPONENT_DIR}/port/esp_sha256.c" "${COMPONENT_DIR}/port/esp_sha512.c" "${COMPONENT_DIR}/port/esp_timing.c" - "${COMPONENT_DIR}/port/mbedtls_debug.c" - "${COMPONENT_DIR}/port/net_sockets.c" "${COMPONENT_DIR}/port/esp32/aes.c" "${COMPONENT_DIR}/port/esp32/sha.c") -target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_mem.c") foreach(target ${mbedtls_targets}) target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h") From 6b16928fbc73d8d78a0efc5e9628bb458ab808cf Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 11 Aug 2019 20:25:54 +0800 Subject: [PATCH 45/46] docs: build system internals --- docs/en/api-guides/build-system.rst | 174 ++++++++++++++++++---------- 1 file changed, 114 insertions(+), 60 deletions(-) diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst index 8a28a1e16..2eed1fa5a 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -453,68 +453,14 @@ The order of components in the ``BUILD_COMPONENTS`` variable determines other or - Order that :ref:`project_include.cmake` files are included into the project. - Order that the list of header paths is generated for compilation (via ``-I`` argument). (Note that for a given component's source files, only that component's dependency's header paths are passed to the compiler.) -Build Process Internals -======================= - -For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. - -project.cmake contents ----------------------- - -When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. - -It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. - -project function ----------------- - -The custom ``project()`` function performs the following steps: - -- Determines the target (set by ``IDF_TARGET`` environment variable) and saves the target in CMake cache. If the target set in the environment does not match the one in cache, exits with an error. -- Evaluates component dependencies and builds the ``BUILD_COMPONENTS`` list of components to include in the build (see :ref:`above`). -- Finds all components in the project (searching ``COMPONENT_DIRS`` and filtering by ``COMPONENTS`` if this is set). -- Loads the project configuration from the ``sdkconfig`` file and generates a ``sdkconfig.cmake`` file and a ``sdkconfig.h`` header. These define configuration values in CMake and C/C++, respectively. If the project configuration changes, cmake will automatically be re-run to re-generate these files and re-configure the project. -- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the correct toolchain file, depending on the target. -- Declares the actual cmake-level project by calling the `CMake project function `_. -- Loads the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_. -- Includes :ref:`project_include.cmake` files from any components which have them. -- Adds each component to the build. Each component CMakeLists file calls ``idf_component_register``, calls the CMake `add_library `_ function to add a library and then adds source files, compile options, etc. -- Adds the final app executable to the build. -- Goes back and adds inter-component dependencies between components (ie adding the public header directories of each component to each other component). - -Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. - -Debugging CMake ---------------- - -Some tips for debugging the ESP-IDF CMake-based build system: - -- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. -- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. -- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. - -When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. - -It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. - -.. _warn-undefined-variables: - -Warning On Undefined Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files. - -If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. - -Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. Overriding Parts of the Project -------------------------------- +=============================== .. _project_include.cmake: project_include.cmake -^^^^^^^^^^^^^^^^^^^^^ +--------------------- For components that have build requirements which must be evaluated before any component CMakeLists files are evaluated, you can create a file called ``project_include.cmake`` in the @@ -531,7 +477,7 @@ Note that ``project_include.cmake`` isn't necessary for the most common componen Take great care when setting variables or targets in a ``project_include.cmake`` file. As the values are included into the top-level project CMake pass, they can influence or break functionality across all components! KConfig.projbuild -^^^^^^^^^^^^^^^^^ +----------------- This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration` KConfig files. If you want to include configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file. @@ -541,11 +487,41 @@ Take care when adding configuration values in this file, as they will be include ``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". Configuration-Only Components -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +============================= Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths. + +Debugging CMake +=============== + +For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. + +Some tips for debugging the ESP-IDF CMake-based build system: + +- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. +- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. +- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. + +When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. + +It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. + +.. _warn-undefined-variables: + +Warning On Undefined Variables +------------------------------ + +By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files. + +If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. + +Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. + +.. _gnu-make-to-cmake: + + Example Component CMakeLists ============================ @@ -1225,7 +1201,86 @@ Any combination of "load", "set", and "save" can be sent in a single command and .. note:: The configuration server does not re-run CMake to regenerate other build files or metadata files after ``sdkconfig`` is updated. This will happen automatically the next time ``CMake`` or ``idf.py`` is run. -.. _gnu-make-to-cmake: +Build System Internals +======================= + +Build Scripts +------------- + +The listfiles for the ESP-IDF build system reside in :idf:`/tools/cmake`. The modules which implement core build system functionality are as follows: + + - build.cmake - Build related commands i.e. build initialization, retrieving/setting build properties, build processing. + - component.cmake - Component related commands i.e. adding components, retrieving/setting component properties, registering components. + - kconfig.cmake - Generation of configuration files (sdkconfig, sdkconfig.h, sdkconfig.cmake, etc.) from Kconfig files. + - ldgen.cmake - Generation of final linker script from linker fragment files. + - target.cmake - Setting build target and toolchain file. + - utilities.cmake - Miscellaneous helper commands. + + Aside from these files, there are two other important CMake scripts in :idf:`/tools/cmake`: + + - idf.cmake - Sets up the build and includes the core modules listed above. Included in CMake projects in order to access ESP-IDF build system functionality. + - project.cmake - Includes ``idf.cmake`` and provides a custom ``project()`` command that takes care of all the heavy lifting of building an executable. Included in the top-level CMakeLists.txt of standard ESP-IDF projects. + +The rest of the files in :idf:`/tools/cmake` are support or third-party scripts used in the build process. + +Build Process +------------- + +This section describes the standard ESP-IDF application build process. The build process can be broken down roughly into four phases: + +.. blockdiag:: + :scale: 100% + :caption: ESP-IDF Build System Process + :align: center + + blockdiag idf-build-system-process { + Initialization -> Enumeration + Enumeration -> Processing + Processing -> Finalization + } + +Initialization +^^^^^^^^^^^^^^ + This phase sets up necessary parameters for the build. + + - Upon inclusion of ``idf.cmake`` in ``project.cmake``, the following steps are performed: + - Set ``IDF_PATH`` from environment variable or inferred from path to ``project.cmake`` included in the top-level CMakeLists.txt. + - Add :idf:`/tools/cmake` to ``CMAKE_MODULE_PATH`` and include core modules plus the various helper/third-party scripts. + - Set build tools/executables such as default Python interpreter, mconf, etc. + - Get ESP-IDF git revision and store as ``IDF_VER``. + - Set global build specifications i.e. compile options, compile definitions, include directories for all components in the build. + - Add components in :idf:`components` to the build. + - The initial part of the custom ``project()`` command performs the following steps: + - Set ``IDF_TARGET`` from environment variable or CMake cache and the corresponding ``CMAKE_TOOLCHAIN_FILE`` to be used. + - Add components in ``EXTRA_COMPONENTS_DIRS`` to the build. + - Prepare arguments for calling command ``idf_build_process()`` from variables such as ``COMPONENTS``/``EXCLUDE_COMPONENTS``, ``SDKCONFIG``, ``SDKCONFIG_DEFAULTS``. + + The call to ``idf_build_process()`` command marks the end of this phase. + +Enumeration +^^^^^^^^^^^ + This phase builds a final list of components to be processed in the build, and is performed in the first half of ``idf_build_process()``. + + - Retrieve each component's public and private requirements. A child process is created which executes each component's CMakeLists.txt in script mode. The values of ``idf_component_register`` REQUIRES and PRIV_REQUIRES argument is returned to the parent build process. This is called early expansion. The variable ``CMAKE_BUILD_EARLY_EXPANSION`` is defined during this step. + - Recursively include components based on public and private requirements. + +Processing +^^^^^^^^^^ + This phase processes the components in the build, and is the second half of ``idf_build_process()``. + + - Load project configuration from sdkconfig file and generate an sdkconfig.cmake and sdkconfig.h header. These define configuration variables/macros that are accessible from the build scripts and C/C++ source/header files, respectively. + - Include each component's ``project_include.cmake``. + - Add each component as a subdirectory, processing its CMakeLists.txt. The component CMakeLists.txt calls the registration command, ``idf_component_register`` which adds source files, include directories, creates component library, links dependencies, etc. + +Finalization +^^^^^^^^^^^^ + This phase is everything after ``idf_build_process()``. + + - Create executable and link the component libraries to it. + - Generate project metadata files such as project_description.json and display relevant information about the project built. + + +Browse :idf_file:`/tools/cmake/project.cmake` for more details. Migrating from ESP-IDF GNU Make System ====================================== @@ -1269,7 +1324,6 @@ Some features are significantly different or removed in the CMake-based system. - ``COMPONENT_CONFIG_ONLY``: Call ``register_config_only_component()`` instead. See `Configuration-Only Components`_. - ``CFLAGS``, ``CPPFLAGS``, ``CXXFLAGS``: Use equivalent CMake commands instead. See `Controlling Component Compilation`_. - No Default Values ----------------- From 53e7beb95b0d4421c99b3af184fa801fb92162e4 Mon Sep 17 00:00:00 2001 From: Hrudaynath Dhabe Date: Thu, 15 Aug 2019 21:10:00 +0800 Subject: [PATCH 46/46] esp_https_ota: Added error checking functionalities. Current implimentation of esp_http_ota does not perform any error-checking in the data writing phase calls `esp_ota_get_next_update_partition()` irrespetive of the received state of the image. A few additional error checking mechanism have now been added inside the esp_https_ota which returns the control in case an invalid header is received and a wrapper to the function `esp_http_client_is_complete_data_received()` of `esp_http_client` has been added. --- .../esp_https_ota/include/esp_https_ota.h | 13 ++++++++++++ components/esp_https_ota/src/esp_https_ota.c | 20 ++++++++++++++----- .../main/advanced_https_ota_example.c | 5 +++++ .../main/native_ota_example.c | 5 +++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/components/esp_https_ota/include/esp_https_ota.h b/components/esp_https_ota/include/esp_https_ota.h index 0c8fd0693..7feba8f7e 100644 --- a/components/esp_https_ota/include/esp_https_ota.h +++ b/components/esp_https_ota/include/esp_https_ota.h @@ -110,6 +110,19 @@ esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_ */ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle); +/** + * @brief Checks if complete data was received or not + * + * @note This API can be called just before esp_https_ota_finish() to validate if the complete image was indeed received. + * + * @param[in] https_ota_handle pointer to esp_https_ota_handle_t structure + * + * @return + * - false + * - true + */ +bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle); + /** * @brief Clean-up HTTPS OTA Firmware upgrade and close HTTPS connection * diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c index baba0bbaa..d2ca50103 100644 --- a/components/esp_https_ota/src/esp_https_ota.c +++ b/components/esp_https_ota/src/esp_https_ota.c @@ -85,17 +85,21 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client static esp_err_t _http_connect(esp_http_client_handle_t http_client) { esp_err_t err = ESP_FAIL; - int status_code; + int status_code, header_ret; do { err = esp_http_client_open(http_client, 0); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); return err; } - esp_http_client_fetch_headers(http_client); + header_ret = esp_http_client_fetch_headers(http_client); + if (header_ret < 0) { + return header_ret; + } status_code = esp_http_client_get_status_code(http_client); - if (_http_handle_response_code(http_client, status_code) != ESP_OK) { - return ESP_FAIL; + err = _http_handle_response_code(http_client, status_code); + if (err != ESP_OK) { + return err; } } while (process_again(status_code)); return err; @@ -276,6 +280,12 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle) return ESP_OK; } +bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle) +{ + esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle; + return esp_http_client_is_complete_data_received(handle->http_client); +} + esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle) { esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle; @@ -361,4 +371,4 @@ esp_err_t esp_https_ota(const esp_http_client_config_t *config) return ota_finish_err; } return ESP_OK; -} \ No newline at end of file +} diff --git a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c index 0387e3e68..aafa48888 100644 --- a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c +++ b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c @@ -88,6 +88,11 @@ void advanced_ota_example_task(void *pvParameter) ESP_LOGD(TAG, "Image bytes read: %d", esp_https_ota_get_image_len_read(https_ota_handle)); } + if (esp_https_ota_is_complete_data_received(&https_ota_handle) != true) { + // the OTA image was not completely received and user can customise the response to this situation. + ESP_LOGE(TAG, "Complete data was not received."); + } + ota_end: ota_finish_err = esp_https_ota_finish(https_ota_handle); if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) { diff --git a/examples/system/ota/native_ota_example/main/native_ota_example.c b/examples/system/ota/native_ota_example/main/native_ota_example.c index fc42b7f3b..9d84cc07c 100644 --- a/examples/system/ota/native_ota_example/main/native_ota_example.c +++ b/examples/system/ota/native_ota_example/main/native_ota_example.c @@ -182,6 +182,11 @@ static void ota_example_task(void *pvParameter) } } ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length); + if (esp_http_client_is_complete_data_received(client) != true) { + ESP_LOGE(TAG, "Error in receiving complete file"); + http_cleanup(client); + task_fatal_error(); + } if (esp_ota_end(update_handle) != ESP_OK) { ESP_LOGE(TAG, "esp_ota_end failed!");