diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 225b48f948..96006f8c8c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,11 +4,25 @@ stages: - deploy before_script: + # add gitlab ssh key + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GITLAB_KEY >> ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + + # if testing master branch, use github wifi libs. + # if testing other branches, use gitlab wifi libs (as maybe changes aren't merged to master yet) + - test "${CI_BUILD_REF_NAME}" = "master" || sed -i "s%https://github.com/espressif/esp32-wifi-lib%ssh://git@gitlab.espressif.cn:27227/idf/esp32-wifi-lib%" .gitmodules + # fetch all submodules - git submodule update --init --recursive build_template_app: stage: build image: espressif/esp32-ci-env + tags: + - build variables: SDK_PATH: "$CI_PROJECT_DIR" @@ -18,12 +32,47 @@ build_template_app: script: - git clone https://github.com/espressif/esp-idf-template.git - cd esp-idf-template + # Try to use the same branch name for esp-idf-template that we're + # using on esp-idf. If it doesn't exist then just stick to the default + # branch + - git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..." - make defconfig - make all + +.build_gitlab: &build_template + stage: build + tags: + - build + image: espressif/esp32-ci-env + + variables: + SDK_PATH: "$CI_PROJECT_DIR" + IDF_PATH: "$CI_PROJECT_DIR" + GIT_STRATEGY: clone + +build_ssc: + <<: *build_template + artifacts: + paths: + - ./SSC/build/*.bin + - ./SSC/build/*.elf + - ./SSC/build/*.map + - ./SSC/build/bootloader/*.bin + expire_in: 6 mos + + script: + - git clone ssh://git@gitlab.espressif.cn:27227/yinling/SSC.git + - cd SSC + - make defconfig + - chmod +x gen_misc_ng.sh + - ./gen_misc_ng.sh + test_nvs_on_host: stage: test image: espressif/esp32-ci-env + tags: + - nvs_host_test script: - cd components/nvs_flash/test - make test @@ -31,15 +80,58 @@ test_nvs_on_host: test_build_system: stage: test image: espressif/esp32-ci-env + tags: + - build_test variables: IDF_PATH: "$CI_PROJECT_DIR" script: - ./make/test_build_system.sh + + +# template for test jobs +.test_template: &test_template + stage: test + when: on_success + only: + - master + + variables: + # need user to set SDK_NAME and CONFIG_FILE (may need to set BIN_PATH and APP_NAME later) in before_script + SCRIPT_PATH: /home/gitlab-runner/auto_test_script + BIN_PATH: ${CI_PROJECT_DIR}/SSC/build/ + APP_NAME: ssc + LOG_PATH: $CI_PROJECT_DIR/$CI_BUILD_REF + + artifacts: + when: always + paths: + - $LOG_PATH + expire_in: 6 mos + + script: + - cd $SCRIPT_PATH + - python CIRunner.py -l $LOG_PATH -c $SDK_NAME/$CONFIG_FILE bin_path $APP_NAME $BIN_PATH + +sanity_test: + <<: *test_template + tags: + - ESP32 + - SSC_T1_1 + - SSC_T2_1 + - SSC_T1_WAN + before_script: + - SDK_NAME=ESP32_IDF + - CONFIG_FILE=sanity_test.yml + + + push_master_to_github: stage: deploy only: - master + tags: + - deploy when: on_success image: espressif/esp32-ci-env variables: diff --git a/.gitmodules b/.gitmodules index bd27e209be..1a0e6b94f1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "components/esp32/lib"] path = components/esp32/lib url = https://github.com/espressif/esp32-wifi-lib.git +[submodule "components/esptool_py/esptool"] + path = components/esptool_py/esptool + url = https://github.com/themadinventor/esptool.git diff --git a/README.buildenv b/README.buildenv deleted file mode 100644 index fd68300055..0000000000 --- a/README.buildenv +++ /dev/null @@ -1,265 +0,0 @@ -The build structure of the Espressif IoT Development Framework explained. - -An ESP-IDF project can be seen as an almagation of a number of components. -For example, for a webserver that shows the current humidity, we would -have: -- The ESP32 base libraries (libc, rom bindings etc) -- The WiFi drivers -- A TCP/IP stack -- The FreeRTOS operating system -- A webserver -- A driver for an humidity sensor -- Main code tying it all together - -ESP-IDF makes these components explicit and configurable. To do that, when a project -is compiled, the build environment will look up all the components in the -ESP-IDF directories, the project directories and optionally custom other component -directories. It then allows the user to configure compile-time options using -a friendly text-based menu system to customize the ESP-IDF as well as other components -to the requirements of the project. After the components are customized, the -build process will compile everything into an output file, which can then be uploaded -into a board in a way that can also be defined by components. - -A project in this sense is defined as a directory under which all the files required -to build it live, excluding the ESP-IDF files and the toolchain. A simple project -tree looks like this: - -- myProject/ - build/ - - components/ - component1/ - Makefile - - Kconfig - - src1.c - - component2/ - Makefile - - Kconfig - - src1.c - - main/ - src1.c - - src2.c - - Makefile - - -As we can see, a project consists of a components/ subdirectory containing its -components as well as one or more directories containing the project-specific -sources; by default a single directory called 'main' is assumed. The project -directory will also have a Makefile where the projects name as well as optionally -other options are defined. After compilation, the project directory will contain -a 'build'-directory containing all of the objects, libraries and other generated -files as well as the final binary. - -Components also have a Makefile containing various definititions influencing -the build process of the component as well as the project it's used in, as -well as a Kconfig file defining the compile-time options that are settable -by means of the menu system. - - -Project makefile variables that can be set by the programmer: -PROJECT_NAME: Mandatory. Name for the project -BUILD_DIR_BASE: Set the directory where all objects/libraries/binaries end up in. - Defaults to $(PROJECT_PATH)/build -COMPONENT_DIRS: Search path for components. Defaults to the component/ directories - in the ESP-IDF path and the project path. -COMPONENTS: A list of component names. Defaults to all the component found in the - COMPONENT_DIRS directory -EXTRA_COMPONENT_DIRS: Defaults to unset. Use this to add directories to the default - COMPONENT_DIRS. -SRCDIRS: Directories under the project dir containing project-specific sources. - Defaults to 'main'. These are treated as 'lite' components: they do not have - include directories that are passed to the compilation pass of all components and - they do not have a Kconfig option. - - -Component makefile variables that can be set by the programmer: -COMPONENT_ADD_INCLUDEDIRS: Relative path to include directories to be added to - the entire project -COMPONENT_PRIV_INCLUDEDIRS: Relative path to include directories that are only used - when compiling this specific component -COMPONENT_DEPENDS: Names of any components that need to be compiled before this component. -COMPONENT_ADD_LDFLAGS: Ld flags to add for this project. Defaults to -l$(COMPONENT_NAME). - Add libraries etc in the current directory as $(abspath libwhatever.a) -COMPONENT_EXTRA_INCLUDES: Any extra include paths. These will be prefixed with '-I' and - passed to the compiler; please put absolute paths here. -COMPONENT_SRCDIRS: Relative directories to look in for sources. Defaults to '.', the current - directory (the root of the component) only. Use this to specify any subdirectories. Note - that specifying this overwrites the default action of compiling everything in the - components root dir; to keep this behaviour please also add '.' as a directory in this - list. -COMPONENT_OBJS: Object files to compile. Defaults to the .o variants of all .c and .S files - that are found in COMPONENT_SRCDIRS. -COMPONENT_EXTRA_CLEAN: Files that are generated using rules in the components Makefile - that also need to be cleaned -COMPONENT_BUILDRECIPE: Recipe to build the component. Optional. Defaults to building all - COMPONENT_OBJS and linking them into lib(componentname).a -COMPONENT_CLEANRECIPE: Recipe to clean the component. Optional. Defaults to removing - all built objects and libraries. -COMPONENT_BUILD_DIR: Equals the cwd of the component build, which is the build dir - of the component (where all the .o etc files should be created). - - -These variables are already set early on in the Makefile and the values in it will -be usable in component or project Makefiles: -CC, LD, AR, OBJCOPY: Xtensa gcc tools -HOSTCC, HOSTLD etc: Host gcc tools -LDFLAGS, CFLAGS: Set to usable values as defined in ESP-IDF Makefile -PROJECT_NAME: Name of the project, as set in project makefile -PROJECT_PATH: Path to the root of the project folder -COMPONENTS: Name of the components to be included -CONFIG_*: Values set by 'make menuconfig' also have corresponding Makefile variables. - -For components, there also are these defines: -COMPONENT_PATH: Absolute path to the root of the source tree of the component we're - compiling -COMPONENT_LIBRARY: The full path to the static library the components compilation pass - is supposed to generate - - -How this works: -The Make process is always invoked from the project directory by the -user; invoking it anywhere else gives an error. This is what happens if -we build a binary: - -The Makefile first determines how it was included. It determines it was -included as a project file in this case and will continue to figure out -various paths as well as the components available to it. It will also -collect the ldflags and includes that the components specify they need. -It does this by running a dummy Make on the components with a target that -will output these values. - -The Makefile will then create targets to build the lib*.a libraries of -all components and make the elf target depend on this. The targets -invoke Make on the makefiles of the components in a subshell: this way -the components have full freedom to do whatever is necessary to build -the library without influencing other components. By default, the -component includes the utility makefile $(IDF_PATH)/make/component.mk. -This provides default targets and configurations that will work -out-of-the-box for most projects. - -For components that have parts that need to be run when building of the -project is done, you can create a file called Makefile.projbuild in the -component root directory. This file will be included in the main -Makefile. For the menu, there's an equivalent: if you want to include -options not in the 'components' submenu, create a Kconfig.projbuild and -it will be included in the main menu of menuconfig. Take good care when -(re)defining stuff here: because it's included with all the other -.projbuild files, it's possible to overwrite variables or re-declare -targets defined in the ESP-IDF makefile/Kconfig and other .projbuild files - - -WRITING COMPONENT MAKEFILES - -A component consists of a directory which doubles as the name for the -component: a component named 'httpd' lives in a directory called 'httpd' -Because components usually live under the project directory (although -they can also reside in an other folder), the path to this may be -something like /home/myuser/projects/myprojects/components/httpd . - -One of the things that most components will have is a Makefile, -containing instructions on how to build the component. Because the -build environment tries to set reasonable defaults that will work most -of the time, a component Makefile can be pretty small. At the absolute -minimum, it will just include the ESP-IDF component makefile, which adds -component functionality: - -----8<---- -include $(IDF_PATH)/make/component.mk ----->8---- - -This will take all the .c and .S files in the component root and compile -them into object files, finally linking them into a library. -Subdirectories are ignored; if your project has sources in subdirectories -instead of in the root of the component, you can tell that to the build -system by setting COMPONENT_SRCDIRS: - -----8<---- -COMPONENT_SRCDIRS := src1 src2 -include $(IDF_PATH)/make/component.mk ----->8---- - -This will compile all source files in the src1/ and src2/ subdirectories -instead. - -The standard component.mk logic adds all .S and .c files in the source -directories as sources to be compiled unconditionally. It is possible -to circumvent that logic and hardcode the objects to be compiled by -manually setting the COMPONENT_OBJS variable to the name of the -objects that need to be generated: - -----8<---- -COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o -include $(IDF_PATH)/make/component.mk ----->8---- - -This can also be used in order to conditionally compile some files -dependent on the options selected in the Makefile: - -Kconfig: -----8<---- -config FOO_ENABLE_BAR - bool "Enable the BAR feature." - help - This enables the BAR feature of the FOO component. ----->8---- - -Makefile: -----8<---- -COMPONENT_OBJS := foo_a.o foo_b.o $(if $(CONFIG_FOO_ENABLE_BAR),foo_bar.o foo_bar_interface.o) -include $(IDF_PATH)/make/component.mk ----->8---- - -Some components will have a situation where a source file isn't supplied -with the component itself but has to be generated from another file. Say -our component has a header file that consists of the converted binary -data of a BMP file, converted using a hypothetical tool called bmp2h. The -header file is then included in as C source file called graphics_lib.c. - -----8<---- -COMPONENT_EXTRA_CLEAN := logo.h - -graphics_lib.o: logo.h - -logo.h: $(COMPONENT_PATH)/logo.bmp - bmp2h -i $^ -o $@ - -include $(IDF_PATH)/make/component.mk ----->8---- - -In this example, graphics_lib.o and logo.h will be generated in the -current directory (the build directory) while logo.bmp comes with the -component and resides under the component path. Because logo.h is a -generated file, it needs to be cleaned when make clean is called which -why it is added to the COMPONENT_EXTRA_CLEAN variable. - - -This will work just fine, but there's one last cosmetic improvement that -can be done. The make system tries to make the make process somewhat -easier on the eyes by hiding the commands (unless you run make with the -V=1 switch) and this does not do that yet. Here's an improved version -that will output in the same style as the rest of the make process: - -----8<---- -COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h - -graphics_lib.o: logo.h - -logo.h: $(COMPONENT_PATH)/logo.bmp - $(summary) BMP2H $@ - $(Q) bmp2h -i $^ -o $@ - -include $(IDF_PATH)/make/component.mk ----->8---- - -Obviously, there are cases where all these recipes are insufficient for a -certain component, for example when the component is basically a wrapper -around another third-party component not originally intended to be -compiled under this build system. In that case, it's possible to forego -the build system entirely by setting COMPONENT_OWNBUILDTARGET and -possibly COMPONENT_OWNCLEANTARGET and defining your own build- and clean -target. The build target can do anything as long as it creates -$(COMPONENT_LIBRARY) for the main file to link into the project binary, -and even that is not necessary: if the COMPONENT_ADD_LDFLAGS variable -is set, the component can instruct the linker to do anything else as well. - - - - - - - - diff --git a/README.md b/README.md index 0c7d437e2d..10fd72a3c3 100644 --- a/README.md +++ b/README.md @@ -49,3 +49,11 @@ The simplest way to use the partition table is to `make menuconfig` and choose o In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table. For more details about partition tables and how to create custom variations, view the `docs/partition_tables.rst` file. + +# Resources + +* The [docs directory of the esp-idf repository](https://github.com/espressif/esp-idf/tree/master/docs) contains esp-idf documentation. + +* The [esp32.com forum](http://esp32.com/) is a place to ask questions and find community resources. + +* [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one. diff --git a/add_path.sh b/add_path.sh new file mode 100644 index 0000000000..6b69f8d44f --- /dev/null +++ b/add_path.sh @@ -0,0 +1,17 @@ +# This shell snippet appends useful esp-idf tools to your PATH environment +# variable. This means you can run esp-idf tools without needing to give the +# full path. +# +# Use this script like this: +# +# . ${IDF_PATH}/add_path.sh +# +if [ -z ${IDF_PATH} ]; then + echo "IDF_PATH must be set before including this script." +else + IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool:${IDF_PATH}/components/partition_table/" + export PATH="${PATH}:${IDF_ADD_PATHS_EXTRAS}" + echo "Added to PATH: ${IDF_ADD_PATHS_EXTRAS}" +fi + + diff --git a/bin/esptool.py b/bin/esptool.py deleted file mode 100755 index 284d9e95dd..0000000000 --- a/bin/esptool.py +++ /dev/null @@ -1,1810 +0,0 @@ -#!/usr/bin/env python -# NB: Before sending a PR to change the above line to '#!/usr/bin/env python2', please read https://github.com/themadinventor/esptool/issues/21 -# -# ESP8266 ROM Bootloader Utility -# https://github.com/themadinventor/esptool -# -# Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton, other contributors as noted. -# ESP31/32 support Copyright (C) 2016 Angus Gratton, based in part on work Copyright -# (C) 2015-2016 Espressif Systems. -# -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin -# Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import argparse -import hashlib -import inspect -import json -import os -import serial -import struct -import subprocess -import sys -import time -import zlib - -__version__ = "2.0-dev" - - -MAX_UINT32 = 0xffffffff -MAX_UINT24 = 0xffffff - - -class ESPROM(object): - """ Base class providing access to ESP ROM bootloader. Subclasses provide - ESP8266, ESP31 & ESP32 specific functionality. - - Don't instantiate this base class directly, either instantiate a subclass or - call ESPROM.detect_chip() which will interrogate the chip and return the - appropriate subclass instance. - - """ - CHIP_NAME = "Espressif device" - - DEFAULT_PORT = "/dev/ttyUSB0" - - # These are the currently known commands supported by the ROM - ESP_FLASH_BEGIN = 0x02 - ESP_FLASH_DATA = 0x03 - ESP_FLASH_END = 0x04 - ESP_MEM_BEGIN = 0x05 - ESP_MEM_END = 0x06 - ESP_MEM_DATA = 0x07 - ESP_SYNC = 0x08 - ESP_WRITE_REG = 0x09 - ESP_READ_REG = 0x0a - - # Maximum block sized for RAM and Flash writes, respectively. - ESP_RAM_BLOCK = 0x1800 - ESP_FLASH_BLOCK = 0x400 - - # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want. - ESP_ROM_BAUD = 115200 - - # First byte of the application image - ESP_IMAGE_MAGIC = 0xe9 - - # Initial state for the checksum routine - ESP_CHECKSUM_MAGIC = 0xef - - # Flash sector size, minimum unit of erase. - ESP_FLASH_SECTOR = 0x1000 - - UART_DATA_REG_ADDR = 0x60000078 - - # SPI peripheral "command" bitmasks - SPI_CMD_READ_ID = 0x10000000 - - # Memory addresses - IROM_MAP_START = 0x40200000 - IROM_MAP_END = 0x40300000 - - # The number of bytes in the response that signify command status - STATUS_BYTES_LENGTH = 2 - - def __init__(self, port=DEFAULT_PORT, baud=ESP_ROM_BAUD, do_connect=True): - """Base constructor for ESPROM objects - - Don't call this constructor, either instantiate ESP8266ROM, - ESP31ROM, or ESP32ROM, or use ESPROM.detect_chip(). - - """ - self._port = serial.Serial(port) - self._slip_reader = slip_reader(self._port) - # setting baud rate in a separate step is a workaround for - # CH341 driver on some Linux versions (this opens at 9600 then - # sets), shouldn't matter for other platforms/drivers. See - # https://github.com/themadinventor/esptool/issues/44#issuecomment-107094446 - self._port.baudrate = baud - if do_connect: - self.connect() - - @staticmethod - def detect_chip(port=DEFAULT_PORT, baud=ESP_ROM_BAUD): - """Use serial access to detect the chip type. - - We use the UART's datecode register for this, it's mapped at - the same address on ESP8266 & ESP31/32 so we can use one - memory read and compare to the datecode register for each chip - type. - - """ - detect_port = ESPROM(port, baud, True) - sys.stdout.write('Detecting chip type... ') - date_reg = detect_port.read_reg(ESPROM.UART_DATA_REG_ADDR) - for cls in [ESP8266ROM, ESP31ROM, ESP32ROM]: - if date_reg == cls.DATE_REG_VALUE: - inst = cls(port, baud, False) # don't connect a second time - print '%s' % inst.CHIP_NAME - return inst - print '' - raise FatalError("Unexpected UART datecode value 0x%08x. Failed to autodetect chip type." % date_reg) - - """ Read a SLIP packet from the serial port """ - def read(self): - return self._slip_reader.next() - - """ Write bytes to the serial port while performing SLIP escaping """ - def write(self, packet): - buf = '\xc0' \ - + (packet.replace('\xdb','\xdb\xdd').replace('\xc0','\xdb\xdc')) \ - + '\xc0' - self._port.write(buf) - - """ Calculate checksum of a blob, as it is defined by the ROM """ - @staticmethod - def checksum(data, state=ESP_CHECKSUM_MAGIC): - for b in data: - state ^= ord(b) - return state - - """ Send a request and read the response """ - def command(self, op=None, data=None, chk=0): - if op is not None: - pkt = struct.pack(' self.STATUS_BYTES_LENGTH: - return data[:-self.STATUS_BYTES_LENGTH] - else: # otherwise, just return the 'val' field which comes from the reply header (this is used by read_reg) - return val - - def flush_input(self): - self._port.flushInput() - self._slip_reader = slip_reader(self._port) - - def sync(self): - """ Perform a connection test """ - self.command(ESPROM.ESP_SYNC, '\x07\x07\x12\x20' + 32 * '\x55') - for i in xrange(7): - self.command() - - def connect(self): - """ Try connecting repeatedly until successful, or giving up """ - print 'Connecting...' - - for _ in xrange(4): - # issue reset-to-bootloader: - # RTS = either CH_PD or nRESET (both active low = chip in reset) - # DTR = GPIO0 (active low = boot to flasher) - self._port.setDTR(False) - self._port.setRTS(True) - time.sleep(0.05) - self._port.setDTR(True) - self._port.setRTS(False) - time.sleep(0.05) - self._port.setDTR(False) - - # worst-case latency timer should be 255ms (probably <20ms) - self._port.timeout = 0.3 - last_exception = None - for _ in xrange(4): - try: - self.flush_input() - self._port.flushOutput() - self.sync() - self._port.timeout = 5 - return - except FatalError as e: - last_exception = e - time.sleep(0.05) - raise FatalError('Failed to connect to %s: %s' % (self.CHIP_NAME, last_exception)) - - """ Read memory address in target """ - def read_reg(self, addr): - # we don't call check_command here because read_reg() function is called - # when detecting chip type, and the way we check for success (STATUS_BYTES_LENGTH) is different - # for different chip types (!) - val, data = self.command(ESPROM.ESP_READ_REG, struct.pack('> 24) | ((id1 & MAX_UINT24) << 8) - - def read_mac(self): - """ Read MAC from OTP ROM """ - mac0 = self.read_reg(self.ESP_OTP_MAC0) - mac1 = self.read_reg(self.ESP_OTP_MAC1) - mac3 = self.read_reg(self.ESP_OTP_MAC3) - if (mac3 != 0): - oui = ((mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff) - elif ((mac1 >> 16) & 0xff) == 0: - oui = (0x18, 0xfe, 0x34) - elif ((mac1 >> 16) & 0xff) == 1: - oui = (0xac, 0xd0, 0x74) - else: - raise FatalError("Unknown OUI") - return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) - - def get_erase_size(self, size): - """ Calculate an erase size given a specific size in bytes. - - Provides a workaround for the bootloader erase bug.""" - - sectors_per_block = 16 - sector_size = self.ESP_FLASH_SECTOR - num_sectors = (size + sector_size - 1) / sector_size - start_sector = offset / sector_size - - head_sectors = sectors_per_block - (start_sector % sectors_per_block) - if num_sectors < head_sectors: - head_sectors = num_sectors - - if num_sectors < 2 * head_sectors: - return (num_sectors + 1) / 2 * sector_size - else: - return (num_sectors - head_sectors) * sector_size - -class ESP31ROM(ESPROM): - """ Access class for ESP31 ROM bootloader - """ - CHIP_NAME = "ESP31" - - DATE_REG_VALUE = 0x15052100 - - SPI_CMD_REG_ADDR = 0x60003000 - SPI_W0_REG_ADDR = 0x60003040 - - EFUSE_BASE = 0x6001a000 - - FLASH_SIZES = { - '1MB':0x00, - '2MB':0x10, - '4MB':0x20, - '8MB':0x30, - '16MB':0x40 - } - - def read_efuse(self, n): - """ Read the nth word of the ESP3x EFUSE region. """ - return self.read_reg(self.EFUSE_BASE + (4 * n)) - - def chip_id(self): - word16 = self.read_efuse(16) - word17 = self.read_efuse(17) - return ((word17 & MAX_UINT24) << 24) | (word16 >> 8) & MAX_UINT24 - - def read_mac(self): - """ Read MAC from EFUSE region """ - word16 = self.read_efuse(16) - word17 = self.read_efuse(17) - word18 = self.read_efuse(18) - word19 = self.read_efuse(19) - wifi_mac = (((word17 >> 16) & 0xff), ((word17 >> 8) & 0xff), ((word17 >> 0) & 0xff), - ((word16 >> 24) & 0xff), ((word16 >> 16) & 0xff), ((word16 >> 8) & 0xff)) - bt_mac = (((word19 >> 16) & 0xff), ((word19 >> 8) & 0xff), ((word19 >> 0) & 0xff), - ((word18 >> 24) & 0xff), ((word18 >> 16) & 0xff), ((word18 >> 8) & 0xff)) - return (wifi_mac,bt_mac) - - def get_erase_size(self, size): - return size - -class ESP32ROM(ESP31ROM): - """Access class for ESP32 ROM bootloader - - """ - CHIP_NAME = "ESP32" - - DATE_REG_VALUE = 0x15122500 - - # ESP32-only commands - ESP_SPI_FLASH_SET = 0xb - - ESP_SPI_ATTACH_REQ = 0xD - - ESP_CHANGE_BAUDRATE = 0x0F - ESP_FLASH_DEFL_BEGIN = 0x10 - ESP_FLASH_DEFL_DATA = 0x11 - ESP_FLASH_DEFL_END = 0x12 - - ESP_SPI_FLASH_MD5 = 0x13 - - IROM_MAP_START = 0x400d0000 - IROM_MAP_END = 0x40400000 - DROM_MAP_START = 0x3F400000 - DROM_MAP_END = 0x3F700000 - - # ESP32 uses a 4 byte status reply - STATUS_BYTES_LENGTH = 4 - - def flash_defl_begin(self, size, compsize, offset): - """ Start downloading compressed data to Flash (performs an erase) """ - old_tmo = self._port.timeout - num_blocks = (compsize + self.ESP_FLASH_BLOCK - 1) / self.ESP_FLASH_BLOCK - erase_blocks = (size + self.ESP_FLASH_BLOCK - 1) / self.ESP_FLASH_BLOCK - - erase_size = size - if erase_size > 0 and (offset + erase_size) >= (16 / 8) * 1024 * 1024: - self.flash_spi_param_set() - - self._port.timeout = 20 - t = time.time() - print "Unc size %d comp size %d comp blocks %d" % (size, compsize, num_blocks) - self.check_command("enter compressed flash mode", self.ESP_FLASH_DEFL_BEGIN, - struct.pack(' 16: - raise FatalError('Invalid firmware image magic=%d segments=%d' % (magic, segments)) - return segments - - def load_segment(self, f, is_irom_segment=False): - """ Load the next segment from the image file """ - file_offs = f.tell() - (offset, size) = struct.unpack(' 0x40200000 or offset < 0x3ffe0000 or size > 65536: - print('WARNING: Suspicious segment 0x%x, length %d' % (offset, size)) - segment_data = f.read(size) - if len(segment_data) < size: - raise FatalError('End of file reading segment 0x%x, length %d (actual length %d)' % (offset, size, len(segment_data))) - segment = ImageSegment(offset, segment_data, file_offs) - self.segments.append(segment) - return segment - - def save_segment(self, f, segment, checksum=None): - """ Save the next segment to the image file, return next checksum value if provided """ - f.write(struct.pack(' 0: - if len(irom_segments) != 1: - raise FatalError('Found %d segments that could be irom0. Bad ELF file?' % len(irom_segments)) - return irom_segments[0] - return None - - def get_non_irom_segments(self): - irom_segment = self.get_irom_segment() - return [s for s in self.segments if s != irom_segment] - - -class ESPFirmwareImage(BaseFirmwareImage): - """ 'Version 1' firmware image, segments loaded directly by the ROM bootloader. """ - def __init__(self, load_file=None): - super(ESPFirmwareImage, self).__init__() - self.flash_mode = 0 - self.flash_size_freq = 0 - self.version = 1 - - if load_file is not None: - segments = self.load_common_header(load_file, ESPROM.ESP_IMAGE_MAGIC) - - for _ in xrange(segments): - self.load_segment(load_file) - self.checksum = self.read_checksum(load_file) - - def default_output_name(self, input_file): - """ Derive a default output name from the ELF name. """ - return input_file + '-' - - def save(self, basename): - """ Save a set of V1 images for flashing. Parameter is a base filename. """ - # IROM data goes in its own plain binary file - irom_segment = self.get_irom_segment() - if irom_segment is not None: - with open("%s0x%05x.bin" % (basename, irom_segment.addr), "wb") as f: - f.write(irom_segment.data) - - # everything but IROM goes at 0x00000 in an image file - normal_segments = self.get_non_irom_segments() - with open("%s0x00000.bin" % basename, 'wb') as f: - self.write_common_header(f, normal_segments) - checksum = ESPROM.ESP_CHECKSUM_MAGIC - for segment in self.segments: - checksum = self.save_segment(f, segment, checksum) - self.append_checksum(f, checksum) - - -class OTAFirmwareImage(BaseFirmwareImage): - """ 'Version 2' firmware image, segments loaded by software bootloader stub - (ie Espressif bootloader or rboot) - """ - def __init__(self, load_file=None): - super(OTAFirmwareImage, self).__init__() - self.version = 2 - if load_file is not None: - segments = self.load_common_header(load_file, ESPBOOTLOADER.IMAGE_V2_MAGIC) - if segments != ESPBOOTLOADER.IMAGE_V2_SEGMENT: - # segment count is not really segment count here, but we expect to see '4' - print 'Warning: V2 header has unexpected "segment" count %d (usually 4)' % segments - - # irom segment comes before the second header - # - # the file is saved in the image with a zero load address - # in the header, so we need to calculate a load address - irom_offs = load_file.tell() - irom_segment = self.load_segment(load_file, True) - irom_segment.addr = irom_offs + ESPROM.IROM_MAP_START - - first_flash_mode = self.flash_mode - first_flash_size_freq = self.flash_size_freq - first_entrypoint = self.entrypoint - # load the second header - self.load_common_header(load_file, ESPROM.ESP_IMAGE_MAGIC) - (magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack(' 0: - #print("Calculated pad length %08x to place next header @ %08x" % (pad_len, f.tell()+pad_len)) - null = ImageSegment(0, '\x00' * pad_len, f.tell()) - checksum = self.save_segment(f, null, checksum) - #print("After padding, at file offset %08x" % f.tell()) - padding_segments += 1 - #print "Comparing file offs %x (data @ %x) with segment load addr %x" % (f.tell(), f.tell() + 8, segment.addr) - # verify that after the 8 byte header is added, were are at the correct offset relative to the segment's vaddr - assert (f.tell() + 8) % IROM_ALIGN == segment.addr % IROM_ALIGN - checksum = self.save_segment(f, segment, checksum) - self.append_checksum(f, checksum) - # kinda hacky: go back to the initial header and write the new segment count - # that includes padding segments. Luckily(?) this header is not checksummed - f.seek(1) - f.write(chr(len(self.segments) + padding_segments)) - - -class ELFFile(object): - SEC_TYPE_PROGBITS = 0x01 - SEC_TYPE_STRTAB = 0x03 - - def __init__(self, name): - # Load sections from the ELF file - self.name = name - with open(self.name, 'rb') as f: - self._read_elf_file(f) - - def _read_elf_file(self, f): - # read the ELF file header - LEN_FILE_HEADER = 0x34 - try: - (ident,_type,machine,_version, - self.entrypoint,_phoff,shoff,_flags, - _ehsize, _phentsize,_phnum,_shentsize, - _shnum,shstrndx) = struct.unpack("<16sHHLLLLLHHHHHH", f.read(LEN_FILE_HEADER)) - except struct.error as e: - raise FatalError("Failed to read a valid ELF header from %s: %s" % (self.name, e)) - - if ident[0] != '\x7f' or ident[1:4] != 'ELF': - raise FatalError("%s has invalid ELF magic header" % self.name) - if machine != 0x5e: - raise FatalError("%s does not appear to be an Xtensa ELF file. e_machine=%04x" % (self.name, machine)) - self._read_sections(f, shoff, shstrndx) - - def _read_sections(self, f, section_header_offs, shstrndx): - f.seek(section_header_offs) - section_header = f.read() - LEN_SEC_HEADER = 0x28 - if len(section_header) == 0: - raise FatalError("No section header found at offset %04x in ELF file." % section_header_offs) - if len(section_header) % LEN_SEC_HEADER != 0: - print 'WARNING: Unexpected ELF section header length %04x is not mod-%02x' % (len(section_header),LEN_SEC_HEADER) - - # walk through the section header and extract all sections - section_header_offsets = range(0, len(section_header), LEN_SEC_HEADER) - - def read_section_header(offs): - name_offs,sec_type,_flags,lma,sec_offs,size = struct.unpack_from(" 0: - esp._port.baudrate = baud_rate - # Read the greeting. - p = esp.read() - if p != 'OHAI': - raise FatalError('Failed to connect to the flasher (got %s)' % hexify(p)) - - def flash_write(self, addr, data, show_progress=False): - assert addr % self._esp.ESP_FLASH_SECTOR == 0, 'Address must be sector-aligned' - assert len(data) % self._esp.ESP_FLASH_SECTOR == 0, 'Length must be sector-aligned' - sys.stdout.write('Writing %d @ 0x%x... ' % (len(data), addr)) - sys.stdout.flush() - self._esp.write(struct.pack(' length: - raise FatalError('Read more than expected') - p = self._esp.read() - if len(p) != 16: - raise FatalError('Expected digest, got: %s' % hexify(p)) - expected_digest = hexify(p).upper() - digest = hashlib.md5(data).hexdigest().upper() - print - if digest != expected_digest: - raise FatalError('Digest mismatch: expected %s, got %s' % (expected_digest, digest)) - p = self._esp.read() - if len(p) != 1: - raise FatalError('Expected status, got: %s' % hexify(p)) - status_code = struct.unpack(', ) or a single -# argument. - -def load_ram(esp, args): - image = LoadFirmwareImage(esp, args.filename) - - print 'RAM boot...' - for (offset, size, data) in image.segments: - print 'Downloading %d bytes at %08x...' % (size, offset), - sys.stdout.flush() - esp.mem_begin(size, div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, offset) - - seq = 0 - while len(data) > 0: - esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq) - data = data[esp.ESP_RAM_BLOCK:] - seq += 1 - print 'done!' - - print 'All segments done, executing at %08x' % image.entrypoint - esp.mem_finish(image.entrypoint) - - -def read_mem(esp, args): - print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address)) - - -def write_mem(esp, args): - esp.write_reg(args.address, args.value, args.mask, 0) - print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address) - - -def dump_mem(esp, args): - f = file(args.filename, 'wb') - for i in xrange(args.size / 4): - d = esp.read_reg(args.address + (i * 4)) - f.write(struct.pack(' 0: - print '\rWriting at 0x%08x... (%d %%)' % (address + seq * esp.ESP_FLASH_BLOCK, 100 * (seq + 1) / blocks), - sys.stdout.flush() - block = image[0:esp.ESP_FLASH_BLOCK] - if args.compress: - esp.flash_defl_block(block, seq) - else: - # Pad the last block - block = block + '\xff' * (esp.ESP_FLASH_BLOCK - len(block)) - # Fix sflash config data - if address == 0 and seq == 0 and block[0] == '\xe9': - block = block[0:2] + flash_info + block[4:] - header_block = block - esp.flash_block(block, seq) - image = image[esp.ESP_FLASH_BLOCK:] - seq += 1 - written += len(block) - t = time.time() - t - print '\rWrote %d bytes at 0x%08x in %.1f seconds (%.1f kbit/s)...' % (written, address, t, written / t * 8 / 1000) - res = esp.flash_md5sum(address, uncsize) - if res != calcmd5: - print 'File md5: %s' % calcmd5 - print 'Flash md5: %s' % res - raise FatalError("MD5 of file does not match data in flash!") - else: - print 'Hash of data verified.' - print '\nLeaving...' - if args.flash_mode == 'dio': - esp.flash_unlock_dio() - else: - esp.flash_begin(0, 0) - if args.compress: - esp.flash_defl_finish(False) - else: - esp.flash_finish(False) - if args.verify: - print 'Verifying just-written flash...' - verify_flash(esp, args, header_block) - - -def image_info(args): - image = LoadFirmwareImage(args.chip, args.filename) - print('Image version: %d' % image.version) - print('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set' - print '%d segments' % len(image.segments) - print - checksum = ESPROM.ESP_CHECKSUM_MAGIC - idx = 0 - for seg in image.segments: - idx += 1 - print 'Segment %d: %r' % (idx, seg) - checksum = ESPROM.checksum(seg.data, checksum) - print - print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!') - - -def make_image(args): - image = ESPFirmwareImage() - if len(args.segfile) == 0: - raise FatalError('No segments specified') - if len(args.segfile) != len(args.segaddr): - raise FatalError('Number of specified files does not match number of specified addresses') - for (seg, addr) in zip(args.segfile, args.segaddr): - data = file(seg, 'rb').read() - image.segments.append(ImageSegment(addr, data)) - image.entrypoint = args.entrypoint - image.save(args.output) - - -def elf2image(args): - e = ELFFile(args.input) - if args.chip == 'auto': # Default to ESP8266 for backwards compatibility - print "Creating image for ESP8266..." - args.chip == 'esp8266' - - if args.chip == 'esp31': - raise FatalError("No elf2image support for ESP31. Use gen_appimage.py from the ESP31 SDK") - elif args.chip == 'esp32': - image = ESP32FirmwareImage() - elif args.version == '1': # ESP8266 - image = ESPFirmwareImage() - else: - image = OTAFirmwareImage() - image.entrypoint = e.entrypoint - image.segments = e.sections # ELFSection is a subclass of ImageSegment - image.flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode] - image.flash_size_freq = ESP8266ROM.FLASH_SIZES[args.flash_size] - image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq] - - if args.output is None: - args.output = image.default_output_name(args.input) - image.save(args.output) - - -def read_mac(esp, args): - mac = esp.read_mac() - print 'MAC: %s' % ':'.join(map(lambda x: '%02x' % x, mac)) - - -def chip_id(esp, args): - chipid = esp.chip_id() - print 'Chip ID: 0x%08x' % chipid - - -def erase_flash(esp, args): - print 'Erasing flash (this may take a while)...' - flasher = CesantaFlasher(esp, args.baud) - flasher.flash_erase() - print 'Erase completed successfully.' - - -def run(esp, args): - esp.run() - - -def flash_id(esp, args): - flash_id = esp.flash_id() - print 'Manufacturer: %02x' % (flash_id & 0xff) - print 'Device: %02x%02x' % ((flash_id >> 8) & 0xff, (flash_id >> 16) & 0xff) - - -def read_flash(esp, args): - flasher = CesantaFlasher(esp, args.baud) - t = time.time() - data = flasher.flash_read(args.address, args.size, not args.no_progress) - t = time.time() - t - print ('\rRead %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...' - % (len(data), args.address, t, len(data) / t * 8 / 1000)) - file(args.filename, 'wb').write(data) - - -def _verify_flash(flasher, args, flash_params=None): - differences = False - for address, argfile in args.addr_filename: - image = argfile.read() - argfile.seek(0) # rewind in case we need it again - if address == 0 and image[0] == '\xe9' and flash_params is not None: - image = image[0:2] + flash_params + image[4:] - image_size = len(image) - print 'Verifying 0x%x (%d) bytes @ 0x%08x in flash against %s...' % (image_size, image_size, address, argfile.name) - # Try digest first, only read if there are differences. - digest, _ = flasher.flash_digest(address, image_size) - digest = hexify(digest).upper() - expected_digest = hashlib.md5(image).hexdigest().upper() - if digest == expected_digest: - print '-- verify OK (digest matched)' - continue - else: - differences = True - if getattr(args, 'diff', 'no') != 'yes': - print '-- verify FAILED (digest mismatch)' - continue - - flash = flasher.flash_read(address, image_size) - assert flash != image - diff = [i for i in xrange(image_size) if flash[i] != image[i]] - print '-- verify FAILED: %d differences, first @ 0x%08x' % (len(diff), address + diff[0]) - for d in diff: - print ' %08x %02x %02x' % (address + d, ord(flash[d]), ord(image[d])) - if differences: - raise FatalError("Verify failed.") - - -def verify_flash(esp, args, flash_params=None): - flasher = CesantaFlasher(esp) - _verify_flash(flasher, args, flash_params) - - -def version(args): - print __version__ - -# -# End of operations functions -# - - -def main(): - parser = argparse.ArgumentParser(description='esptool.py v%s - ESP8266 ROM Bootloader Utility' % __version__, prog='esptool') - - parser.add_argument('--chip', '-c', - help='Target chip type', - choices=['auto', 'esp8266', 'esp31', 'esp32'], - default=os.environ.get('ESPTOOL_CHIP', 'auto')) - - parser.add_argument( - '--port', '-p', - help='Serial port device', - default=os.environ.get('ESPTOOL_PORT', ESPROM.DEFAULT_PORT)) - - parser.add_argument( - '--baud', '-b', - help='Serial port baud rate used when flashing/reading', - type=arg_auto_int, - default=os.environ.get('ESPTOOL_BAUD', ESPROM.ESP_ROM_BAUD)) - - subparsers = parser.add_subparsers( - dest='operation', - help='Run esptool {command} -h for additional help') - - parser_load_ram = subparsers.add_parser( - 'load_ram', - help='Download an image to RAM and execute') - parser_load_ram.add_argument('filename', help='Firmware image') - - parser_dump_mem = subparsers.add_parser( - 'dump_mem', - help='Dump arbitrary memory to disk') - parser_dump_mem.add_argument('address', help='Base address', type=arg_auto_int) - parser_dump_mem.add_argument('size', help='Size of region to dump', type=arg_auto_int) - parser_dump_mem.add_argument('filename', help='Name of binary dump') - - parser_read_mem = subparsers.add_parser( - 'read_mem', - help='Read arbitrary memory location') - parser_read_mem.add_argument('address', help='Address to read', type=arg_auto_int) - - parser_write_mem = subparsers.add_parser( - 'write_mem', - help='Read-modify-write to arbitrary memory location') - parser_write_mem.add_argument('address', help='Address to write', type=arg_auto_int) - parser_write_mem.add_argument('value', help='Value', type=arg_auto_int) - parser_write_mem.add_argument('mask', help='Mask of bits to write', type=arg_auto_int) - - def add_spi_flash_subparsers(parent): - """ Add common parser arguments for SPI flash properties """ - parent.add_argument('--flash_freq', '-ff', help='SPI Flash frequency', - choices=['40m', '26m', '20m', '80m'], - default=os.environ.get('ESPTOOL_FF', '40m')) - parent.add_argument('--flash_mode', '-fm', help='SPI Flash mode', - choices=['qio', 'qout', 'dio', 'dout'], - default=os.environ.get('ESPTOOL_FM', 'qio')) - parent.add_argument('--flash_size', '-fs', help='SPI Flash size in MegaBytes (1MB, 2MB, 4MB, 8MB, 16M)' - ' plus ESP8266-only (256KB, 512KB, 2MB-c1, 4MB-c1, 4MB-2)', - action=FlashSizeAction, - default=os.environ.get('ESPTOOL_FS', '1MB')) - - parser_write_flash = subparsers.add_parser( - 'write_flash', - help='Write a binary blob to flash') - parser_write_flash.add_argument('addr_filename', metavar='
', help='Address followed by binary filename, separated by space', - action=AddrFilenamePairAction) - add_spi_flash_subparsers(parser_write_flash) - parser_write_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true") - parser_write_flash.add_argument('--verify', help='Verify just-written data (only necessary if very cautious, data is already CRCed', action='store_true') - parser_write_flash.add_argument('--ucIsHspi', '-ih', help='Config SPI PORT/PINS (Espressif internal feature)',default='0') - parser_write_flash.add_argument('--ucIsLegacy', '-il', help='Config SPI LEGACY (Espressif internal feature)',default='0') - parser_write_flash.add_argument('--compress', '-z', help='Compress data in transfer',action="store_true") - - subparsers.add_parser( - 'run', - help='Run application code in flash') - - parser_image_info = subparsers.add_parser( - 'image_info', - help='Dump headers from an application image') - parser_image_info.add_argument('filename', help='Image file to parse') - - parser_make_image = subparsers.add_parser( - 'make_image', - help='Create an application image from binary files') - parser_make_image.add_argument('output', help='Output image file') - parser_make_image.add_argument('--segfile', '-f', action='append', help='Segment input file') - parser_make_image.add_argument('--segaddr', '-a', action='append', help='Segment base address', type=arg_auto_int) - parser_make_image.add_argument('--entrypoint', '-e', help='Address of entry point', type=arg_auto_int, default=0) - - parser_elf2image = subparsers.add_parser( - 'elf2image', - help='Create an application image from ELF file') - parser_elf2image.add_argument('input', help='Input ELF file') - parser_elf2image.add_argument('--output', '-o', help='Output filename prefix (for version 1 image), or filename (for version 2 single image)', type=str) - parser_elf2image.add_argument('--version', '-e', help='Output image version', choices=['1','2'], default='1') - add_spi_flash_subparsers(parser_elf2image) - - subparsers.add_parser( - 'read_mac', - help='Read MAC address from OTP ROM') - - subparsers.add_parser( - 'chip_id', - help='Read Chip ID from OTP ROM') - - subparsers.add_parser( - 'flash_id', - help='Read SPI flash manufacturer and device ID') - - parser_read_flash = subparsers.add_parser( - 'read_flash', - help='Read SPI flash content') - parser_read_flash.add_argument('address', help='Start address', type=arg_auto_int) - parser_read_flash.add_argument('size', help='Size of region to dump', type=arg_auto_int) - parser_read_flash.add_argument('filename', help='Name of binary dump') - parser_read_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true") - - parser_verify_flash = subparsers.add_parser( - 'verify_flash', - help='Verify a binary blob against flash') - parser_verify_flash.add_argument('addr_filename', help='Address and binary file to verify there, separated by space', - action=AddrFilenamePairAction) - parser_verify_flash.add_argument('--diff', '-d', help='Show differences', - choices=['no', 'yes'], default='no') - - subparsers.add_parser( - 'erase_flash', - help='Perform Chip Erase on SPI flash') - - subparsers.add_parser( - 'version', help='Print esptool version') - - # internal sanity check - every operation matches a module function of the same name - for operation in subparsers.choices.keys(): - assert operation in globals(), "%s should be a module function" % operation - - args = parser.parse_args() - - print 'esptool.py v%s' % __version__ - - # operation function can take 1 arg (args), 2 args (esp, arg) - # or be a member function of the ESPROM class. - - operation_func = globals()[args.operation] - operation_args,_,_,_ = inspect.getargspec(operation_func) - if operation_args[0] == 'esp': # operation function takes an ESPROM connection object - initial_baud = min(ESPROM.ESP_ROM_BAUD, args.baud) # don't sync faster than the default baud rate - chip_constructor_fun = { - 'auto': ESPROM.detect_chip, - 'esp8266': ESP8266ROM, - 'esp31': ESP31ROM, - 'esp32': ESP32ROM, - }[args.chip] - esp = chip_constructor_fun(args.port, initial_baud) - # try to set a higher baud, this is a no-op if we need to - # wait for the flasher stub to kick in before doing this. - esp.change_baud(args.baud) - - operation_func(esp, args) - else: - operation_func(args) - - -class FlashSizeAction(argparse.Action): - """ Custom flash size parser class to support backwards compatibility with megabit size arguments. - - (At next major relase, remove deprecated sizes and this can become a 'normal' choices= argument again.) - """ - def __init__(self, option_strings, dest, nargs=1, **kwargs): - super(FlashSizeAction, self).__init__(option_strings, dest, nargs, **kwargs) - - def __call__(self, parser, namespace, values, option_string=None): - try: - value = { - '2m': '256KB', - '4m': '512KB', - '8m': '1MB', - '16m': '2MB', - '32m': '4MB', - '16m-c1': '2MB-c1', - '32m-c1': '4MB-c1', - '32m-c2': '4MB-c2' - }[values[0]] - print("WARNING: Flash size arguments in megabits like '%s' are deprecated." % (values[0])) - print("Please use the equivalent size '%s'." % (value)) - print("Megabit arguments may be removed in a future release.") - except KeyError: - values = values[0] - - known_sizes = dict(ESP8266ROM.FLASH_SIZES) - known_sizes.update(ESP32ROM.FLASH_SIZES) - if value not in known_sizes: - raise argparse.ArgumentError(self, '%s is not a known flash size. Known sizes: %s' % (value, ", ".join(known_sizes.keys()))) - setattr(namespace, self.dest, value) - - -class AddrFilenamePairAction(argparse.Action): - """ Custom parser class for the address/filename pairs passed as arguments """ - def __init__(self, option_strings, dest, nargs='+', **kwargs): - super(AddrFilenamePairAction, self).__init__(option_strings, dest, nargs, **kwargs) - - def __call__(self, parser, namespace, values, option_string=None): - # validate pair arguments - pairs = [] - for i in range(0,len(values),2): - try: - address = int(values[i],0) - except ValueError as e: - raise argparse.ArgumentError(self,'Address "%s" must be a number' % values[i]) - try: - argfile = open(values[i + 1], 'rb') - except IOError as e: - raise argparse.ArgumentError(self, e) - except IndexError: - raise argparse.ArgumentError(self,'Must be pairs of an address and the binary filename to write there') - pairs.append((address, argfile)) - setattr(namespace, self.dest, pairs) - -# This is "wrapped" stub_flasher.c, to be loaded using run_stub. -_CESANTA_FLASHER_STUB = """\ -{"code_start": 1074790404, "code": "080000601C000060000000601000006031FCFF71FCFF\ -81FCFFC02000680332D218C020004807404074DCC48608005823C0200098081BA5A9239245005803\ -1B555903582337350129230B446604DFC6F3FF21EEFFC0200069020DF0000000010078480040004A\ -0040B449004012C1F0C921D911E901DD0209312020B4ED033C2C56C2073020B43C3C56420701F5FF\ -C000003C4C569206CD0EEADD860300202C4101F1FFC0000056A204C2DCF0C02DC0CC6CCAE2D1EAFF\ -0606002030F456D3FD86FBFF00002020F501E8FFC00000EC82D0CCC0C02EC0C73DEB2ADC46030020\ -2C4101E1FFC00000DC42C2DCF0C02DC056BCFEC602003C5C8601003C6C4600003C7C08312D0CD811\ -C821E80112C1100DF0000C180000140010400C0000607418000064180000801800008C1800008418\ -0000881800009018000018980040880F0040A80F0040349800404C4A0040740F0040800F0040980F\ -00400099004012C1E091F5FFC961CD0221EFFFE941F9310971D9519011C01A223902E2D1180C0222\ -6E1D21E4FF31E9FF2AF11A332D0F42630001EAFFC00000C030B43C2256A31621E1FF1A2228022030\ -B43C3256B31501ADFFC00000DD023C4256ED1431D6FF4D010C52D90E192E126E0101DDFFC0000021\ -D2FF32A101C020004802303420C0200039022C0201D7FFC00000463300000031CDFF1A333803D023\ -C03199FF27B31ADC7F31CBFF1A3328030198FFC0000056C20E2193FF2ADD060E000031C6FF1A3328\ -030191FFC0000056820DD2DD10460800000021BEFF1A2228029CE231BCFFC020F51A33290331BBFF\ -C02C411A332903C0F0F4222E1D22D204273D9332A3FFC02000280E27B3F721ABFF381E1A2242A400\ -01B5FFC00000381E2D0C42A40001B3FFC0000056120801B2FFC00000C02000280EC2DC0422D2FCC0\ -2000290E01ADFFC00000222E1D22D204226E1D281E22D204E7B204291E860000126E012198FF32A0\ -042A21C54C003198FF222E1D1A33380337B202C6D6FF2C02019FFFC000002191FF318CFF1A223A31\ -019CFFC00000218DFF1C031A22C549000C02060300003C528601003C624600003C72918BFF9A1108\ -71C861D851E841F83112C1200DF00010000068100000581000007010000074100000781000007C10\ -0000801000001C4B0040803C004091FDFF12C1E061F7FFC961E941F9310971D9519011C01A662906\ -21F3FFC2D1101A22390231F2FF0C0F1A33590331EAFFF26C1AED045C2247B3028636002D0C016DFF\ -C0000021E5FF41EAFF2A611A4469040622000021E4FF1A222802F0D2C0D7BE01DD0E31E0FF4D0D1A\ -3328033D0101E2FFC00000561209D03D2010212001DFFFC000004D0D2D0C3D01015DFFC0000041D5\ -FFDAFF1A444804D0648041D2FF1A4462640061D1FF106680622600673F1331D0FF10338028030C43\ -853A002642164613000041CAFF222C1A1A444804202FC047328006F6FF222C1A273F3861C2FF222C\ -1A1A6668066732B921BDFF3D0C1022800148FFC0000021BAFF1C031A2201BFFFC000000C02460300\ -5C3206020000005C424600005C5291B7FF9A110871C861D851E841F83112C1200DF0B0100000C010\ -0000D010000012C1E091FEFFC961D951E9410971F931CD039011C0ED02DD0431A1FF9C1422A06247\ -B302062D0021F4FF1A22490286010021F1FF1A223902219CFF2AF12D0F011FFFC00000461C0022D1\ -10011CFFC0000021E9FFFD0C1A222802C7B20621E6FF1A22F8022D0E3D014D0F0195FFC000008C52\ -22A063C6180000218BFF3D01102280F04F200111FFC00000AC7D22D1103D014D0F010DFFC0000021\ -D6FF32D110102280010EFFC0000021D3FF1C031A220185FFC00000FAEEF0CCC056ACF821CDFF317A\ -FF1A223A310105FFC0000021C9FF1C031A22017CFFC000002D0C91C8FF9A110871C861D851E841F8\ -3112C1200DF0000200600000001040020060FFFFFF0012C1E00C02290131FAFF21FAFF026107C961\ -C02000226300C02000C80320CC10564CFF21F5FFC02000380221F4FF20231029010C432D010163FF\ -C0000008712D0CC86112C1200DF00080FE3F8449004012C1D0C9A109B17CFC22C1110C13C51C0026\ -1202463000220111C24110B68202462B0031F5FF3022A02802A002002D011C03851A0066820A2801\ -32210105A6FF0607003C12C60500000010212032A01085180066A20F2221003811482105B3FF2241\ -10861A004C1206FDFF2D011C03C5160066B20E280138114821583185CFFF06F7FF005C1286F5FF00\ -10212032A01085140066A20D2221003811482105E1FF06EFFF0022A06146EDFF45F0FFC6EBFF0000\ -01D2FFC0000006E9FF000C022241100C1322C110C50F00220111060600000022C1100C13C50E0022\ -011132C2FA303074B6230206C8FF08B1C8A112C1300DF0000000000010404F484149007519031027\ -000000110040A8100040BC0F0040583F0040CC2E00401CE20040D83900408000004021F4FF12C1E0\ -C961C80221F2FF097129010C02D951C91101F4FFC0000001F3FFC00000AC2C22A3E801F2FFC00000\ -21EAFFC031412A233D0C01EFFFC000003D0222A00001EDFFC00000C1E4FF2D0C01E8FFC000002D01\ -32A004450400C5E7FFDD022D0C01E3FFC00000666D1F4B2131DCFF4600004B22C0200048023794F5\ -31D9FFC0200039023DF08601000001DCFFC000000871C861D85112C1200DF000000012C1F0026103\ -01EAFEC00000083112C1100DF000643B004012C1D0E98109B1C9A1D991F97129013911E2A0C001FA\ -FFC00000CD02E792F40C0DE2A0C0F2A0DB860D00000001F4FFC00000204220E71240F7921C226102\ -01EFFFC0000052A0DC482157120952A0DD571205460500004D0C3801DA234242001BDD3811379DC5\ -C6000000000C0DC2A0C001E3FFC00000C792F608B12D0DC8A1D891E881F87112C1300DF00000", "\ -entry": 1074792180, "num_params": 1, "params_start": 1074790400, "data": "FE0510\ -401A0610403B0610405A0610407A061040820610408C0610408C061040", "data_start": 10736\ -43520} -""" - -if __name__ == '__main__': - try: - main() - except FatalError as e: - print '\nA fatal error occurred: %s' % e - sys.exit(2) diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild new file mode 100644 index 0000000000..74028b6e90 --- /dev/null +++ b/components/bootloader/Kconfig.projbuild @@ -0,0 +1,33 @@ +menu "Bootloader config" + +choice BOOTLOADER_LOG_LEVEL + bool "Bootloader log verbosity" + default BOOTLOADER_LOG_LEVEL_NOTICE + help + Specify how much output to see in the bootloader logs. + + Note that if MTDO is HIGH on reset, all early boot output + (including bootloader logs) are suppressed. +config BOOTLOADER_LOG_LEVEL_NONE + bool "No output" +config BOOTLOADER_LOG_LEVEL_ERROR + bool "Error" +config BOOTLOADER_LOG_LEVEL_WARN + bool "Warning" +config BOOTLOADER_LOG_LEVEL_INFO + bool "Info" +config BOOTLOADER_LOG_LEVEL_NOTICE + bool "Notice" +config BOOTLOADER_LOG_LEVEL_DEBUG + bool "Debug" +endchoice + +config BOOTLOADER_LOG_COLORS + bool "Use ANSI terminal colors in bootloader log output" + default "y" + help + Enable ANSI terminal color codes in bootloader output. + + In order to view these, your terminal program must support ANSI color codes. + +endmenu diff --git a/components/bootloader/Makefile.projbuild b/components/bootloader/Makefile.projbuild index 48c09d4816..aaebd4d263 100644 --- a/components/bootloader/Makefile.projbuild +++ b/components/bootloader/Makefile.projbuild @@ -8,6 +8,7 @@ # basically runs Make in the src/ directory but it needs to zero some variables # the ESP-IDF project.mk makefile exports first, to not let them interfere. # +ifeq ("$(IS_BOOTLOADER_BUILD)","") BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH) BOOTLOADER_BUILD_DIR=$(BUILD_DIR_BASE)/bootloader @@ -47,3 +48,5 @@ $(COMPONENT_PATH)/src/sdkconfig: $(PROJECT_PATH)/sdkconfig # bootloader-flash calls flash in the bootloader dummy project bootloader-flash: $(BOOTLOADER_BIN) $(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src flash MAKEFLAGS= V=$(V) + +endif diff --git a/components/bootloader/src/Makefile b/components/bootloader/src/Makefile index 191fbef110..b6b0c1af02 100644 --- a/components/bootloader/src/Makefile +++ b/components/bootloader/src/Makefile @@ -4,7 +4,12 @@ # PROJECT_NAME := bootloader -COMPONENTS := esptool_py +COMPONENTS := esptool_py bootloader + +# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included. +# +# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op +IS_BOOTLOADER_BUILD := 1 #We cannot include the esp32 component directly but we need its includes. This is fixed by #adding it in the main/Makefile directory. diff --git a/components/bootloader/src/main/bootloader_log.h b/components/bootloader/src/main/bootloader_log.h index 32bc4852e2..1f7ec62ad5 100644 --- a/components/bootloader/src/main/bootloader_log.h +++ b/components/bootloader/src/main/bootloader_log.h @@ -19,39 +19,64 @@ extern "C" { #endif +#include "sdkconfig.h" +#define BOOT_LOG_LEVEL_NONE (0) #define BOOT_LOG_LEVEL_ERROR (1) #define BOOT_LOG_LEVEL_WARN (2) #define BOOT_LOG_LEVEL_INFO (3) #define BOOT_LOG_LEVEL_NOTICE (4) #define BOOT_LOG_LEVEL_DEBUG (5) -#define Black 0;30 -#define Red 0;31 -#define Green 0;32 -#define Brown 0;33 -#define Blue 0;34 -#define Purple 0;35 -#define Cyan 0;36 +#define Black "30" +#define Red "31" +#define Green "32" +#define Brown "33" +#define Blue "34" +#define Purple "35" +#define Cyan "36" -// TODO: move BOOT_LOG_LEVEL into menuconfig -//#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_ERROR -#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_NOTICE +#if CONFIG_BOOTLOADER_LOG_COLORS +#define LOG_COLOR(COLOR) "\033[0;"COLOR"m" +#define LOG_BOLD(COLOR) "\033[1;"COLOR"m" +#define LOG_RESET_COLOR "\033[0m" +#else +#define LOG_COLOR(...) +#define LOG_BOLD(...) +#define LOG_RESET_COLOR "" +#endif + +// BOOT_LOG_LEVEL defined by make menuconfig +#if CONFIG_BOOTLOADER_LOG_LEVEL_NONE +#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_NONE +#elif CONFIG_BOOTLOADER_LOG_LEVEL_ERROR +#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_ERROR +#elif CONFIG_BOOTLOADER_LOG_LEVEL_WARN +#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_WARN +#elif CONFIG_BOOTLOADER_LOG_LEVEL_INFO +#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO +#elif CONFIG_BOOTLOADER_LOG_LEVEL_NOTICE +#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_NOTICE +#elif CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG +#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_DEBUG +#else +#error "No bootloader log level set in menuconfig!" +#endif //printf("\033[0;36m[NOTICE][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); #define log_notice(format, ...) \ do{\ if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE){\ - ets_printf("\033[0;36m" format "\r\n", ##__VA_ARGS__);\ - ets_printf("\033[0m"); \ + ets_printf(LOG_COLOR(Cyan) format "\r\n", ##__VA_ARGS__); \ + ets_printf(LOG_RESET_COLOR); \ }\ }while(0) #define log_info(format, ...) \ do{\ if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_INFO){\ - ets_printf("\033[1;36m" format "\r\n", ##__VA_ARGS__);\ - ets_printf("\033[0m"); \ + ets_printf(LOG_BOLD(Cyan) format "\r\n", ##__VA_ARGS__); \ + ets_printf(LOG_RESET_COLOR); \ }\ }while(0) @@ -59,8 +84,8 @@ extern "C" #define log_error(format, ...) \ do{\ if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_ERROR){\ - ets_printf("\033[0;31m[ERROR][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);\ - ets_printf("\033[0m"); \ + ets_printf(LOG_COLOR(Red) "[ERROR][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ets_printf(LOG_RESET_COLOR); \ }\ }while(0) @@ -68,8 +93,8 @@ extern "C" #define log_warn(format, ...) \ do{\ if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_WARN){\ - ets_printf("\033[1;33m[WARN][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);\ - ets_printf("\033[0m"); \ + ets_printf(LOG_BOLD(Brown) "[WARN][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ets_printf(LOG_RESET_COLOR); \ }\ }while(0) @@ -77,8 +102,8 @@ extern "C" #define log_debug(format, ...) \ do{\ if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_DEBUG){\ - ets_printf("\033[1;32m[DEBUG][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ - ets_printf("\033[0m"); \ + ets_printf(LOG_BOLD(Green) "[DEBUG][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ets_printf(LOG_RESET_COLOR); \ }\ }while(0) @@ -86,4 +111,4 @@ extern "C" } #endif -#endif /* __BOOT_LOGGING_H__ */ \ No newline at end of file +#endif /* __BOOT_LOGGING_H__ */ diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index b9df64012a..2dbf0e8269 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -276,8 +276,6 @@ void bootloader_main() { //Run start routine. /*ESP32 2ND bootload start here*/ - - log_info( "\n" ); log_info( "**************************************" ); log_info( "* hello espressif ESP32! *" ); @@ -294,7 +292,7 @@ void bootloader_main() log_notice( "compile time %s\n", __TIME__ ); /* close watch dog here */ REG_CLR_BIT( RTC_WDTCONFIG0, RTC_CNTL_WDT_FLASHBOOT_MOD_EN ); - REG_CLR_BIT( WDTCONFIG0, TIMERS_WDT_FLASHBOOT_MOD_EN ); + REG_CLR_BIT( WDTCONFIG0(0), TIMERS_WDT_FLASHBOOT_MOD_EN ); SPIUnlock(); /*register first sector in drom0 page 0 */ boot_cache_redirect( 0, 0x5000 ); diff --git a/components/bootloader/src/main/Makefile b/components/bootloader/src/main/component.mk similarity index 86% rename from components/bootloader/src/main/Makefile rename to components/bootloader/src/main/component.mk index 2bb773b9c6..1671095f1b 100644 --- a/components/bootloader/src/main/Makefile +++ b/components/bootloader/src/main/component.mk @@ -1,7 +1,7 @@ # # Main Makefile. This is basically the same as a component makefile. # -# This Makefile should, at the very least, just include $(IDF_PATH)/make/component.mk. By default, +# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default, # this will take the sources in the src/ directory, compile them and link them into # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, # please read the esp-idf build system document if you need to do this. @@ -10,4 +10,4 @@ COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld COMPONENT_EXTRA_INCLUDES := $(IDF_PATH)/components/esp32/include -include $(IDF_PATH)/make/component.mk +include $(IDF_PATH)/make/component_common.mk diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index af34c4a336..154ee4150e 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -7,7 +7,6 @@ config WIFI_ENABLED This compiles in the low-level WiFi stack. Temporarily, this option requires that FreeRTOS runs in single core mode. - depends on FREERTOS_UNICORE config WIFI_AUTO_STARTUP bool "Start WiFi with system startup" diff --git a/components/esp32/Makefile b/components/esp32/component.mk similarity index 67% rename from components/esp32/Makefile rename to components/esp32/component.mk index 1d55d0ff63..6bb7c951a2 100644 --- a/components/esp32/Makefile +++ b/components/esp32/component.mk @@ -1,7 +1,7 @@ # # Component Makefile # -# This Makefile should, at the very least, just include $(IDF_PATH)/make/component.mk. By default, +# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default, # this will take the sources in this directory, compile them and link them into # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, # please read the esp-idf build system document if you need to do this. @@ -33,18 +33,13 @@ COMPONENT_ADD_LDFLAGS := -lesp32 \ -L $(abspath ld) \ $(LINKER_SCRIPTS) -include $(IDF_PATH)/make/component.mk +include $(IDF_PATH)/make/component_common.mk ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) -# The binary libraries are in a git submodule, so this target will -# be invoked if any modules are missing (probably because -# git submodule update --init needs to be run). -$(ALL_LIB_FILES): - $(Q) [ -d ${IDF_PATH}/.git ] || ( @echo "ERROR: Missing libraries in esp32 component. esp-idf must be cloned from git to work."; exit 1 ) - $(Q) [ -x $(which git) ] || ( @echo "ERROR: Missing libraries in esp32 component. Need to run 'git submodule update --init' in esp-idf root directory."; exit 1 ) - @echo "Warning: Missing libraries in components/esp32/lib/ submodule. Going to try running 'git submodule update --init' in esp-idf root directory..." - cd ${IDF_PATH} && git submodule update --init +# automatically trigger a git submodule update +# if any libraries are missing +$(eval $(call SubmoduleRequiredForFiles,$(ALL_LIB_FILES))) # this is a hack to make sure the app is re-linked if the binary # libraries change or are updated. If they change, the main esp32 diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 85d3009ef3..e1a5f027b7 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -18,6 +18,7 @@ #include "esp_err.h" #include "rom/ets_sys.h" +#include "rom/uart.h" #include "soc/dport_reg.h" #include "soc/io_mux_reg.h" @@ -36,6 +37,8 @@ #include "esp_spi_flash.h" #include "nvs_flash.h" #include "esp_event.h" +#include "esp_spi_flash.h" +#include "esp_ipc.h" static void IRAM_ATTR user_start_cpu0(void); static void IRAM_ATTR call_user_start_cpu1(); @@ -59,11 +62,6 @@ We arrive here after the bootloader finished loading the program from flash. The flash cache is down and the app CPU is in reset. We do have a stack, so we can do the initialization in C. */ -void Uart_Init(int no); -void uartAttach(); -void ets_set_appcpu_boot_addr(uint32_t ent); -int ets_getAppEntry(); - static bool app_cpu_started = false; void IRAM_ATTR call_user_start_cpu0() { @@ -180,53 +178,55 @@ void IRAM_ATTR call_user_start_cpu1() { user_start_cpu1(); } -extern volatile int port_xSchedulerRunning; -extern int xPortStartScheduler(); +extern volatile int port_xSchedulerRunning[2]; -void user_start_cpu1(void) { - //Wait for the freertos initialization is finished on CPU0 - while (port_xSchedulerRunning == 0) ; - ets_printf("Core0 started initializing FreeRTOS. Jumping to scheduler.\n"); - //Okay, start the scheduler! +void IRAM_ATTR user_start_cpu1(void) { + // Wait for FreeRTOS initialization to finish on PRO CPU + while (port_xSchedulerRunning[0] == 0) { + ; + } + ets_printf("Starting scheduler on APP CPU.\n"); xPortStartScheduler(); } extern void (*__init_array_start)(void); extern void (*__init_array_end)(void); -extern esp_err_t app_main(); static void do_global_ctors(void) { void (**p)(void); for(p = &__init_array_start; p != &__init_array_end; ++p) (*p)(); } +extern esp_err_t app_main(void *ctx); void user_start_cpu0(void) { ets_setup_syscalls(); do_global_ctors(); + esp_ipc_init(); + spi_flash_init(); #if CONFIG_WIFI_ENABLED - ets_printf("nvs_flash_init\n"); esp_err_t ret = nvs_flash_init(5, 3); if (ret != ESP_OK) { - ets_printf("nvs_flash_init fail, ret=%d\n", ret); + printf("nvs_flash_init failed, ret=%d\n", ret); } system_init(); - esp_event_init(NULL); + esp_event_init(NULL, NULL); tcpip_adapter_init(); #endif #if CONFIG_WIFI_ENABLED && CONFIG_WIFI_AUTO_STARTUP #include "esp_wifi.h" - esp_wifi_startup(app_main); + esp_wifi_startup(app_main, NULL); #else - app_main(); + app_main(NULL); #endif + ets_printf("Starting scheduler on PRO CPU.\n"); vTaskStartScheduler(); } diff --git a/components/esp32/event.c b/components/esp32/event.c index 92b751038d..53ffd642eb 100644 --- a/components/esp32/event.c +++ b/components/esp32/event.c @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #include #include #include @@ -29,10 +30,13 @@ #define ESP32_WORKAROUND 1 #if CONFIG_WIFI_ENABLED +static bool event_init_flag = false; static xQueueHandle g_event_handler = NULL; -static system_event_cb_t g_event_handler_cb; -#define WIFI_DEBUG(...) +static system_event_cb_t g_event_handler_cb; +static void *g_event_ctx; + +#define WIFI_DEBUG(...) #define WIFI_API_CALL_CHECK(info, api_call, ret) \ do{\ esp_err_t __err = (api_call);\ @@ -43,6 +47,7 @@ do{\ } while(0) typedef esp_err_t (*system_event_handle_fn_t)(system_event_t *e); + typedef struct { system_event_id_t event_id; system_event_handle_fn_t event_handle; @@ -55,7 +60,7 @@ static esp_err_t system_event_sta_start_handle_default(system_event_t *event); static esp_err_t system_event_sta_stop_handle_default(system_event_t *event); static esp_err_t system_event_sta_connected_handle_default(system_event_t *event); static esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event); -static esp_err_t system_event_sta_gotip_default(system_event_t *event); +static esp_err_t system_event_sta_got_ip_default(system_event_t *event); static system_event_handle_t g_system_event_handle_table[] = { {SYSTEM_EVENT_WIFI_READY, NULL}, @@ -65,7 +70,7 @@ static system_event_handle_t g_system_event_handle_table[] = { {SYSTEM_EVENT_STA_CONNECTED, system_event_sta_connected_handle_default}, {SYSTEM_EVENT_STA_DISCONNECTED, system_event_sta_disconnected_handle_default}, {SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL}, - {SYSTEM_EVENT_STA_GOTIP, system_event_sta_gotip_default}, + {SYSTEM_EVENT_STA_GOT_IP, system_event_sta_got_ip_default}, {SYSTEM_EVENT_AP_START, system_event_ap_start_handle_default}, {SYSTEM_EVENT_AP_STOP, system_event_ap_stop_handle_default}, {SYSTEM_EVENT_AP_STACONNECTED, NULL}, @@ -74,15 +79,15 @@ static system_event_handle_t g_system_event_handle_table[] = { {SYSTEM_EVENT_MAX, NULL}, }; -static esp_err_t system_event_sta_gotip_default(system_event_t *event) +static esp_err_t system_event_sta_got_ip_default(system_event_t *event) { extern esp_err_t esp_wifi_set_sta_ip(void); WIFI_API_CALL_CHECK("esp_wifi_set_sta_ip", esp_wifi_set_sta_ip(), ESP_OK); printf("ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR "\n", - IP2STR(&event->event_info.got_ip.ip_info.ip), - IP2STR(&event->event_info.got_ip.ip_info.netmask), - IP2STR(&event->event_info.got_ip.ip_info.gw)); + IP2STR(&event->event_info.got_ip.ip_info.ip), + IP2STR(&event->event_info.got_ip.ip_info.netmask), + IP2STR(&event->event_info.got_ip.ip_info.gw)); return ESP_OK; } @@ -132,7 +137,7 @@ esp_err_t system_event_sta_stop_handle_default(system_event_t *event) esp_err_t system_event_sta_connected_handle_default(system_event_t *event) { tcpip_adapter_dhcp_status_t status; - + WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_STA, (wifi_rxcb_t)tcpip_adapter_sta_input), ESP_OK); tcpip_adapter_up(TCPIP_ADAPTER_IF_STA); @@ -150,7 +155,7 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event) system_event_t evt; //notify event - evt.event_id = SYSTEM_EVENT_STA_GOTIP; + evt.event_id = SYSTEM_EVENT_STA_GOT_IP; memcpy(&evt.event_info.got_ip.ip_info, &sta_ip, sizeof(tcpip_adapter_ip_info_t)); esp_event_send(&evt); @@ -172,7 +177,7 @@ esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event) static esp_err_t esp_wifi_post_event_to_user(system_event_t *event) { if (g_event_handler_cb) { - return (*g_event_handler_cb)(event); + return (*g_event_handler_cb)(g_event_ctx, event); } return ESP_OK; @@ -187,102 +192,88 @@ static esp_err_t esp_system_event_debug(system_event_t *event) WIFI_DEBUG("received event: "); switch (event->event_id) { - case SYSTEM_EVENT_WIFI_READY: - { - WIFI_DEBUG("SYSTEM_EVENT_WIFI_READY\n"); - break; - } - case SYSTEM_EVENT_SCAN_DONE: - { - system_event_sta_scan_done_t *scan_done; - scan_done = &event->event_info.scan_done; - WIFI_DEBUG("SYSTEM_EVENT_SCAN_DONE\nstatus:%d, number:%d\n", scan_done->status, scan_done->number); - break; - } - case SYSTEM_EVENT_STA_START: - { - WIFI_DEBUG("SYSTEM_EVENT_STA_START\n"); - break; - } - case SYSTEM_EVENT_STA_STOP: - { - WIFI_DEBUG("SYSTEM_EVENT_STA_STOP\n"); - break; - } - case SYSTEM_EVENT_STA_CONNECTED: - { - system_event_sta_connected_t *connected; - connected = &event->event_info.connected; - WIFI_DEBUG("SYSTEM_EVENT_STA_CONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d\n", \ - connected->ssid, connected->ssid_len, connected->bssid[0], connected->bssid[0], connected->bssid[1], \ - connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel, connected->authmode); - break; - } - case SYSTEM_EVENT_STA_DISCONNECTED: - { - system_event_sta_disconnected_t *disconnected; - disconnected = &event->event_info.disconnected; - WIFI_DEBUG("SYSTEM_EVENT_STA_DISCONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d\n", \ - disconnected->ssid, disconnected->ssid_len, disconnected->bssid[0], disconnected->bssid[0], disconnected->bssid[1], \ - disconnected->bssid[3], disconnected->bssid[4], disconnected->bssid[5], disconnected->reason); - break; - } - case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: - { - system_event_sta_authmode_change_t *auth_change; - auth_change = &event->event_info.auth_change; - WIFI_DEBUG("SYSTEM_EVENT_STA_AUTHMODE_CHNAGE\nold_mode:%d, new_mode:%d\n", auth_change->old_mode, auth_change->new_mode); - break; - } - case SYSTEM_EVENT_STA_GOTIP: - { - system_event_sta_got_ip_t *got_ip; - got_ip = &event->event_info.got_ip; - WIFI_DEBUG("SYSTEM_EVENT_STA_GOTIP\n"); - break; - } - case SYSTEM_EVENT_AP_START: - { - WIFI_DEBUG("SYSTEM_EVENT_AP_START\n"); - break; - } - case SYSTEM_EVENT_AP_STOP: - { - WIFI_DEBUG("SYSTEM_EVENT_AP_STOP\n"); - break; - } - case SYSTEM_EVENT_AP_STACONNECTED: - { - system_event_ap_staconnected_t *staconnected; - staconnected = &event->event_info.sta_connected; - WIFI_DEBUG("SYSTEM_EVENT_AP_STACONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \ - staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \ - staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid); - break; - } - case SYSTEM_EVENT_AP_STADISCONNECTED: - { - system_event_ap_stadisconnected_t *stadisconnected; - stadisconnected = &event->event_info.sta_disconnected; - WIFI_DEBUG("SYSTEM_EVENT_AP_STADISCONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \ - stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \ - stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid); - break; - } - case SYSTEM_EVENT_AP_PROBEREQRECVED: - { - system_event_ap_probe_req_rx_t *ap_probereqrecved; - ap_probereqrecved = &event->event_info.ap_probereqrecved; - WIFI_DEBUG("SYSTEM_EVENT_AP_PROBEREQRECVED\nrssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x\n", \ - ap_probereqrecved->rssi, ap_probereqrecved->mac[0], ap_probereqrecved->mac[0], ap_probereqrecved->mac[1], \ - ap_probereqrecved->mac[3], ap_probereqrecved->mac[4], ap_probereqrecved->mac[5]); - break; - } - default: - { - printf("Error: no such kind of event!\n"); - break; - } + case SYSTEM_EVENT_WIFI_READY: { + WIFI_DEBUG("SYSTEM_EVENT_WIFI_READY\n"); + break; + } + case SYSTEM_EVENT_SCAN_DONE: { + system_event_sta_scan_done_t *scan_done; + scan_done = &event->event_info.scan_done; + WIFI_DEBUG("SYSTEM_EVENT_SCAN_DONE\nstatus:%d, number:%d\n", scan_done->status, scan_done->number); + break; + } + case SYSTEM_EVENT_STA_START: { + WIFI_DEBUG("SYSTEM_EVENT_STA_START\n"); + break; + } + case SYSTEM_EVENT_STA_STOP: { + WIFI_DEBUG("SYSTEM_EVENT_STA_STOP\n"); + break; + } + case SYSTEM_EVENT_STA_CONNECTED: { + system_event_sta_connected_t *connected; + connected = &event->event_info.connected; + WIFI_DEBUG("SYSTEM_EVENT_STA_CONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d\n", \ + connected->ssid, connected->ssid_len, connected->bssid[0], connected->bssid[0], connected->bssid[1], \ + connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel, connected->authmode); + break; + } + case SYSTEM_EVENT_STA_DISCONNECTED: { + system_event_sta_disconnected_t *disconnected; + disconnected = &event->event_info.disconnected; + WIFI_DEBUG("SYSTEM_EVENT_STA_DISCONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d\n", \ + disconnected->ssid, disconnected->ssid_len, disconnected->bssid[0], disconnected->bssid[0], disconnected->bssid[1], \ + disconnected->bssid[3], disconnected->bssid[4], disconnected->bssid[5], disconnected->reason); + break; + } + case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: { + system_event_sta_authmode_change_t *auth_change; + auth_change = &event->event_info.auth_change; + WIFI_DEBUG("SYSTEM_EVENT_STA_AUTHMODE_CHNAGE\nold_mode:%d, new_mode:%d\n", auth_change->old_mode, auth_change->new_mode); + break; + } + case SYSTEM_EVENT_STA_GOT_IP: { + system_event_sta_got_ip_t *got_ip; + got_ip = &event->event_info.got_ip; + WIFI_DEBUG("SYSTEM_EVENT_STA_GOTIP\n"); + break; + } + case SYSTEM_EVENT_AP_START: { + WIFI_DEBUG("SYSTEM_EVENT_AP_START\n"); + break; + } + case SYSTEM_EVENT_AP_STOP: { + WIFI_DEBUG("SYSTEM_EVENT_AP_STOP\n"); + break; + } + case SYSTEM_EVENT_AP_STACONNECTED: { + system_event_ap_staconnected_t *staconnected; + staconnected = &event->event_info.sta_connected; + WIFI_DEBUG("SYSTEM_EVENT_AP_STACONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \ + staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \ + staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid); + break; + } + case SYSTEM_EVENT_AP_STADISCONNECTED: { + system_event_ap_stadisconnected_t *stadisconnected; + stadisconnected = &event->event_info.sta_disconnected; + WIFI_DEBUG("SYSTEM_EVENT_AP_STADISCONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \ + stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \ + stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid); + break; + } + case SYSTEM_EVENT_AP_PROBEREQRECVED: { + system_event_ap_probe_req_rx_t *ap_probereqrecved; + ap_probereqrecved = &event->event_info.ap_probereqrecved; + WIFI_DEBUG("SYSTEM_EVENT_AP_PROBEREQRECVED\nrssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x\n", \ + ap_probereqrecved->rssi, ap_probereqrecved->mac[0], ap_probereqrecved->mac[0], ap_probereqrecved->mac[1], \ + ap_probereqrecved->mac[3], ap_probereqrecved->mac[4], ap_probereqrecved->mac[5]); + break; + } + default: { + printf("Error: no such kind of event!\n"); + break; + } } return ESP_OK; @@ -296,8 +287,8 @@ static esp_err_t esp_system_event_handler(system_event_t *event) } esp_system_event_debug(event); - if ((event->event_id < SYSTEM_EVENT_MAX) && (event->event_id == g_system_event_handle_table[event->event_id].event_id)){ - if (g_system_event_handle_table[event->event_id].event_handle){ + if ((event->event_id < SYSTEM_EVENT_MAX) && (event->event_id == g_system_event_handle_table[event->event_id].event_id)) { + if (g_system_event_handle_table[event->event_id].event_handle) { WIFI_DEBUG("enter default callback\n"); g_system_event_handle_table[event->event_id].event_handle(event); WIFI_DEBUG("exit default callback\n"); @@ -317,42 +308,57 @@ static void esp_system_event_task(void *pvParameters) while (1) { if (xQueueReceive(g_event_handler, &evt, portMAX_DELAY) == pdPASS) { ret = esp_system_event_handler(&evt); - if (ret == ESP_FAIL) + if (ret == ESP_FAIL) { printf("esp wifi post event to user fail!\n"); + } } } } -system_event_cb_t esp_event_set_cb(system_event_cb_t cb) +system_event_cb_t esp_event_set_cb(system_event_cb_t cb, void *ctx) { system_event_cb_t old_cb = g_event_handler_cb; + g_event_handler_cb = cb; + g_event_ctx = ctx; + return old_cb; } esp_err_t esp_event_send(system_event_t *event) { portBASE_TYPE ret; - + ret = xQueueSendToBack((xQueueHandle)g_event_handler, event, 0); - if (pdPASS != ret){ - if (event) printf("e=%d f\n", event->event_id); - else printf("e null\n"); + + if (pdPASS != ret) { + if (event) { + printf("e=%d f\n", event->event_id); + } else { + printf("e null\n"); + } return ESP_FAIL; } return ESP_OK; } -void* esp_event_get_handler(void) +void *esp_event_get_handler(void) { - return (void*)g_event_handler; + return (void *)g_event_handler; } -esp_err_t esp_event_init(system_event_cb_t cb) +esp_err_t esp_event_init(system_event_cb_t cb, void *ctx) { - g_event_handler_cb = (system_event_cb_t)cb; + if (event_init_flag) { + return ESP_FAIL; + } + + g_event_handler_cb = cb; + g_event_ctx = ctx; + g_event_handler = xQueueCreate(CONFIG_WIFI_ENENT_QUEUE_SIZE, sizeof(system_event_t)); + xTaskCreatePinnedToCore(esp_system_event_task, "eventTask", CONFIG_WIFI_EVENT_TASK_STACK_SIZE, NULL, 5, NULL, 0); // TODO: rearrange task priority return ESP_OK; } diff --git a/components/esp32/include/esp_err.h b/components/esp32/include/esp_err.h index 39b60a905a..6ea176991c 100644 --- a/components/esp32/include/esp_err.h +++ b/components/esp32/include/esp_err.h @@ -27,7 +27,10 @@ typedef int32_t esp_err_t; #define ESP_OK 0 #define ESP_FAIL -1 -#define ESP_ERR_NO_MEM 0x101 +#define ESP_ERR_NO_MEM 0x101 +#define ESP_ERR_INVALID_ARG 0x102 +#define ESP_ERR_INVALID_STATE 0x103 + #ifdef __cplusplus } diff --git a/components/esp32/include/esp_event.h b/components/esp32/include/esp_event.h old mode 100755 new mode 100644 index 04a53636bb..0b61b70219 --- a/components/esp32/include/esp_event.h +++ b/components/esp32/include/esp_event.h @@ -28,24 +28,24 @@ extern "C" { #endif typedef enum { - SYSTEM_EVENT_WIFI_READY = 0, /**< ESP32 wifi ready */ + SYSTEM_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */ SYSTEM_EVENT_SCAN_DONE, /**< ESP32 finish scanning AP */ SYSTEM_EVENT_STA_START, /**< ESP32 station start */ - SYSTEM_EVENT_STA_STOP, /**< ESP32 station start */ + SYSTEM_EVENT_STA_STOP, /**< ESP32 station stop */ SYSTEM_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */ - SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected to AP */ + SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */ SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */ - SYSTEM_EVENT_STA_GOTIP, /**< ESP32 station received IP address */ - SYSTEM_EVENT_AP_START, /**< ESP32 softap start */ - SYSTEM_EVENT_AP_STOP, /**< ESP32 softap start */ + SYSTEM_EVENT_STA_GOT_IP, /**< ESP32 station got IP from connected AP */ + SYSTEM_EVENT_AP_START, /**< ESP32 soft-AP start */ + SYSTEM_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */ - SYSTEM_EVENT_AP_STADISCONNECTED, /**< a station disconnected to ESP32 soft-AP */ + SYSTEM_EVENT_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */ SYSTEM_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */ SYSTEM_EVENT_MAX } system_event_id_t; typedef struct { - uint32_t status; /**< status of scanning APs*/ + uint32_t status; /**< status of scanning APs */ uint8_t number; uint8_t scan_id; } system_event_sta_scan_done_t; @@ -94,10 +94,10 @@ typedef union { system_event_sta_disconnected_t disconnected; /**< ESP32 station disconnected to AP */ system_event_sta_scan_done_t scan_done; /**< ESP32 station scan (APs) done */ system_event_sta_authmode_change_t auth_change; /**< the auth mode of AP ESP32 station connected to changed */ - system_event_sta_got_ip_t got_ip; + system_event_sta_got_ip_t got_ip; /**< ESP32 station got IP */ system_event_ap_staconnected_t sta_connected; /**< a station connected to ESP32 soft-AP */ system_event_ap_stadisconnected_t sta_disconnected; /**< a station disconnected to ESP32 soft-AP */ - system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP32 softAP receive probe request packet */ + system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP32 soft-AP receive probe request packet */ } system_event_info_t; typedef struct { @@ -105,11 +105,65 @@ typedef struct { system_event_info_t event_info; /**< event information */ } system_event_t; -typedef esp_err_t (*system_event_cb_t)(system_event_t *event); -system_event_cb_t esp_event_set_cb(system_event_cb_t cb); -esp_err_t esp_event_send(system_event_t * event); -void* esp_event_get_handler(void); -esp_err_t esp_event_init(system_event_cb_t cb); +/** + * @brief Application specified event callback function + * + * @param void *ctx : reserved for user + * @param system_event_t *event : event type defined in this file + * + * @return ESP_OK : succeed + * @return others : fail + */ +typedef esp_err_t (*system_event_cb_t)(void *ctx, system_event_t *event); + +/** + * @brief Set application specified event callback function + * + * @attention 1. If cb is NULL, means application don't need to handle + * If cb is not NULL, it will be call when an event is received, after the default event callback is completed + * + * @param system_event_cb_t cb : callback + * @param void *ctx : reserved for user + * + * @return system_event_cb_t : old callback + */ +system_event_cb_t esp_event_set_cb(system_event_cb_t cb, void *ctx); + +/** + * @brief Send a event to event task + * + * @attention 1. Other task/modules, such as the TCPIP module, can call this API to send an event to event task + * + * @param system_event_t * event : event + * + * @return ESP_OK : succeed + * @return others : fail + */ +esp_err_t esp_event_send(system_event_t *event); + +/** + * @brief Get the event handler + * + * @attention : currently this API returns event queue handler, by this event queue, + * users can notice when WiFi has done something like scanning done, connected to AP or disconnected from AP. + * + * @param null + * + * @return void * : event queue pointer + */ +void *esp_event_get_handler(void); + +/** + * @brief Init the event module + * Create the event handler and task + * + * @param system_event_cb_t cb : application specified event callback, it can be modified by call esp_event_set_cb + * @param void *ctx : reserved for user + * + * @return ESP_OK : succeed + * @return others : fail + */ +esp_err_t esp_event_init(system_event_cb_t cb, void *ctx); #ifdef __cplusplus } diff --git a/components/esp32/include/esp_intr.h b/components/esp32/include/esp_intr.h index fc20838897..e138133f64 100644 --- a/components/esp32/include/esp_intr.h +++ b/components/esp32/include/esp_intr.h @@ -61,8 +61,8 @@ extern "C" { #define ESP_GPIO_INTR_ATTACH(func, arg) \ xt_set_interrupt_handler(ETS_GPIO_INUM, (func), (void *)(arg)) -#define ESP_UART_INTR_ATTACH(func, arg) \ - xt_set_interrupt_handler(ETS_UART_INUM, (func), (void *)(arg)) +#define ESP_UART0_INTR_ATTACH(func, arg) \ + xt_set_interrupt_handler(ETS_UART0_INUM, (func), (void *)(arg)) #define ESP_WDT_INTR_ATTACH(func, arg) \ xt_set_interrupt_handler(ETS_WDT_INUM, (func), (void *)(arg)) @@ -142,11 +142,11 @@ extern "C" { #define ESP_BB_INTR_DISABLE() \ ESP_INTR_DISABLE(ETS_BB_INUM) -#define ESP_UART_INTR_ENABLE() \ - ESP_INTR_ENABLE(ETS_UART_INUM) +#define ESP_UART0_INTR_ENABLE() \ + ESP_INTR_ENABLE(ETS_UART0_INUM) -#define ESP_UART_INTR_DISABLE() \ - ESP_INTR_DISABLE(ETS_UART_INUM) +#define ESP_UART0_INTR_DISABLE() \ + ESP_INTR_DISABLE(ETS_UART0_INUM) #define ESP_LEDC_INTR_ENABLE() \ ESP_INTR_ENABLE(ETS_LEDC_INUM) diff --git a/components/esp32/include/esp_ipc.h b/components/esp32/include/esp_ipc.h new file mode 100644 index 0000000000..a77b4932fe --- /dev/null +++ b/components/esp32/include/esp_ipc.h @@ -0,0 +1,88 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_IPC_H__ +#define __ESP_IPC_H__ + +#include + +typedef void (*esp_ipc_func_t)(void* arg); + +/** + * @brief Inter-processor call APIs + * + * FreeRTOS provides several APIs which can be used to communicate between + * different tasks, including tasks running on different CPUs. + * This module provides additional APIs to run some code on the other CPU. + * + * These APIs can only be used when FreeRTOS scheduler is running. + */ + + +/** + * @brief Initialize inter-processor call module. + * + * This function start two tasks, one on each CPU. These tasks are started + * with high priority. These tasks are normally inactive, waiting until one of + * the esp_ipc_call_* functions to be used. One of these tasks will be + * woken up to execute the callback provided to esp_ipc_call_nonblocking or + * esp_ipc_call_blocking. + */ +void esp_ipc_init(); + + +/** + * @brief Execute function on the given CPU + * + * This will wake a high-priority task on CPU indicated by cpu_id argument, + * and run func(arg) in the context of that task. + * This function returns as soon as the high-priority task is woken up. + * If another IPC call is already being executed, this function will also wait + * for it to complete. + * + * In single-core mode, returns ESP_ERR_INVALID_ARG for cpu_id 1. + * + * @param cpu_id CPU where function should be executed (0 or 1) + * @param func pointer to a function which should be executed + * @param arg arbitrary argument to be passed into function + * + * @return ESP_ERR_INVALID_ARG if cpu_id is invalid + * ESP_ERR_INVALID_STATE if FreeRTOS scheduler is not running + * ESP_OK otherwise + */ +esp_err_t esp_ipc_call(uint32_t cpu_id, esp_ipc_func_t func, void* arg); + + +/** + * @brief Execute function on the given CPU and wait for it to finish + * + * This will wake a high-priority task on CPU indicated by cpu_id argument, + * and run func(arg) in the context of that task. + * This function waits for func to return. + * + * In single-core mode, returns ESP_ERR_INVALID_ARG for cpu_id 1. + * + * @param cpu_id CPU where function should be executed (0 or 1) + * @param func pointer to a function which should be executed + * @param arg arbitrary argument to be passed into function + * + * @return ESP_ERR_INVALID_ARG if cpu_id is invalid + * ESP_ERR_INVALID_STATE if FreeRTOS scheduler is not running + * ESP_OK otherwise + */ +esp_err_t esp_ipc_call_blocking(uint32_t cpu_id, esp_ipc_func_t func, void* arg); + + + +#endif /* __ESP_IPC_H__ */ diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h old mode 100755 new mode 100644 index 357788225a..19ba856dea --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -12,6 +12,48 @@ // See the License for the specific language governing permissions and // limitations under the License. + +/* Notes about WiFi Programming + * + * The esp32 WiFi programming model can be depicted as following picture: + * + * + * default handler user handler + * ------------- --------------- --------------- + * | | event | | callback or | | + * | tcpip | ---------> | event | ----------> | application | + * | stack | | task | event | task | + * |-----------| |-------------| |-------------| + * /|\ | + * | | + * event | | + * | | + * | | + * --------------- | + * | | | + * | WiFi Driver |/__________________| + * | |\ API call + * | | + * |-------------| + * + * The WiFi driver can be consider as black box, it knows nothing about the high layer code, such as + * TCPIP stack, application task, event task etc, all it can do is to receive API call from high layer + * or post event queue to a specified Queue, which is initialized by API esp_wifi_init(). + * + * The event task is a daemon task, which receives events from WiFi driver or from other subsystem, such + * as TCPIP stack, event task will call the default callback function on receiving the event. For example, + * on receiving event SYSTEM_EVENT_STA_CONNECTED, it will call tcpip_adapter_start() to start the DHCP + * client in it's default handler. + * + * Application can register it's own event callback function by API esp_event_init, then the application callback + * function will be called after the default callback. Also, if application doesn't want to execute the callback + * in the event task, what it needs to do is to post the related event to application task in the application callback function. + * + * The application task (code) generally mixes all these thing together, it calls APIs to init the system/WiFi and + * handle the events when necessary. + * + */ + #ifndef __ESP_WIFI_H__ #define __ESP_WIFI_H__ @@ -40,10 +82,10 @@ typedef enum { } wifi_interface_t; typedef enum { - WIFI_COUNTRY_CN = 0, - WIFI_COUNTRY_JP, - WIFI_COUNTRY_US, - WIFI_COUNTRY_EU, + WIFI_COUNTRY_CN = 0, /**< country China, channel range [1, 14] */ + WIFI_COUNTRY_JP, /**< country Japan, channel range [1, 14] */ + WIFI_COUNTRY_US, /**< country USA, channel range [1, 11] */ + WIFI_COUNTRY_EU, /**< country Europe, channel range [1, 13] */ WIFI_COUNTRY_MAX } wifi_country_t; @@ -89,54 +131,205 @@ enum { }; typedef enum { - WIFI_SECOND_CHAN_NONE = 0, - WIFI_SECOND_CHAN_ABOVE, - WIFI_SECOND_CHAN_BELOW, + WIFI_SECOND_CHAN_NONE = 0, /**< the channel width is HT20 */ + WIFI_SECOND_CHAN_ABOVE, /**< the channel width is HT40 and the second channel is above the primary channel */ + WIFI_SECOND_CHAN_BELOW, /**< the channel width is HT40 and the second channel is below the primary channel */ } wifi_second_chan_t; -typedef esp_err_t (* wifi_startup_cb_t)(void); +/** + * @brief startup WiFi driver and register application specific callback function + * + * @attention 1. This API should be called in application startup code to init WiFi driver + * @attention 2. The callback function is used to provide application specific WiFi configuration, + * such as, set the WiFi mode, register the event callback, set AP SSID etc before + * WiFi is startup + * @attention 3. Avoid to create application task in the callback, otherwise you may get wrong behavior + * @attention 4. If the callback return is not ESP_OK, the startup will fail! + * @attention 5. Before this API can be called, system_init()/esp_event_init()/tcpip_adapter_init() should + * be called firstly + * + * @param wifi_startup_cb_t cb : application specific callback function + * @param void *ctx : reserved for user + * + * @return ESP_OK : succeed + * @return others : fail + */ +typedef esp_err_t (* wifi_startup_cb_t)(void *ctx); -void esp_wifi_startup(wifi_startup_cb_t cb); +esp_err_t esp_wifi_startup(wifi_startup_cb_t cb, void *ctx); typedef struct { - void *event_q; + void *event_q; /**< WiFi event q handler, it's a freeRTOS queue */ uint8_t rx_ba_win; /**< TBC */ uint8_t tx_ba_win; /**< TBC */ uint8_t rx_buf_cnt; /**< TBC */ uint8_t tx_buf_cnt; /**< TBC */ } wifi_init_config_t; +/** + * @brief Init WiFi + * Alloc resource for WiFi driver, such as WiFi control structure, RX/TX buffer, + * WiFi NVS structure etc, this WiFi also start WiFi task + * + * @attention 1. This API must be called before all other WiFi API can be called + * @attention 2. Generally we should init event_q in *config, WiFi driver will post the event + * to this queue when event happens, such as, when station connects to WiFi, WiFi driver + * will post station connected event to this queue. If the queue is not initialized, WiFi + * will not post any events + * @attention 3. For other parameters, currently it's not ready, just ignore it. + * + * @param wifi_init_config_t *config : provide WiFi init configuration + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_init(wifi_init_config_t *config); +/** + * @brief Deinit WiFi + * Free all resource allocated in esp_wifi_init and stop WiFi task + * + * @attention 1. This API should be called if you want to remove WiFi driver from the system + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_deinit(void); +/** + * @brief Set the WiFi operating mode + * + * Set the WiFi operating mode as station, soft-AP or station+soft-AP, + * The default mode is soft-AP mode. + * + * @param wifi_mode_t mode : WiFi operating modes: + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_mode(wifi_mode_t mode); +/** + * @brief Get current operating mode of WiFi + * + * @param wifi_mode_t *mode : store current WiFi mode + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode); +/** + * @brief Start WiFi according to current configuration + * If mode is WIFI_MODE_STA, it create station control block and start station + * If mode is WIFI_MODE_AP, it create soft-AP control block and start soft-AP + * If mode is WIFI_MODE_APSTA, it create soft-AP and station control block and start soft-AP and station + * + * @param null + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_start(void); +/** + * @brief Stop WiFi + If mode is WIFI_MODE_STA, it stop station and free station control block + * If mode is WIFI_MODE_AP, it stop soft-AP and free soft-AP control block + * If mode is WIFI_MODE_APSTA, it stop station/soft-AP and free station/soft-AP control block + * + * @param null + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_stop(void); +/** + * @brief Connect the ESP32 WiFi station to the AP. + * + * @attention 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode + * @attention 2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect. + * + * @param null + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_connect(void); +/** + * @brief Disconnect the ESP32 WiFi station from the AP. + * + * @param null + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_disconnect(void); +/** + * @brief Currently this API is just an stub API + * + * @param null + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_clear_fast_connect(void); +/** + * @brief Kick the all station or associated id equals to aid + * + * @param uint16_t aid : when aid is 0, kick all stations, otherwise kick station whose associated id is aid + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_kick_station(uint16_t aid); typedef struct { char *ssid; /**< SSID of AP */ uint8_t *bssid; /**< MAC address of AP */ uint8_t channel; /**< channel, scan the specific channel */ - bool show_hidden; /**< enable to scan AP whose SSID is hidden */ + bool show_hidden; /**< enable to scan AP whose SSID is hidden */ } wifi_scan_config_t; +/** + * @brief Scan all available APs. + * + * @attention If this API is called, the found APs are stored in WiFi driver dynamic allocated memory and the + * will be freed in esp_wifi_get_ap_list, so generally, call esp_wifi_get_ap_list to cause + * the memory to be freed once the scan is done + * + * @param struct scan_config *config : configuration of scanning + * @param bool block : if block is true, this API will block the caller until the scan is done, otherwise + * it will return immediately + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf, bool block); +/** + * @brief Stop the scan in process + * + * @param null + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_scan_stop(void); +/** + * @brief Get number of APs found in last scan + * + * @param uint16_t *number : store number of APIs found in last scan + * + * @attention This API can only be called when the scan is completed, otherwise it may get wrong value + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_ap_num(uint16_t *number); typedef struct { @@ -144,58 +337,226 @@ typedef struct { uint8_t ssid[32]; /**< SSID of AP */ uint8_t primary; /**< channel of AP */ wifi_second_chan_t second; /**< second channel of AP */ - signed char rssi; /**< signal strength of AP */ + int8_t rssi; /**< signal strength of AP */ wifi_auth_mode_t authmode; /**< authmode of AP */ -}wifi_ap_list_t; +} wifi_ap_list_t; +/** + * @brief Get AP list found in last scan + * + * @param uint16_t *number : as input param, it stores max AP number ap_list can hold, as output param, it store + the actual AP number this API returns + * @param wifi_ap_list_t *ap_list : a list to hold the found APs + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_ap_list(uint16_t *number, wifi_ap_list_t *ap_list); typedef enum { - WIFI_PS_NONE, - WIFI_PS_MODEM, - WIFI_PS_LIGHT, - WIFI_PS_MAC, + WIFI_PS_NONE, /**< No power save */ + WIFI_PS_MODEM, /**< Modem power save */ + WIFI_PS_LIGHT, /**< Light power save */ + WIFI_PS_MAC, /**< MAC power save */ } wifi_ps_type_t; +/** + * @brief Set current power save type + * + * @param wifi_ps_type_t type : power save type + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_ps(wifi_ps_type_t type); +/** + * @brief Get current power save type + * + * @param wifi_ps_type_t *type : store current power save type + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type); #define WIFI_PROTOCOL_11B 1 #define WIFI_PROTOCOL_11G 2 #define WIFI_PROTOCOL_11N 4 -esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol); +/** + * @brief Set protocol type of specified interface + * The default protocol is (WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N) + * + * @attention Currently we only support 802.11b or 802.11bg or 802.11bgn mode + * + * @param wifi_interface_t ifx : interfaces + * @param uint8_t protocol : WiFi protocol bitmap + * + * @return ESP_OK : succeed + * @return others : fail + */ +esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap); -esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol); +/** + * @brief Get the current protocol bitmap of specified ifx + * + * @param wifi_interface_t ifx : interfaces + * @param uint8_t protocol : store current WiFi protocol bitmap of interface ifx + * + * @return ESP_OK : succeed + * @return others : fail + */ +esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap); typedef enum { - WIFI_BW_HT20 = 0, - WIFI_BW_HT40, + WIFI_BW_HT20 = 0, /* Bandwidth is HT20 */ + WIFI_BW_HT40, /* Bandwidth is HT40 */ } wifi_bandwidth_t; +/** + * @brief Set the bandwidth of ESP32 specified interface + * + * @attention 1. API return false if try to configure a interface that is not enable + * @attention 2. WIFI_BW_HT40 is supported only when the interface support 11N + * + * @param wifi_interface_t ifx : interface to be configured + * @param wifi_bandwidth_t bw : bandwidth + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw); +/** + * @brief Get the bandwidth of ESP32 specified interface + * + * @attention 1. API return false if try to get a interface that is not enable + * + * @param wifi_interface_t ifx : interface to be configured + * @param wifi_bandwidth_t *bw : store bandwidth of interface ifx + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw); +/** + * @brief Set primary/second channel of ESP32 + * + * @attention 1. This is a special API for sniffer + * + * @param uint8_t primary : for HT20, primary is the channel number, for HT40, primary is the primary channel + * @param wifi_second_chan_t second : for HT20, second is ignored, for HT40, second is the second channel + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second); +/** + * @brief Get the primary/second channel of ESP32 + * + * @attention 1. API return false if try to get a interface that is not enable + * + * @param uint8_t *primary : store current primary channel + * @param wifi_second_chan_t *second : store current second channel + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); +/** + * @brief Set country code + * The default value is WIFI_COUNTRY_CN + * + * @param wifi_country_t country : country type + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_country(wifi_country_t country); +/** + * @brief Get country code + * + * @param wifi_country_t country : store current country + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_country(wifi_country_t *country); +/** + * @brief Set MAC address of the ESP32 WiFi station or the soft-AP interface. + * + * @attention 1. This API can only be called when the interface is disabled + * @attention 2. ESP32 soft-AP and station have different MAC addresses, do not set them to be the same. + * - The bit0 of the first byte of ESP32 MAC address can not be 1. For example, the MAC address + * can set to be "1a:XX:XX:XX:XX:XX", but can not be "15:XX:XX:XX:XX:XX". + * + * @param wifi_interface_t ifx : interface + * @param uint8 mac[6]: the MAC address. + * + * @return true : succeed + * @return false : fail + */ esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6]); +/** + * @brief Get mac of specified interface + * + * @param uint8_t mac[6] : store mac of this interface ifx + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]); +/** + * @brief The RX callback function in the promiscuous mode. + * + * Each time a packet is received, the callback function will be called. + * + * @param void *buf : the data received + * @param uint16_t len : data length + * + * @return ESP_OK : succeed + * @return others : fail + */ typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len); +/** + * @brief Register the RX callback function in the promiscuous mode. + * + * Each time a packet is received, the registered callback function will be called. + * + * @param wifi_promiscuous_cb_t cb : callback + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); +/** + * @brief Enable the promiscuous mode. + * + * @param uint8 promiscuous : 0 - disable / 1 - enable + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_promiscuous(uint8_t enable); +/** + * @brief Get the promiscuous mode. + * + * @param uint8 *enable : store the current status of promiscuous mode + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_promiscuous(uint8_t *enable); typedef struct { @@ -206,7 +567,7 @@ typedef struct { wifi_auth_mode_t authmode; /**< Auth mode of ESP32 soft-AP. Do not support AUTH_WEP in soft-AP mode */ uint8_t ssid_hidden; /**< Broadcast SSID or not, default 0, broadcast the SSID */ uint8_t max_connection; /**< Max number of stations allowed to connect in, default 4, max 4 */ - uint16_t beacon_interval; /**< Beacon interval, 100 ~ 60000 ms, default 100 */ + uint16_t beacon_interval; /**< Beacon interval, 100 ~ 60000 ms, default 100 ms */ } wifi_ap_config_t; typedef struct { @@ -217,12 +578,35 @@ typedef struct { } wifi_sta_config_t; typedef union { - wifi_ap_config_t ap; - wifi_sta_config_t sta; + wifi_ap_config_t ap; /**< configuration of AP */ + wifi_sta_config_t sta; /**< configuration of STA */ } wifi_config_t; +/** + * @brief Set the configuration of the ESP32 STA or AP + * + * @attention 1. This API can be called only when specified interface is enabled, otherwise, API fail + * @attention 2. For station configuration, bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP. + * @attention 3. ESP32 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as + * the channel of the ESP32 station. + * + * @param wifi_interface_t ifx : interface + * @param wifi_config_t *conf : station or soft-AP configuration + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf); +/** + * @brief Get configuration of specified interface + * + * @param wifi_interface_t ifx : interface + * @param wifi_config_t *conf : station or soft-AP configuration + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf); struct station_info { @@ -230,23 +614,79 @@ struct station_info { uint8_t bssid[6]; }; +/** + * @brief Get STAs associated with soft-AP + * + * @attention SSC only API + * + * @param struct station_info **station : station list + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_station_list(struct station_info **station); esp_err_t esp_wifi_free_station_list(void); typedef enum { - WIFI_STORAGE_RAM, - WIFI_STORAGE_FLASH, + WIFI_STORAGE_FLASH, /**< all configuration will strore in both memory and flash */ + WIFI_STORAGE_RAM, /**< all configuration will only store in the memory */ } wifi_storage_t; +/** + * @brief Set the WiFi API configuration storage type + * + * @attention 1. The default value is WIFI_STORAGE_FLASH + * + * @param wifi_storage_t storage : storage type + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_storage(wifi_storage_t storage); -typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void* eb); +/** + * @brief The WiFi RX callback function + * + * Each time the WiFi need to forward the packets to high layer, the callback function will be called + * + */ +typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void *eb); +/** + * @brief Set the WiFi RX callback + * + * @attention 1. Currently we support only one RX callback for each interface + * + * @param wifi_interface_t ifx : interface + * @param wifi_rxcb_t fn : WiFi RX callback + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn); +/** + * @brief Set auto connect + * The default value is true + * + * @attention 1. + * + * @param bool en : true - enable auto connect / false - disable auto connect + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_set_auto_connect(bool en); +/** + * @brief Get the auto connect flag + * + * @param bool *en : store current auto connect configuration + * + * @return ESP_OK : succeed + * @return others : fail + */ esp_err_t esp_wifi_get_auto_connect(bool *en); #ifdef __cplusplus diff --git a/components/esp32/include/rom/aes.h b/components/esp32/include/rom/aes.h index 9fd0e5baea..d81d8f6f9b 100644 --- a/components/esp32/include/rom/aes.h +++ b/components/esp32/include/rom/aes.h @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #ifndef _ROM_AES_H_ #define _ROM_AES_H_ @@ -21,6 +22,7 @@ extern "C" { #endif +//TODO, add comment for aes apis enum AES_BITS { AES128, AES192, @@ -32,8 +34,8 @@ void ets_aes_enable(void); void ets_aes_disable(void); void ets_aes_set_endian(bool key_word_swap, bool key_byte_swap, - bool in_word_swap, bool in_byte_swap, - bool out_word_swap, bool out_byte_swap); + bool in_word_swap, bool in_byte_swap, + bool out_word_swap, bool out_byte_swap); bool ets_aes_setkey_enc(const uint8_t *key, enum AES_BITS bits); diff --git a/components/esp32/include/rom/bigint.h b/components/esp32/include/rom/bigint.h index 461469cacd..ab4246c6da 100644 --- a/components/esp32/include/rom/bigint.h +++ b/components/esp32/include/rom/bigint.h @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #ifndef _ROM_BIGINT_H_ #define _ROM_BIGINT_H_ @@ -21,6 +22,7 @@ extern "C" { #endif +//TODO: add comment here void ets_bigint_enable(void); void ets_bigint_disable(void); diff --git a/components/esp32/include/rom/cache.h b/components/esp32/include/rom/cache.h index b9e59448f1..fb84bca03c 100644 --- a/components/esp32/include/rom/cache.h +++ b/components/esp32/include/rom/cache.h @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #ifndef _ROM_CACHE_H_ #define _ROM_CACHE_H_ @@ -18,50 +19,126 @@ extern "C" { #endif -//=========================================== -// function : cache_init -// description: initialise cache mmu, mark all entries as invalid. -// conditions: -// Call Cache_Read_Disable() before calling this function. -// inputs: -// cpu_no is CPU number,0(PRO CPU) or 1(APP CPU), -// output: NONE -//=========================================== +/** \defgroup uart_apis, uart configuration and communication related apis + * @brief uart apis + */ + +/** @addtogroup uart_apis + * @{ + */ + +/** + * @brief Initialise cache mmu, mark all entries as invalid. + * Please do not call this function in your SDK application. + * + * @param int cpu_no : 0 for PRO cpu, 1 for APP cpu. + * + * @return None + */ void mmu_init(int cpu_no); -//=========================================== -// function : cache_flash_mmu_set -// description: Configure MMU to cache a flash region. -// conditions: -// Call this function to configure the flash cache before enabling it. -// Check return value to verify MMU was set correctly. -// inputs: -// cpu_no is CPU number,0(PRO CPU) or 1(APP CPU), -// pid is process identifier. Range 0~7 -// vaddr is "virtual" address in CPU address space. Can be IRam0, IRam1, IRom0 and DRom0 memory address. -// Should be aligned by psize -// paddr is "physical" address in flash controller's address space. -// ie for 16M flash the range is 0x000000~0xFFFFFF. Should be aligned by psize -// psize is page size of flash, in kilobytes. Can be 64, 32, 16. -// num is number of pages to be set, valid range 0 ~ (flash size)/(page size) -// output: error status -// 0 : mmu set success -// 1 : vaddr or paddr is not aligned -// 2 : pid error -// 3 : psize error -// 4 : mmu table to be written is out of range -// 5 : vaddr is out of range -//=========================================== +/** + * @brief Set Flash-Cache mmu mapping. + * Please do not call this function in your SDK application. + * + * @param int cpu_no : CPU number, 0 for PRO cpu, 1 for APP cpu. + * + * @param int pod : process identifier. Range 0~7. + * + * @param unsigned int vaddr : virtual address in CPU address space. + * Can be IRam0, IRam1, IRom0 and DRom0 memory address. + * Should be aligned by psize. + * + * @param unsigned int paddr : physical address in Flash. + * Should be aligned by psize. + * + * @param int psize : page size of flash, in kilobytes. Should be 64 here. + * + * @param int num : pages to be set. + * + * @return unsigned int: error status + * 0 : mmu set success + * 1 : vaddr or paddr is not aligned + * 2 : pid error + * 3 : psize error + * 4 : mmu table to be written is out of range + * 5 : vaddr is out of range + */ unsigned int cache_flash_mmu_set(int cpu_no, int pid, unsigned int vaddr, unsigned int paddr, int psize, int num); -unsigned int cache_sram_mmu_set(int cpu_no, int pid,unsigned int vaddr, unsigned int paddr, int psize, int num); +/** + * @brief Set Ext-SRAM-Cache mmu mapping. + * Please do not call this function in your SDK application. + * + * @param int cpu_no : CPU number, 0 for PRO cpu, 1 for APP cpu. + * + * @param int pod : process identifier. Range 0~7. + * + * @param unsigned int vaddr : virtual address in CPU address space. + * Can be IRam0, IRam1, IRom0 and DRom0 memory address. + * Should be aligned by psize. + * + * @param unsigned int paddr : physical address in Ext-SRAM. + * Should be aligned by psize. + * + * @param int psize : page size of flash, in kilobytes. Should be 32 here. + * + * @param int num : pages to be set. + * + * @return unsigned int: error status + * 0 : mmu set success + * 1 : vaddr or paddr is not aligned + * 2 : pid error + * 3 : psize error + * 4 : mmu table to be written is out of range + * 5 : vaddr is out of range + */ +unsigned int cache_sram_mmu_set(int cpu_no, int pid, unsigned int vaddr, unsigned int paddr, int psize, int num); +/** + * @brief Initialise cache access for the cpu. + * Please do not call this function in your SDK application. + * + * @param int cpu_no : 0 for PRO cpu, 1 for APP cpu. + * + * @return None + */ void Cache_Read_Init(int cpu_no); +/** + * @brief Flush the cache value for the cpu. + * Please do not call this function in your SDK application. + * + * @param int cpu_no : 0 for PRO cpu, 1 for APP cpu. + * + * @return None + */ +void Cache_Flush(int cpu_no); + +/** + * @brief Disable Cache access for the cpu. + * Please do not call this function in your SDK application. + * + * @param int cpu_no : 0 for PRO cpu, 1 for APP cpu. + * + * @return None + */ void Cache_Read_Disable(int cpu_no); +/** + * @brief Enable Cache access for the cpu. + * Please do not call this function in your SDK application. + * + * @param int cpu_no : 0 for PRO cpu, 1 for APP cpu. + * + * @return None + */ void Cache_Read_Enable(int cpu_no); +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/components/esp32/include/rom/crc.h b/components/esp32/include/rom/crc.h index be763d7dc5..84e17882de 100644 --- a/components/esp32/include/rom/crc.h +++ b/components/esp32/include/rom/crc.h @@ -11,20 +11,113 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #ifndef ROM_CRC_H #define ROM_CRC_H +#include + #ifdef __cplusplus extern "C" { #endif +/** \defgroup uart_apis, uart configuration and communication related apis + * @brief uart apis + */ + +/** @addtogroup uart_apis + * @{ + */ + + /* Standard CRC8/16/32 algorithms. */ -uint32_t crc32_le(uint32_t crc, uint8_t const * buf, uint32_t len); -uint32_t crc32_be(uint32_t crc, uint8_t const * buf, uint32_t len); -uint16_t crc16_le(uint16_t crc, uint8_t const * buf, uint32_t len); -uint16_t crc16_be(uint16_t crc, uint8_t const * buf, uint32_t len); -uint8_t crc8_le(uint8_t crc, uint8_t const * buf, uint32_t len); -uint8_t crc8_be(uint8_t crc, uint8_t const * buf, uint32_t len); +// CRC-8 x8+x2+x1+1 0x07 +// CRC16-CCITT x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS +// CRC32: +//G(x) = x32 +x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x1 + 1 +//If your buf is not continuous, you can use the first result to be the second parameter. + +/** + * @brief Crc32 value that is in little endian. + * + * @param uint32_t crc : init crc value, use 0 at the first use. + * + * @param uint8_t const *buf : buffer to start calculate crc. + * + * @param uint32_t len : buffer length in byte. + * + * @return None + */ +uint32_t crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len); + +/** + * @brief Crc32 value that is in big endian. + * + * @param uint32_t crc : init crc value, use 0 at the first use. + * + * @param uint8_t const *buf : buffer to start calculate crc. + * + * @param uint32_t len : buffer length in byte. + * + * @return None + */ +uint32_t crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len); + +/** + * @brief Crc16 value that is in little endian. + * + * @param uint16_t crc : init crc value, use 0 at the first use. + * + * @param uint8_t const *buf : buffer to start calculate crc. + * + * @param uint32_t len : buffer length in byte. + * + * @return None + */ +uint16_t crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len); + +/** + * @brief Crc16 value that is in big endian. + * + * @param uint16_t crc : init crc value, use 0 at the first use. + * + * @param uint8_t const *buf : buffer to start calculate crc. + * + * @param uint32_t len : buffer length in byte. + * + * @return None + */ +uint16_t crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len); + +/** + * @brief Crc8 value that is in little endian. + * + * @param uint8_t crc : init crc value, use 0 at the first use. + * + * @param uint8_t const *buf : buffer to start calculate crc. + * + * @param uint32_t len : buffer length in byte. + * + * @return None + */ +uint8_t crc8_le(uint8_t crc, uint8_t const *buf, uint32_t len); + +/** + * @brief Crc8 value that is in big endian. + * + * @param uint32_t crc : init crc value, use 0 at the first use. + * + * @param uint8_t const *buf : buffer to start calculate crc. + * + * @param uint32_t len : buffer length in byte. + * + * @return None + */ +uint8_t crc8_be(uint8_t crc, uint8_t const *buf, uint32_t len); + +/** + * @} + */ #ifdef __cplusplus } diff --git a/components/esp32/include/rom/efuse.h b/components/esp32/include/rom/efuse.h index 6d0252b5e4..58cfdb20bc 100644 --- a/components/esp32/include/rom/efuse.h +++ b/components/esp32/include/rom/efuse.h @@ -11,17 +11,100 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #ifndef _ROM_EFUSE_H_ #define _ROM_EFUSE_H_ +#include + #ifdef __cplusplus extern "C" { #endif +/** \defgroup efuse_APIs efuse APIs + * @brief ESP32 efuse read/write APIs + * @attention + * + */ + +/** @addtogroup efuse_APIs + * @{ + */ + +/** + * @brief Do a efuse read operation, to update the efuse value to efuse read registers. + * + * @param null + * + * @return null + */ void ets_efuse_read_op(void); +/** + * @brief Do a efuse write operation, to update efuse write registers to efuse, then you need call ets_efuse_read_op again. + * + * @param null + * + * @return null + */ void ets_efuse_program_op(void); +/** + * @brief Read 8M Analog Clock value(8 bit) in efuse, the analog clock will not change with temperature. + * It can be used to test the external xtal frequency, do not touch this efuse field. + * + * @param null + * + * @return u32: 1 for 100KHZ, range is 0 to 255. + */ +uint32_t ets_efuse_get_8M_clock(void); + +/** + * @brief Read spi pad configuration, show gpio number of flash pad, includes 5 pads. + * + * @param null + * + * @return uint32_t: 0, invalid, flash pad decided by strapping + * else, bit[5:0] spiclk, bit[11:6] spiq, bit[17:12] spid, bit[23:18] spics0, bit[29:24] spihd + */ +uint32_t ets_efuse_get_spiconfig(void); + +#define EFUSE_SPICONFIG_RET_SPICLK_MASK 0x3f +#define EFUSE_SPICONFIG_RET_SPICLK_SHIFT 0 +#define EFUSE_SPICONFIG_RET_SPICLK(ret) (((ret) >> EFUSE_SPICONFIG_RET_SPICLK_SHIFT) & EFUSE_SPICONFIG_RET_SPICLK_MASK) + +#define EFUSE_SPICONFIG_RET_SPIQ_MASK 0x3f +#define EFUSE_SPICONFIG_RET_SPIQ_SHIFT 6 +#define EFUSE_SPICONFIG_RET_SPIQ(ret) (((ret) >> EFUSE_SPICONFIG_RET_SPIQ_SHIFT) & EFUSE_SPICONFIG_RET_SPIQ_MASK) + +#define EFUSE_SPICONFIG_RET_SPID_MASK 0x3f +#define EFUSE_SPICONFIG_RET_SPID_SHIFT 12 +#define EFUSE_SPICONFIG_RET_SPID(ret) (((ret) >> EFUSE_SPICONFIG_RET_SPID_SHIFT) & EFUSE_SPICONFIG_RET_SPID_MASK) + +#define EFUSE_SPICONFIG_RET_SPICS0_MASK 0x3f +#define EFUSE_SPICONFIG_RET_SPICS0_SHIFT 18 +#define EFUSE_SPICONFIG_RET_SPICS0(ret) (((ret) >> EFUSE_SPICONFIG_RET_SPICS0_SHIFT) & EFUSE_SPICONFIG_RET_SPICS0_MASK) + + +#define EFUSE_SPICONFIG_RET_SPIHD_MASK 0x3f +#define EFUSE_SPICONFIG_RET_SPIHD_SHIFT 24 +#define EFUSE_SPICONFIG_RET_SPIHD(ret) (((ret) >> EFUSE_SPICONFIG_RET_SPIHD_SHIFT) & EFUSE_SPICONFIG_RET_SPIHD_MASK) + +/** + * @brief A crc8 algorithm used in efuse check. + * + * @param unsigned char const *p : Pointer to original data. + * + * @param unsigned int len : Data length in byte. + * + * @return unsigned char: Crc value. + */ +unsigned char esp_crc8(unsigned char const *p, unsigned int len); + +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/components/esp32/include/rom/ets_sys.h b/components/esp32/include/rom/ets_sys.h index fd7bbdb9c4..c412c9b41f 100644 --- a/components/esp32/include/rom/ets_sys.h +++ b/components/esp32/include/rom/ets_sys.h @@ -24,82 +24,242 @@ extern "C" { #endif -#define ETS_DEBUG -#define ETS_SERIAL_ENABLED() (1) +/** \defgroup ets_sys_apis, ets system related apis + * @brief ets system apis + */ + +/** @addtogroup ets_sys_apis + * @{ + */ + +/************************************************************************ + * NOTE + * Many functions in this header files can't be run in FreeRTOS. + * Please see the comment of the Functions. + * There are also some functions that doesn't work on FreeRTOS + * without listed in the header, such as: + * xtos functions start with "_xtos_" in ld file. + * + *********************************************************************** + */ + +/** \defgroup ets_apis, Espressif Task Scheduler related apis + * @brief ets apis + */ + +/** @addtogroup ets_apis + * @{ + */ typedef enum { - ETS_OK = 0, - ETS_FAILED = 1 + ETS_OK = 0, /**< return successful in ets*/ + ETS_FAILED = 1 /**< return failed in ets*/ } ETS_STATUS; typedef uint32_t ETSSignal; typedef uint32_t ETSParam; -typedef struct ETSEventTag ETSEvent; +typedef struct ETSEventTag ETSEvent; /**< Event transmit/receive in ets*/ struct ETSEventTag { - ETSSignal sig; - ETSParam par; + ETSSignal sig; /**< Event signal, in same task, different Event with different signal*/ + ETSParam par; /**< Event parameter, sometimes without usage, then will be set as 0*/ }; -typedef void (*ETSTask)(ETSEvent *e); - -enum ETS_User_Priorities { - /* task priorities... */ - TICK_TASK_A_PRIO = 2, - KBD_TASK_PRIO = 5, - MAX_ETS_USER_PRIO = 16, - - /* ISR priorities... */ - MAX_ETS_USER_ISR_PRIO = 0xFF - 16 -}; - -/* ETS interrupt entry and exit */ -/* actually we don't need the following 2 macros any more since we won't exit - * isr until it is finised, more over, we don't do nest interrupt - */ +typedef void (*ETSTask)(ETSEvent *e); /**< Type of the Task processer*/ +typedef void (* ets_idle_cb_t)(void *arg); /**< Type of the system idle callback*/ +/** + * @brief Start the Espressif Task Scheduler, which is an infinit loop. Please do not add code after it. + * + * @param none + * + * @return none + */ void ets_run(void); +/** + * @brief Set the Idle callback, when Tasks are processed, will call the callback before CPU goto sleep. + * + * @param ets_idle_cb_t func : The callback function. + * + * @param void *arg : Argument of the callback. + * + * @return None + */ +void ets_set_idle_cb(ets_idle_cb_t func, void *arg); + +/** + * @brief Init a task with processer, priority, queue to receive Event, queue length. + * + * @param ETSTask task : The task processer. + * + * @param uint8_t prio : Task priority, 0-31, bigger num with high priority, one priority with one task. + * + * @param ETSEvent *queue : Queue belongs to the task, task always receives Events, Queue is circular used. + * + * @param uint8_t qlen : Queue length. + * + * @return None + */ void ets_task(ETSTask task, uint8_t prio, ETSEvent *queue, uint8_t qlen); -ETS_STATUS ets_post(uint8_t prio, ETSSignal sig, ETSParam par); +/** + * @brief Post an event to an Task. + * + * @param uint8_t prio : Priority of the Task. + * + * @param ETSSignal sig : Event signal. + * + * @param ETSParam par : Event parameter + * + * @return ETS_OK : post successful + * @return ETS_FAILED : post failed + */ +ETS_STATUS ets_post(uint8_t prio, ETSSignal sig, ETSParam par); -/* - * now things become complicated, print could be directed to uart and/or SDIO - */ +/** + * @} + */ + +/** \defgroup ets_boot_apis, Boot routing related apis + * @brief ets boot apis + */ + +/** @addtogroup ets_apis + * @{ + */ + +extern const char *const exc_cause_table[40]; ///**< excption cause that defined by the core.*/ + +/** + * @brief Set Pro cpu Entry code, code can be called in PRO CPU when booting is not completed. + * When Pro CPU booting is completed, Pro CPU will call the Entry code if not NULL. + * + * @param uint32_t start : the PRO Entry code address value in uint32_t + * + * @return None + */ +void ets_set_user_start(uint32_t start); + +/** + * @brief Set Pro cpu Startup code, code can be called when booting is not completed, or in Entry code. + * When Entry code completed, CPU will call the Startup code if not NULL, else call ets_run. + * + * @param uint32_t callback : the Startup code address value in uint32_t + * + * @return None : post successful + */ +void ets_set_startup_callback(uint32_t callback); + +/** + * @brief Set App cpu Entry code, code can be called in PRO CPU. + * When APP booting is completed, APP CPU will call the Entry code if not NULL. + * + * @param uint32_t start : the APP Entry code address value in uint32_t, stored in register APPCPU_CTRL_REG_D. + * + * @return None + */ +void ets_set_appcpu_boot_addr(uint32_t start); + +/** + * @brief unpack the image in flash to iram and dram, no using cache. + * + * @param uint32_t pos : Flash physical address. + * + * @param uint32_t *entry_addr: the pointer of an variable that can store Entry code address. + * + * @param bool jump : Jump into the code in the function or not. + * + * @param bool config : Config the flash when unpacking the image, config should be done only once. + * + * @return ETS_OK : unpack successful + * @return ETS_FAILED : unpack failed + */ +ETS_STATUS ets_unpack_flash_code_legacy(uint32_t pos, uint32_t *entry_addr, bool jump, bool config); + +/** + * @brief unpack the image in flash to iram and dram, using cache, maybe decrypting. + * + * @param uint32_t pos : Flash physical address. + * + * @param uint32_t *entry_addr: the pointer of an variable that can store Entry code address. + * + * @param bool jump : Jump into the code in the function or not. + * + * @param bool sb_need_check : Do security boot check or not. + * + * @param bool config : Config the flash when unpacking the image, config should be done only once. + * + * @return ETS_OK : unpack successful + * @return ETS_FAILED : unpack failed + */ +ETS_STATUS ets_unpack_flash_code(uint32_t pos, uint32_t *entry_addr, bool jump, bool sb_need_check, bool config); + +/** + * @} + */ + +/** \defgroup ets_printf_apis, ets_printf related apis used in ets + * @brief ets printf apis + */ + +/** @addtogroup ets_printf_apis + * @{ + */ + +/** + * @brief Printf the strings to uart or other devices, similar with printf, simple than printf. + * Can not print float point data format, or longlong data format. + * So we maybe only use this in ROM. + * + * @param const char *fmt : See printf. + * + * @param ... : See printf. + * + * @return int : the length printed to the output device. + */ int ets_printf(const char *fmt, ...); -/* by default it's UART, just install_uart_printf, set putc1 to NULL to disable */ +/** + * @brief Output a char to uart, which uart to output(which is in uart module in ROM) is not in scope of the function. + * Can not print float point data format, or longlong data format + * + * @param char c : char to output. + * + * @return None + */ +void ets_write_char_uart(char c); + +/** + * @brief Ets_printf have two output functions: putc1 and putc2, both of which will be called if need ouput. + * To install putc1, which is defaulted installed as ets_write_char_uart in none silent boot mode, as NULL in silent mode. + * + * @param void (*)(char) p: Output function to install. + * + * @return None + */ void ets_install_putc1(void (*p)(char c)); -void ets_install_uart_printf(void); -/* no need to install, call directly */ -int ets_uart_printf(const char *fmt, ...); - -/* usually we don't need to call this, unless we want to disable SDIO print */ +/** + * @brief Ets_printf have two output functions: putc1 and putc2, both of which will be called if need ouput. + * To install putc2, which is defaulted installed as NULL. + * + * @param void (*)(char) p: Output function to install. + * + * @return None + */ void ets_install_putc2(void (*p)(char c)); -/* @prepare_buf: allocate buffer for printf internal writting - * @putc: just set to NULL, let printf write to to buffer, unless if you want more fancy stuff - * @post_printf: will be called every time printf finish write buffer - * - * main idea of external printf is re-directing content to an external buffer. - * e.g. sip module allocates an event buffer in prepare_buf() and send the event to host in post_printf() - * moreover, you can check printf_buf_remain_len in post_printf(), send the event to host till buf is - * about to full. - * - * TBD: Another approach is sending printf parameter to host and let host to decode, which could save some bytes. - */ -void ets_install_external_printf(void (*prepare_buf)(char ** bufptr, uint16_t *buflen, uint32_t *cookie), - void (*putc)(char c), - void (*post_printf)(uint32_t cookie)); - -uint16_t est_get_printf_buf_remain_len(void); -void est_reset_printf_buf_len(void); - -/* external (SDIO) printf only, still need to install*/ -int ets_external_printf(const char *fmt, ...); +/** + * @brief Install putc1 as ets_write_char_uart. + * In silent boot mode(to void interfere the UART attached MCU), we can call this function, after booting ok. + * + * @param None + * + * @return None + */ +void ets_install_uart_printf(void); #define ETS_PRINTF(...) ets_printf(...) @@ -110,82 +270,251 @@ int ets_external_printf(const char *fmt, ...); } \ } while (0); -/* memory and string support */ -int8_t ets_char2xdigit(char ch); -uint8_t * ets_str2macaddr(uint8_t *macaddr, char *str); -void ets_getc(char *c); -void ets_putc(char c); +/** + * @} + */ -/* timer related */ -typedef uint32_t ETSHandle; -typedef void ETSTimerFunc(void *timer_arg); +/** \defgroup ets_timer_apis, ets_timer related apis used in ets + * @brief ets timer apis + */ + +/** @addtogroup ets_timer_apis + * @{ + */ +typedef void ETSTimerFunc(void *timer_arg);/**< timer handler*/ typedef struct _ETSTIMER_ { - struct _ETSTIMER_ *timer_next; - uint32_t timer_expire; - uint32_t timer_period; - ETSTimerFunc *timer_func; - void *timer_arg; + struct _ETSTIMER_ *timer_next; /**< timer linker*/ + uint32_t timer_expire; /**< abstruct time when timer expire*/ + uint32_t timer_period; /**< timer period, 0 means timer is not periodic repeated*/ + ETSTimerFunc *timer_func; /**< timer handler*/ + void *timer_arg; /**< timer handler argument*/ } ETSTimer; +/** + * @brief Init ets timer, this timer range is 640 us to 429496 ms + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param None + * + * @return None + */ void ets_timer_init(void); + +/** + * @brief Arm an ets timer, this timer range is 640 us to 429496 ms. + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param ETSTimer *timer : Timer struct pointer. + * + * @param uint32_t tmout : Timer value in ms, range is 1 to 429496. + * + * @param bool repeat : Timer is periodic repeated. + * + * @return None + */ void ets_timer_arm(ETSTimer *timer, uint32_t tmout, bool repeat); + +/** + * @brief Arm an ets timer, this timer range is 640 us to 429496 ms. + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param ETSTimer *timer : Timer struct pointer. + * + * @param uint32_t tmout : Timer value in us, range is 1 to 429496729. + * + * @param bool repeat : Timer is periodic repeated. + * + * @return None + */ +void ets_timer_arm_us(ETSTimer *ptimer, uint32_t us, bool repeat); + +/** + * @brief Disarm an ets timer. + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param ETSTimer *timer : Timer struct pointer. + * + * @return None + */ void ets_timer_disarm(ETSTimer *timer); -void ets_timer_done(ETSTimer *ptimer); + +/** + * @brief Set timer callback and argument. + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param ETSTimer *timer : Timer struct pointer. + * + * @param ETSTimerFunc *pfunction : Timer callback. + * + * @param void *parg : Timer callback argument. + * + * @return None + */ void ets_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunction, void *parg); -/* watchdog related */ -typedef enum { - WDT_NONE = -1, - WDT_DISABLED = 0, - WDT_CONTROL_RESET = 1, - WDT_CONTROL_INTR = 2, /* usually we use this mode? */ - WDT_CONTROL_EXTERNAL_FEED = 3, - WDT_TESET_OVERFLOW = 4, // intend to make watchdog overflow to test -} WDT_MODE; +/** + * @brief Unset timer callback and argument to NULL. + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param ETSTimer *timer : Timer struct pointer. + * + * @return None + */ +void ets_timer_done(ETSTimer *ptimer); -typedef enum{ - WDT_INTERVAL_THREE_SEC = 3, - WDT_INTERVAL_SIX_SEC = 6, - WDT_INTERVAL_TWELVE_SEC = 12, -} WDT_INTERVAL_TIME; +/** + * @brief CPU do while loop for some time. + * In FreeRTOS task, please call FreeRTOS apis. + * + * @param uint32_t us : Delay time in us. + * + * @return None + */ +void ets_delay_us(uint32_t us); -void ets_wdt_init(void); -WDT_MODE ets_wdt_get_mode(void); -void ets_wdt_enable(WDT_MODE mode, WDT_INTERVAL_TIME feed_interval, - WDT_INTERVAL_TIME expire_interval); -WDT_MODE ets_wdt_disable(void); -void ets_wdt_restore(WDT_MODE old_mode); +/** + * @brief Set the real CPU ticks per us to the ets, so that ets_delay_us will be accurate. + * Call this function when CPU frequency is changed. + * + * @param uint32_t ticks_per_us : CPU ticks per us. + * + * @return None + */ +void ets_update_cpu_frequency(uint32_t ticks_per_us); -/* interrupt related */ -typedef void (* ets_isr_t)(void *); +/** + * @brief Get the real CPU ticks per us to the ets. + * This function do not return real CPU ticks per us, just the record in ets. It can be used to check with the real CPU frequency. + * + * @param None + * + * @return uint32_t : CPU ticks per us record in ets. + */ +uint32_t ets_get_cpu_frequency(void); -#define ETS_WMAC_SOURCE 0 -#define ETS_SLC_SOURCE 1 -#define ETS_UART_SOURCE 13 -#define ETS_UART1_SOURCE 14 -#define ETS_FRC_TIMER2_SOURCE 43 +/** + * @brief Get xtal_freq/analog_8M*256 value calibrated in rtc module. + * + * @param None + * + * @return uint32_t : xtal_freq/analog_8M*256. + */ +uint32_t ets_get_xtal_scale(void); -#define ETS_WMAC_INUM 0 -#define ETS_SLC_INUM 1 -#define ETS_SPI_INUM 2 -#define ETS_HSIP_INUM 2 -#define ETS_I2S_INUM 2 -#define ETS_RTC_INUM 3 -#define ETS_FRC_TIMER1_INUM 9 /* use edge*/ -#define ETS_FRC_TIMER2_INUM 10 /* use edge*/ -#define ETS_WDT_INUM 8 /* use edge*/ -#define ETS_GPIO_INUM 4 -#define ETS_UART_INUM 5 -#define ETS_UART1_INUM 5 -#define ETS_MAX_INUM 6 +/** + * @brief Get xtal_freq value, If value not stored in RTC_STORE5, than store. + * + * @param None + * + * @return uint32_t : if rtc store the value (RTC_STORE5 high 16 bits and low 16 bits with same value), read from rtc register. + * clock = (REG_READ(RTC_STORE5) & 0xffff) << 12; + * else if analog_8M in efuse + * clock = ets_get_xtal_scale() * 15625 * ets_efuse_get_8M_clock() / 40; + * else clock = 26M. + */ +uint32_t ets_get_detected_xtal_freq(void); +/** + * @} + */ +/** \defgroup ets_intr_apis, ets interrupt configure related apis + * @brief ets intr apis + */ + +/** @addtogroup ets_intr_apis + * @{ + */ + +typedef void (* ets_isr_t)(void *);/**< interrupt handler type*/ + +/** + * @brief Attach a interrupt handler to a CPU interrupt number. + * This function equals to _xtos_set_interrupt_handler_arg(i, func, arg). + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param int i : CPU interrupt number. + * + * @param ets_isr_t func : Interrupt handler. + * + * @param void *arg : argument of the handler. + * + * @return None + */ void ets_isr_attach(int i, ets_isr_t func, void *arg); + +/** + * @brief Mask the interrupts which show in mask bits. + * This function equals to _xtos_ints_off(mask). + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param uint32_t mask : BIT(i) means mask CPU interrupt number i. + * + * @return None + */ void ets_isr_mask(uint32_t mask); + +/** + * @brief Unmask the interrupts which show in mask bits. + * This function equals to _xtos_ints_on(mask). + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param uint32_t mask : BIT(i) means mask CPU interrupt number i. + * + * @return None + */ void ets_isr_unmask(uint32_t unmask); + +/** + * @brief Lock the interrupt to level 2. + * This function direct set the CPU registers. + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param None + * + * @return None + */ void ets_intr_lock(void); + +/** + * @brief Unlock the interrupt to level 0. + * This function direct set the CPU registers. + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param None + * + * @return None + */ void ets_intr_unlock(void); + +/** + * @brief Unlock the interrupt to level 0, and CPU will go into power save mode(wait interrupt). + * This function direct set the CPU registers. + * In FreeRTOS, please call FreeRTOS apis, never call this api. + * + * @param None + * + * @return None + */ +void ets_waiti0(void); + +/** + * @brief Attach an CPU interrupt to a hardware source. + * We have 4 steps to use an interrupt: + * 1.Attach hardware interrupt source to CPU. intr_matrix_set(0, ETS_WIFI_MAC_INTR_SOURCE, ETS_WMAC_INUM); + * 2.Set interrupt handler. xt_set_interrupt_handler(ETS_WMAC_INUM, func, NULL); + * 3.Enable interrupt for CPU. xt_ints_on(1 << ETS_WMAC_INUM); + * 4.Enable interrupt in the module. + * + * @param int cpu_no : The CPU which the interrupt number belongs. + * + * @param uint32_t model_num : The interrupt hardware source number, please see the interrupt hardware source table. + * + * @param uint32_t intr_num : The interrupt number CPU, please see the interrupt cpu using table. + * + * @return None + */ void intr_matrix_set(int cpu_no, uint32_t model_num, uint32_t intr_num); #define _ETSTR(v) # v @@ -194,126 +523,80 @@ void intr_matrix_set(int cpu_no, uint32_t model_num, uint32_t intr_num); : "=a" (__tmp) : : "memory" ); \ }) +#ifdef CONFIG_NONE_OS #define ETS_INTR_LOCK() \ - ets_intr_lock() + ets_intr_lock() #define ETS_INTR_UNLOCK() \ - ets_intr_unlock() - -#define ETS_CCOMPARE_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_CCOMPARE_INUM, (func), (void *)(arg)) - -#define ETS_PWM_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_PWM_INUM, (func), (void *)(arg)) - -#define ETS_WMAC_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_WMAC_INUM, (func), (void *)(arg)) - -#define ETS_FRC_TIMER1_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_FRC_TIMER1_INUM, (func), (void *)(arg)) - -#define ETS_FRC_TIMER2_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_FRC_TIMER2_INUM, (func), (void *)(arg)) - -#define ETS_GPIO_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_GPIO_INUM, (func), (void *)(arg)) - -#define ETS_UART_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_UART_INUM, (func), (void *)(arg)) - -#define ETS_WDT_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_WDT_INUM, (func), (void *)(arg)) - -#define ETS_RTC_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_RTC_INUM, (func), (void *)(arg)) - -#define ETS_SLC_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_SLC_INUM, (func), (void *)(arg)) + ets_intr_unlock() +#define ETS_ISR_ATTACH \ + ets_isr_attach #define ETS_INTR_ENABLE(inum) \ - xt_ints_on((1<= '0') && (c <= '9')) - -#define isxdigit(c) (((c >= '0') && (c <= '9')) || \ - ((c >= 'a') && (c <= 'f')) || \ - ((c >= 'A') && (c <= 'F')) ) - -#define isblank(c) ((c == ' ') || (c == '\t')) - -#define isupper(c) ((c >= 'A') && (c <= 'Z')) + ETS_INTR_DISABLE(ETS_SLC_INUM) #endif +/** + * @} + */ #ifndef MAC2STR #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] @@ -322,6 +605,10 @@ uint32_t ets_get_detected_xtal_freq(); #define ETS_MEM_BAR() asm volatile ( "" : : : "memory" ) +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/components/esp32/include/rom/gpio.h b/components/esp32/include/rom/gpio.h index afb8e20184..a6ca66f1de 100644 --- a/components/esp32/include/rom/gpio.h +++ b/components/esp32/include/rom/gpio.h @@ -25,6 +25,14 @@ extern "C" { #endif +/** \defgroup gpio_apis, uart configuration and communication related apis + * @brief gpio apis + */ + +/** @addtogroup gpio_apis + * @{ + */ + #define GPIO_REG_READ(reg) READ_PERI_REG(reg) #define GPIO_REG_WRITE(reg, val) WRITE_PERI_REG(reg, val) #define GPIO_PIN_COUNT 40 @@ -37,17 +45,14 @@ extern "C" { #define GPIO_REGID_TO_PINIDX(reg_id) ((reg_id) - GPIO_ID_PIN0) -typedef enum{ - GPIO_PIN_INTR_DISABLE = 0, - GPIO_PIN_INTR_POSEDGE = 1, - GPIO_PIN_INTR_NEGEDGE = 2, - GPIO_PIN_INTR_ANYEGDE = 3, - GPIO_PIN_INTR_LOLEVEL = 4, - GPIO_PIN_INTR_HILEVEL = 5 -}GPIO_INT_TYPE; - -#define GREEN_LED_ON() GPIO_OUTPUT_SET(GPIO_ID_PIN(1) , 0) -#define GREEN_LED_OFF() GPIO_OUTPUT_SET(GPIO_ID_PIN(1) , 1) +typedef enum { + GPIO_PIN_INTR_DISABLE = 0, + GPIO_PIN_INTR_POSEDGE = 1, + GPIO_PIN_INTR_NEGEDGE = 2, + GPIO_PIN_INTR_ANYEGDE = 3, + GPIO_PIN_INTR_LOLEVEL = 4, + GPIO_PIN_INTR_HILEVEL = 5 +} GPIO_INT_TYPE; #define GPIO_OUTPUT_SET(gpio_no, bit_value) \ ((gpio_no < 32) ? gpio_output_set(bit_value<BIT(0). + * There is no particular ordering guaranteed; so if the order of writes is significant, + * calling code should divide a single call into multiple calls. + * + * @param uint32_t set_mask : the gpios that need high level. + * + * @param uint32_t clear_mask : the gpios that need low level. + * + * @param uint32_t enable_mask : the gpios that need be changed. + * + * @param uint32_t disable_mask : the gpios that need diable output. + * + * @return None + */ +void gpio_output_set(uint32_t set_mask, uint32_t clear_mask, uint32_t enable_mask, uint32_t disable_mask); -/* - * Change GPIO pin output by setting, clearing, or disabling pins. - * In general, it is expected that a bit will be set in at most one - * of these masks. If a bit is clear in all masks, the output state - * remains unchanged. - * - * There is no particular ordering guaranteed; so if the order of - * writes is significant, calling code should divide a single call - * into multiple calls. - */ -void gpio_output_set(uint32_t set_mask, - uint32_t clear_mask, - uint32_t enable_mask, - uint32_t disable_mask) ROMFN_ATTR; -void gpio_output_set_high(uint32_t set_mask, - uint32_t clear_mask, - uint32_t enable_mask, - uint32_t disable_mask) ROMFN_ATTR; -/* - * Sample the value of GPIO input pins and returns a bitmask. - */ -uint32_t gpio_input_get(void) ROMFN_ATTR; -uint32_t gpio_input_get_high(void) ROMFN_ATTR; +/** + * @brief Change GPIO(32-39) pin output by setting, clearing, or disabling pins, GPIO32<->BIT(0). + * There is no particular ordering guaranteed; so if the order of writes is significant, + * calling code should divide a single call into multiple calls. + * + * @param uint32_t set_mask : the gpios that need high level. + * + * @param uint32_t clear_mask : the gpios that need low level. + * + * @param uint32_t enable_mask : the gpios that need be changed. + * + * @param uint32_t disable_mask : the gpios that need diable output. + * + * @return None + */ +void gpio_output_set_high(uint32_t set_mask, uint32_t clear_mask, uint32_t enable_mask, uint32_t disable_mask); -/* - * Set the specified GPIO register to the specified value. - * This is a very general and powerful interface that is not - * expected to be used during normal operation. It is intended - * mainly for debug, or for unusual requirements. - */ -void gpio_register_set(uint32_t reg_id, uint32_t value) ROMFN_ATTR; +/** + * @brief Sample the value of GPIO input pins(0-31) and returns a bitmask. + * + * @param None + * + * @return uint32_t : bitmask for GPIO input pins, BIT(0) for GPIO0. + */ +uint32_t gpio_input_get(void); -/* Get the current value of the specified GPIO register. */ -uint32_t gpio_register_get(uint32_t reg_id) ROMFN_ATTR; +/** + * @brief Sample the value of GPIO input pins(32-39) and returns a bitmask. + * + * @param None + * + * @return uint32_t : bitmask for GPIO input pins, BIT(0) for GPIO32. + */ +uint32_t gpio_input_get_high(void); -/* - * Register an application-specific interrupt handler for GPIO pin - * interrupts. Once the interrupt handler is called, it will not - * be called again until after a call to gpio_intr_ack. Any GPIO - * interrupts that occur during the interim are masked. - * - * The application-specific handler is called with a mask of - * pending GPIO interrupts. After processing pin interrupts, the - * application-specific handler may wish to use gpio_intr_pending - * to check for any additional pending interrupts before it returns. - */ -void gpio_intr_handler_register(gpio_intr_handler_fn_t fn, void *arg) ROMFN_ATTR; +/** + * @brief Register an application-specific interrupt handler for GPIO pin interrupts. + * Once the interrupt handler is called, it will not be called again until after a call to gpio_intr_ack. + * Please do not call this function in SDK. + * + * @param gpio_intr_handler_fn_t fn : gpio application-specific interrupt handler + * + * @param void *arg : gpio application-specific interrupt handler argument. + * + * @return None + */ +void gpio_intr_handler_register(gpio_intr_handler_fn_t fn, void *arg); -/* Determine which GPIO interrupts are pending. */ -uint32_t gpio_intr_pending(void) ROMFN_ATTR; -uint32_t gpio_intr_pending_high(void) ROMFN_ATTR; +/** + * @brief Get gpio interrupts which happens but not processed. + * Please do not call this function in SDK. + * + * @param None + * + * @return uint32_t : bitmask for GPIO pending interrupts, BIT(0) for GPIO0. + */ +uint32_t gpio_intr_pending(void); -/* - * Acknowledge GPIO interrupts. - * Intended to be called from the gpio_intr_handler_fn. - */ -void gpio_intr_ack(uint32_t ack_mask) ROMFN_ATTR; -void gpio_intr_ack_high(uint32_t ack_mask) ROMFN_ATTR; +/** + * @brief Get gpio interrupts which happens but not processed. + * Please do not call this function in SDK. + * + * @param None + * + * @return uint32_t : bitmask for GPIO pending interrupts, BIT(0) for GPIO32. + */ +uint32_t gpio_intr_pending_high(void); -void gpio_pin_wakeup_enable(uint32_t i, GPIO_INT_TYPE intr_state) ROMFN_ATTR; +/** + * @brief Ack gpio interrupts to process pending interrupts. + * Please do not call this function in SDK. + * + * @param uint32_t ack_mask: bitmask for GPIO ack interrupts, BIT(0) for GPIO0. + * + * @return None + */ +void gpio_intr_ack(uint32_t ack_mask); -void gpio_pin_wakeup_disable() ROMFN_ATTR; +/** + * @brief Ack gpio interrupts to process pending interrupts. + * Please do not call this function in SDK. + * + * @param uint32_t ack_mask: bitmask for GPIO ack interrupts, BIT(0) for GPIO32. + * + * @return None + */ +void gpio_intr_ack_high(uint32_t ack_mask); -//extern void gpio_module_install(struct gpio_api *api); +/** + * @brief Set GPIO to wakeup the ESP32. + * Please do not call this function in SDK. + * + * @param uint32_t i: gpio number. + * + * @param GPIO_INT_TYPE intr_state : only GPIO_PIN_INTR_LOLEVEL\GPIO_PIN_INTR_HILEVEL can be used + * + * @return None + */ +void gpio_pin_wakeup_enable(uint32_t i, GPIO_INT_TYPE intr_state); -void gpio_matrix_in(uint32_t gpio, uint32_t signal_idx, bool inv) ROMFN_ATTR; +/** + * @brief disable GPIOs to wakeup the ESP32. + * Please do not call this function in SDK. + * + * @param None + * + * @return None + */ +void gpio_pin_wakeup_disable(void); -void gpio_matrix_out(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) ROMFN_ATTR; +/** + * @brief set gpio input to a signal, one gpio can input to several signals. + * + * @param uint32_t gpio : gpio number, 0~0x27 + * gpio == 0x30, input 0 to signal + * gpio == 0x34, ??? + * gpio == 0x38, input 1 to signal + * + * @param uint32_t signal_idx : signal index. + * + * @param bool inv : the signal is inv or not + * + * @return None + */ +void gpio_matrix_in(uint32_t gpio, uint32_t signal_idx, bool inv); + +/** + * @brief set signal output to gpio, one signal can output to several gpios. + * + * @param uint32_t gpio : gpio number, 0~0x27 + * + * @param uint32_t signal_idx : signal index. + * signal_idx == 0x100, cancel output put to the gpio + * + * @param bool out_inv : the signal output is inv or not + * + * @param bool oen_inv : the signal output enable is inv or not + * + * @return None + */ +void gpio_matrix_out(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv); + +/** + * @brief Select pad as a gpio function from IOMUX. + * + * @param uint32_t gpio_num : gpio number, 0~0x27 + * + * @return None + */ +void gpio_pad_select_gpio(uint8_t gpio_num); + +/** + * @brief Set pad driver capability. + * + * @param uint32_t gpio_num : gpio number, 0~0x27 + * + * @param uint8_t drv : 0-3 + * + * @return None + */ +void gpio_pad_set_drv(uint8_t gpio_num, uint8_t drv); + +/** + * @brief Pull up the pad from gpio number. + * + * @param uint32_t gpio_num : gpio number, 0~0x27 + * + * @return None + */ +void gpio_pad_pullup(uint8_t gpio_num); + +/** + * @brief Pull down the pad from gpio number. + * + * @param uint32_t gpio_num : gpio number, 0~0x27 + * + * @return None + */ +void gpio_pad_pulldown(uint8_t gpio_num); + +/** + * @brief Unhold the pad from gpio number. + * + * @param uint32_t gpio_num : gpio number, 0~0x27 + * + * @return None + */ +void gpio_pad_unhold(uint8_t gpio_num); + +/** + * @brief Hold the pad from gpio number. + * + * @param uint32_t gpio_num : gpio number, 0~0x27 + * + * @return None + */ +void gpio_pad_hold(uint8_t gpio_num); + +/** + * @} + */ #ifdef __cplusplus } diff --git a/components/esp32/include/rom/rtc.h b/components/esp32/include/rom/rtc.h index 31323646f0..d8c0c789a3 100644 --- a/components/esp32/include/rom/rtc.h +++ b/components/esp32/include/rom/rtc.h @@ -26,30 +26,68 @@ extern "C" { #endif +/** \defgroup rtc_apis, rtc registers and memory related apis + * @brief rtc apis + */ + +/** @addtogroup rtc_apis + * @{ + */ + +/************************************************************************************** + * Note: * + * Some Rtc memory and registers are used, in ROM or in internal library. * + * Please do not use reserved or used rtc memory or registers. * + * * + ************************************************************************************* + * RTC Memory & Store Register usage + ************************************************************************************* + * rtc memory addr type size usage + * 0x3ff61000(0x50000000) Slow SIZE_CP Co-Processor code/Reset Entry + * 0x3ff61000+SIZE_CP Slow 6144-SIZE_CP + * 0x3ff62800 Slow 2048 Reserved + * + * 0x3ff80000(0x400c0000) Fast 8192 deep sleep entry code + * + ************************************************************************************* + * Rtc store registers usage + * RTC_STORE0 + * RTC_STORE1 + * RTC_STORE2 + * RTC_STORE3 + * RTC_STORE4 Reserved + * RTC_STORE5 External Xtal Frequency + * RTC_STORE6 FAST_RTC_MEMORY_ENTRY + * RTC_STORE7 FAST_RTC_MEMORY_CRC + ************************************************************************************* + */ +#define RTC_ENTRY_ADDR RTC_STORE6 +#define RTC_MEMORY_CRC RTC_STORE7 + + typedef enum { - AWAKE = 0, //CPU ON + AWAKE = 0, // 1 : skip (n - 1) commands. + */ +uint16_t SPI_Common_Command(SpiCommonCmd *cmd); + +/** + * @brief Unlock SPI write protect. + * Please do not call this function in SDK. + * + * @param None. + * + * @return SPI_FLASH_RESULT_OK : Unlock OK. + * SPI_FLASH_RESULT_ERR : Unlock error. + * SPI_FLASH_RESULT_TIMEOUT : Unlock timeout. + */ +SpiFlashOpResult SPIUnlock(void); + +/** + * @brief SPI write protect. + * Please do not call this function in SDK. + * + * @param None. + * + * @return SPI_FLASH_RESULT_OK : Lock OK. + * SPI_FLASH_RESULT_ERR : Lock error. + * SPI_FLASH_RESULT_TIMEOUT : Lock timeout. + */ +SpiFlashOpResult SPILock(void); + +/** + * @brief Update SPI Flash parameter. + * Please do not call this function in SDK. + * + * @param uint32_t deviceId : Device ID read from SPI, the low 32 bit. + * + * @param uint32_t chip_size : The Flash size. + * + * @param uint32_t block_size : The Flash block size. + * + * @param uint32_t sector_size : The Flash sector size. + * + * @param uint32_t page_size : The Flash page size. + * + * @param uint32_t status_mask : The Mask used when read status from Flash(use single CMD). + * + * @return SPI_FLASH_RESULT_OK : Update OK. + * SPI_FLASH_RESULT_ERR : Update error. + * SPI_FLASH_RESULT_TIMEOUT : Update timeout. + */ +SpiFlashOpResult SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t block_size, uint32_t sector_size, uint32_t page_size, uint32_t status_mask); + +/** + * @brief Erase whole flash chip. + * Please do not call this function in SDK. + * + * @param None + * + * @return SPI_FLASH_RESULT_OK : Erase OK. + * SPI_FLASH_RESULT_ERR : Erase error. + * SPI_FLASH_RESULT_TIMEOUT : Erase timeout. + */ +SpiFlashOpResult SPIEraseChip(void); + +/** + * @brief Erase a block of flash. + * Please do not call this function in SDK. + * + * @param uint32_t block_num : Which block to erase. + * + * @return SPI_FLASH_RESULT_OK : Erase OK. + * SPI_FLASH_RESULT_ERR : Erase error. + * SPI_FLASH_RESULT_TIMEOUT : Erase timeout. + */ +SpiFlashOpResult SPIEraseBlock(uint32_t block_num); + +/** + * @brief Erase a sector of flash. + * Please do not call this function in SDK. + * + * @param uint32_t sector_num : Which sector to erase. + * + * @return SPI_FLASH_RESULT_OK : Erase OK. + * SPI_FLASH_RESULT_ERR : Erase error. + * SPI_FLASH_RESULT_TIMEOUT : Erase timeout. + */ +SpiFlashOpResult SPIEraseSector(uint32_t sector_num); + +/** + * @brief Erase some sectors. + * Please do not call this function in SDK. + * + * @param uint32_t start_addr : Start addr to erase, should be sector aligned. + * + * @param uint32_t area_len : Length to erase, should be sector aligned. + * + * @return SPI_FLASH_RESULT_OK : Erase OK. + * SPI_FLASH_RESULT_ERR : Erase error. + * SPI_FLASH_RESULT_TIMEOUT : Erase timeout. + */ +SpiFlashOpResult SPIEraseArea(uint32_t start_addr, uint32_t area_len); + +/** + * @brief Write Data to Flash, you should Erase it yourself if need. + * Please do not call this function in SDK. + * + * @param uint32_t dest_addr : Address to write, should be 4 bytes aligned. + * + * @param const uint32_t *src : The pointer to data which is to write. + * + * @param uint32_t len : Length to write, should be 4 bytes aligned. + * + * @return SPI_FLASH_RESULT_OK : Write OK. + * SPI_FLASH_RESULT_ERR : Write error. + * SPI_FLASH_RESULT_TIMEOUT : Write timeout. + */ +SpiFlashOpResult SPIWrite(uint32_t dest_addr, const uint32_t *src, int32_t len); + +/** + * @brief Read Data from Flash, you should Erase it yourself if need. + * Please do not call this function in SDK. + * + * @param uint32_t src_addr : Address to read, should be 4 bytes aligned. + * + * @param uint32_t *dest : The buf to read the data. + * + * @param uint32_t len : Length to read, should be 4 bytes aligned. + * + * @return SPI_FLASH_RESULT_OK : Read OK. + * SPI_FLASH_RESULT_ERR : Read error. + * SPI_FLASH_RESULT_TIMEOUT : Read timeout. + */ +SpiFlashOpResult SPIRead(uint32_t src_addr, uint32_t *dest, int32_t len); + +/** + * @brief SPI1 go into encrypto mode. + * Please do not call this function in SDK. + * + * @param None + * + * @return None + */ +void SPI_Write_Encrypt_Enable(void); + +/** + * @brief Prepare 32 Bytes data to encrpto writing, you should Erase it yourself if need. + * Please do not call this function in SDK. + * + * @param uint32_t flash_addr : Address to write, should be 32 bytes aligned. + * + * @param uint32_t *data : The pointer to data which is to write. + * + * @return SPI_FLASH_RESULT_OK : Prepare OK. + * SPI_FLASH_RESULT_ERR : Prepare error. + * SPI_FLASH_RESULT_TIMEOUT : Prepare timeout. + */ +SpiFlashOpResult SPI_Prepare_Encrypt_Data(uint32_t flash_addr, uint32_t *data); + +/** + * @brief SPI1 go out of encrypto mode. + * Please do not call this function in SDK. + * + * @param None + * + * @return None + */ +void SPI_Write_Encrypt_Disable(void); + +/** + * @brief Encrpto writing data to flash, you should Erase it yourself if need. + * Please do not call this function in SDK. + * + * @param uint32_t flash_addr : Address to write, should be 32 bytes aligned. + * + * @param uint32_t *data : The pointer to data which is to write. + * + * @param uint32_t len : Length to write, should be 32 bytes aligned. + * + * @return SPI_FLASH_RESULT_OK : Encrypto write OK. + * SPI_FLASH_RESULT_ERR : Encrypto write error. + * SPI_FLASH_RESULT_TIMEOUT : Encrypto write timeout. + */ +SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len); + +/** + * @} + */ #ifdef __cplusplus } diff --git a/components/esp32/include/rom/ssc.h b/components/esp32/include/rom/ssc.h deleted file mode 100755 index 509e0da2f8..0000000000 --- a/components/esp32/include/rom/ssc.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2011-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef _ROM_SSC_H_ -#define _ROM_SSC_H_ - -#include "esp_types.h" - -#include "esp_attr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct cmd_s { - char *cmd_str; -#define CMD_T_ASYNC 0x01 -#define CMD_T_SYNC 0x02 - uint8_t flag; - uint8_t id; - void (* cmd_func)(void); - void (* cmd_callback)(void *arg); -} ssc_cmd_t; - -#define ssc_printf ets_printf -#define SSC_CMD_N 10 //since the command not added in ssc_cmd.c -#define MAX_LINE_N 40 -#define PROMPT ":>" -#define SSC_EVT_N 4 - - -#define SSC_PRIO 30 -enum { - CMD_SET_SSID = 0, - CMD_SCAN, - CMD_CONNECT, - CMD_DISCONNECT, - CMD_SET_MACADDR, - CMD_PING, - CMD_PING_COUNT, - CMD_PING_LENGTH, - CMD_SET_IP, -// CMD_RD_I2C, -// CMD_SET_NULL, it's just for solving the old rom bug -// CMD_SET_I2C, -// CMD_RD_I2CM, -// CMD_SET_I2CM, -// CMD_SET_PBUS, -// CMD_SET_TXTONE, -// CMD_SET_STOPTONE, - CMD_END, -}; - -enum { - SIG_SSC_RUNCMD, - SIG_SSC_CMDDONE, - SIG_SSC_RESTART, - SIG_SSC_UART_RX_CHAR, -}; - -void ssc_attach(void) ROMFN_ATTR; -void ssc_cmd_done(int cmd_id, STATUS status) ROMFN_ATTR; -int ssc_param_len(void) ROMFN_ATTR; -char * ssc_param_str(void) ROMFN_ATTR; -void ssc_register(ssc_cmd_t *cmdset, uint8_t cmdnum, void (* help)(void)) ROMFN_ATTR; - -extern ssc_cmd_t sscCmdSet[]; -void ssc_help(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _ROM_SSC_H_ */ diff --git a/components/esp32/include/rom/uart.h b/components/esp32/include/rom/uart.h old mode 100755 new mode 100644 index b295697730..8e3125133c --- a/components/esp32/include/rom/uart.h +++ b/components/esp32/include/rom/uart.h @@ -22,6 +22,14 @@ extern "C" { #endif +/** \defgroup uart_apis, uart configuration and communication related apis + * @brief uart apis + */ + +/** @addtogroup uart_apis + * @{ + */ + #define RX_BUFF_SIZE 0x100 #define TX_BUFF_SIZE 100 @@ -52,9 +60,9 @@ extern "C" { #define UART_RCV_ERR_FLAG BIT7 //send and receive message frame head -#define FRAME_FLAG 0x7E +#define FRAME_FLAG 0x7E -typedef enum{ +typedef enum { UART_LINE_STATUS_INT_FLAG = 0x06, UART_RCV_FIFO_INT_FLAG = 0x04, UART_RCV_TMOUT_INT_FLAG = 0x0C, @@ -82,9 +90,9 @@ typedef enum { } UartStopBitsNum; typedef enum { - NONE_BITS = 0, - ODD_BITS = 2, - EVEN_BITS = 3 + NONE_BITS = 0, + ODD_BITS = 2, + EVEN_BITS = 3 } UartParityMode; @@ -113,7 +121,7 @@ typedef enum { typedef enum { EMPTY, UNDER_WRITE, - WRITE_OVER + WRITE_OVER } RcvMsgBuffState; typedef struct { @@ -121,9 +129,9 @@ typedef struct { uint8_t *pRcvMsgBuff; uint8_t *pWritePos; uint8_t *pReadPos; - uint8_t TrigLvl; //JLU: may need to pad + uint8_t TrigLvl; RcvMsgBuffState BuffState; -}RcvMsgBuff; +} RcvMsgBuff; typedef struct { uint32_t TrxBuffSize; @@ -138,7 +146,7 @@ typedef enum { RCV_ESC_CHAR, } RcvMsgState; -typedef struct{ +typedef struct { UartBautRate baut_rate; UartBitsNum4Char data_bits; UartExistParity exist_parity; @@ -153,33 +161,249 @@ typedef struct{ int received; } UartDevice; -void Uart_Init(uint8_t uart_no, uint32_t clock) ROMFN_ATTR; -STATUS UartTxString(uint8_t* pString) ROMFN_ATTR; -STATUS UartRxString(uint8_t* pString, uint8_t MaxStrlen) ROMFN_ATTR; +/** + * @brief Init uart device struct value and reset uart0/uart1 rx. + * Please do not call this function in SDK. + * + * @param None + * + * @return None + */ +void uartAttach(void); -STATUS uart_tx_one_char(uint8_t TxChar) ROMFN_ATTR;//for print -STATUS uart_tx_one_char2(uint8_t TxChar) ROMFN_ATTR;//for send message -STATUS uart_rx_one_char(uint8_t* pRxChar) ROMFN_ATTR; -char uart_rx_one_char_block(void) ROMFN_ATTR; -void uart_rx_intr_handler(void * para) ROMFN_ATTR; -STATUS uart_rx_readbuff( RcvMsgBuff* pRxBuff, uint8_t* pRxByte) ROMFN_ATTR; -STATUS UartGetCmdLn(uint8_t * pCmdLn) ROMFN_ATTR; -UartDevice * GetUartDevice() ROMFN_ATTR; +/** + * @brief Init uart0 or uart1 for UART download booting mode. + * Please do not call this function in SDK. + * + * @param uint8_t uart_no : 0 for UART0, else for UART1. + * + * @param uint32_t clock : clock used by uart module, to adjust baudrate. + * + * @return None + */ +void Uart_Init(uint8_t uart_no, uint32_t clock); -void uartToggleInterrupt(bool en) ROMFN_ATTR; +/** + * @brief Modify uart baudrate. + * This function will reset RX/TX fifo for uart. + * + * @param uint8_t uart_no : 0 for UART0, 1 for UART1. + * + * @param uint32_t DivLatchValue : (clock << 4)/baudrate. + * + * @return None + */ +void uart_div_modify(uint8_t uart_no, uint32_t DivLatchValue); -STATUS SendMsg(uint8_t *pData, uint16_t DataLen) ROMFN_ATTR; +/** + * @brief Init uart0 or uart1 for UART download booting mode. + * Please do not call this function in SDK. + * + * @param uint8_t uart_no : 0 for UART0, 1 for UART1. + * + * @param uint8_t is_sync : 0, only one UART module, easy to detect, wait until detected; + * 1, two UART modules, hard to detect, detect and return. + * + * @return None + */ +int uart_baudrate_detect(uint8_t uart_no, uint8_t is_sync); -STATUS RcvMsg(uint8_t *pData, uint16_t MaxDataLen, uint8_t is_sync) ROMFN_ATTR; +/** + * @brief Switch printf channel of uart_tx_one_char. + * Please do not call this function when printf. + * + * @param uint8_t uart_no : 0 for UART0, 1 for UART1. + * + * @return None + */ +void uart_tx_switch(uint8_t uart_no); + +/** + * @brief Switch message exchange channel for UART download booting. + * Please do not call this function in SDK. + * + * @param uint8_t uart_no : 0 for UART0, 1 for UART1. + * + * @return None + */ +void uart_buff_switch(uint8_t uart_no); + +/** + * @brief Output a char to printf channel, wait until fifo not full. + * + * @param None + * + * @return OK. + */ +STATUS uart_tx_one_char(uint8_t TxChar); + +/** + * @brief Output a char to message exchange channel, wait until fifo not full. + * Please do not call this function in SDK. + * + * @param None + * + * @return OK. + */ +STATUS uart_tx_one_char2(uint8_t TxChar);//for send message + +/** + * @brief Wait until uart tx full empty. + * + * @param uint8_t uart_no : 0 for UART0, 1 for UART1. + * + * @return None. + */ +void uart_tx_flush(uint8_t uart_no); + +/** + * @brief Wait until uart tx full empty and the last char send ok. + * + * @param uint8_t uart_no : 0 for UART0, 1 for UART1. + * + * @return None. + */ +void uart_tx_wait_idle(uint8_t uart_no); + +/** + * @brief Get an input char from message channel. + * Please do not call this function in SDK. + * + * @param uint8_t *pRxChar : the pointer to store the char. + * + * @return OK for successful. + * FAIL for failed. + */ +STATUS uart_rx_one_char(uint8_t *pRxChar); + +/** + * @brief Get an input char to message channel, wait until successful. + * Please do not call this function in SDK. + * + * @param None + * + * @return char : input char value. + */ +char uart_rx_one_char_block(void); + +/** + * @brief Get an input string line from message channel. + * Please do not call this function in SDK. + * + * @param uint8_t *pString : the pointer to store the string. + * + * @param uint8_t MaxStrlen : the max string length, incude '\0'. + * + * @return OK. + */ +STATUS UartRxString(uint8_t *pString, uint8_t MaxStrlen); + +/** + * @brief Process uart recevied information in the interrupt handler. + * Please do not call this function in SDK. + * + * @param void *para : the message receive buffer. + * + * @return None + */ +void uart_rx_intr_handler(void *para); + +/** + * @brief Get an char from receive buffer. + * Please do not call this function in SDK. + * + * @param RcvMsgBuff *pRxBuff : the pointer to the struct that include receive buffer. + * + * @param uint8_t *pRxByte : the pointer to store the char. + * + * @return OK for successful. + * FAIL for failed. + */ +STATUS uart_rx_readbuff( RcvMsgBuff *pRxBuff, uint8_t *pRxByte); + +/** + * @brief Get all chars from receive buffer. + * Please do not call this function in SDK. + * + * @param uint8_t *pCmdLn : the pointer to store the string. + * + * @return OK for successful. + * FAIL for failed. + */ +STATUS UartGetCmdLn(uint8_t *pCmdLn); + +/** + * @brief Get uart configuration struct. + * Please do not call this function in SDK. + * + * @param None + * + * @return UartDevice * : uart configuration struct pointer. + */ +UartDevice *GetUartDevice(void); + +/** + * @brief Send an packet to download tool, with SLIP escaping. + * Please do not call this function in SDK. + * + * @param uint8_t *p : the pointer to output string. + * + * @param int len : the string length. + * + * @return None. + */ +void send_packet(uint8_t *p, int len); + +/** + * @brief Receive an packet from download tool, with SLIP escaping. + * Please do not call this function in SDK. + * + * @param uint8_t *p : the pointer to input string. + * + * @param int len : If string length > len, the string will be truncated. + * + * @param uint8_t is_sync : 0, only one UART module; + * 1, two UART modules. + * + * @return int : the length of the string. + */ +int recv_packet(uint8_t *p, int len, uint8_t is_sync); + +/** + * @brief Send an packet to download tool, with SLIP escaping. + * Please do not call this function in SDK. + * + * @param uint8_t *pData : the pointer to input string. + * + * @param uint16_t DataLen : the string length. + * + * @return OK for successful. + * FAIL for failed. + */ +STATUS SendMsg(uint8_t *pData, uint16_t DataLen); + +/** + * @brief Receive an packet from download tool, with SLIP escaping. + * Please do not call this function in SDK. + * + * @param uint8_t *pData : the pointer to input string. + * + * @param uint16_t MaxDataLen : If string length > MaxDataLen, the string will be truncated. + * + * @param uint8_t is_sync : 0, only one UART module; + * 1, two UART modules. + * + * @return OK for successful. + * FAIL for failed. + */ +STATUS RcvMsg(uint8_t *pData, uint16_t MaxDataLen, uint8_t is_sync); -void uartAttach() ROMFN_ATTR; -void uart_div_modify(uint8_t uart_no, uint32_t DivLatchValue) ROMFN_ATTR; -int uart_baudrate_detect(uint8_t uart_no, uint8_t is_sync) ROMFN_ATTR; -void uart_buff_switch(uint8_t uart_no) ROMFN_ATTR; -void uart_tx_flush(uint8_t uart_no) ROMFN_ATTR; -void uart_tx_wait_idle(uint8_t uart_no) ROMFN_ATTR; extern UartDevice UartDev; +/** + * @} + */ + #ifdef __cplusplus } #endif diff --git a/components/esp32/include/rom/wdt.h b/components/esp32/include/rom/wdt.h deleted file mode 100644 index 04a31c3293..0000000000 --- a/components/esp32/include/rom/wdt.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef _ROM_WDT_H_ -#define _ROM_WDT_H_ - -#include "soc.h" -#include "ets_sys.h" - -#define WDT_RESET_VALUE 0x73 -#define WDT_RESET_LEN 7 //real time: (1<<(WDT_RESET_LEN+1))*pclk -#define WDT_CONTROL_ENABLED BIT0 -#define WDT_MODE_SET(v) (v) -#define WDT_TARGET_SET(v) (v) -#define WDT_ADDRESS 0 - -#define SEC_TO_WDT_TICK(s) (s * WDT_CLK_FREQ) //it's Pclk clock,44MHz - -typedef enum{ - NEXT_OVERFLOW_RESET = 0, - NEXT_OVERFLOW_NO_RESET = 1, - EACH_OVERFLOW_RESET = 2, -} WDT_RESP_MODE; - -#define WDT_DEFAULT_FEED_INTERVAL WDT_INTERVAL_SIX_SEC /* 6 seconds */ -#define WDT_DEFAULT_EXPIRE_INTERVAL WDT_INTERVAL_TWELVE_SEC /* 12 seconds */ - -#endif /* _ROM_WDT_H_ */ - diff --git a/components/esp32/include/soc/io_mux_reg.h b/components/esp32/include/soc/io_mux_reg.h index bc9f769b73..e5027a71d3 100644 --- a/components/esp32/include/soc/io_mux_reg.h +++ b/components/esp32/include/soc/io_mux_reg.h @@ -80,21 +80,24 @@ #define FUNC_GPIO33_GPIO33_0 0 #define PERIPHS_IO_MUX_GPIO25_U (DR_REG_IO_MUX_BASE +0x24) +#define FUNC_GPIO25_EMAC_RXD0 5 #define FUNC_GPIO25_GPIO25 2 #define FUNC_GPIO25_GPIO25_0 0 #define PERIPHS_IO_MUX_GPIO26_U (DR_REG_IO_MUX_BASE +0x28) +#define FUNC_GPIO26_EMAC_RXD1 5 #define FUNC_GPIO26_GPIO26 2 #define FUNC_GPIO26_GPIO26_0 0 #define PERIPHS_IO_MUX_GPIO27_U (DR_REG_IO_MUX_BASE +0x2c) -#define FUNC_GPIO27_EMAC_RXD2 5 +#define FUNC_GPIO27_EMAC_RX_DV 5 #define FUNC_GPIO27_GPIO27 2 #define FUNC_GPIO27_GPIO27_0 0 #define PERIPHS_IO_MUX_MTMS_U (DR_REG_IO_MUX_BASE +0x30) #define FUNC_MTMS_EMAC_TXD2 5 #define FUNC_MTMS_SD_CLK 4 +#define FUNC_MTMS_HS2_CLk 3 #define FUNC_MTMS_GPIO14 2 #define FUNC_MTMS_HSPICLK 1 #define FUNC_MTMS_MTMS 0 @@ -102,6 +105,7 @@ #define PERIPHS_IO_MUX_MTDI_U (DR_REG_IO_MUX_BASE +0x34) #define FUNC_MTDI_EMAC_TXD3 5 #define FUNC_MTDI_SD_DATA2 4 +#define FUNC_MTDI_HS2_DATA2 3 #define FUNC_MTDI_GPIO12 2 #define FUNC_MTDI_HSPIQ 1 #define FUNC_MTDI_MTDI 0 @@ -109,7 +113,7 @@ #define PERIPHS_IO_MUX_MTCK_U (DR_REG_IO_MUX_BASE +0x38) #define FUNC_MTCK_EMAC_RX_ER 5 #define FUNC_MTCK_SD_DATA3 4 -#define FUNC_MTCK_U0CTS 3 +#define FUNC_MTCK_HS2_DATA3 3 #define FUNC_MTCK_GPIO13 2 #define FUNC_MTCK_HSPID 1 #define FUNC_MTCK_MTCK 0 @@ -117,21 +121,20 @@ #define PERIPHS_IO_MUX_MTDO_U (DR_REG_IO_MUX_BASE +0x3c) #define FUNC_MTDO_EMAC_RXD3 5 #define FUNC_MTDO_SD_CMD 4 -#define FUNC_MTDO_U0RTS 3 +#define FUNC_MTDO_HS2_CMD 3 #define FUNC_MTDO_GPIO15 2 #define FUNC_MTDO_HSPICS0 1 #define FUNC_MTDO_MTDO 0 #define PERIPHS_IO_MUX_GPIO2_U (DR_REG_IO_MUX_BASE +0x40) -#define FUNC_GPIO2_EMAC_RX_DV 5 #define FUNC_GPIO2_SD_DATA0 4 +#define FUNC_GPIO2_HS2_DATA0 3 #define FUNC_GPIO2_GPIO2 2 #define FUNC_GPIO2_HSPIWP 1 #define FUNC_GPIO2_GPIO2_0 0 #define PERIPHS_IO_MUX_GPIO0_U (DR_REG_IO_MUX_BASE +0x44) #define FUNC_GPIO0_EMAC_TX_CLK 5 -#define FUNC_GPIO0_HS2_CMD 3 #define FUNC_GPIO0_GPIO0 2 #define FUNC_GPIO0_CLK_OUT1 1 #define FUNC_GPIO0_GPIO0_0 0 @@ -139,6 +142,7 @@ #define PERIPHS_IO_MUX_GPIO4_U (DR_REG_IO_MUX_BASE +0x48) #define FUNC_GPIO4_EMAC_TX_ER 5 #define FUNC_GPIO4_SD_DATA1 4 +#define FUNC_GPIO4_HS2_DATA1 3 #define FUNC_GPIO4_GPIO4 2 #define FUNC_GPIO4_HSPIHD 1 #define FUNC_GPIO4_GPIO4_0 0 @@ -207,15 +211,14 @@ #define FUNC_GPIO5_GPIO5_0 0 #define PERIPHS_IO_MUX_GPIO18_U (DR_REG_IO_MUX_BASE +0x70) -#define FUNC_GPIO18_EMAC_TXD0 5 #define FUNC_GPIO18_HS1_DATA7 3 #define FUNC_GPIO18_GPIO18 2 #define FUNC_GPIO18_VSPICLK 1 #define FUNC_GPIO18_GPIO18_0 0 #define PERIPHS_IO_MUX_GPIO19_U (DR_REG_IO_MUX_BASE +0x74) -#define FUNC_GPIO19_EMAC_TXD1 5 -#define FUNC_GPIO19_HS2_DATA2 3 +#define FUNC_GPIO19_EMAC_TXD0 5 +#define FUNC_GPIO19_U0CTS 3 #define FUNC_GPIO19_GPIO19 2 #define FUNC_GPIO19_VSPIQ 1 #define FUNC_GPIO19_GPIO19_0 0 @@ -225,33 +228,30 @@ #define FUNC_GPIO20_GPIO20_0 0 #define PERIPHS_IO_MUX_GPIO21_U (DR_REG_IO_MUX_BASE +0x7c) -#define FUNC_GPIO21_EMAC_RXD0 5 -#define FUNC_GPIO21_HS2_DATA3 3 +#define FUNC_GPIO21_EMAC_TX_EN 5 #define FUNC_GPIO21_GPIO21 2 #define FUNC_GPIO21_VSPIHD 1 #define FUNC_GPIO21_GPIO21_0 0 #define PERIPHS_IO_MUX_GPIO22_U (DR_REG_IO_MUX_BASE +0x80) -#define FUNC_GPIO22_EMAC_RXD1 5 -#define FUNC_GPIO22_HS2_CLK 3 +#define FUNC_GPIO22_EMAC_TXD1 5 +#define FUNC_GPIO22_U0RTS 3 #define FUNC_GPIO22_GPIO22 2 #define FUNC_GPIO22_VSPIWP 1 #define FUNC_GPIO22_GPIO22_0 0 #define PERIPHS_IO_MUX_U0RXD_U (DR_REG_IO_MUX_BASE +0x84) -#define FUNC_U0RXD_HS2_DATA0 3 #define FUNC_U0RXD_GPIO3 2 #define FUNC_U0RXD_CLK_OUT2 1 #define FUNC_U0RXD_U0RXD 0 #define PERIPHS_IO_MUX_U0TXD_U (DR_REG_IO_MUX_BASE +0x88) -#define FUNC_U0TXD_HS2_DATA1 3 +#define FUNC_U0TXD_EMAC_RXD2 3 #define FUNC_U0TXD_GPIO1 2 #define FUNC_U0TXD_CLK_OUT3 1 #define FUNC_U0TXD_U0TXD 0 #define PERIPHS_IO_MUX_GPIO23_U (DR_REG_IO_MUX_BASE +0x8c) -#define FUNC_GPIO23_EMAC_TX_EN 5 #define FUNC_GPIO23_HS1_STROBE 3 #define FUNC_GPIO23_GPIO23 2 #define FUNC_GPIO23_VSPID 1 diff --git a/components/esp32/include/soc/soc.h b/components/esp32/include/soc/soc.h index d542efe28e..2deab13e53 100755 --- a/components/esp32/include/soc/soc.h +++ b/components/esp32/include/soc/soc.h @@ -58,98 +58,93 @@ #define BIT(nr) (1UL << (nr)) +//write value to register #define REG_WRITE(_r, _v) (*(volatile uint32_t *)(_r)) = (_v) + +//read value from register #define REG_READ(_r) (*(volatile uint32_t *)(_r)) +//get bit or get bits from register #define REG_GET_BIT(_r, _b) (*(volatile uint32_t*)(_r) & (_b)) + +//set bit or set bits to register #define REG_SET_BIT(_r, _b) (*(volatile uint32_t*)(_r) |= (_b)) + +//clear bit or clear bits of register #define REG_CLR_BIT(_r, _b) (*(volatile uint32_t*)(_r) &= ~(_b)) + +//set bits of register controlled by mask #define REG_SET_BITS(_r, _b, _m) (*(volatile uint32_t*)(_r) = (*(volatile uint32_t*)(_r) & ~(_m)) | ((_b) & (_m))) -#define VALUE_GET_FIELD(_r, _f) (((_r) >> (_f##_S)) & (_f)) -#define VALUE_GET_FIELD2(_r, _f) (((_r) & (_f))>> (_f##_S)) -#define VALUE_SET_FIELD(_r, _f, _v) ((_r)=(((_r) & ~((_f) << (_f##_S)))|((_v)<<(_f##_S)))) -#define VALUE_SET_FIELD2(_r, _f, _v) ((_r)=(((_r) & ~(_f))|((_v)<<(_f##_S)))) -#define FIELD_TO_VALUE(_f, _v) (((_v)&(_f))<<_f##_S) -#define FIELD_TO_VALUE2(_f, _v) (((_v)<<_f##_S) & (_f)) + +//get field from register, used when _f is not left shifted by _f##_S #define REG_GET_FIELD(_r, _f) ((REG_READ(_r) >> (_f##_S)) & (_f)) + +//set field to register, used when _f is not left shifted by _f##_S #define REG_SET_FIELD(_r, _f, _v) (REG_WRITE((_r),((REG_READ(_r) & ~((_f) << (_f##_S)))|(((_v) & (_f))<<(_f##_S))))) +//get field value from a variable, used when _f is not left shifted by _f##_S +#define VALUE_GET_FIELD(_r, _f) (((_r) >> (_f##_S)) & (_f)) +//get field value from a variable, used when _f is left shifted by _f##_S +#define VALUE_GET_FIELD2(_r, _f) (((_r) & (_f))>> (_f##_S)) + +//set field value to a variable, used when _f is not left shifted by _f##_S +#define VALUE_SET_FIELD(_r, _f, _v) ((_r)=(((_r) & ~((_f) << (_f##_S)))|((_v)<<(_f##_S)))) + +//set field value to a variable, used when _f is left shifted by _f##_S +#define VALUE_SET_FIELD2(_r, _f, _v) ((_r)=(((_r) & ~(_f))|((_v)<<(_f##_S)))) + +//generate a value from a field value, used when _f is not left shifted by _f##_S +#define FIELD_TO_VALUE(_f, _v) (((_v)&(_f))<<_f##_S) + +//generate a value from a field value, used when _f is left shifted by _f##_S +#define FIELD_TO_VALUE2(_f, _v) (((_v)<<_f##_S) & (_f)) + +//read value from register #define READ_PERI_REG(addr) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) + +//write value to register #define WRITE_PERI_REG(addr, val) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val) + +//clear bits of register controlled by mask #define CLEAR_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)&(~(mask)))) + +//set bits of register controlled by mask #define SET_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)|(mask))) + +//get bits of register controlled by mask #define GET_PERI_REG_MASK(reg, mask) (READ_PERI_REG(reg) & (mask)) -#define GET_PERI_REG_BITS(reg, hipos,lowpos) ((READ_PERI_REG(reg)>>(lowpos))&((1<<((hipos)-(lowpos)+1))-1)) + +//get bits of register controlled by highest bit and lowest bit +#define GET_PERI_REG_BITS(reg, hipos,lowpos) ((READ_PERI_REG(reg)>>(lowpos))&((1<<((hipos)-(lowpos)+1))-1)) + +//set bits of register controlled by mask and shift #define SET_PERI_REG_BITS(reg,bit_map,value,shift) (WRITE_PERI_REG((reg),(READ_PERI_REG(reg)&(~((bit_map)<<(shift))))|(((value) & bit_map)<<(shift)) )) + +//get field of register #define GET_PERI_REG_BITS2(reg, mask,shift) ((READ_PERI_REG(reg)>>(shift))&(mask)) //}} //Periheral Clock {{ -#define APB_CLK_FREQ_ROM 13*1000000 +#define APB_CLK_FREQ_ROM 26*1000000 #define CPU_CLK_FREQ_ROM APB_CLK_FREQ_ROM #define CPU_CLK_FREQ APB_CLK_FREQ #define APB_CLK_FREQ 80*1000000 //unit: Hz #define UART_CLK_FREQ APB_CLK_FREQ -//#define WDT_CLK_FREQ APB_CLK_FREQ +#define WDT_CLK_FREQ APB_CLK_FREQ #define TIMER_CLK_FREQ (80000000>>4) //80MHz divided by 16 #define SPI_CLK_DIV 4 -//#define RTC_CLK_FREQ 32768 //unit:Hz -//#define RTC_CLK_FREQ 100000 //unit:Hz -//#define CALIB_CLK_MHZ 40 -#define TICKS_PER_US 13 // CPU is 80MHz +#define TICKS_PER_US_ROM 26 // CPU is 80MHz //}} -#if 0 -//Peripheral device base address define{{ -#define DR_REG_DPORT_BASE 0x3ff00000 -#define DR_REG_UART_BASE 0x60000000 -#define DR_REG_SPI1_BASE 0x60002000 //no -#define DR_REG_SPI0_BASE 0x60003000 //no -#define DR_REG_GPIO_BASE 0x60004000 //no -#define DR_REG_FE2_BASE 0x60005000 -#define DR_REG_FE_BASE 0x60006000 -#define DR_REG_TIMER_BASE 0x60007000 //no -#define DR_REG_RTCCNTL_BASE 0x60008000 -#define DR_REG_RTCIO_BASE 0x60008400 - -#define DR_REG_RTCMEM0_BASE 0x60021000 -#define DR_REG_RTCMEM1_BASE 0x60022000 -#define DR_REG_RTCMEM2_BASE 0x60023000 - -#define DR_REG_IO_MUX_BASE 0x60009000 //no -#define DR_REG_WDG_BASE 0x6000A000 //no -#define DR_REG_HINF_BASE 0x6000B000 //no -#define DR_REG_UHCI1_BASE 0x6000C000 -//#define DR_REG_MISC_BASE 0x6000D000 //no use -#define DR_REG_I2C_BASE 0x6000E000 //no -#define DR_REG_I2S_BASE 0x6000F000 -#define DR_REG_UART1_BASE 0x60010000 -#define DR_REG_BT_BASE 0x60011000 -//#define DR_REG_BT_BUFFER_BASE 0x60012000 //no use -#define DR_REG_I2C_EXT_BASE 0x60013000 //no -#define DR_REG_UHCI0_BASE 0x60014000 -#define DR_REG_SLCHOST_BASE 0x60015000 -#define DR_REG_RMT_BASE 0x60016000 -#define DR_REG_PCNT_BASE 0x60017000 -#define DR_REG_SLC_BASE 0x60018000 -#define DR_REG_LEDC_BASE 0x60019000 -#define DR_REG_EFUSE_BASE 0x6001A000 -#define DR_REG_SPI_ENCRYPT_BASE 0x6001B000 -#define DR_REG_PWM_BASE 0x6001C000 //no -#define DR_REG_TIMERGROUP_BASE 0x6001D000 //no -#define DR_REG_TIMERGROUP1_BASE 0x6001E000 //no -#define DR_REG_BB_BASE 0x6001F000 -#define DR_REG_GPIO_SD_BASE 0x60004f00 -#else #define DR_REG_DPORT_BASE 0x3ff00000 #define DR_REG_UART_BASE 0x3ff40000 -#define DR_REG_SPI1_BASE 0x3ff42000 //no -#define DR_REG_SPI0_BASE 0x3ff43000 //no -#define DR_REG_GPIO_BASE 0x3ff44000 //no +#define DR_REG_SPI1_BASE 0x3ff42000 +#define DR_REG_SPI0_BASE 0x3ff43000 +#define DR_REG_GPIO_BASE 0x3ff44000 #define DR_REG_FE2_BASE 0x3ff45000 #define DR_REG_FE_BASE 0x3ff46000 -#define DR_REG_TIMER_BASE 0x3ff47000 //no +#define DR_REG_TIMER_BASE 0x3ff47000 #define DR_REG_RTCCNTL_BASE 0x3ff48000 #define DR_REG_RTCIO_BASE 0x3ff48400 @@ -157,18 +152,16 @@ #define DR_REG_RTCMEM1_BASE 0x3ff62000 #define DR_REG_RTCMEM2_BASE 0x3ff63000 -#define DR_REG_IO_MUX_BASE 0x3ff49000 //no -#define DR_REG_WDG_BASE 0x3ff4A000 //no -#define DR_REG_HINF_BASE 0x3ff4B000 //no +#define DR_REG_IO_MUX_BASE 0x3ff49000 +#define DR_REG_WDG_BASE 0x3ff4A000 +#define DR_REG_HINF_BASE 0x3ff4B000 #define DR_REG_UHCI1_BASE 0x3ff4C000 -//#define DR_REG_MISC_BASE 0x6000D000 //no use -#define DR_REG_I2C_BASE 0x3ff4E000 //no +#define DR_REG_I2C_BASE 0x3ff4E000 #define DR_REG_I2S_BASE 0x3ff4F000 #define DR_REG_I2S1_BASE 0x3ff6D000 #define DR_REG_UART1_BASE 0x3ff50000 #define DR_REG_BT_BASE 0x3ff51000 -//#define DR_REG_BT_BUFFER_BASE 0x60012000 //no use -#define DR_REG_I2C_EXT_BASE 0x3ff53000 //no +#define DR_REG_I2C_EXT_BASE 0x3ff53000 #define DR_REG_UHCI0_BASE 0x3ff54000 #define DR_REG_SLCHOST_BASE 0x3ff55000 #define DR_REG_RMT_BASE 0x3ff56000 @@ -177,94 +170,139 @@ #define DR_REG_LEDC_BASE 0x3ff59000 #define DR_REG_EFUSE_BASE 0x3ff5A000 #define DR_REG_SPI_ENCRYPT_BASE 0x3ff5B000 -#define DR_REG_PWM_BASE 0x3ff5C000 //no -#define DR_REG_TIMERS_BASE 0x3ff5F000 //no -#define DR_REG_TIMERGROUP1_BASE 0x3ff5E000 //no -#define DR_REG_BB_BASE 0x3ff5F000 +#define DR_REG_BB_BASE 0x3ff5C000 +#define DR_REG_PWM_BASE 0x3ff5E000 +#define DR_REG_TIMERS_BASE(i) (0x3ff5F000 + i * (0x1000)) #define DR_REG_GPIO_SD_BASE 0x3ff44f00 -#endif //}} #define REG_SPI_BASE(i) (DR_REG_SPI0_BASE - i*(0x1000)) #define PERIPHS_TIMER_BASEDDR DR_REG_TIMER_BASE #define PERIPHS_SPI_ENCRYPT_BASEADDR DR_REG_SPI_ENCRYPT_BASE -#define UART0_UNHOLD_MASK 0x3 -#define UART1_UNHOLD_MASK 0x60 -#define SDIO_UNHOLD_MASK 0xfc -#define SPI_UNHOLD_MASK 0xfc +//Interrupt hardware source table +//This table is decided by hardware, don't touch this. +#define ETS_WIFI_MAC_INTR_SOURCE 0/**< interrupt of WiFi MAC, level*/ +#define ETS_WIFI_MAC_NMI_SOURCE 1/**< interrupt of WiFi MAC, NMI, use if MAC have bug to fix in NMI*/ +#define ETS_WIFI_BB_INTR_SOURCE 2/**< interrupt of WiFi BB, level, we can do some calibartion*/ +#define ETS_BT_MAC_INTR_SOURCE 3/**< will be cancelled*/ +#define ETS_BT_BB_INTR_SOURCE 4/**< interrupt of BT BB, level*/ +#define ETS_BT_BB_NMI_SOURCE 5/**< interrupt of BT BB, NMI, use if BB have bug to fix in NMI*/ +#define ETS_RWBT_INTR_SOURCE 6/**< interrupt of RWBT, level*/ +#define ETS_RWBLE_INTR_SOURCE 7/**< interrupt of RWBLE, level*/ +#define ETS_RWBT_NMI_SOURCE 8/**< interrupt of RWBT, NMI, use if RWBT have bug to fix in NMI*/ +#define ETS_RWBLE_NMI_SOURCE 9/**< interrupt of RWBLE, NMI, use if RWBT have bug to fix in NMI*/ +#define ETS_SLC0_INTR_SOURCE 10/**< interrupt of SLC0, level*/ +#define ETS_SLC1_INTR_SOURCE 11/**< interrupt of SLC1, level*/ +#define ETS_UHCI0_INTR_SOURCE 12/**< interrupt of UHCI0, level*/ +#define ETS_UHCI1_INTR_SOURCE 13/**< interrupt of UHCI1, level*/ +#define ETS_TG0_T0_LEVEL_INTR_SOURCE 14/**< interrupt of TIMER_GROUP0, TIMER0, level, we would like use EDGE for timer if permission*/ +#define ETS_TG0_T1_LEVEL_INTR_SOURCE 15/**< interrupt of TIMER_GROUP0, TIMER1, level, we would like use EDGE for timer if permission*/ +#define ETS_TG0_WDT_LEVEL_INTR_SOURCE 16/**< interrupt of TIMER_GROUP0, WATCHDOG, level*/ +#define ETS_TG0_LACT_LEVEL_INTR_SOURCE 17/**< interrupt of TIMER_GROUP0, LACT, level*/ +#define ETS_TG1_T0_LEVEL_INTR_SOURCE 18/**< interrupt of TIMER_GROUP1, TIMER0, level, we would like use EDGE for timer if permission*/ +#define ETS_TG1_T1_LEVEL_INTR_SOURCE 19/**< interrupt of TIMER_GROUP1, TIMER1, level, we would like use EDGE for timer if permission*/ +#define ETS_TG1_WDT_LEVEL_INTR_SOURCE 20/**< interrupt of TIMER_GROUP1, WATCHDOG, level*/ +#define ETS_TG1_LACT_LEVEL_INTR_SOURCE 21/**< interrupt of TIMER_GROUP1, LACT, level*/ +#define ETS_GPIO_INTR_SOURCE 22/**< interrupt of GPIO, level*/ +#define ETS_GPIO_NMI_SOURCE 23/**< interrupt of GPIO, NMI*/ +#define ETS_FROM_CPU_INTR0_SOURCE 24/**< interrupt0 generated from a CPU, level*/ +#define ETS_FROM_CPU_INTR1_SOURCE 25/**< interrupt1 generated from a CPU, level*/ +#define ETS_FROM_CPU_INTR2_SOURCE 26/**< interrupt2 generated from a CPU, level*/ +#define ETS_FROM_CPU_INTR3_SOURCE 27/**< interrupt3 generated from a CPU, level*/ +#define ETS_SPI0_INTR_SOURCE 28/**< interrupt of SPI0, level, SPI0 is for Cache Access, do not use this*/ +#define ETS_SPI1_INTR_SOURCE 29/**< interrupt of SPI1, level, SPI1 is for flash read/write, do not use this*/ +#define ETS_SPI2_INTR_SOURCE 30/**< interrupt of SPI2, level*/ +#define ETS_SPI3_INTR_SOURCE 31/**< interrupt of SPI3, level*/ +#define ETS_I2S0_INTR_SOURCE 32/**< interrupt of I2S0, level*/ +#define ETS_I2S1_INTR_SOURCE 33/**< interrupt of I2S1, level*/ +#define ETS_UART0_INTR_SOURCE 34/**< interrupt of UART0, level*/ +#define ETS_UART1_INTR_SOURCE 35/**< interrupt of UART1, level*/ +#define ETS_UART2_INTR_SOURCE 36/**< interrupt of UART2, level*/ +#define ETS_SDIO_HOST_INTR_SOURCE 37/**< interrupt of SD/SDIO/MMC HOST, level*/ +#define ETS_ETH_MAC_INTR_SOURCE 38/**< interrupt of ethernet mac, level*/ +#define ETS_PWM0_INTR_SOURCE 39/**< interrupt of PWM0, level, Reserved*/ +#define ETS_PWM1_INTR_SOURCE 40/**< interrupt of PWM1, level, Reserved*/ +#define ETS_PWM2_INTR_SOURCE 41/**< interrupt of PWM2, level*/ +#define ETS_PWM3_INTR_SOURCE 42/**< interruot of PWM3, level*/ +#define ETS_LEDC_INTR_SOURCE 43/**< interrupt of LED PWM, level*/ +#define ETS_EFUSE_INTR_SOURCE 44/**< interrupt of efuse, level, not likely to use*/ +#define ETS_CAN_INTR_SOURCE 45/**< interrupt of can, level*/ +#define ETS_RTC_CORE_INTR_SOURCE 46/**< interrupt of rtc core, level, include rtc watchdog*/ +#define ETS_RMT_INTR_SOURCE 47/**< interrupt of remote controller, level*/ +#define ETS_PCNT_INTR_SOURCE 48/**< interrupt of pluse count, level*/ +#define ETS_I2C_EXT0_INTR_SOURCE 49/**< interrupt of I2C controller1, level*/ +#define ETS_I2C_EXT1_INTR_SOURCE 50/**< interrupt of I2C controller0, level*/ +#define ETS_RSA_INTR_SOURCE 51/**< interrupt of RSA accelerator, level*/ +#define ETS_SPI1_DMA_INTR_SOURCE 52/**< interrupt of SPI1 DMA, SPI1 is for flash read/write, do not use this*/ +#define ETS_SPI2_DMA_INTR_SOURCE 53/**< interrupt of SPI2 DMA, level*/ +#define ETS_SPI3_DMA_INTR_SOURCE 54/**< interrupt of SPI3 DMA, level*/ +#define ETS_WDT_INTR_SOURCE 55/**< will be cancelled*/ +#define ETS_TIMER1_INTR_SOURCE 56/**< will be cancelled*/ +#define ETS_TIMER2_INTR_SOURCE 57/**< will be cancelled*/ +#define ETS_TG0_T0_EDGE_INTR_SOURCE 58/**< interrupt of TIMER_GROUP0, TIMER0, EDGE*/ +#define ETS_TG0_T1_EDGE_INTR_SOURCE 59/**< interrupt of TIMER_GROUP0, TIMER1, EDGE*/ +#define ETS_TG0_WDT_EDGE_INTR_SOURCE 60/**< interrupt of TIMER_GROUP0, WATCH DOG, EDGE*/ +#define ETS_TG0_LACT_EDGE_INTR_SOURCE 61/**< interrupt of TIMER_GROUP0, LACT, EDGE*/ +#define ETS_TG1_T0_EDGE_INTR_SOURCE 62/**< interrupt of TIMER_GROUP1, TIMER0, EDGE*/ +#define ETS_TG1_T1_EDGE_INTR_SOURCE 63/**< interrupt of TIMER_GROUP1, TIMER1, EDGE*/ +#define ETS_TG1_WDT_EDGE_INTR_SOURCE 64/**< interrupt of TIMER_GROUP1, WATCHDOG, EDGE*/ +#define ETS_TG1_LACT_EDGE_INTR_SOURCE 65/**< interrupt of TIMER_GROUP0, LACT, EDGE*/ +#define ETS_MMU_IA_INTR_SOURCE 66/**< interrupt of MMU Invalid Access, LEVEL*/ +#define ETS_MPU_IA_INTR_SOURCE 67/**< interrupt of MPU Invalid Access, LEVEL*/ +#define ETS_CACHE_IA_INTR_SOURCE 68/**< interrupt of Cache Invalied Access, LEVEL*/ -// TIMER reg {{ -#define TIMER_REG_READ(addr) READ_PERI_REG(addr) -#define TIMER_REG_WRITE(addr, val) WRITE_PERI_REG(addr, val) -#define TIMER_SET_REG_MASK(reg, mask) WRITE_PERI_REG(reg, (READ_PERI_REG(reg)|(mask))) -/* Returns the current time according to the timer timer. */ -#define NOW() TIMER_REG_READ(FRC2_COUNT_ADDRESS) -//load initial_value to timer1 -#define FRC1_LOAD_ADDRESS (PERIPHS_TIMER_BASEDDR +0x00) -#define FRC1_LOAD_DATA_MSB 22 -#define FRC1_LOAD_DATA_LSB 0 -#define FRC1_LOAD_DATA_MASK 0x007fffff +//interrupt cpu using table, Please see the core-isa.h +/************************************************************************************************************* + * Intr num Level Type PRO CPU usage APP CPU uasge + * 0 1 extern level WMAC Reserved + * 1 1 extern level BT/BLE Host Reserved + * 2 1 extern level FROM_CPU FROM_CPU + * 3 1 extern level TG0_WDT Reserved + * 4 1 extern level WBB + * 5 1 extern level Reserved + * 6 1 timer FreeRTOS Tick(L1) FreeRTOS Tick(L1) + * 7 1 software Reserved Reserved + * 8 1 extern level Reserved + * 9 1 extern level + * 10 1 extern edge Internal Timer + * 11 3 profiling + * 12 1 extern level + * 13 1 extern level + * 14 7 nmi Reserved Reserved + * 15 3 timer FreeRTOS Tick(L3) FreeRTOS Tick(L3) + * 16 5 timer + * 17 1 extern level + * 18 1 extern level + * 19 2 extern level + * 20 2 extern level + * 21 2 extern level + * 22 3 extern edge + * 23 3 extern level + * 24 4 extern level + * 25 4 extern level Reserved Reserved + * 26 5 extern level Reserved Reserved + * 27 3 extern level Reserved Reserved + * 28 4 extern edge + * 29 3 software Reserved Reserved + * 30 4 extern edge Reserved Reserved + * 31 5 extern level Reserved Reserved + ************************************************************************************************************* + */ -//timer1's counter value(count from initial_value to 0) -#define FRC1_COUNT_ADDRESS (PERIPHS_TIMER_BASEDDR +0x04) -#define FRC1_COUNT_DATA_MSB 22 -#define FRC1_COUNT_DATA_LSB 0 -#define FRC1_COUNT_DATA_MASK 0x007fffff +//CPU0 Interrupt number reserved, not touch this. +#define ETS_WMAC_INUM 0 +#define ETS_BT_HOST_INUM 1 +#define ETS_FROM_CPU_INUM 2 +#define ETS_T0_WDT_INUM 3 +#define ETS_WBB_INUM 4 +#define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/ -#define FRC1_CTRL_ADDRESS (PERIPHS_TIMER_BASEDDR +0x08) -#define FRC1_CTRL_DATA_MSB 7 -#define FRC1_CTRL_DATA_LSB 0 -#define FRC1_CTRL_DATA_MASK 0x000000ff +//CPU0 Intrrupt number used in ROM, should be cancelled in SDK +#define ETS_SLC_INUM 1 +#define ETS_UART0_INUM 5 +#define ETS_UART1_INUM 5 -//clear timer1's interrupt when write this address -#define FRC1_INT_ADDRESS (PERIPHS_TIMER_BASEDDR +0x0c) -#define FRC1_INT_CLR_MSB 0 -#define FRC1_INT_CLR_LSB 0 -#define FRC1_INT_CLR_MASK 0x00000001 -//only used for simulation -#define FRC1_TEST_ADDRESS (PERIPHS_TIMER_BASEDDR +0x10) -#define FRC1_TEST_MODE_MSB 0 -#define FRC1_TEST_MODE_LSB 0 -#define FRC1_TEST_MODE_MASK 0x00000001 - -//load initial_value to timer2 -#define FRC2_LOAD_ADDRESS (PERIPHS_TIMER_BASEDDR +0x20) -#define FRC2_LOAD_DATA_MSB 31 -#define FRC2_LOAD_DATA_LSB 0 -#define FRC2_LOAD_DATA_MASK 0xffffffff - -//timer2's counter value(count from initial_value to 0) -#define FRC2_COUNT_ADDRESS (PERIPHS_TIMER_BASEDDR +0x24) -#define FRC2_COUNT_DATA_MSB 31 -#define FRC2_COUNT_DATA_LSB 0 -#define FRC2_COUNT_DATA_MASK 0xffffffff - -#define FRC2_CTRL_ADDRESS (PERIPHS_TIMER_BASEDDR +0x28) -#define FRC2_CTRL_DATA_MSB 7 -#define FRC2_CTRL_DATA_LSB 0 -#define FRC2_CTRL_DATA_MASK 0x000000ff - -//clear interrupt when write this address -#define FRC2_INT_ADDRESS (PERIPHS_TIMER_BASEDDR +0x2c) -#define FRC2_INT_CLR_MSB 0 -#define FRC2_INT_CLR_LSB 0 -#define FRC2_INT_CLR_MASK 0x00000001 - -//set Alarm_value for timer2 to generate interrupt -#define FRC2_ALARM_ADDRESS (PERIPHS_TIMER_BASEDDR +0x30) -#define FRC2_ALARM_DATA_MSB 31 -#define FRC2_ALARM_DATA_LSB 0 -#define FRC2_ALARM_DATA_MASK 0xffffffff -// }} - -#define SPI_ENCRYPT_CNTL (PERIPHS_SPI_ENCRYPT_BASEADDR + 0x20) -#define SPI_ENCRYPT_CNTL_ENA BIT(0) - -#define SPI_ENCRYPT_ADDR (PERIPHS_SPI_ENCRYPT_BASEADDR + 0x24) - -#define SPI_ENCRYPT_CHECKDONE (PERIPHS_SPI_ENCRYPT_BASEADDR + 0x28) -#define SPI_ENCRYPT_CHECKDONE_STATUS BIT(0) #endif /* _ESP32_SOC_H_ */ diff --git a/components/esp32/include/soc/timers_reg.h b/components/esp32/include/soc/timers_reg.h index 577f375aa7..21ddfafcb6 100644 --- a/components/esp32/include/soc/timers_reg.h +++ b/components/esp32/include/soc/timers_reg.h @@ -16,7 +16,7 @@ #include "soc.h" -#define T0CONFIG (DR_REG_TIMERS_BASE + 0x0000) +#define T0CONFIG(i) (DR_REG_TIMERS_BASE(i) + 0x0000) #define TIMERS_T0_EN (BIT(31)) #define TIMERS_T0_EN_S 31 #define TIMERS_T0_INCREASE (BIT(30)) @@ -32,39 +32,39 @@ #define TIMERS_T0_ALARM_EN (BIT(10)) #define TIMERS_T0_ALARM_EN_S 10 -#define T0LO (DR_REG_TIMERS_BASE + 0x0004) +#define T0LO(i) (DR_REG_TIMERS_BASE(i) + 0x0004) #define TIMERS_T0_LO 0xFFFFFFFF #define TIMERS_T0_LO_S 0 -#define T0HI (DR_REG_TIMERS_BASE + 0x0008) +#define T0HI(i) (DR_REG_TIMERS_BASE(i) + 0x0008) #define TIMERS_T0_HI 0xFFFFFFFF #define TIMERS_T0_HI_S 0 -#define T0UPDATE (DR_REG_TIMERS_BASE + 0x000c) +#define T0UPDATE(i) (DR_REG_TIMERS_BASE(i) + 0x000c) #define TIMERS_T0_UPDATE 0xFFFFFFFF #define TIMERS_T0_UPDATE_S 0 -#define T0ALARMLO (DR_REG_TIMERS_BASE + 0x0010) +#define T0ALARMLO(i) (DR_REG_TIMERS_BASE(i) + 0x0010) #define TIMERS_T0_ALARM_LO 0xFFFFFFFF #define TIMERS_T0_ALARM_LO_S 0 -#define T0ALARMHI (DR_REG_TIMERS_BASE + 0x0014) +#define T0ALARMHI(i) (DR_REG_TIMERS_BASE(i) + 0x0014) #define TIMERS_T0_ALARM_HI 0xFFFFFFFF #define TIMERS_T0_ALARM_HI_S 0 -#define T0LOADLO (DR_REG_TIMERS_BASE + 0x0018) +#define T0LOADLO(i) (DR_REG_TIMERS_BASE(i) + 0x0018) #define TIMERS_T0_LOAD_LO 0xFFFFFFFF #define TIMERS_T0_LOAD_LO_S 0 -#define T0LOADHI (DR_REG_TIMERS_BASE + 0x001c) +#define T0LOADHI(i) (DR_REG_TIMERS_BASE(i) + 0x001c) #define TIMERS_T0_LOAD_HI 0xFFFFFFFF #define TIMERS_T0_LOAD_HI_S 0 -#define T0LOAD (DR_REG_TIMERS_BASE + 0x0020) +#define T0LOAD(i) (DR_REG_TIMERS_BASE(i) + 0x0020) #define TIMERS_T0_LOAD 0xFFFFFFFF #define TIMERS_T0_LOAD_S 0 -#define T1CONFIG (DR_REG_TIMERS_BASE + 0x0024) +#define T1CONFIG(i) (DR_REG_TIMERS_BASE(i) + 0x0024) #define TIMERS_T1_EN (BIT(31)) #define TIMERS_T1_EN_S 31 #define TIMERS_T1_INCREASE (BIT(30)) @@ -80,39 +80,39 @@ #define TIMERS_T1_ALARM_EN (BIT(10)) #define TIMERS_T1_ALARM_EN_S 10 -#define T1LO (DR_REG_TIMERS_BASE + 0x0028) +#define T1LO(i) (DR_REG_TIMERS_BASE(i) + 0x0028) #define TIMERS_T1_LO 0xFFFFFFFF #define TIMERS_T1_LO_S 0 -#define T1HI (DR_REG_TIMERS_BASE + 0x002c) +#define T1HI(i) (DR_REG_TIMERS_BASE(i) + 0x002c) #define TIMERS_T1_HI 0xFFFFFFFF #define TIMERS_T1_HI_S 0 -#define T1UPDATE (DR_REG_TIMERS_BASE + 0x0030) +#define T1UPDATE(i) (DR_REG_TIMERS_BASE(i) + 0x0030) #define TIMERS_T1_UPDATE 0xFFFFFFFF #define TIMERS_T1_UPDATE_S 0 -#define T1ALARMLO (DR_REG_TIMERS_BASE + 0x0034) +#define T1ALARMLO(i) (DR_REG_TIMERS_BASE(i) + 0x0034) #define TIMERS_T1_ALARM_LO 0xFFFFFFFF #define TIMERS_T1_ALARM_LO_S 0 -#define T1ALARMHI (DR_REG_TIMERS_BASE + 0x0038) +#define T1ALARMHI(i) (DR_REG_TIMERS_BASE(i) + 0x0038) #define TIMERS_T1_ALARM_HI 0xFFFFFFFF #define TIMERS_T1_ALARM_HI_S 0 -#define T1LOADLO (DR_REG_TIMERS_BASE + 0x003c) +#define T1LOADLO(i) (DR_REG_TIMERS_BASE(i) + 0x003c) #define TIMERS_T1_LOAD_LO 0xFFFFFFFF #define TIMERS_T1_LOAD_LO_S 0 -#define T1LOADHI (DR_REG_TIMERS_BASE + 0x0040) +#define T1LOADHI(i) (DR_REG_TIMERS_BASE(i) + 0x0040) #define TIMERS_T1_LOAD_HI 0xFFFFFFFF #define TIMERS_T1_LOAD_HI_S 0 -#define T1LOAD (DR_REG_TIMERS_BASE + 0x0044) +#define T1LOAD(i) (DR_REG_TIMERS_BASE(i) + 0x0044) #define TIMERS_T1_LOAD 0xFFFFFFFF #define TIMERS_T1_LOAD_S 0 -#define WDTCONFIG0 (DR_REG_TIMERS_BASE + 0x0048) +#define WDTCONFIG0(i) (DR_REG_TIMERS_BASE(i) + 0x0048) #define TIMERS_WDT_EN (BIT(31)) #define TIMERS_WDT_EN_S 31 #define TIMERS_WDT_STG0 0x00000003 @@ -134,35 +134,35 @@ #define TIMERS_WDT_FLASHBOOT_MOD_EN (BIT(14)) #define TIMERS_WDT_FLASHBOOT_MOD_EN_S 14 -#define WDTCONFIG1 (DR_REG_TIMERS_BASE + 0x004c) +#define WDTCONFIG1(i) (DR_REG_TIMERS_BASE(i) + 0x004c) #define TIMERS_WDT_CLK_PRESCALE 0x0000FFFF #define TIMERS_WDT_CLK_PRESCALE_S 16 -#define WDTCONFIG2 (DR_REG_TIMERS_BASE + 0x0050) +#define WDTCONFIG2(i) (DR_REG_TIMERS_BASE(i) + 0x0050) #define TIMERS_WDT_STG0_HOLD 0xFFFFFFFF #define TIMERS_WDT_STG0_HOLD_S 0 -#define WDTCONFIG3 (DR_REG_TIMERS_BASE + 0x0054) +#define WDTCONFIG3(i) (DR_REG_TIMERS_BASE(i) + 0x0054) #define TIMERS_WDT_STG1_HOLD 0xFFFFFFFF #define TIMERS_WDT_STG1_HOLD_S 0 -#define WDTCONFIG4 (DR_REG_TIMERS_BASE + 0x0058) +#define WDTCONFIG4(i) (DR_REG_TIMERS_BASE(i) + 0x0058) #define TIMERS_WDT_STG2_HOLD 0xFFFFFFFF #define TIMERS_WDT_STG2_HOLD_S 0 -#define WDTCONFIG5 (DR_REG_TIMERS_BASE + 0x005c) +#define WDTCONFIG5(i) (DR_REG_TIMERS_BASE(i) + 0x005c) #define TIMERS_WDT_STG3_HOLD 0xFFFFFFFF #define TIMERS_WDT_STG3_HOLD_S 0 -#define WDTFEED (DR_REG_TIMERS_BASE + 0x0060) +#define WDTFEED(i) (DR_REG_TIMERS_BASE(i) + 0x0060) #define TIMERS_WDT_FEED 0xFFFFFFFF #define TIMERS_WDT_FEED_S 0 -#define WDTWPROTECT (DR_REG_TIMERS_BASE + 0x0064) +#define WDTWPROTECT(i) (DR_REG_TIMERS_BASE(i) + 0x0064) #define TIMERS_WDT_WKEY 0xFFFFFFFF #define TIMERS_WDT_WKEY_S 0 -#define RTCCALICFG (DR_REG_TIMERS_BASE + 0x0068) +#define RTCCALICFG(i) (DR_REG_TIMERS_BASE(i) + 0x0068) #define TIMERS_RTC_CALI_START (BIT(31)) #define TIMERS_RTC_CALI_START_S 31 #define TIMERS_RTC_CALI_MAX 0x00007FFF @@ -174,11 +174,11 @@ #define TIMERS_RTC_CALI_START_CYCLING (BIT(12)) #define TIMERS_RTC_CALI_START_CYCLING_S 12 -#define RTCCALICFG1 (DR_REG_TIMERS_BASE + 0x006c) +#define RTCCALICFG1(i) (DR_REG_TIMERS_BASE(i) + 0x006c) #define TIMERS_RTC_CALI_VALUE 0x01FFFFFF #define TIMERS_RTC_CALI_VALUE_S 7 -#define LACTCONFIG (DR_REG_TIMERS_BASE + 0x0070) +#define LACTCONFIG(i) (DR_REG_TIMERS_BASE(i) + 0x0070) #define TIMERS_LACT_EN (BIT(31)) #define TIMERS_LACT_EN_S 31 #define TIMERS_LACT_INCREASE (BIT(30)) @@ -200,43 +200,43 @@ #define TIMERS_LACT_RTC_ONLY (BIT(7)) #define TIMERS_LACT_RTC_ONLY_S 7 -#define LACTRTC (DR_REG_TIMERS_BASE + 0x0074) +#define LACTRTC(i) (DR_REG_TIMERS_BASE(i) + 0x0074) #define TIMERS_LACT_RTC_STEP_LEN 0x03FFFFFF #define TIMERS_LACT_RTC_STEP_LEN_S 6 -#define LACTLO (DR_REG_TIMERS_BASE + 0x0078) +#define LACTLO(i) (DR_REG_TIMERS_BASE(i) + 0x0078) #define TIMERS_LACT_LO 0xFFFFFFFF #define TIMERS_LACT_LO_S 0 -#define LACTHI (DR_REG_TIMERS_BASE + 0x007c) +#define LACTHI(i) (DR_REG_TIMERS_BASE(i) + 0x007c) #define TIMERS_LACT_HI 0xFFFFFFFF #define TIMERS_LACT_HI_S 0 -#define LACTUPDATE (DR_REG_TIMERS_BASE + 0x0080) +#define LACTUPDATE(i) (DR_REG_TIMERS_BASE(i) + 0x0080) #define TIMERS_LACT_UPDATE 0xFFFFFFFF #define TIMERS_LACT_UPDATE_S 0 -#define LACTALARMLO (DR_REG_TIMERS_BASE + 0x0084) +#define LACTALARMLO(i) (DR_REG_TIMERS_BASE(i) + 0x0084) #define TIMERS_LACT_ALARM_LO 0xFFFFFFFF #define TIMERS_LACT_ALARM_LO_S 0 -#define LACTALARMHI (DR_REG_TIMERS_BASE + 0x0088) +#define LACTALARMHI(i) (DR_REG_TIMERS_BASE(i) + 0x0088) #define TIMERS_LACT_ALARM_HI 0xFFFFFFFF #define TIMERS_LACT_ALARM_HI_S 0 -#define LACTLOADLO (DR_REG_TIMERS_BASE + 0x008c) +#define LACTLOADLO(i) (DR_REG_TIMERS_BASE(i) + 0x008c) #define TIMERS_LACT_LOAD_LO 0xFFFFFFFF #define TIMERS_LACT_LOAD_LO_S 0 -#define LACTLOADHI (DR_REG_TIMERS_BASE + 0x0090) +#define LACTLOADHI(i) (DR_REG_TIMERS_BASE(i) + 0x0090) #define TIMERS_LACT_LOAD_HI 0xFFFFFFFF #define TIMERS_LACT_LOAD_HI_S 0 -#define LACTLOAD (DR_REG_TIMERS_BASE + 0x0094) +#define LACTLOAD(i) (DR_REG_TIMERS_BASE(i) + 0x0094) #define TIMERS_LACT_LOAD 0xFFFFFFFF #define TIMERS_LACT_LOAD_S 0 -#define INT_ENA_TIMERS (DR_REG_TIMERS_BASE + 0x0098) +#define INT_ENA_TIMERS(i) (DR_REG_TIMERS_BASE(i) + 0x0098) #define TIMERS_LACT_INT_ENA (BIT(3)) #define TIMERS_LACT_INT_ENA_S 3 #define TIMERS_WDT_INT_ENA (BIT(2)) @@ -246,7 +246,7 @@ #define TIMERS_T0_INT_ENA (BIT(0)) #define TIMERS_T0_INT_ENA_S 0 -#define INT_RAW_TIMERS (DR_REG_TIMERS_BASE + 0x009c) +#define INT_RAW_TIMERS(i) (DR_REG_TIMERS_BASE(i) + 0x009c) #define TIMERS_LACT_INT_RAW (BIT(3)) #define TIMERS_LACT_INT_RAW_S 3 #define TIMERS_WDT_INT_RAW (BIT(2)) @@ -256,7 +256,7 @@ #define TIMERS_T0_INT_RAW (BIT(0)) #define TIMERS_T0_INT_RAW_S 0 -#define INT_ST_TIMERS (DR_REG_TIMERS_BASE + 0x00a0) +#define INT_ST_TIMERS(i) (DR_REG_TIMERS_BASE(i) + 0x00a0) #define TIMERS_LACT_INT_ST (BIT(3)) #define TIMERS_LACT_INT_ST_S 3 #define TIMERS_WDT_INT_ST (BIT(2)) @@ -266,7 +266,7 @@ #define TIMERS_T0_INT_ST (BIT(0)) #define TIMERS_T0_INT_ST_S 0 -#define INT_CLR_TIMERS (DR_REG_TIMERS_BASE + 0x00a4) +#define INT_CLR_TIMERS(i) (DR_REG_TIMERS_BASE(i) + 0x00a4) #define TIMERS_LACT_INT_CLR (BIT(3)) #define TIMERS_LACT_INT_CLR_S 3 #define TIMERS_WDT_INT_CLR (BIT(2)) @@ -276,12 +276,12 @@ #define TIMERS_T0_INT_CLR (BIT(0)) #define TIMERS_T0_INT_CLR_S 0 -#define NTIMERS_DATE (DR_REG_TIMERS_BASE + 0x00f8) +#define NTIMERS_DATE(i) (DR_REG_TIMERS_BASE(i) + 0x00f8) #define TIMERS_NTIMERS_DATE 0x0FFFFFFF #define TIMERS_NTIMERS_DATE_S 0 #define TIMERS_NTIMERS_DATE_VERSION 0x1604290 -#define REGCLK (DR_REG_TIMERS_BASE + 0x00fc) +#define REGCLK(i) (DR_REG_TIMERS_BASE(i) + 0x00fc) #define TIMERS_CLK_EN (BIT(31)) #define TIMERS_CLK_EN_S 31 diff --git a/components/esp32/ipc.c b/components/esp32/ipc.c new file mode 100644 index 0000000000..b7524cae68 --- /dev/null +++ b/components/esp32/ipc.c @@ -0,0 +1,117 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include "esp_err.h" +#include "esp_ipc.h" +#include "esp_attr.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + + +static TaskHandle_t s_ipc_tasks[portNUM_PROCESSORS]; // Two high priority tasks, one for each CPU +static SemaphoreHandle_t s_ipc_mutex; // This mutex is used as a global lock for esp_ipc_* APIs +static SemaphoreHandle_t s_ipc_sem[portNUM_PROCESSORS]; // Two semaphores used to wake each of s_ipc_tasks +static SemaphoreHandle_t s_ipc_ack; // Semaphore used to acknowledge that task was woken up, + // or function has finished running +static volatile esp_ipc_func_t s_func; // Function which should be called by high priority task +static void * volatile s_func_arg; // Argument to pass into s_func +typedef enum { + IPC_WAIT_FOR_START, + IPC_WAIT_FOR_END +} esp_ipc_wait_t; + +static volatile esp_ipc_wait_t s_ipc_wait; // This variable tells high priority task when it should give + // s_ipc_ack semaphore: before s_func is called, or + // after it returns + +static void IRAM_ATTR ipc_task(void* arg) +{ + const uint32_t cpuid = (uint32_t) arg; + assert(cpuid == xPortGetCoreID()); + while (true) { + // Wait for IPC to be initiated. + // This will be indicated by giving the semaphore corresponding to + // this CPU. + if (xSemaphoreTake(s_ipc_sem[cpuid], portMAX_DELAY) != pdTRUE) { + // TODO: when can this happen? + abort(); + } + + esp_ipc_func_t func = s_func; + void* arg = s_func_arg; + + if (s_ipc_wait == IPC_WAIT_FOR_START) { + xSemaphoreGive(s_ipc_ack); + } + (*func)(arg); + if (s_ipc_wait == IPC_WAIT_FOR_END) { + xSemaphoreGive(s_ipc_ack); + } + } + // TODO: currently this is unreachable code. Introduce esp_ipc_uninit + // function which will signal to both tasks that they can shut down. + // Not critical at this point, we don't have a use case for stopping + // IPC yet. + // Also need to delete the semaphore here. + vTaskDelete(NULL); +} + +void esp_ipc_init() +{ + s_ipc_mutex = xSemaphoreCreateMutex(); + s_ipc_ack = xSemaphoreCreateBinary(); + const char* task_names[2] = {"ipc0", "ipc1"}; + for (int i = 0; i < portNUM_PROCESSORS; ++i) { + s_ipc_sem[i] = xSemaphoreCreateBinary(); + xTaskCreatePinnedToCore(ipc_task, task_names[i], XT_STACK_MIN_SIZE, (void*) i, + configMAX_PRIORITIES - 1, &s_ipc_tasks[i], i); + } +} + +static esp_err_t esp_ipc_call_and_wait(uint32_t cpu_id, esp_ipc_func_t func, void* arg, esp_ipc_wait_t wait_for) +{ + if (cpu_id >= portNUM_PROCESSORS) { + return ESP_ERR_INVALID_ARG; + } + if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { + return ESP_ERR_INVALID_STATE; + } + + xSemaphoreTake(s_ipc_mutex, portMAX_DELAY); + + s_func = func; + s_func_arg = arg; + s_ipc_wait = IPC_WAIT_FOR_START; + xSemaphoreGive(s_ipc_sem[cpu_id]); + xSemaphoreTake(s_ipc_ack, portMAX_DELAY); + xSemaphoreGive(s_ipc_mutex); + return ESP_OK; +} + +esp_err_t esp_ipc_call(uint32_t cpu_id, esp_ipc_func_t func, void* arg) +{ + return esp_ipc_call_and_wait(cpu_id, func, arg, IPC_WAIT_FOR_START); +} + +esp_err_t esp_ipc_call_blocking(uint32_t cpu_id, esp_ipc_func_t func, void* arg) +{ + return esp_ipc_call_and_wait(cpu_id, func, arg, IPC_WAIT_FOR_END); +} + diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index 3777405fe4..823ca4c6e8 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -64,6 +64,8 @@ PROVIDE ( Cache_Read_Disable = 0x40009ab8 ); PROVIDE ( Cache_Read_Enable = 0x40009a84 ); PROVIDE ( Cache_Read_Init = 0x40009950 ); PROVIDE ( cache_sram_mmu_set = 0x400097f4 ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( calc_rtc_memory_crc = 0x40008170 ); PROVIDE ( calloc = 0x4000bee4 ); PROVIDE ( _calloc_r = 0x4000bbf8 ); PROVIDE ( check_pos = 0x400068b8 ); @@ -1585,12 +1587,20 @@ PROVIDE ( SPIParamCfg = 0x40063238 ); PROVIDE ( SPI_Prepare_Encrypt_Data = 0x40062e1c ); PROVIDE ( SPIRead = 0x40062ed8 ); PROVIDE ( SPIReadModeCnfig = 0x40062944 ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( SPI_read_status = 0x4006226c ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( SPI_read_status_high = 0x40062448 ); PROVIDE ( SPIUnlock = 0x400628b0 ); PROVIDE ( SPI_user_command_read = 0x400621b0 ); PROVIDE ( spi_w25q16 = 0x3ffae270 ); PROVIDE ( SPIWrite = 0x40062d50 ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( SPI_write_enable = 0x40062320 ); PROVIDE ( SPI_Write_Encrypt_Disable = 0x40062e60 ); PROVIDE ( SPI_Write_Encrypt_Enable = 0x40062df4 ); +/* This is static function, but can be used, not generated by script*/ +PROVIDE ( SPI_write_status = 0x400622f0 ); PROVIDE ( sprintf = 0x40056c08 ); PROVIDE ( _sprintf_r = 0x40056bbc ); PROVIDE ( __sprint_r = 0x400577e4 ); @@ -1826,4 +1836,4 @@ PROVIDE ( _xtos_unhandled_exception = 0x4000c024 ); PROVIDE ( _xtos_unhandled_interrupt = 0x4000c01c ); PROVIDE ( _xtos_vpri_enabled = 0x3ffe0654 ); -PROVIDE ( I2S0 = 0x6000F000 ); \ No newline at end of file +PROVIDE ( I2S0 = 0x6000F000 ); diff --git a/components/esp32/lib b/components/esp32/lib index b95a359c34..e793e8ac04 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit b95a359c344cd052f45e3c38515e4613dd29f298 +Subproject commit e793e8ac04cae3a5ca87bbccc46021a93288df05 diff --git a/components/esp32/syscalls.c b/components/esp32/syscalls.c index 636e32670e..1aff0167aa 100644 --- a/components/esp32/syscalls.c +++ b/components/esp32/syscalls.c @@ -44,10 +44,17 @@ void _free_r(struct _reent *r, void* ptr) { return vPortFree(ptr); } -// TODO: improve realloc to grow buffer in place if possible void* _realloc_r(struct _reent *r, void* ptr, size_t size) { - void* new_chunk = pvPortMalloc(size); - if (new_chunk) { + void* new_chunk; + if (size == 0) { + if (ptr) { + vPortFree(ptr); + } + return NULL; + } + + new_chunk = pvPortMalloc(size); + if (new_chunk && ptr) { memcpy(new_chunk, ptr, size); vPortFree(ptr); } diff --git a/components/esp32/wifi.c b/components/esp32/wifi.c index 5ac3c990b8..9900069759 100644 --- a/components/esp32/wifi.c +++ b/components/esp32/wifi.c @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #include #include #include @@ -26,9 +27,12 @@ #if CONFIG_WIFI_ENABLED -static wifi_startup_cb_t startup_cb; +static bool wifi_startup_flag = false; -#define WIFI_DEBUG(...) +static wifi_startup_cb_t startup_cb; +static void *startup_ctx; + +#define WIFI_DEBUG(...) #define WIFI_API_CALL_CHECK(info, api_call, ret) \ do{\ esp_err_t __err = (api_call);\ @@ -54,7 +58,7 @@ static void esp_wifi_task(void *pvParameters) } if (startup_cb) { - err = (*startup_cb)(); + err = (*startup_cb)(startup_ctx); if (err != ESP_OK) { WIFI_DEBUG("startup_cb fail, ret=%d\n", err); break; @@ -71,7 +75,7 @@ static void esp_wifi_task(void *pvParameters) wifi_mode_t mode; bool auto_connect; err = esp_wifi_get_mode(&mode); - if (err != ESP_OK){ + if (err != ESP_OK) { WIFI_DEBUG("esp_wifi_get_mode fail, ret=%d\n", err); } @@ -94,9 +98,17 @@ static void esp_wifi_task(void *pvParameters) vTaskDelete(NULL); } -void esp_wifi_startup(wifi_startup_cb_t cb) +esp_err_t esp_wifi_startup(wifi_startup_cb_t cb, void *ctx) { + if (wifi_startup_flag) { + return ESP_FAIL; + } + startup_cb = cb; + startup_ctx = ctx; + xTaskCreatePinnedToCore(esp_wifi_task, "wifiTask", 4096, NULL, 5, NULL, 0);// TODO: rearrange task priority + + return ESP_OK; } #endif diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index 9ec51d8961..ef82e42e72 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -11,19 +11,23 @@ PYTHON ?= $(call dequote,$(CONFIG_PYTHON)) # to invoke esptool.py (with or without serial port args) # # NB: esptool.py lives in the sdk/bin directory not the component directory -ESPTOOLPY := $(PYTHON) $(IDF_PATH)/bin/esptool.py --chip esp32 +ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py +ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32 ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD) -ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) +# the no-stub argument is temporary until esptool.py fully supports compressed uploads +ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) $(if $(CONFIG_ESPTOOLPY_COMPRESSED),--no-stub) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) -$(APP_BIN): $(APP_ELF) +$(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC) $(Q) $(ESPTOOLPY) elf2image --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) -o $@ $< -flash: all_binaries +flash: all_binaries $(ESPTOOLPY_SRC) @echo "Flashing project app to $(CONFIG_APP_OFFSET)..." $(Q) $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) -app-flash: $(APP_BIN) +app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(Q) $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) + +$(eval $(call SubmoduleRequiredForFiles,$(ESPTOOLPY_SRC))) diff --git a/components/esptool_py/esptool b/components/esptool_py/esptool new file mode 160000 index 0000000000..7c84dd4335 --- /dev/null +++ b/components/esptool_py/esptool @@ -0,0 +1 @@ +Subproject commit 7c84dd433512bac80e4c01c569e42b4fe76646a7 diff --git a/components/freertos/Makefile b/components/freertos/component.mk similarity index 80% rename from components/freertos/Makefile rename to components/freertos/component.mk index e4003eb146..6702d1b95c 100644 --- a/components/freertos/Makefile +++ b/components/freertos/component.mk @@ -6,4 +6,4 @@ COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) -Wl,--undefined=uxTopUsedPriority COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := include/freertos -include $(IDF_PATH)/make/component.mk +include $(IDF_PATH)/make/component_common.mk diff --git a/components/freertos/include/freertos/portmacro.h b/components/freertos/include/freertos/portmacro.h index 908206eb37..ab83b0e05a 100644 --- a/components/freertos/include/freertos/portmacro.h +++ b/components/freertos/include/freertos/portmacro.h @@ -167,6 +167,9 @@ typedef struct { #define portDISABLE_INTERRUPTS() do { XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); portbenchmarkINTERRUPT_DISABLE(); } while (0) #define portENABLE_INTERRUPTS() do { portbenchmarkINTERRUPT_RESTORE(0); XTOS_SET_INTLEVEL(0); } while (0) +#define portASSERT_IF_IN_ISR() vPortAssertIfInISR() +void vPortAssertIfInISR(); + #define portCRITICAL_NESTING_IN_TCB 1 /* @@ -213,6 +216,7 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux); // Cleaner and preferred solution allows nested interrupts disabling and restoring via local registers or stack. // They can be called from interrupts too. +//NOT SMP-COMPATIBLE! Use only if all you want is to disable the interrupts locally! static inline unsigned portENTER_CRITICAL_NESTED() { unsigned state = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); portbenchmarkINTERRUPT_DISABLE(); return state; } #define portEXIT_CRITICAL_NESTED(state) do { portbenchmarkINTERRUPT_RESTORE(state); XTOS_RESTORE_JUST_INTLEVEL(state); } while (0) diff --git a/components/freertos/port.c b/components/freertos/port.c index afa4978639..6117a2804e 100644 --- a/components/freertos/port.c +++ b/components/freertos/port.c @@ -248,14 +248,17 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMOR #endif +void vPortAssertIfInISR() +{ + configASSERT(port_interruptNesting[xPortGetCoreID()]==0) +} + /* * Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare * *mux to compare, and if it's the same, will set *mux to set. It will return the old value * of *addr. * - * Note: the NOPs are needed on the ESP31 processor but superfluous on the ESP32. - * * Warning: From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the * *bitwise inverse* of the old mem if the mem wasn't written. This doesn't seem to happen on the * ESP32, though. (Would show up directly if it did because the magic wouldn't match.) diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index f9ad8ff8cd..a4595154ed 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -163,6 +163,7 @@ typedef struct tskTaskControlBlock #if ( portCRITICAL_NESTING_IN_TCB == 1 ) UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ + uint32_t uxOldInterruptState; /*< Interrupt state before the outer taskEnterCritical was called */ #endif #if ( configUSE_TRACE_FACILITY == 1 ) @@ -2595,8 +2596,7 @@ BaseType_t xReturn; /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be called from a critical section within an ISR. */ -//That makes the taskENTER_CRITICALs here unnecessary, right? -JD -// taskENTER_CRITICAL(&xTaskQueueMutex); + taskENTER_CRITICAL_ISR(&xTaskQueueMutex); /* The event list is sorted in priority order, so the first in the list can be removed as it is known to be the highest priority. Remove the TCB from the delayed list, and add it to the ready list. @@ -2654,7 +2654,7 @@ BaseType_t xReturn; prvResetNextTaskUnblockTime(); } #endif -// taskEXIT_CRITICAL(&xTaskQueueMutex); + taskEXIT_CRITICAL_ISR(&xTaskQueueMutex); return xReturn; } @@ -3614,6 +3614,7 @@ In fact, nothing below this line has/is. { if( pxTCB->uxPriority < pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) { + taskENTER_CRITICAL(&xTaskQueueMutex); /* Adjust the mutex holder state to account for its new priority. Only reset the event list item value if the value is not being used for anything else. */ @@ -3649,6 +3650,8 @@ In fact, nothing below this line has/is. pxTCB->uxPriority = pxCurrentTCB[ xPortGetCoreID() ]->uxPriority; } + taskEXIT_CRITICAL(&xTaskQueueMutex); + traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ); } else @@ -3686,6 +3689,7 @@ In fact, nothing below this line has/is. /* Only disinherit if no other mutexes are held. */ if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ) { + taskENTER_CRITICAL(&xTaskQueueMutex); /* A task can only have an inhertied priority if it holds the mutex. If the mutex is held by a task then it cannot be given from an interrupt, and if a mutex is given by the @@ -3720,6 +3724,7 @@ In fact, nothing below this line has/is. switch should occur when the last mutex is returned whether a task is waiting on it or not. */ xReturn = pdTRUE; + taskEXIT_CRITICAL(&xTaskQueueMutex); } else { @@ -3761,7 +3766,14 @@ scheduler will re-enable the interrupts instead. */ void vTaskEnterCritical( portMUX_TYPE *mux ) #endif { - portDISABLE_INTERRUPTS(); + BaseType_t oldInterruptLevel=0; + if( xSchedulerRunning != pdFALSE ) + { + //Interrupts may already be disabled (because we're doing this recursively) but we can't get the interrupt level after + //vPortCPUAquireMutex, because it also may mess with interrupts. Get it here first, then later figure out if we're nesting + //and save for real there. + oldInterruptLevel=portENTER_CRITICAL_NESTED(); + } #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG vPortCPUAcquireMutex( mux, function, line ); #else @@ -3772,16 +3784,30 @@ scheduler will re-enable the interrupts instead. */ { ( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting )++; - /* This is not the interrupt safe version of the enter critical + if( xSchedulerRunning != pdFALSE && pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting == 1 ) + { + //This is the first time we get called. Save original interrupt level. + pxCurrentTCB[ xPortGetCoreID() ]->uxOldInterruptState=oldInterruptLevel; + } + + /* Original FreeRTOS comment, saved for reference: + This is not the interrupt safe version of the enter critical function so assert() if it is being called from an interrupt context. Only API functions that end in "FromISR" can be used in an interrupt. Only assert if the critical nesting count is 1 to protect against recursive calls if the assert function also uses a critical section. */ + + /* DISABLED in the esp32 port - because of SMP, vTaskEnterCritical + has to be used in way more places than before, and some are called + both from ISR as well as non-ISR code, thus we re-organized + vTaskEnterCritical to also work in ISRs. */ +#if 0 if( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting == 1 ) { portASSERT_IF_IN_ISR(); } +#endif } else @@ -3814,7 +3840,7 @@ scheduler will re-enable the interrupts instead. */ if( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting == 0U ) { - portENABLE_INTERRUPTS(); + portEXIT_CRITICAL_NESTED(pxCurrentTCB[ xPortGetCoreID() ]->uxOldInterruptState); } else { diff --git a/components/lwip/api/sockets.c b/components/lwip/api/sockets.c index 5b109eb375..91a5222e68 100755 --- a/components/lwip/api/sockets.c +++ b/components/lwip/api/sockets.c @@ -388,19 +388,30 @@ static void lwip_socket_drop_registered_memberships(int s); #endif /* LWIP_IGMP */ #ifdef LWIP_ESP8266 -extern size_t system_get_free_heap_size(void); -#define DELAY_WHEN_MEMORY_NOT_ENOUGH() \ -do{\ - uint8_t _wait_delay = 0;\ - while (system_get_free_heap_size() < HEAP_HIGHWAT){\ - vTaskDelay(_wait_delay/portTICK_RATE_MS);\ - if (_wait_delay < 64) _wait_delay *= 2;\ - }\ -}while(0) +/* Since esp_wifi_tx_is_stop/system_get_free_heap_size are not an public wifi API, so extern them here*/ +extern size_t system_get_free_heap_size(void); +extern bool esp_wifi_tx_is_stop(void); + +/* Please be notified that this flow control is just a workaround for fixing wifi Q full issue. + * Under UDP/TCP pressure test, we found that the sockets may cause wifi tx queue full if the socket + * sending speed is faster than the wifi sending speed, it will finally cause the packet to be dropped + * in wifi layer, it's not acceptable in some application. That's why we introdue the tx flow control here. + * However, current solution is just a workaround, we need to consider the return value of wifi tx interface, + * and feedback the return value to lwip and let lwip do the flow control itself. + */ +static inline void esp32_tx_flow_ctrl(void) +{ + uint8_t _wait_delay = 0; + + while ((system_get_free_heap_size() < HEAP_HIGHWAT) || esp_wifi_tx_is_stop()){ + vTaskDelay(_wait_delay/portTICK_RATE_MS); + if (_wait_delay < 64) _wait_delay *= 2; + } +} #else -#define DELAY_WHEN_MEMORY_NOT_ENOUGH() +#define esp32_tx_flow_ctrl() #endif /** The global array of available sockets */ @@ -1219,7 +1230,7 @@ lwip_send(int s, const void *data, size_t size, int flags) #endif /* (LWIP_UDP || LWIP_RAW) */ } - DELAY_WHEN_MEMORY_NOT_ENOUGH(); + esp32_tx_flow_ctrl(); write_flags = NETCONN_COPY | ((flags & MSG_MORE) ? NETCONN_MORE : 0) | @@ -1402,7 +1413,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #endif /* LWIP_TCP */ } - DELAY_WHEN_MEMORY_NOT_ENOUGH(); + esp32_tx_flow_ctrl(); if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ diff --git a/components/lwip/Makefile b/components/lwip/component.mk similarity index 65% rename from components/lwip/Makefile rename to components/lwip/component.mk index e159c25c2d..4fb0be5b63 100644 --- a/components/lwip/Makefile +++ b/components/lwip/component.mk @@ -6,6 +6,6 @@ COMPONENT_ADD_INCLUDEDIRS := include/lwip include/lwip/port COMPONENT_SRCDIRS := api apps/sntp apps core/ipv4 core/ipv6 core netif port/freertos port/netif port -EXTRA_CFLAGS := -Wno-error=address -Waddress -DLWIP_ESP8266 +EXTRA_CFLAGS := -Wno-error=address -Waddress -include $(IDF_PATH)/make/component.mk +include $(IDF_PATH)/make/component_common.mk diff --git a/components/lwip/core/ipv4/dhcp.c b/components/lwip/core/ipv4/dhcp.c index cd780d00ae..1f3758fa91 100755 --- a/components/lwip/core/ipv4/dhcp.c +++ b/components/lwip/core/ipv4/dhcp.c @@ -712,10 +712,10 @@ void dhcp_cleanup(struct netif *netif) /* Espressif add start. */ -/** Set callback for dhcp, reversed parameter for future use. +/** Set callback for dhcp, reserved parameter for future use. * * @param netif the netif from which to remove the struct dhcp - * @param cb callback for chcp + * @param cb callback for dhcp */ void dhcp_set_cb(struct netif *netif, void (*cb)(void)) { diff --git a/components/lwip/include/lwip/port/arch/sys_arch.h b/components/lwip/include/lwip/port/arch/sys_arch.h index 945b4e170a..be8ff72260 100644 --- a/components/lwip/include/lwip/port/arch/sys_arch.h +++ b/components/lwip/include/lwip/port/arch/sys_arch.h @@ -68,7 +68,5 @@ void sys_delay_ms(uint32_t ms); sys_sem_t* sys_thread_sem_init(void); void sys_thread_sem_deinit(void); sys_sem_t* sys_thread_sem_get(void); - - #endif /* __SYS_ARCH_H__ */ diff --git a/components/lwip/include/lwip/port/lwipopts.h b/components/lwip/include/lwip/port/lwipopts.h index 00151a2ff9..26d3c8dcbd 100755 --- a/components/lwip/include/lwip/port/lwipopts.h +++ b/components/lwip/include/lwip/port/lwipopts.h @@ -34,6 +34,8 @@ #include +/* Enable all Espressif-only options */ +#define LWIP_ESP8266 /* ----------------------------------------------- diff --git a/components/newlib/Makefile b/components/newlib/component.mk similarity index 77% rename from components/newlib/Makefile rename to components/newlib/component.mk index 970461698a..7c8c74debe 100644 --- a/components/newlib/Makefile +++ b/components/newlib/component.mk @@ -5,4 +5,4 @@ define COMPONENT_BUILDRECIPE #Nothing to do; this does not generate a library. endef -include $(IDF_PATH)/make/component.mk +include $(IDF_PATH)/make/component_common.mk diff --git a/components/nvs_flash/Makefile b/components/nvs_flash/component.mk similarity index 66% rename from components/nvs_flash/Makefile rename to components/nvs_flash/component.mk index 58232cc89b..02ff8cf038 100755 --- a/components/nvs_flash/Makefile +++ b/components/nvs_flash/component.mk @@ -6,4 +6,4 @@ COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_SRCDIRS := src -include $(IDF_PATH)/make/component.mk +include $(IDF_PATH)/make/component_common.mk diff --git a/components/partition_table/Makefile.projbuild b/components/partition_table/Makefile.projbuild index 0790733ac6..98631cc854 100644 --- a/components/partition_table/Makefile.projbuild +++ b/components/partition_table/Makefile.projbuild @@ -9,7 +9,7 @@ .PHONY: partition_table partition_table-flash partition_table-clean # NB: gen_esp32part.py lives in the sdk/bin/ dir not component dir -GEN_ESP32PART := $(PYTHON) $(IDF_PATH)/bin/gen_esp32part.py -q +GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q # Path to partition CSV file is relative to project path for custom # partition CSV files, but relative to component dir otherwise.$ diff --git a/bin/gen_esp32part.py b/components/partition_table/gen_esp32part.py similarity index 100% rename from bin/gen_esp32part.py rename to components/partition_table/gen_esp32part.py diff --git a/components/spi_flash/Makefile b/components/spi_flash/Makefile deleted file mode 100755 index fc41e5f430..0000000000 --- a/components/spi_flash/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -COMPONENT_ADD_INCLUDEDIRS := include - -include $(IDF_PATH)/make/component.mk diff --git a/components/spi_flash/component.mk b/components/spi_flash/component.mk new file mode 100755 index 0000000000..ef497a7ecb --- /dev/null +++ b/components/spi_flash/component.mk @@ -0,0 +1,3 @@ +COMPONENT_ADD_INCLUDEDIRS := include + +include $(IDF_PATH)/make/component_common.mk diff --git a/components/spi_flash/esp_spi_flash.c b/components/spi_flash/esp_spi_flash.c index df919bc2d0..b0a31e8201 100644 --- a/components/spi_flash/esp_spi_flash.c +++ b/components/spi_flash/esp_spi_flash.c @@ -12,15 +12,217 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include #include #include #include - -#include #include #include -#include +#include #include +#include "sdkconfig.h" +#include "esp_ipc.h" +#include "esp_attr.h" +#include "esp_spi_flash.h" + + +/* + Driver for SPI flash read/write/erase operations + + In order to perform some flash operations, we need to make sure both CPUs + are not running any code from flash for the duration of the flash operation. + In a single-core setup this is easy: we disable interrupts/scheduler and do + the flash operation. In the dual-core setup this is slightly more complicated. + We need to make sure that the other CPU doesn't run any code from flash. + + + When SPI flash API is called on CPU A (can be PRO or APP), we start + spi_flash_op_block_func function on CPU B using esp_ipc_call API. This API + wakes up high priority task on CPU B and tells it to execute given function, + in this case spi_flash_op_block_func. This function disables cache on CPU B and + signals that cache is disabled by setting s_flash_op_can_start flag. + Then the task on CPU A disables cache as well, and proceeds to execute flash + operation. + + While flash operation is running, interrupts can still run on CPU B. + We assume that all interrupt code is placed into RAM. + + Once flash operation is complete, function on CPU A sets another flag, + s_flash_op_complete, to let the task on CPU B know that it can re-enable + cache and release the CPU. Then the function on CPU A re-enables the cache on + CPU A as well and returns control to the calling code. + + Additionally, all API functions are protected with a mutex (s_flash_op_mutex). + + In a single core environment (CONFIG_FREERTOS_UNICORE enabled), we simply + disable both caches, no inter-CPU communication takes place. +*/ + +static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc); +static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state); +static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state); + +static uint32_t s_flash_op_cache_state[2]; + +#ifndef CONFIG_FREERTOS_UNICORE +static SemaphoreHandle_t s_flash_op_mutex; +static bool s_flash_op_can_start = false; +static bool s_flash_op_complete = false; +#endif //CONFIG_FREERTOS_UNICORE + + +#ifndef CONFIG_FREERTOS_UNICORE + +static void IRAM_ATTR spi_flash_op_block_func(void* arg) +{ + // Disable scheduler on this CPU + vTaskSuspendAll(); + uint32_t cpuid = (uint32_t) arg; + // Disable cache so that flash operation can start + spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]); + s_flash_op_can_start = true; + while (!s_flash_op_complete) { + // until we have a way to use interrupts for inter-CPU communication, + // busy loop here and wait for the other CPU to finish flash operation + } + // Flash operation is complete, re-enable cache + spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]); + // Re-enable scheduler + xTaskResumeAll(); +} + +void spi_flash_init() +{ + s_flash_op_mutex = xSemaphoreCreateMutex(); +} + +static void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() +{ + // Take the API lock + xSemaphoreTake(s_flash_op_mutex, portMAX_DELAY); + + const uint32_t cpuid = xPortGetCoreID(); + const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; + + if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { + // Scheduler hasn't been started yet, it means that spi_flash API is being + // called from the 2nd stage bootloader or from user_start_cpu0, i.e. from + // PRO CPU. APP CPU is either in reset or spinning inside user_start_cpu1, + // which is in IRAM. So it is safe to disable cache for the other_cpuid here. + assert(other_cpuid == 1); + spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]); + } else { + // Signal to the spi_flash_op_block_task on the other CPU that we need it to + // disable cache there and block other tasks from executing. + s_flash_op_can_start = false; + s_flash_op_complete = false; + esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void*) other_cpuid); + while (!s_flash_op_can_start) { + // Busy loop and wait for spi_flash_op_block_func to disable cache + // on the other CPU + } + // Disable scheduler on CPU cpuid + vTaskSuspendAll(); + // This is guaranteed to run on CPU because the other CPU is now + // occupied by highest priority task + assert(xPortGetCoreID() == cpuid); + } + // Disable cache on this CPU as well + spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]); +} + +static void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() +{ + const uint32_t cpuid = xPortGetCoreID(); + const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; + + // Re-enable cache on this CPU + spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]); + + if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { + // Scheduler is not running yet — this means we are running on PRO CPU. + // other_cpuid is APP CPU, and it is either in reset or is spinning in + // user_start_cpu1, which is in IRAM. So we can simply reenable cache. + assert(other_cpuid == 1); + spi_flash_restore_cache(other_cpuid, s_flash_op_cache_state[other_cpuid]); + } else { + // Signal to spi_flash_op_block_task that flash operation is complete + s_flash_op_complete = true; + // Resume tasks on the current CPU + xTaskResumeAll(); + } + // Release API lock + xSemaphoreGive(s_flash_op_mutex); +} + +#else // CONFIG_FREERTOS_UNICORE + +void spi_flash_init() +{ + // No-op in single core mode +} + +static void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() +{ + vTaskSuspendAll(); + spi_flash_disable_cache(0, &s_flash_op_cache_state[0]); +} + +static void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu() +{ + spi_flash_restore_cache(0, s_flash_op_cache_state[0]); + xTaskResumeAll(); +} + +#endif // CONFIG_FREERTOS_UNICORE + + +SpiFlashOpResult IRAM_ATTR spi_flash_unlock() +{ + static bool unlocked = false; + if (!unlocked) { + SpiFlashOpResult rc = SPIUnlock(); + if (rc != SPI_FLASH_RESULT_OK) { + return rc; + } + unlocked = true; + } + return SPI_FLASH_RESULT_OK; +} + +esp_err_t IRAM_ATTR spi_flash_erase_sector(uint16_t sec) +{ + spi_flash_disable_interrupts_caches_and_other_cpu(); + SpiFlashOpResult rc; + rc = spi_flash_unlock(); + if (rc == SPI_FLASH_RESULT_OK) { + rc = SPIEraseSector(sec); + } + spi_flash_enable_interrupts_caches_and_other_cpu(); + return spi_flash_translate_rc(rc); +} + +esp_err_t IRAM_ATTR spi_flash_write(uint32_t dest_addr, const uint32_t *src, uint32_t size) +{ + spi_flash_disable_interrupts_caches_and_other_cpu(); + SpiFlashOpResult rc; + rc = spi_flash_unlock(); + if (rc == SPI_FLASH_RESULT_OK) { + rc = SPIWrite(dest_addr, src, (int32_t) size); + } + spi_flash_enable_interrupts_caches_and_other_cpu(); + return spi_flash_translate_rc(rc); +} + +esp_err_t IRAM_ATTR spi_flash_read(uint32_t src_addr, uint32_t *dest, uint32_t size) +{ + spi_flash_disable_interrupts_caches_and_other_cpu(); + SpiFlashOpResult rc; + rc = SPIRead(src_addr, dest, (int32_t) size); + spi_flash_enable_interrupts_caches_and_other_cpu(); + return spi_flash_translate_rc(rc); +} static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc) { @@ -35,72 +237,36 @@ static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc) } } -extern void Cache_Flush(int); +static const uint32_t cache_mask = DPORT_APP_CACHE_MASK_OPSDRAM | DPORT_APP_CACHE_MASK_DROM0 | + DPORT_APP_CACHE_MASK_DRAM1 | DPORT_APP_CACHE_MASK_IROM0 | + DPORT_APP_CACHE_MASK_IRAM1 | DPORT_APP_CACHE_MASK_IRAM0; -static void IRAM_ATTR spi_flash_disable_interrupts_caches_and_app_cpu() +static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state) { - vTaskSuspendAll(); - // SET_PERI_REG_MASK(APPCPU_CTRL_REG_C, DPORT_APPCPU_RUNSTALL); - Cache_Read_Disable(0); - Cache_Read_Disable(1); -} - -static void IRAM_ATTR spi_flash_enable_interrupts_caches_and_app_cpu() -{ - Cache_Read_Enable(0); - Cache_Read_Enable(1); - // CLEAR_PERI_REG_MASK(APPCPU_CTRL_REG_C, DPORT_APPCPU_RUNSTALL); - xTaskResumeAll(); -} - -esp_err_t IRAM_ATTR spi_flash_erase_sector(uint16_t sec) -{ - spi_flash_disable_interrupts_caches_and_app_cpu(); - SpiFlashOpResult rc; - if (xPortGetCoreID() == 1) { - rc = SPI_FLASH_RESULT_ERR; - } - else { - rc = SPIUnlock(); - if (rc == SPI_FLASH_RESULT_OK) { - rc = SPIEraseSector(sec); + uint32_t ret = 0; + if (cpuid == 0) { + ret |= GET_PERI_REG_BITS2(PRO_CACHE_CTRL1_REG, cache_mask, 0); + while (GET_PERI_REG_BITS2(PRO_DCACHE_DBUG_REG0, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) { + ; } - } - Cache_Flush(0); - Cache_Flush(1); - spi_flash_enable_interrupts_caches_and_app_cpu(); - return spi_flash_translate_rc(rc); -} - -esp_err_t IRAM_ATTR spi_flash_write(uint32_t dest_addr, const uint32_t *src, uint32_t size) -{ - spi_flash_disable_interrupts_caches_and_app_cpu(); - SpiFlashOpResult rc; - if (xPortGetCoreID() == 1) { - rc = SPI_FLASH_RESULT_ERR; - } - else { - rc = SPIUnlock(); - if (rc == SPI_FLASH_RESULT_OK) { - rc = SPIWrite(dest_addr, src, (int32_t) size); + SET_PERI_REG_BITS(PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S); + } else { + ret |= GET_PERI_REG_BITS2(APP_CACHE_CTRL1_REG, cache_mask, 0); + while (GET_PERI_REG_BITS2(APP_DCACHE_DBUG_REG0, DPORT_APP_CACHE_STATE, DPORT_APP_CACHE_STATE_S) != 1) { + ; } + SET_PERI_REG_BITS(APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S); } - Cache_Flush(0); - Cache_Flush(1); - spi_flash_enable_interrupts_caches_and_app_cpu(); - return spi_flash_translate_rc(rc); + *saved_state = ret; } -esp_err_t IRAM_ATTR spi_flash_read(uint32_t src_addr, uint32_t *dest, uint32_t size) +static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state) { - spi_flash_disable_interrupts_caches_and_app_cpu(); - SpiFlashOpResult rc; - if (xPortGetCoreID() == 1) { - rc = SPI_FLASH_RESULT_ERR; + if (cpuid == 0) { + SET_PERI_REG_BITS(PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S); + SET_PERI_REG_BITS(PRO_CACHE_CTRL1_REG, cache_mask, saved_state, 0); + } else { + SET_PERI_REG_BITS(APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S); + SET_PERI_REG_BITS(APP_CACHE_CTRL1_REG, cache_mask, saved_state, 0); } - else { - rc = SPIRead(src_addr, dest, (int32_t) size); - } - spi_flash_enable_interrupts_caches_and_app_cpu(); - return spi_flash_translate_rc(rc); } diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index aa12b2aa42..da6b03c0d1 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -28,6 +28,15 @@ extern "C" { #define SPI_FLASH_SEC_SIZE 4096 /**< SPI Flash sector size */ +/** + * @brief Initialize SPI flash access driver + * + * This function must be called exactly once, before any other + * spi_flash_* functions are called. + * + */ +void spi_flash_init(); + /** * @brief Erase the Flash sector. * diff --git a/components/tcpip_adapter/Makefile b/components/tcpip_adapter/Makefile deleted file mode 100755 index 4028caf4a3..0000000000 --- a/components/tcpip_adapter/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Component Makefile -# - -EXTRA_CFLAGS := -DLWIP_ESP8266 - -include $(IDF_PATH)/make/component.mk diff --git a/components/tcpip_adapter/component.mk b/components/tcpip_adapter/component.mk new file mode 100755 index 0000000000..a57ae0b12b --- /dev/null +++ b/components/tcpip_adapter/component.mk @@ -0,0 +1,5 @@ +# +# Component Makefile +# + +include $(IDF_PATH)/make/component_common.mk diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 2facea578c..0f681d9135 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -454,7 +454,7 @@ static void tcpip_adapter_dhcpc_cb(void) ip4_addr_set(&ip_info->gw, ip_2_ip4(&netif->gw)); //notify event - evt.event_id = SYSTEM_EVENT_STA_GOTIP; + evt.event_id = SYSTEM_EVENT_STA_GOT_IP; memcpy(&evt.event_info.got_ip.ip_info, ip_info, sizeof(tcpip_adapter_ip_info_t)); esp_event_send(&evt); diff --git a/docs/build_system.rst b/docs/build_system.rst new file mode 100644 index 0000000000..24381019b5 --- /dev/null +++ b/docs/build_system.rst @@ -0,0 +1,302 @@ +Build System +------------ + +This document explains the Espressif IoT Development Framework build system and the +concept of "components" + +Read this document if you want to know how to organise a new ESP-IDF project. + +We recommend using the esp-idf-template_ project as a starting point for your project. + +Overview +======== + +An ESP-IDF project can be seen as an almagation of a number of components. +For example, for a webserver that shows the current humidity, we would +have: + +- The ESP32 base libraries (libc, rom bindings etc) +- The WiFi drivers +- A TCP/IP stack +- The FreeRTOS operating system +- A webserver +- A driver for an humidity sensor +- Main code tying it all together + +ESP-IDF makes these components explicit and configurable. To do that, when a project +is compiled, the build environment will look up all the components in the +ESP-IDF directories, the project directories and optionally custom other component +directories. It then allows the user to configure compile-time options using +a friendly text-based menu system to customize the ESP-IDF as well as other components +to the requirements of the project. After the components are customized, the +build process will compile everything into an output file, which can then be uploaded +into a board in a way that can also be defined by components. + +A project in this sense is defined as a directory under which all the files required +to build it live, excluding the ESP-IDF files and the toolchain. A simple project +tree might look like this:: + + - myProject/ - build/ + - components/ - component1/ - component.mk + - Kconfig + - src1.c + - component2/ - component.mk + - Kconfig + - src1.c + - main/ - src1.c + - src2.c + - Makefile + +As we can see, a project consists of a components/ subdirectory containing its +components as well as one or more directories containing the project-specific +sources; by default a single directory called 'main' is assumed. The project +directory will also have a Makefile where the projects name as well as optionally +other options are defined. After compilation, the project directory will contain +a 'build'-directory containing all of the objects, libraries and other generated +files as well as the final binary. + +Components also have a custom makefile - ``component.mk``. This contains various definititions +influencing the build process of the component as well as the project it's used +in. Components may also include a Kconfig file defining the compile-time options that are +settable by means of the menu system. + +Project makefile variables that can be set by the programmer:: + + PROJECT_NAME: Mandatory. Name for the project + BUILD_DIR_BASE: Set the directory where all objects/libraries/binaries end up in. + Defaults to $(PROJECT_PATH)/build + COMPONENT_DIRS: Search path for components. Defaults to the component/ directories + in the ESP-IDF path and the project path. + COMPONENTS: A list of component names. Defaults to all the component found in the + COMPONENT_DIRS directory + EXTRA_COMPONENT_DIRS: Defaults to unset. Use this to add directories to the default + COMPONENT_DIRS. + SRCDIRS: Directories under the project dir containing project-specific sources. + Defaults to 'main'. These are treated as 'lite' components: they do not have + include directories that are passed to the compilation pass of all components and + they do not have a Kconfig option. + +Component makefile variables that can be set by the programmer:: + + COMPONENT_ADD_INCLUDEDIRS: Relative path to include directories to be added to + the entire project + COMPONENT_PRIV_INCLUDEDIRS: Relative path to include directories that are only used + when compiling this specific component + COMPONENT_DEPENDS: Names of any components that need to be compiled before this component. + COMPONENT_ADD_LDFLAGS: Ld flags to add for this project. Defaults to -l$(COMPONENT_NAME). + Add libraries etc in the current directory as $(abspath libwhatever.a) + COMPONENT_EXTRA_INCLUDES: Any extra include paths. These will be prefixed with '-I' and + passed to the compiler; please put absolute paths here. + COMPONENT_SRCDIRS: Relative directories to look in for sources. Defaults to '.', the current + directory (the root of the component) only. Use this to specify any subdirectories. Note + that specifying this overwrites the default action of compiling everything in the + components root dir; to keep this behaviour please also add '.' as a directory in this + list. + COMPONENT_OBJS: Object files to compile. Defaults to the .o variants of all .c and .S files + that are found in COMPONENT_SRCDIRS. + COMPONENT_EXTRA_CLEAN: Files that are generated using rules in the components Makefile + that also need to be cleaned + COMPONENT_BUILDRECIPE: Recipe to build the component. Optional. Defaults to building all + COMPONENT_OBJS and linking them into lib(componentname).a + COMPONENT_CLEANRECIPE: Recipe to clean the component. Optional. Defaults to removing + all built objects and libraries. + COMPONENT_BUILD_DIR: Equals the cwd of the component build, which is the build dir + of the component (where all the .o etc files should be created). + +These variables are already set early on in the Makefile and the values in it will +be usable in component or project Makefiles:: + + CC, LD, AR, OBJCOPY: Xtensa gcc tools + HOSTCC, HOSTLD etc: Host gcc tools + LDFLAGS, CFLAGS: Set to usable values as defined in ESP-IDF Makefile + PROJECT_NAME: Name of the project, as set in project makefile + PROJECT_PATH: Path to the root of the project folder + COMPONENTS: Name of the components to be included + CONFIG_*: All values set by 'make menuconfig' have corresponding Makefile variables. + +For components, there also are these defines:: + + COMPONENT_PATH: Absolute path to the root of the source tree of the component we're + compiling + COMPONENT_LIBRARY: The full path to the static library the components compilation pass + is supposed to generate + +Make Process +------------ + +The Make process is always invoked from the project directory by the +user; invoking it anywhere else gives an error. This is what happens if +we build a binary: + +The Makefile first determines how it was included. It figures out +various paths as well as the components available to it. It will also +collect the ldflags and includes that the components specify they need. +It does this by running a dummy make on the components with a "get_variable" +target that will output these values. + +The Makefile will then create targets to build the lib*.a libraries of +all components and make the elf target depend on this. The main Makefile +invokes Make on the componen.mk of each components inside a sub-mke: this way +the components have full freedom to do whatever is necessary to build +the library without influencing other components. By default, the +component.mk includes the utility makefile $(IDF_PATH)/make/component_common.mk. +This provides default targets and configurations that will work +out-of-the-box for most projects. + +KConfig +------- + +Each component can also have a Kconfig file, alongside the component.mk, that contains +details to add to "menuconfig" for this component. + +Makefile.projbuild +------------------ + +For components that have parts that need to be run when building of the +project is done, you can create a file called Makefile.projbuild in the +component root directory. This file will be included in the main +Makefile. + + +KConfig.projbuild +----------------- + +There's an equivalent to Makefile.projbuild for KConfig: if you want to include +options at the top-level, not inside the 'components' submenu then create a Kconfig.projbuild and +it will be included in the main menu of menuconfig. + +Take good care when (re)defining stuff here: because it's included with all the other +.projbuild files, it's possible to overwrite variables or re-declare targets defined in +the ESP-IDF makefile/Kconfig and other .projbuild files. It's generally better to just +create a KConfig file, if you can. + + +Writing Component Makefiles +--------------------------- + +A component consists of a directory which doubles as the name for the +component: a component named 'httpd' lives in a directory called 'httpd' +Because components usually live under the project directory (although +they can also reside in an other folder), the path to this may be +something like /home/myuser/projects/myprojects/components/httpd . + +One of the things that most components will have is a component.mk makefile, +containing instructions on how to build the component. Because the +build environment tries to set reasonable defaults that will work most +of the time, component.mk can be very small. + +Simplest component.mk +===================== + +At the minimum, component.mk will just include the ESP-IDF component "common" makefile, +which adds common component functionality:: + + include $(IDF_PATH)/make/component_common.mk + +This will take all the .c and .S files in the component root and compile +them into object files, finally linking them into a library. + + +Adding source directories +========================= + +By default, subdirectories are ignored. If your project has sources in subdirectories +instead of in the root of the component then you can tell that to the build +system by setting COMPONENT_SRCDIRS:: + + COMPONENT_SRCDIRS := src1 src2 + include $(IDF_PATH)/make/component_common.mk + +This will compile all source files in the src1/ and src2/ subdirectories +instead. + +Specifying source files +======================= + +The standard component.mk logic adds all .S and .c files in the source +directories as sources to be compiled unconditionally. It is possible +to circumvent that logic and hardcode the objects to be compiled by +manually setting the COMPONENT_OBJS variable to the name of the +objects that need to be generated:: + + COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o + include $(IDF_PATH)/make/component_common.mk + + +Adding conditional configuration +================================ + +The configuration system can be used to conditionally compile some files +dependending on the options selected in ``make menuconfig``: + +Kconfig:: + config FOO_ENABLE_BAR + bool "Enable the BAR feature." + help + This enables the BAR feature of the FOO component. + +Makefile:: + COMPONENT_OBJS := foo_a.o foo_b.o $(if $(CONFIG_FOO_ENABLE_BAR),foo_bar.o foo_bar_interface.o) + include $(IDF_PATH)/make/component_common.mk + + +Source Code Generation +====================== + +Some components will have a situation where a source file isn't supplied +with the component itself but has to be generated from another file. Say +our component has a header file that consists of the converted binary +data of a BMP file, converted using a hypothetical tool called bmp2h. The +header file is then included in as C source file called graphics_lib.c:: + + COMPONENT_EXTRA_CLEAN := logo.h + + graphics_lib.o: logo.h + + logo.h: $(COMPONENT_PATH)/logo.bmp + bmp2h -i $^ -o $@ + + include $(IDF_PATH)/make/component_common.mk + +In this example, graphics_lib.o and logo.h will be generated in the +current directory (the build directory) while logo.bmp comes with the +component and resides under the component path. Because logo.h is a +generated file, it needs to be cleaned when make clean is called which +why it is added to the COMPONENT_EXTRA_CLEAN variable. + +Cosmetic Improvements +===================== + +The above example will work just fine, but there's one last cosmetic +improvement that can be done. The make system tries to make the make +process somewhat easier on the eyes by hiding the commands (unless you +run make with the V=1 switch) and this does not do that yet. Here's an +improved version that will output in the same style as the rest of the +make process:: + + COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h + + graphics_lib.o: logo.h + + logo.h: $(COMPONENT_PATH)/logo.bmp + $(summary) BMP2H $@ + $(Q) bmp2h -i $^ -o $@ + + include $(IDF_PATH)/make/component_common.mk + +Fully Overriding The Component Makefile +--------------------------------------- + +Obviously, there are cases where all these recipes are insufficient for a +certain component, for example when the component is basically a wrapper +around another third-party component not originally intended to be +compiled under this build system. In that case, it's possible to forego +the build system entirely by setting COMPONENT_OWNBUILDTARGET and +possibly COMPONENT_OWNCLEANTARGET and defining your own build- and clean +target. The build target can do anything as long as it creates +$(COMPONENT_LIBRARY) for the main file to link into the project binary, +and even that is not necessary: if the COMPONENT_ADD_LDFLAGS variable +is set, the component can instruct the linker to do anything else as well. + + +.. _esp-idf-template: https://github.com/espressif/esp-idf-template diff --git a/docs/eclipse-setup.rst b/docs/eclipse-setup.rst index 07c8c2538e..21d83a7f06 100644 --- a/docs/eclipse-setup.rst +++ b/docs/eclipse-setup.rst @@ -39,9 +39,9 @@ Project Properties *Windows users only, follow these two additional steps:* -* On the same Environment property page, edit the PATH environment variable and append ``;C:\msys32\usr\bin;C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin`` to the end of the default value. (If you installed msys32 to a different directory then you'll need to change these paths to match.) +* On the same Environment property page, edit the PATH environment variable. Delete the existing value and replace it with ``C:\msys32\usr\bin;C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin`` (If you installed msys32 to a different directory then you'll need to change these paths to match). -* Click on the "C/C++ Build" top-level properties page then uncheck "Use default build command" and enter this for the custom build command: ``bash ${IDF_PATH}/bin/eclipse_windows_make.sh``. +* Click on the "C/C++ Build" top-level properties page then uncheck "Use default build command" and enter this for the custom build command: ``bash ${IDF_PATH}/tools/windows/eclipse_make.sh``. *All users, continue with these steps:* @@ -60,7 +60,7 @@ Flash from Eclipse You can integrate the "make flash" target into your Eclipse project to flash using esptool.py from the Eclipse UI: -* Right-click your project in Project Explorer (important to make sure you don't select a subdirectory of the project or Eclipse may find the wrong Makefile.) +* Right-click your project in Project Explorer (important to make sure you select the project, not a directory in the project, or Eclipse may find the wrong Makefile.) * Select Make Targets -> Create from the context menu. @@ -73,3 +73,8 @@ Note that you will need to use "make menuconfig" to set the serial port and othe Follow the same steps to add ``bootloader`` and ``partition_table`` targets, if necessary. .. _eclipse.org: http://www.eclipse.org/ + +Eclipse Troubleshooting +----------------------- + +* ``*** Make was invoked from ... However please do not run make from the sdk or a component directory; ...`` - Eclipse will detect any directory with a Makefile in it as being a possible directory to run "make" in. All component directories also contain a Makefile (the wrong one), so it is important when using Project -> Make Target to always select the top-level project directory in Project Explorer. diff --git a/make/common.mk b/make/common.mk index 7f372cc305..adae46738e 100644 --- a/make/common.mk +++ b/make/common.mk @@ -49,6 +49,23 @@ summary := @echo details := @true endif +# Pseudo-target to handle the case where submodules need to be +# re-initialised. +# +# $(eval $(call SubmoduleRequiredForFiles,FILENAMES)) to create a target that +# automatically runs 'git submodule update --init' if those files +# are missing, and fails if this is not possible. +define SubmoduleRequiredForFiles +$(1): + @echo "WARNING: Missing submodule for $$@..." + $(Q) [ -d ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) + $(Q) [ -x $(which git) ] || ( echo "ERROR: Need to run 'git submodule --init' in esp-idf root directory."; exit 1) + @echo "Attempting 'git submodule update --init' in esp-idf root directory..." + cd ${IDF_PATH} && git submodule update --init +endef + + + # General make utilities # convenience variable for printing an 80 asterisk wide separator line diff --git a/make/component.mk b/make/component_common.mk similarity index 100% rename from make/component.mk rename to make/component_common.mk diff --git a/make/project.mk b/make/project.mk index ac2b3e59d3..ca80697cb6 100644 --- a/make/project.mk +++ b/make/project.mk @@ -1,13 +1,13 @@ # # Main Project Makefile -# This Makefile is included directly from the user project Makefile in order to call the Makefiles of all the -# components (in a separate make process) to build all the libraries, then links them together -# into the final file. If so, PWD is the project dir (we assume). +# This Makefile is included directly from the user project Makefile in order to call the component.mk +# makefiles of all components (in a separate make process) to build all the libraries, then links them +# together into the final file. If so, PWD is the project dir (we assume). # # -# This Makefile requires the environment variable IDF_PATH to be set to the directory where this -# Makefile is located. +# This makefile requires the environment variable IDF_PATH to be set to the top-level esp-idf directory +# where this file is located. # .PHONY: build-components menuconfig defconfig all build clean all_binaries @@ -77,9 +77,9 @@ SRCDIRS ?= main COMPONENT_PATHS := $(foreach comp,$(COMPONENTS),$(firstword $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/$(comp))))) COMPONENT_PATHS += $(abspath $(SRCDIRS)) -#A component is buildable if it has a Makefile; we assume that a 'make -C $(component dir) build' results in a -#lib$(componentname).a. -COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/Makefile),$(cp))) +#A component is buildable if it has a component.mk makefile; we assume that a +# 'make -C $(component dir) -f component.mk build' results in a lib$(componentname).a +COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/component.mk),$(cp))) # Assemble global list of include dirs (COMPONENT_INCLUDES), and # LDFLAGS args (COMPONENT_LDFLAGS) supplied by each component. @@ -98,7 +98,7 @@ COMPONENT_LDFLAGS := # # Debugging this? Replace $(shell with $(error and you'll see the full command as-run. define GetVariable -$(shell "$(MAKE)" -s --no-print-directory -C $(1) get_variable PROJECT_PATH=$(PROJECT_PATH) GET_VARIABLE=$(2) | sed -En "s/^$(2)=(.+)/\1/p" ) +$(shell "$(MAKE)" -s --no-print-directory -C $(1) -f component.mk get_variable PROJECT_PATH=$(PROJECT_PATH) GET_VARIABLE=$(2) | sed -En "s/^$(2)=(.+)/\1/p" ) endef COMPONENT_INCLUDES := $(abspath $(foreach comp,$(COMPONENT_PATHS_BUILDABLE),$(addprefix $(comp)/, \ @@ -193,7 +193,7 @@ define GenerateComponentPhonyTarget # $(2) - target to generate (build, clean) .PHONY: $(notdir $(1))-$(2) $(notdir $(1))-$(2): | $(BUILD_DIR_BASE)/$(notdir $(1)) - @+$(MAKE) -C $(BUILD_DIR_BASE)/$(notdir $(1)) -f $(1)/Makefile COMPONENT_BUILD_DIR=$(BUILD_DIR_BASE)/$(notdir $(1)) $(2) + @+$(MAKE) -C $(BUILD_DIR_BASE)/$(notdir $(1)) -f $(1)/component.mk COMPONENT_BUILD_DIR=$(BUILD_DIR_BASE)/$(notdir $(1)) $(2) endef define GenerateComponentTargets @@ -206,7 +206,7 @@ $(BUILD_DIR_BASE)/$(notdir $(1)): # only invoked for the targets whose libraries appear in COMPONENT_LIBRARIES and hence the # APP_ELF dependencies.) $(BUILD_DIR_BASE)/$(notdir $(1))/lib$(notdir $(1)).a: $(notdir $(1))-build - $(details) echo "$$^ responsible for $$@" # echo which build target built this file + $(details) "Target '$$^' responsible for '$$@'" # echo which build target built this file endef $(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentTargets,$(component)))) diff --git a/make/test_build_system.sh b/make/test_build_system.sh index 5de216dea3..cb42356f05 100755 --- a/make/test_build_system.sh +++ b/make/test_build_system.sh @@ -26,9 +26,10 @@ function run_tests() print_status "Checking prerequisites" [ -z ${IDF_PATH} ] && echo "IDF_PATH is not set. Need path to esp-idf installation." && exit 2 - print_status "Cloning template..." + print_status "Cloning template from ${ESP_IDF_TEMPLATE_GIT}..." git clone ${ESP_IDF_TEMPLATE_GIT} template cd template + git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..." print_status "Updating template config..." make defconfig || exit $? diff --git a/bin/eclipse_windows_make.sh b/tools/windows/eclipse_make.sh similarity index 92% rename from bin/eclipse_windows_make.sh rename to tools/windows/eclipse_make.sh index 115ecac2fa..200d798ffa 100755 --- a/bin/eclipse_windows_make.sh +++ b/tools/windows/eclipse_make.sh @@ -5,5 +5,5 @@ # process uses MinGW paths of the form /c/dir/dir/file. So parse these out... # # (regexp deliberate only matches after a space character to try and avoid false-positives.) -echo "Running make in $(dirname $0)" +echo "Running make in $(pwd)" make $@ V=1 | sed -E "s@ /([a-z])/(.+)/@ \1:/\2/@g" | sed -E "s@-I/([a-z])/(.+)/@-I\1:/\2/@g" | sed -E "s@-L/([a-z])/(.+)/@-L\1:/\2/@g"