kopia lustrzana https://github.com/espressif/esp-idf
Merge branch 'master' into feature/btdm_bluedroid
1. update bt lib submodule # Conflicts: # components/bootloader/src/main/esp32.bootloader.ld # components/bt/component.mk # components/esp32/component.mk # components/esp32/libpull/111/merge
commit
7a41ab6982
|
@ -19,3 +19,13 @@ GPATH
|
|||
examples/*/sdkconfig
|
||||
examples/*/sdkconfig.old
|
||||
examples/*/build
|
||||
|
||||
#Doc build artifacts
|
||||
docs/_build/
|
||||
docs/doxygen-warning-log.txt
|
||||
docs/xml/
|
||||
|
||||
# Unit test app files
|
||||
tools/unit-test-app/sdkconfig
|
||||
tools/unit-test-app/sdkconfig.old
|
||||
tools/unit-test-app/build
|
||||
|
|
120
.gitlab-ci.yml
120
.gitlab-ci.yml
|
@ -1,6 +1,8 @@
|
|||
stages:
|
||||
- build
|
||||
- unit_test
|
||||
- test
|
||||
- test_report
|
||||
- deploy
|
||||
|
||||
before_script:
|
||||
|
@ -61,10 +63,7 @@ build_ssc:
|
|||
<<: *build_template
|
||||
artifacts:
|
||||
paths:
|
||||
- ./SSC/build/*.bin
|
||||
- ./SSC/build/*.elf
|
||||
- ./SSC/build/*.map
|
||||
- ./SSC/build/bootloader/*.bin
|
||||
- ./SSC/ssc_bin
|
||||
expire_in: 6 mos
|
||||
|
||||
script:
|
||||
|
@ -75,6 +74,22 @@ build_ssc:
|
|||
- chmod +x gen_misc_ng.sh
|
||||
- ./gen_misc_ng.sh
|
||||
|
||||
build_esp_idf_tests:
|
||||
<<: *build_template
|
||||
artifacts:
|
||||
paths:
|
||||
- ./tools/unit-test-app/build/*.bin
|
||||
- ./tools/unit-test-app/build/*.elf
|
||||
- ./tools/unit-test-app/build/*.map
|
||||
- ./tools/unit-test-app/build/bootloader/*.bin
|
||||
expire_in: 6 mos
|
||||
|
||||
script:
|
||||
- cd tools/unit-test-app
|
||||
- git checkout ${CI_BUILD_REF_NAME} || echo "Using default branch..."
|
||||
- make defconfig
|
||||
- make
|
||||
|
||||
build_examples:
|
||||
<<: *build_template
|
||||
artifacts:
|
||||
|
@ -92,13 +107,30 @@ build_examples:
|
|||
- cd build_examples
|
||||
- ${IDF_PATH}/make/build_examples.sh
|
||||
|
||||
build_docs:
|
||||
stage: build
|
||||
image: espressif/esp32-ci-env
|
||||
tags:
|
||||
- build_docs
|
||||
script:
|
||||
- cd docs
|
||||
- doxygen
|
||||
# If not building master branch, and there are Doxygen warnings, print them and bail out
|
||||
- test "${CI_BUILD_REF_NAME}" = "master" || test $(cat doxygen-warning-log.txt | wc -l) -eq 0 || ( echo "Doxygen pass had some warnings:" && cat doxygen-warning-log.txt && false )
|
||||
- make html
|
||||
artifacts:
|
||||
paths:
|
||||
- docs/_build/html
|
||||
expire_in: 1 mos
|
||||
|
||||
|
||||
test_nvs_on_host:
|
||||
stage: test
|
||||
image: espressif/esp32-ci-env
|
||||
tags:
|
||||
- nvs_host_test
|
||||
script:
|
||||
- cd components/nvs_flash/test
|
||||
- cd components/nvs_flash/test_nvs_host
|
||||
- make test
|
||||
|
||||
test_build_system:
|
||||
|
@ -112,13 +144,12 @@ test_build_system:
|
|||
- ./make/test_build_system.sh
|
||||
|
||||
test_report:
|
||||
stage: deploy
|
||||
stage: test_report
|
||||
only:
|
||||
- master
|
||||
- triggers
|
||||
tags:
|
||||
- test_report
|
||||
allow_failure: true
|
||||
variables:
|
||||
LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
|
||||
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test"
|
||||
|
@ -127,7 +158,8 @@ test_report:
|
|||
when: always
|
||||
paths:
|
||||
- $REPORT_PATH
|
||||
expire_in: 6 mos
|
||||
- $LOG_PATH
|
||||
expire_in: 12 mos
|
||||
script:
|
||||
# clone test bench
|
||||
- git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git
|
||||
|
@ -159,6 +191,31 @@ push_master_to_github:
|
|||
- git push --follow-tags github HEAD:master
|
||||
|
||||
|
||||
deploy_docs:
|
||||
before_script:
|
||||
- echo "Not setting up GitLab key, not fetching submodules"
|
||||
stage: deploy
|
||||
only:
|
||||
- master
|
||||
- triggers
|
||||
tags:
|
||||
- deploy
|
||||
image: espressif/esp32-ci-env
|
||||
script:
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
- echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64
|
||||
- base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa
|
||||
- chmod 600 ~/.ssh/id_rsa
|
||||
- echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config
|
||||
- export GIT_VER=$(git describe --always)
|
||||
- cd docs/_build/
|
||||
- mv html $GIT_VER
|
||||
- tar czvf $GIT_VER.tar.gz $GIT_VER
|
||||
- scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH
|
||||
- ssh $DOCS_SERVER -x "cd $DOCS_PATH && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest"
|
||||
|
||||
|
||||
# AUTO GENERATED PART START, DO NOT MODIFY CONTENT BELOW
|
||||
# template for test jobs
|
||||
.test_template: &test_template
|
||||
|
@ -172,11 +229,11 @@ push_master_to_github:
|
|||
variables:
|
||||
# LOCAL_ENV_CONFIG_PATH: define in template and jobs can overwrite if required
|
||||
LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF
|
||||
BIN_PATH: "$CI_PROJECT_DIR/SSC/build/"
|
||||
BIN_PATH: "$CI_PROJECT_DIR/SSC/ssc_bin/SSC"
|
||||
APP_NAME: "ssc"
|
||||
LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
|
||||
# append test level folder to TEST_CASE_FILE_PATH in before_script of test job
|
||||
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test"
|
||||
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/integration_test"
|
||||
# jobs MUST set CONFIG_FILE in before_script, and overwrite the variables above if necessary
|
||||
|
||||
artifacts:
|
||||
|
@ -222,13 +279,34 @@ push_master_to_github:
|
|||
# run test
|
||||
- python CIRunner.py -l $LOG_PATH -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH bin_path $APP_NAME $BIN_PATH
|
||||
|
||||
# template for unit test jobs
|
||||
.unit_test_template: &unit_test_template
|
||||
<<: *test_template
|
||||
allow_failure: false
|
||||
stage: unit_test
|
||||
|
||||
variables:
|
||||
# jobs MUST set CONFIG_FILE in before_script, and overwrite the variables above if necessary
|
||||
LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF
|
||||
BIN_PATH: "$CI_PROJECT_DIR/esp-idf-tests/build/"
|
||||
LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
|
||||
APP_NAME: "ut"
|
||||
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/unit_test"
|
||||
|
||||
UT_Function_SYS_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
before_script:
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/UT_Function_SYS_01.yml
|
||||
|
||||
IT_Function_SYS_01:
|
||||
<<: *test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_SYS_01.yml
|
||||
|
||||
IT_Function_WIFI_01:
|
||||
|
@ -238,7 +316,6 @@ IT_Function_WIFI_01:
|
|||
- SSC_T1_1
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_01.yml
|
||||
|
||||
IT_Function_WIFI_02:
|
||||
|
@ -248,7 +325,6 @@ IT_Function_WIFI_02:
|
|||
- SSC_T1_1
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_02.yml
|
||||
|
||||
IT_Function_TCPIP_01:
|
||||
|
@ -258,7 +334,6 @@ IT_Function_TCPIP_01:
|
|||
- SSC_T1_1
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_01.yml
|
||||
|
||||
IT_Function_TCPIP_02:
|
||||
|
@ -268,7 +343,6 @@ IT_Function_TCPIP_02:
|
|||
- SSC_T1_1
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_02.yml
|
||||
|
||||
IT_Function_TCPIP_03:
|
||||
|
@ -278,7 +352,6 @@ IT_Function_TCPIP_03:
|
|||
- SSC_T1_1
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_03.yml
|
||||
|
||||
IT_Function_TCPIP_04:
|
||||
|
@ -288,7 +361,6 @@ IT_Function_TCPIP_04:
|
|||
- SSC_T1_1
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_04.yml
|
||||
|
||||
IT_Function_TCPIP_05:
|
||||
|
@ -298,7 +370,6 @@ IT_Function_TCPIP_05:
|
|||
- SSC_T1_1
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_05.yml
|
||||
|
||||
IT_Function_TCPIP_06:
|
||||
|
@ -307,7 +378,6 @@ IT_Function_TCPIP_06:
|
|||
- ESP32_IDF
|
||||
- SSC_T1_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_06.yml
|
||||
|
||||
IT_Function_WIFI_03:
|
||||
|
@ -316,7 +386,6 @@ IT_Function_WIFI_03:
|
|||
- ESP32_IDF
|
||||
- SSC_T3_PhyMode
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_03.yml
|
||||
|
||||
IT_Function_WIFI_04:
|
||||
|
@ -325,7 +394,6 @@ IT_Function_WIFI_04:
|
|||
- ESP32_IDF
|
||||
- SSC_T1_APC
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_04.yml
|
||||
|
||||
IT_Function_WIFI_05:
|
||||
|
@ -334,7 +402,6 @@ IT_Function_WIFI_05:
|
|||
- ESP32_IDF
|
||||
- SSC_T1_WEP
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_05.yml
|
||||
|
||||
IT_Function_WIFI_06:
|
||||
|
@ -343,7 +410,6 @@ IT_Function_WIFI_06:
|
|||
- ESP32_IDF
|
||||
- SSC_T2_PhyMode
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_06.yml
|
||||
|
||||
IT_Function_TCPIP_07:
|
||||
|
@ -354,7 +420,6 @@ IT_Function_TCPIP_07:
|
|||
- SSC_T1_2
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_07.yml
|
||||
|
||||
IT_Function_TCPIP_08:
|
||||
|
@ -363,7 +428,6 @@ IT_Function_TCPIP_08:
|
|||
- ESP32_IDF
|
||||
- SSC_T1_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_08.yml
|
||||
|
||||
IT_Function_TCPIP_09:
|
||||
|
@ -372,7 +436,6 @@ IT_Function_TCPIP_09:
|
|||
- ESP32_IDF
|
||||
- SSC_T1_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_09.yml
|
||||
|
||||
IT_Function_TCPIP_10:
|
||||
|
@ -383,7 +446,6 @@ IT_Function_TCPIP_10:
|
|||
- SSC_T1_2
|
||||
- SSC_T2_1
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_10.yml
|
||||
|
||||
IT_Function_TCPIP_11:
|
||||
|
@ -391,8 +453,8 @@ IT_Function_TCPIP_11:
|
|||
tags:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_1
|
||||
- SSC_T1_2
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_11.yml
|
||||
|
||||
IT_Function_TCPIP_12:
|
||||
|
@ -400,7 +462,5 @@ IT_Function_TCPIP_12:
|
|||
tags:
|
||||
- ESP32_IDF
|
||||
- SSC_T1_1
|
||||
- SSC_T1_2
|
||||
before_script:
|
||||
- TEST_CASE_FILE_PATH=$TEST_CASE_FILE_PATH/integration_test
|
||||
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_12.yml
|
||||
|
|
|
@ -7,3 +7,6 @@
|
|||
[submodule "components/bt/lib"]
|
||||
path = components/bt/lib
|
||||
url = https://github.com/espressif/esp32-bt-lib.git
|
||||
[submodule "components/micro-ecc/micro-ecc"]
|
||||
path = components/micro-ecc/micro-ecc
|
||||
url = https://github.com/kmackay/micro-ecc.git
|
||||
|
|
|
@ -1,30 +1,36 @@
|
|||
# Contributions Guide
|
||||
Contributions Guide
|
||||
===================
|
||||
|
||||
We welcome contributions to the esp-idf project!
|
||||
|
||||
## How to Contribute
|
||||
How to Contribute
|
||||
-----------------
|
||||
|
||||
Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via [Github Pull Requests](https://help.github.com/articles/about-pull-requests/).
|
||||
Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via `Github Pull Requests <https://help.github.com/articles/about-pull-requests/>`_.
|
||||
|
||||
## Before Contributing
|
||||
Before Contributing
|
||||
-------------------
|
||||
|
||||
Before sending us a Pull Request, please consider this list of points:
|
||||
|
||||
* Is the contribution entirely your own work, or already licensed under an Apache License 2.0 compatible Open Source License? If not then we unfortunately cannot accept it.
|
||||
|
||||
* Does any new code conform to the esp-idf Style Guide? (Style Guide currently pending).
|
||||
* Does any new code conform to the esp-idf :doc:`Style Guide <style-guide>`?
|
||||
|
||||
* Does the code documentation follow requirements in :doc:`documenting-code`?
|
||||
|
||||
* Is the code adequately commented for people to understand how it is structured?
|
||||
|
||||
* Is there documentation or examples that go with code contributions? [There are additional suggestions for writing good examples in the examples README](examples/README.md).
|
||||
* Is there documentation or examples that go with code contributions? `There are additional suggestions for writing good examples in the examples README <https://github.com/espressif/esp-idf/tree/master/examples>`_.
|
||||
|
||||
* Are comments and documentation written in clear English, with no spelling or grammar errors?
|
||||
|
||||
* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" [squashed into previous commits](http://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/)?
|
||||
* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" `squashed into previous commits <http://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/>`_?
|
||||
|
||||
* If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback.
|
||||
|
||||
## Pull Request Process
|
||||
Pull Request Process
|
||||
--------------------
|
||||
|
||||
After you open the Pull Request, there will probably be some discussion in the comments field of the request itself.
|
||||
|
||||
|
@ -32,6 +38,10 @@ Once the Pull Request is ready to merge, it will first be merged into our intern
|
|||
|
||||
If this process passes, it will be merged onto the public github repository.
|
||||
|
||||
## Legal Part
|
||||
Legal Part
|
||||
----------
|
||||
|
||||
Before a contribution can be accepted, you will need to sign our :doc:`contributor-agreement`. You will be prompted for this automatically as part of the Pull Request process.
|
||||
|
||||
|
||||
|
||||
Before a contribution can be accepted, you will need to sign our [Contributor Agreement](docs/contributor-agreement.rst). You will be prompted for this automatically as part of the Pull Request process.
|
|
@ -1,5 +1,7 @@
|
|||
# Using Espressif IoT Development Framework with the ESP32
|
||||
|
||||
[![alt text](https://readthedocs.org/projects/docs/badge/?version=latest "Documentation Status")](http://esp-idf.readthedocs.io/en/latest/?badge=latest)
|
||||
|
||||
# Setting Up ESP-IDF
|
||||
|
||||
In the [docs](docs) directory you will find per-platform setup guides:
|
||||
|
@ -60,14 +62,15 @@ 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.
|
||||
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](docs) contains esp-idf documentation.
|
||||
* The [docs directory of the esp-idf repository](docs) contains source of [esp-idf](http://esp-idf.readthedocs.io/) 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.
|
||||
|
||||
* If you're interested in contributing to esp-idf, please check the [CONTRIBUTING.md](CONTRIBUTING.md) file.
|
||||
* If you're interested in contributing to esp-idf, please check the [Contributions Guide](http://esp-idf.readthedocs.io/en/latest/contributing.html>).
|
||||
|
||||
|
|
|
@ -20,12 +20,99 @@ config LOG_BOOTLOADER_LEVEL_VERBOSE
|
|||
endchoice
|
||||
|
||||
config LOG_BOOTLOADER_LEVEL
|
||||
int
|
||||
default 0 if LOG_BOOTLOADER_LEVEL_NONE
|
||||
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
|
||||
default 2 if LOG_BOOTLOADER_LEVEL_WARN
|
||||
default 3 if LOG_BOOTLOADER_LEVEL_INFO
|
||||
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
|
||||
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
|
||||
int
|
||||
default 0 if LOG_BOOTLOADER_LEVEL_NONE
|
||||
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
|
||||
default 2 if LOG_BOOTLOADER_LEVEL_WARN
|
||||
default 3 if LOG_BOOTLOADER_LEVEL_INFO
|
||||
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
|
||||
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
|
||||
menu "Secure boot configuration"
|
||||
|
||||
choice SECURE_BOOTLOADER
|
||||
bool "Secure bootloader"
|
||||
default SECURE_BOOTLOADER_DISABLED
|
||||
help
|
||||
Build a bootloader with the secure boot flag enabled.
|
||||
|
||||
Secure bootloader can be one-time-flash (chip will only ever
|
||||
boot that particular bootloader), or a digest key can be used
|
||||
to allow the secure bootloader to be re-flashed with
|
||||
modifications. Secure boot also permanently disables JTAG.
|
||||
|
||||
See docs/security/secure-boot.rst for details.
|
||||
|
||||
config SECURE_BOOTLOADER_DISABLED
|
||||
bool "Disabled"
|
||||
|
||||
config SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
bool "One-time flash"
|
||||
help
|
||||
On first boot, the bootloader will generate a key which is not readable externally or by software. A digest is generated from the bootloader image itself. This digest will be verified on each subsequent boot.
|
||||
|
||||
Enabling this option means that the bootloader cannot be changed after the first time it is booted.
|
||||
|
||||
config SECURE_BOOTLOADER_REFLASHABLE
|
||||
bool "Reflashable"
|
||||
help
|
||||
Generate a reusable secure bootloader key, derived (via SHA-256) from the secure boot signing key.
|
||||
|
||||
This allows the secure bootloader to be re-flashed by anyone with access to the secure boot signing key.
|
||||
|
||||
This option is less secure than one-time flash, because a leak of the digest key from one device allows reflashing of any device that uses it.
|
||||
|
||||
endchoice
|
||||
|
||||
config SECURE_BOOT_SIGNING_KEY
|
||||
string "Secure boot signing key"
|
||||
depends on SECURE_BOOTLOADER_ENABLED
|
||||
default secure_boot_signing_key.pem
|
||||
help
|
||||
Path to the key file used to sign partition tables and app images for secure boot.
|
||||
|
||||
Key file is an ECDSA private key (NIST256p curve) in PEM format.
|
||||
|
||||
Path is evaluated relative to the project directory.
|
||||
|
||||
You can generate a new signing key by running the following command:
|
||||
espsecure.py generate_signing_key secure_boot_signing_key.pem
|
||||
|
||||
See docs/security/secure-boot.rst for details.
|
||||
|
||||
config SECURE_BOOT_DISABLE_JTAG
|
||||
bool "First boot: Permanently disable JTAG"
|
||||
depends on SECURE_BOOTLOADER_ENABLED
|
||||
default Y
|
||||
help
|
||||
Bootloader permanently disable JTAG (across entire chip) when enabling secure boot. This happens on first boot of the bootloader.
|
||||
|
||||
It is recommended this option remains set for production environments.
|
||||
|
||||
config SECURE_BOOT_DISABLE_ROM_BASIC
|
||||
bool "First boot: Permanently disable ROM BASIC fallback"
|
||||
depends on SECURE_BOOTLOADER_ENABLED
|
||||
default Y
|
||||
help
|
||||
Bootloader permanently disables ROM BASIC (on UART console) as a fallback if the bootloader image becomes invalid. This happens on first boot.
|
||||
|
||||
It is recommended this option remains set in production environments.
|
||||
|
||||
config SECURE_BOOT_TEST_MODE
|
||||
bool "Test mode: don't actually enable secure boot"
|
||||
depends on SECURE_BOOTLOADER_ENABLED
|
||||
default N
|
||||
help
|
||||
If this option is set, all permanent secure boot changes (via Efuse) are disabled.
|
||||
|
||||
This option is for testing purposes only - it effectively completely disables secure boot protection.
|
||||
|
||||
config SECURE_BOOTLOADER_ENABLED
|
||||
bool
|
||||
default SECURE_BOOTLOADER_ONE_TIME_FLASH || SECURE_BOOTLOADER_REFLASHABLE
|
||||
|
||||
endmenu
|
|
@ -13,45 +13,110 @@ ifndef IS_BOOTLOADER_BUILD
|
|||
BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||
BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader)
|
||||
BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin
|
||||
BOOTLOADER_SDKCONFIG=$(BOOTLOADER_BUILD_DIR)/sdkconfig
|
||||
|
||||
# signing key path is resolved relative to the project directory
|
||||
SECURE_BOOT_SIGNING_KEY=$(abspath $(call dequote,$(CONFIG_SECURE_BOOT_SIGNING_KEY)))
|
||||
export SECURE_BOOT_SIGNING_KEY # used by bootloader_support component
|
||||
|
||||
# Custom recursive make for bootloader sub-project
|
||||
BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
|
||||
V=$(V) SDKCONFIG=$(BOOTLOADER_SDKCONFIG) \
|
||||
BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) \
|
||||
V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) TEST_COMPONENTS=
|
||||
|
||||
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
|
||||
|
||||
$(BOOTLOADER_BIN): | $(BOOTLOADER_BUILD_DIR)/sdkconfig
|
||||
$(Q) $(BOOTLOADER_MAKE) $@
|
||||
|
||||
bootloader-clean:
|
||||
$(Q) $(BOOTLOADER_MAKE) app-clean config-clean
|
||||
$(Q) rm -f $(BOOTLOADER_SDKCONFIG) $(BOOTLOADER_SDKCONFIG).old
|
||||
$(BOOTLOADER_BIN): $(SDKCONFIG_MAKEFILE)
|
||||
$(BOOTLOADER_MAKE) $@
|
||||
|
||||
clean: bootloader-clean
|
||||
|
||||
bootloader: $(BOOTLOADER_BIN)
|
||||
@echo "Bootloader built. Default flash command is:"
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
|
||||
ifdef CONFIG_SECURE_BOOTLOADER_DISABLED
|
||||
# If secure boot disabled, bootloader flashing is integrated
|
||||
# with 'make flash' and no warnings are printed.
|
||||
|
||||
all_binaries: $(BOOTLOADER_BIN)
|
||||
bootloader: $(BOOTLOADER_BIN)
|
||||
@echo $(SEPARATOR)
|
||||
@echo "Bootloader built. Default flash command is:"
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^"
|
||||
|
||||
ESPTOOL_ALL_FLASH_ARGS += 0x1000 $(BOOTLOADER_BIN)
|
||||
|
||||
# bootloader-flash calls flash in the bootloader dummy project
|
||||
bootloader-flash: $(BOOTLOADER_BIN)
|
||||
$(BOOTLOADER_MAKE) flash
|
||||
$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^
|
||||
|
||||
# synchronise the project level config to the bootloader's
|
||||
# config
|
||||
$(BOOTLOADER_SDKCONFIG): $(PROJECT_PATH)/sdkconfig | $(BOOTLOADER_BUILD_DIR)
|
||||
$(Q) cp $< $@
|
||||
else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
|
||||
#### TEMPORARILY DISABLE THIS OPTION
|
||||
ifneq ("$(IDF_INSECURE_SECURE_BOOT)","1")
|
||||
bootloader:
|
||||
@echo "Secure boot features are not yet mature, so the current secure bootloader will not properly secure the device"
|
||||
@echo "If you flash this bootloader, you will be left with an non-updateable bootloader that is missing features."
|
||||
@echo "If you really want to do this, set the environment variable IDF_INSECURE_SECURE_BOOT=1 and rerun make."
|
||||
exit 1
|
||||
else
|
||||
|
||||
# One time flashing requires user to run esptool.py command themselves,
|
||||
# and warning is printed about inability to reflash.
|
||||
|
||||
bootloader: $(BOOTLOADER_BIN)
|
||||
@echo $(SEPARATOR)
|
||||
@echo "Bootloader built. One-time flash command is:"
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
|
||||
@echo $(SEPARATOR)
|
||||
@echo "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device"
|
||||
|
||||
endif # IDF_INSECURE_SECURE_BOOT
|
||||
else ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE
|
||||
# Reflashable secure bootloader
|
||||
# generates a digest binary (bootloader + digest)
|
||||
|
||||
#### TEMPORARILY DISABLE THIS OPTION
|
||||
ifneq ("$(IDF_INSECURE_SECURE_BOOT)","1")
|
||||
bootloader:
|
||||
@echo "Secure boot features are not yet mature, so the current secure bootloader will not properly secure the device."
|
||||
@echo "If using this feature, expect to reflash the bootloader at least one more time."
|
||||
@echo "If you really want to do this, set the environment variable IDF_INSECURE_SECURE_BOOT=1 and rerun make."
|
||||
exit 1
|
||||
else
|
||||
|
||||
BOOTLOADER_DIGEST_BIN := $(BOOTLOADER_BUILD_DIR)/bootloader-reflash-digest.bin
|
||||
SECURE_BOOTLOADER_KEY := $(BOOTLOADER_BUILD_DIR)/secure-bootloader-key.bin
|
||||
|
||||
$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY)
|
||||
$(Q) $(ESPSECUREPY) digest_private_key -k $< $@
|
||||
|
||||
bootloader: $(BOOTLOADER_DIGEST_BIN)
|
||||
@echo $(SEPARATOR)
|
||||
@echo "Bootloader built and secure digest generated. First time flash command is:"
|
||||
@echo "$(ESPEFUSEPY) burn_key secure_boot $(SECURE_BOOTLOADER_KEY)"
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
|
||||
@echo $(SEPARATOR)
|
||||
@echo "To reflash the bootloader after initial flash:"
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x0 $(BOOTLOADER_DIGEST_BIN)"
|
||||
@echo $(SEPARATOR)
|
||||
@echo "* After first boot, only re-flashes of this kind (with same key) will be accepted."
|
||||
@echo "* Not recommended to re-use the same secure boot keyfile on multiple production devices."
|
||||
|
||||
$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY)
|
||||
@echo "DIGEST $(notdir $@)"
|
||||
$(Q) $(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOTLOADER_KEY) -o $@ $<
|
||||
|
||||
endif # IDF_INSECURE_SECURE_BOOT
|
||||
else
|
||||
bootloader:
|
||||
@echo "Invalid bootloader target: bad sdkconfig?"
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
all_binaries: $(BOOTLOADER_BIN)
|
||||
|
||||
bootloader-clean:
|
||||
$(BOOTLOADER_MAKE) app-clean
|
||||
rm -f $(SECURE_BOOTLOADER_KEY) $(BOOTLOADER_DIGEST_BIN)
|
||||
|
||||
$(BOOTLOADER_BUILD_DIR):
|
||||
$(Q) mkdir -p $@
|
||||
mkdir -p $@
|
||||
|
||||
else
|
||||
CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include
|
||||
CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include
|
||||
|
||||
endif
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
#
|
||||
|
||||
PROJECT_NAME := bootloader
|
||||
COMPONENTS := esptool_py bootloader log spi_flash
|
||||
|
||||
#We cannot include the esp32 component directly but we need its includes.
|
||||
#This is fixed by adding CFLAGS from Makefile.projbuild
|
||||
COMPONENTS := esptool_py bootloader bootloader_support log spi_flash micro-ecc
|
||||
|
||||
# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
|
||||
#
|
||||
|
@ -12,7 +15,7 @@ COMPONENTS := esptool_py bootloader log spi_flash
|
|||
IS_BOOTLOADER_BUILD := 1
|
||||
export IS_BOOTLOADER_BUILD
|
||||
|
||||
#We cannot include the esp32 component directly but we need its includes.
|
||||
#This is fixed by adding CFLAGS from Makefile.projbuild
|
||||
# include the top-level "project" include directory, for sdkconfig.h
|
||||
CFLAGS += -I$(BUILD_DIR_BASE)/../include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
|
|
@ -25,8 +25,6 @@ extern "C"
|
|||
|
||||
#define BOOT_VERSION "V0.1"
|
||||
#define SPI_SEC_SIZE 0x1000
|
||||
#define MEM_CACHE(offset) (uint8_t *)(0x3f400000 + (offset))
|
||||
#define CACHE_READ_32(offset) ((uint32_t *)(0x3f400000 + (offset)))
|
||||
#define IROM_LOW 0x400D0000
|
||||
#define IROM_HIGH 0x40400000
|
||||
#define DROM_LOW 0x3F400000
|
||||
|
@ -36,7 +34,6 @@ extern "C"
|
|||
#define RTC_DATA_LOW 0x50000000
|
||||
#define RTC_DATA_HIGH 0x50002000
|
||||
|
||||
|
||||
#define PART_TYPE_APP 0x00
|
||||
#define PART_SUBTYPE_FACTORY 0x00
|
||||
#define PART_SUBTYPE_OTA_FLAG 0x10
|
||||
|
@ -62,12 +59,7 @@ typedef struct {
|
|||
uint32_t selected_subtype;
|
||||
} bootloader_state_t;
|
||||
|
||||
void boot_cache_redirect( uint32_t pos, size_t size );
|
||||
uint32_t get_bin_len(uint32_t pos);
|
||||
|
||||
bool flash_encrypt(bootloader_state_t *bs);
|
||||
bool secure_boot(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
#include "soc/timer_group_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "bootloader_flash.h"
|
||||
|
||||
#include "bootloader_config.h"
|
||||
|
||||
|
@ -49,9 +52,9 @@ flash cache is down and the app CPU is in reset. We do have a stack, so we can d
|
|||
extern void Cache_Flush(int);
|
||||
|
||||
void bootloader_main();
|
||||
void unpack_load_app(const esp_partition_pos_t *app_node);
|
||||
static void unpack_load_app(const esp_partition_pos_t *app_node);
|
||||
void print_flash_info(const esp_image_header_t* pfhdr);
|
||||
void IRAM_ATTR set_cache_and_start_app(uint32_t drom_addr,
|
||||
void set_cache_and_start_app(uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
uint32_t drom_size,
|
||||
uint32_t irom_addr,
|
||||
|
@ -94,53 +97,6 @@ void IRAM_ATTR call_start_cpu0()
|
|||
bootloader_main();
|
||||
}
|
||||
|
||||
/**
|
||||
* @function : get_bin_len
|
||||
* @description: get bin's length
|
||||
*
|
||||
* @inputs: pos bin locate address in flash
|
||||
* @return: uint32 length of bin,if bin MAGIC error return 0
|
||||
*/
|
||||
|
||||
uint32_t get_bin_len(uint32_t pos)
|
||||
{
|
||||
uint32_t len = 8 + 16;
|
||||
uint8_t i;
|
||||
ESP_LOGD(TAG, "pos %d %x",pos,*(uint8_t *)pos);
|
||||
if(0xE9 != *(uint8_t *)pos) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < *(uint8_t *)(pos + 1); i++) {
|
||||
len += *(uint32_t *)(pos + len + 4) + 8;
|
||||
}
|
||||
if (len % 16 != 0) {
|
||||
len = (len / 16 + 1) * 16;
|
||||
} else {
|
||||
len += 16;
|
||||
}
|
||||
ESP_LOGD(TAG, "bin length = %d", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function : boot_cache_redirect
|
||||
* @description: Configure several pages in flash map so that `size` bytes
|
||||
* starting at `pos` are mapped to 0x3f400000.
|
||||
* This sets up mapping only for PRO CPU.
|
||||
*
|
||||
* @inputs: pos address in flash
|
||||
* size size of the area to map, in bytes
|
||||
*/
|
||||
void boot_cache_redirect( uint32_t pos, size_t size )
|
||||
{
|
||||
uint32_t pos_aligned = pos & 0xffff0000;
|
||||
uint32_t count = (size + 0xffff) / 0x10000;
|
||||
Cache_Read_Disable( 0 );
|
||||
Cache_Flush( 0 );
|
||||
ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", pos_aligned, count );
|
||||
cache_flash_mmu_set( 0, 0, 0x3f400000, pos_aligned, 64, count );
|
||||
Cache_Read_Enable( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @function : load_partition_table
|
||||
|
@ -148,85 +104,103 @@ void boot_cache_redirect( uint32_t pos, size_t size )
|
|||
* OTA info sector, factory app sector, and test app sector.
|
||||
*
|
||||
* @inputs: bs bootloader state structure used to save the data
|
||||
* addr address of partition table in flash
|
||||
* @return: return true, if the partition table is loaded (and MD5 checksum is valid)
|
||||
*
|
||||
*/
|
||||
bool load_partition_table(bootloader_state_t* bs, uint32_t addr)
|
||||
bool load_partition_table(bootloader_state_t* bs)
|
||||
{
|
||||
esp_partition_info_t partition;
|
||||
uint32_t end = addr + 0x1000;
|
||||
int index = 0;
|
||||
const esp_partition_info_t *partitions;
|
||||
const int ESP_PARTITION_TABLE_DATA_LEN = 0xC00; /* length of actual data (signature is appended to this) */
|
||||
const int MAX_PARTITIONS = ESP_PARTITION_TABLE_DATA_LEN / sizeof(esp_partition_info_t);
|
||||
char *partition_usage;
|
||||
|
||||
ESP_LOGI(TAG, "Partition Table:");
|
||||
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
|
||||
|
||||
while (addr < end) {
|
||||
ESP_LOGD(TAG, "load partition table entry from %x(%08x)", addr, MEM_CACHE(addr));
|
||||
memcpy(&partition, MEM_CACHE(addr), sizeof(partition));
|
||||
ESP_LOGD(TAG, "type=%x subtype=%x", partition.type, partition.subtype);
|
||||
#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||
if(esp_secure_boot_enabled()) {
|
||||
ESP_LOGI(TAG, "Verifying partition table signature...");
|
||||
esp_err_t err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify partition table signature.");
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "Partition table signature verified");
|
||||
}
|
||||
#endif
|
||||
|
||||
partitions = bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
|
||||
if (!partitions) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions);
|
||||
|
||||
for(int i = 0; i < MAX_PARTITIONS; i++) {
|
||||
const esp_partition_info_t *partition = &partitions[i];
|
||||
ESP_LOGD(TAG, "load partition table entry 0x%x", (intptr_t)partition);
|
||||
ESP_LOGD(TAG, "type=%x subtype=%x", partition->type, partition->subtype);
|
||||
partition_usage = "unknown";
|
||||
|
||||
if (partition.magic == ESP_PARTITION_MAGIC) { /* valid partition definition */
|
||||
switch(partition.type) {
|
||||
case PART_TYPE_APP: /* app partition */
|
||||
switch(partition.subtype) {
|
||||
case PART_SUBTYPE_FACTORY: /* factory binary */
|
||||
bs->factory = partition.pos;
|
||||
partition_usage = "factory app";
|
||||
break;
|
||||
case PART_SUBTYPE_TEST: /* test binary */
|
||||
bs->test = partition.pos;
|
||||
partition_usage = "test app";
|
||||
break;
|
||||
default:
|
||||
/* OTA binary */
|
||||
if ((partition.subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
|
||||
bs->ota[partition.subtype & PART_SUBTYPE_OTA_MASK] = partition.pos;
|
||||
++bs->app_count;
|
||||
partition_usage = "OTA app";
|
||||
}
|
||||
else {
|
||||
partition_usage = "Unknown app";
|
||||
}
|
||||
break;
|
||||
if (partition->magic != ESP_PARTITION_MAGIC) {
|
||||
/* invalid partition definition indicates end-of-table */
|
||||
break;
|
||||
}
|
||||
|
||||
/* valid partition table */
|
||||
switch(partition->type) {
|
||||
case PART_TYPE_APP: /* app partition */
|
||||
switch(partition->subtype) {
|
||||
case PART_SUBTYPE_FACTORY: /* factory binary */
|
||||
bs->factory = partition->pos;
|
||||
partition_usage = "factory app";
|
||||
break;
|
||||
case PART_SUBTYPE_TEST: /* test binary */
|
||||
bs->test = partition->pos;
|
||||
partition_usage = "test app";
|
||||
break;
|
||||
default:
|
||||
/* OTA binary */
|
||||
if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
|
||||
bs->ota[partition->subtype & PART_SUBTYPE_OTA_MASK] = partition->pos;
|
||||
++bs->app_count;
|
||||
partition_usage = "OTA app";
|
||||
}
|
||||
break; /* PART_TYPE_APP */
|
||||
case PART_TYPE_DATA: /* data partition */
|
||||
switch(partition.subtype) {
|
||||
case PART_SUBTYPE_DATA_OTA: /* ota data */
|
||||
bs->ota_info = partition.pos;
|
||||
partition_usage = "OTA data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_RF:
|
||||
partition_usage = "RF data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_WIFI:
|
||||
partition_usage = "WiFi data";
|
||||
break;
|
||||
default:
|
||||
partition_usage = "Unknown data";
|
||||
break;
|
||||
else {
|
||||
partition_usage = "Unknown app";
|
||||
}
|
||||
break; /* PARTITION_USAGE_DATA */
|
||||
default: /* other partition type */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* invalid partition magic number */
|
||||
else {
|
||||
break; /* todo: validate md5 */
|
||||
break; /* PART_TYPE_APP */
|
||||
case PART_TYPE_DATA: /* data partition */
|
||||
switch(partition->subtype) {
|
||||
case PART_SUBTYPE_DATA_OTA: /* ota data */
|
||||
bs->ota_info = partition->pos;
|
||||
partition_usage = "OTA data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_RF:
|
||||
partition_usage = "RF data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_WIFI:
|
||||
partition_usage = "WiFi data";
|
||||
break;
|
||||
default:
|
||||
partition_usage = "Unknown data";
|
||||
break;
|
||||
}
|
||||
break; /* PARTITION_USAGE_DATA */
|
||||
default: /* other partition type */
|
||||
break;
|
||||
}
|
||||
|
||||
/* print partition type info */
|
||||
ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", index, partition.label, partition_usage,
|
||||
partition.type, partition.subtype,
|
||||
partition.pos.offset, partition.pos.size);
|
||||
index++;
|
||||
addr += sizeof(partition);
|
||||
ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", i, partition->label, partition_usage,
|
||||
partition->type, partition->subtype,
|
||||
partition->pos.offset, partition->pos.size);
|
||||
}
|
||||
|
||||
bootloader_munmap(partitions);
|
||||
|
||||
ESP_LOGI(TAG,"End of partition table");
|
||||
return true;
|
||||
}
|
||||
|
@ -254,8 +228,10 @@ void bootloader_main()
|
|||
|
||||
esp_image_header_t fhdr;
|
||||
bootloader_state_t bs;
|
||||
SpiFlashOpResult spiRet1,spiRet2;
|
||||
SpiFlashOpResult spiRet1,spiRet2;
|
||||
esp_ota_select_entry_t sa,sb;
|
||||
const esp_ota_select_entry_t *ota_select_map;
|
||||
|
||||
memset(&bs, 0, sizeof(bs));
|
||||
|
||||
ESP_LOGI(TAG, "compile time " __TIME__ );
|
||||
|
@ -263,16 +239,17 @@ void bootloader_main()
|
|||
REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
|
||||
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
|
||||
SPIUnlock();
|
||||
/*register first sector in drom0 page 0 */
|
||||
boot_cache_redirect( 0, 0x5000 );
|
||||
|
||||
memcpy((unsigned int *) &fhdr, MEM_CACHE(0x1000), sizeof(esp_image_header_t) );
|
||||
if(esp_image_load_header(0x1000, &fhdr) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to load bootloader header!");
|
||||
return;
|
||||
}
|
||||
|
||||
print_flash_info(&fhdr);
|
||||
|
||||
update_flash_config(&fhdr);
|
||||
|
||||
if (!load_partition_table(&bs, ESP_PARTITION_TABLE_ADDR)) {
|
||||
if (!load_partition_table(&bs)) {
|
||||
ESP_LOGE(TAG, "load partition table error!");
|
||||
return;
|
||||
}
|
||||
|
@ -281,9 +258,19 @@ void bootloader_main()
|
|||
|
||||
if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
|
||||
//ESP_LOGE("OTA info sector handling is not implemented");
|
||||
boot_cache_redirect(bs.ota_info.offset, bs.ota_info.size );
|
||||
memcpy(&sa,MEM_CACHE(bs.ota_info.offset & 0x0000ffff),sizeof(sa));
|
||||
memcpy(&sb,MEM_CACHE((bs.ota_info.offset + 0x1000)&0x0000ffff) ,sizeof(sb));
|
||||
if (bs.ota_info.size < 2 * sizeof(esp_ota_select_entry_t)) {
|
||||
ESP_LOGE(TAG, "ERROR: ota_info partition size %d is too small (minimum %d bytes)", bs.ota_info.size, sizeof(esp_ota_select_entry_t));
|
||||
return;
|
||||
}
|
||||
ota_select_map = bootloader_mmap(bs.ota_info.offset, bs.ota_info.size);
|
||||
if (!ota_select_map) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs.ota_info.offset, bs.ota_info.size);
|
||||
return;
|
||||
}
|
||||
sa = ota_select_map[0];
|
||||
sb = ota_select_map[1];
|
||||
bootloader_munmap(ota_select_map);
|
||||
|
||||
if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
|
||||
// init status flash
|
||||
load_part_pos = bs.ota[0];
|
||||
|
@ -329,35 +316,61 @@ void bootloader_main()
|
|||
}
|
||||
|
||||
ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
|
||||
if(fhdr.secure_boot_flag == 0x01) {
|
||||
/* protect the 2nd_boot */
|
||||
if(false == secure_boot()){
|
||||
ESP_LOGE(TAG, "secure boot failed");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||
/* Generate secure digest from this bootloader to protect future
|
||||
modifications */
|
||||
esp_err_t err = esp_secure_boot_permanently_enable();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.", err);
|
||||
/* Allow booting to continue, as the failure is probably
|
||||
due to user-configured EFUSEs for testing...
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
if(fhdr.encrypt_flag == 0x01) {
|
||||
/* encrypt flash */
|
||||
/* encrypt flash */
|
||||
if (false == flash_encrypt(&bs)) {
|
||||
ESP_LOGE(TAG, "flash encrypt failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// copy sections to RAM, set up caches, and start application
|
||||
// copy loaded segments to RAM, set up caches for mapped segments, and start application
|
||||
unpack_load_app(&load_part_pos);
|
||||
}
|
||||
|
||||
|
||||
void unpack_load_app(const esp_partition_pos_t* partition)
|
||||
static void unpack_load_app(const esp_partition_pos_t* partition)
|
||||
{
|
||||
boot_cache_redirect(partition->offset, partition->size);
|
||||
|
||||
uint32_t pos = 0;
|
||||
esp_err_t err;
|
||||
esp_image_header_t image_header;
|
||||
memcpy(&image_header, MEM_CACHE(pos), sizeof(image_header));
|
||||
pos += sizeof(image_header);
|
||||
uint32_t image_length;
|
||||
|
||||
/* TODO: verify the app image as part of OTA boot decision, so can have fallbacks */
|
||||
err = esp_image_basic_verify(partition->offset, &image_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGI(TAG, "Verifying app signature @ 0x%x (length 0x%x)", partition->offset, image_length);
|
||||
err = esp_secure_boot_verify_signature(partition->offset, image_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "App image @ 0x%x failed signature verification (%d)", partition->offset, err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "App signature is valid");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (esp_image_load_header(partition->offset, &image_header) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to load app image header @ 0x%x", partition->offset);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t drom_addr = 0;
|
||||
uint32_t drom_load_addr = 0;
|
||||
|
@ -366,24 +379,27 @@ void unpack_load_app(const esp_partition_pos_t* partition)
|
|||
uint32_t irom_load_addr = 0;
|
||||
uint32_t irom_size = 0;
|
||||
|
||||
/* Reload the RTC memory sections whenever a non-deepsleep reset
|
||||
/* Reload the RTC memory segments whenever a non-deepsleep reset
|
||||
is occurring */
|
||||
bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
|
||||
|
||||
ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
|
||||
image_header.blocks,
|
||||
image_header.segment_count,
|
||||
image_header.spi_mode,
|
||||
image_header.spi_size,
|
||||
(unsigned)image_header.entry_addr);
|
||||
|
||||
for (uint32_t section_index = 0;
|
||||
section_index < image_header.blocks;
|
||||
++section_index) {
|
||||
esp_image_section_header_t section_header = {0};
|
||||
memcpy(§ion_header, MEM_CACHE(pos), sizeof(section_header));
|
||||
pos += sizeof(section_header);
|
||||
for (int segment = 0; segment < image_header.segment_count; segment++) {
|
||||
esp_image_segment_header_t segment_header;
|
||||
uint32_t data_offs;
|
||||
if(esp_image_load_segment_header(segment, partition->offset,
|
||||
&image_header, &segment_header,
|
||||
&data_offs) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to load segment header #%d", segment);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t address = section_header.load_addr;
|
||||
const uint32_t address = segment_header.load_addr;
|
||||
bool load = true;
|
||||
bool map = false;
|
||||
if (address == 0x00000000) { // padding, ignore block
|
||||
|
@ -395,47 +411,50 @@ void unpack_load_app(const esp_partition_pos_t* partition)
|
|||
}
|
||||
|
||||
if (address >= DROM_LOW && address < DROM_HIGH) {
|
||||
ESP_LOGD(TAG, "found drom section, map from %08x to %08x", pos,
|
||||
section_header.load_addr);
|
||||
drom_addr = partition->offset + pos - sizeof(section_header);
|
||||
drom_load_addr = section_header.load_addr;
|
||||
drom_size = section_header.data_len + sizeof(section_header);
|
||||
ESP_LOGD(TAG, "found drom segment, map from %08x to %08x", data_offs,
|
||||
segment_header.load_addr);
|
||||
drom_addr = data_offs;
|
||||
drom_load_addr = segment_header.load_addr;
|
||||
drom_size = segment_header.data_len + sizeof(segment_header);
|
||||
load = false;
|
||||
map = true;
|
||||
}
|
||||
|
||||
if (address >= IROM_LOW && address < IROM_HIGH) {
|
||||
ESP_LOGD(TAG, "found irom section, map from %08x to %08x", pos,
|
||||
section_header.load_addr);
|
||||
irom_addr = partition->offset + pos - sizeof(section_header);
|
||||
irom_load_addr = section_header.load_addr;
|
||||
irom_size = section_header.data_len + sizeof(section_header);
|
||||
ESP_LOGD(TAG, "found irom segment, map from %08x to %08x", data_offs,
|
||||
segment_header.load_addr);
|
||||
irom_addr = data_offs;
|
||||
irom_load_addr = segment_header.load_addr;
|
||||
irom_size = segment_header.data_len + sizeof(segment_header);
|
||||
load = false;
|
||||
map = true;
|
||||
}
|
||||
|
||||
if (!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) {
|
||||
ESP_LOGD(TAG, "Skipping RTC code section at %08x\n", pos);
|
||||
ESP_LOGD(TAG, "Skipping RTC code segment at %08x\n", data_offs);
|
||||
load = false;
|
||||
}
|
||||
|
||||
if (!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) {
|
||||
ESP_LOGD(TAG, "Skipping RTC data section at %08x\n", pos);
|
||||
ESP_LOGD(TAG, "Skipping RTC data segment at %08x\n", data_offs);
|
||||
load = false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos,
|
||||
section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":"");
|
||||
ESP_LOGI(TAG, "segment %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", segment, data_offs - sizeof(esp_image_segment_header_t),
|
||||
segment_header.load_addr, segment_header.data_len, segment_header.data_len, (load)?"load":(map)?"map":"");
|
||||
|
||||
if (!load) {
|
||||
pos += section_header.data_len;
|
||||
continue;
|
||||
if (load) {
|
||||
const void *data = bootloader_mmap(data_offs, segment_header.data_len);
|
||||
if(!data) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%xc, 0x%x) failed",
|
||||
data_offs, segment_header.data_len);
|
||||
return;
|
||||
}
|
||||
memcpy((void *)segment_header.load_addr, data, segment_header.data_len);
|
||||
bootloader_munmap(data);
|
||||
}
|
||||
|
||||
memcpy((void*) section_header.load_addr, MEM_CACHE(pos), section_header.data_len);
|
||||
pos += section_header.data_len;
|
||||
}
|
||||
|
||||
|
||||
set_cache_and_start_app(drom_addr,
|
||||
drom_load_addr,
|
||||
drom_size,
|
||||
|
@ -445,7 +464,7 @@ void unpack_load_app(const esp_partition_pos_t* partition)
|
|||
image_header.entry_addr);
|
||||
}
|
||||
|
||||
void IRAM_ATTR set_cache_and_start_app(
|
||||
void set_cache_and_start_app(
|
||||
uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
uint32_t drom_size,
|
||||
|
@ -456,9 +475,7 @@ void IRAM_ATTR set_cache_and_start_app(
|
|||
{
|
||||
ESP_LOGD(TAG, "configure drom and irom and start");
|
||||
Cache_Read_Disable( 0 );
|
||||
Cache_Read_Disable( 1 );
|
||||
Cache_Flush( 0 );
|
||||
Cache_Flush( 1 );
|
||||
uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
||||
ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
|
||||
int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||
|
@ -474,7 +491,8 @@ void IRAM_ATTR set_cache_and_start_app(
|
|||
REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 );
|
||||
REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 );
|
||||
Cache_Read_Enable( 0 );
|
||||
Cache_Read_Enable( 1 );
|
||||
|
||||
// Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)
|
||||
|
||||
ESP_LOGD(TAG, "start: 0x%08x", entry_addr);
|
||||
typedef void (*entry_t)(void);
|
||||
|
@ -521,7 +539,7 @@ void print_flash_info(const esp_image_header_t* phdr)
|
|||
#if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
|
||||
|
||||
ESP_LOGD(TAG, "magic %02x", phdr->magic );
|
||||
ESP_LOGD(TAG, "blocks %02x", phdr->blocks );
|
||||
ESP_LOGD(TAG, "segments %02x", phdr->segment_count );
|
||||
ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode );
|
||||
ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed );
|
||||
ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size );
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
# Main bootloader Makefile.
|
||||
#
|
||||
# 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.
|
||||
# This is basically the same as a component makefile, but in the case of the bootloader
|
||||
# we pull in bootloader-specific linker arguments.
|
||||
#
|
||||
|
||||
COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld
|
||||
COMPONENT_ADD_LDFLAGS := -L $(COMPONENT_PATH) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
|
|
@ -15,7 +15,7 @@ MEMORY
|
|||
of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
|
||||
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||
dport0_seg (RW) : org = 0x3FF00000, len = 0x10 /* IO */
|
||||
iram_seg (RWX) : org = 0x4009A000, len = 0x1000
|
||||
iram_seg (RWX) : org = 0x40080000, len = 0x400 /* 1k of IRAM used by bootloader functions which need to flush/enable APP CPU cache */
|
||||
iram_pool_1_seg (RWX) : org = 0x40078000, len = 0x8000 /* IRAM POOL1, used for APP CPU cache. We can abuse it in bootloader because APP CPU is still held in reset, until we enable APP CPU cache */
|
||||
dram_seg (RW) : org = 0x3FFC0000, len = 0x20000 /* Shared RAM, minus rom bss/data/stack.*/
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "esp_types.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "rom/cache.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
@ -30,6 +31,7 @@
|
|||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_config.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
static const char* TAG = "flash_encrypt";
|
||||
|
||||
|
@ -90,103 +92,97 @@ bool flash_encrypt_write(uint32_t pos, uint32_t len)
|
|||
Cache_Read_Enable(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @function : flash_encrypt
|
||||
* @description: encrypt 2nd boot ,partition table ,factory bin <EFBFBD><EFBFBD>test bin (if use)<EFBFBD><EFBFBD>ota bin
|
||||
* <EFBFBD><EFBFBD>OTA info sector.
|
||||
*
|
||||
* @inputs: bs bootloader state structure used to save the data
|
||||
*
|
||||
*
|
||||
* @return: return true, if the encrypt flash success
|
||||
*
|
||||
*
|
||||
*/
|
||||
bool flash_encrypt(bootloader_state_t *bs)
|
||||
{
|
||||
uint32_t bin_len = 0;
|
||||
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT);
|
||||
uint8_t count = bitcount(flash_crypt_cnt);
|
||||
int i = 0;
|
||||
ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count);
|
||||
esp_err_t err;
|
||||
uint32_t image_len = 0;
|
||||
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT);
|
||||
uint8_t count = bitcount(flash_crypt_cnt);
|
||||
ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count);
|
||||
|
||||
if ((count % 2) == 0) {
|
||||
boot_cache_redirect( 0, 64*1024);
|
||||
/* encrypt iv and abstruct */
|
||||
if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt iv and abstract error");
|
||||
return false;
|
||||
}
|
||||
if ((count % 2) == 0) {
|
||||
/* encrypt iv and abstract */
|
||||
if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt iv and abstract error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* encrypt bootloader image */
|
||||
err = esp_image_basic_verify(0x1000, &image_len);
|
||||
if(err == ESP_OK && image_len != 0) {
|
||||
if (false == flash_encrypt_write(0x1000, image_len)) {
|
||||
ESP_LOGE(TAG, "encrypt 2nd boot error");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "2nd boot len error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* encrypt write boot bin*/
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
|
||||
if(bin_len != 0) {
|
||||
if (false == flash_encrypt_write(0x1000, bin_len)) {
|
||||
ESP_LOGE(TAG, "encrypt 2nd boot error");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "2nd boot len error");
|
||||
return false;
|
||||
}
|
||||
/* encrypt partition table */
|
||||
if (false == flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt partition table error");
|
||||
return false;
|
||||
}
|
||||
if (false == flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt partition table error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* encrypt write factory bin */
|
||||
if(bs->factory.offset != 0x00) {
|
||||
ESP_LOGD(TAG, "have factory bin");
|
||||
boot_cache_redirect(bs->factory.offset, bs->factory.size);
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->factory.offset&0xffff));
|
||||
if(bin_len != 0) {
|
||||
if (false == flash_encrypt_write(bs->factory.offset, bin_len)) {
|
||||
ESP_LOGE(TAG, "encrypt factory bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bs->factory.offset != 0 && bs->factory.size != 0) {
|
||||
ESP_LOGD(TAG, "have factory bin");
|
||||
if (false == flash_encrypt_write(bs->factory.offset, bs->factory.size)) {
|
||||
ESP_LOGE(TAG, "encrypt factory bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* encrypt write test bin */
|
||||
if(bs->test.offset != 0x00) {
|
||||
ESP_LOGD(TAG, "have test bin");
|
||||
boot_cache_redirect(bs->test.offset, bs->test.size);
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->test.offset&0xffff));
|
||||
if(bin_len != 0) {
|
||||
if (false == flash_encrypt_write(bs->test.offset, bin_len)) {
|
||||
ESP_LOGE(TAG, "encrypt test bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bs->test.offset != 0 && bs->test.size != 0) {
|
||||
ESP_LOGD(TAG, "have test bin");
|
||||
if (false == flash_encrypt_write(bs->test.offset, bs->test.size)) {
|
||||
ESP_LOGE(TAG, "encrypt test bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* encrypt write ota bin */
|
||||
for (i = 0;i<16;i++) {
|
||||
if(bs->ota[i].offset != 0x00) {
|
||||
ESP_LOGD(TAG, "have ota[%d] bin",i);
|
||||
boot_cache_redirect(bs->ota[i].offset, bs->ota[i].size);
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->ota[i].offset&0xffff));
|
||||
if(bin_len != 0) {
|
||||
if (false == flash_encrypt_write(bs->ota[i].offset, bin_len)) {
|
||||
ESP_LOGE(TAG, "encrypt ota bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if(bs->ota[i].offset != 0 && bs->ota[i].size != 0) {
|
||||
ESP_LOGD(TAG, "have ota[%d] bin",i);
|
||||
if (false == flash_encrypt_write(bs->ota[i].offset, bs->ota[i].size)) {
|
||||
ESP_LOGE(TAG, "encrypt ota bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* encrypt write ota info bin */
|
||||
if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt ota info error");
|
||||
return false;
|
||||
}
|
||||
REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04);
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
|
||||
ESP_LOGW(TAG, "burn flash_crypt_cnt");
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "flash already encrypted.");
|
||||
return true;
|
||||
}
|
||||
if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
|
||||
ESP_LOGE(TAG, "encrypt ota info error");
|
||||
return false;
|
||||
}
|
||||
|
||||
REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04);
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
|
||||
ESP_LOGW(TAG, "burn flash_crypt_cnt");
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "flash already encrypted.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "rom/cache.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/secure_boot.h"
|
||||
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_config.h"
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
/**
|
||||
* @function : secure_boot_generate
|
||||
* @description: generate boot abstract & iv
|
||||
*
|
||||
* @inputs: bool
|
||||
*/
|
||||
bool secure_boot_generate(uint32_t bin_len){
|
||||
SpiFlashOpResult spiRet;
|
||||
uint16_t i;
|
||||
uint32_t buf[32];
|
||||
if (bin_len % 128 != 0) {
|
||||
bin_len = (bin_len / 128 + 1) * 128;
|
||||
}
|
||||
ets_secure_boot_start();
|
||||
ets_secure_boot_rd_iv(buf);
|
||||
ets_secure_boot_hash(NULL);
|
||||
Cache_Read_Disable(0);
|
||||
/* iv stored in sec 0 */
|
||||
spiRet = SPIEraseSector(0);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
/* write iv to flash, 0x0000, 128 bytes (1024 bits) */
|
||||
spiRet = SPIWrite(0, buf, 128);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "write iv to flash.");
|
||||
Cache_Read_Enable(0);
|
||||
/* read 4K code image from flash, for test */
|
||||
for (i = 0; i < bin_len; i+=128) {
|
||||
ets_secure_boot_hash((uint32_t *)(0x3f400000 + 0x1000 + i));
|
||||
}
|
||||
|
||||
ets_secure_boot_obtain();
|
||||
ets_secure_boot_rd_abstract(buf);
|
||||
ets_secure_boot_finish();
|
||||
Cache_Read_Disable(0);
|
||||
/* write abstract to flash, 0x0080, 64 bytes (512 bits) */
|
||||
spiRet = SPIWrite(0x80, buf, 64);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "write abstract to flash.");
|
||||
Cache_Read_Enable(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @function : secure_boot
|
||||
* @description: protect boot code in flash
|
||||
*
|
||||
* @inputs: bool
|
||||
*/
|
||||
bool secure_boot(void){
|
||||
uint32_t bin_len = 0;
|
||||
if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0)
|
||||
{
|
||||
ESP_LOGD(TAG, "already secure boot !");
|
||||
return true;
|
||||
} else {
|
||||
boot_cache_redirect( 0, 64*1024);
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
|
||||
if (bin_len == 0) {
|
||||
ESP_LOGE(TAG, "boot len is error");
|
||||
return false;
|
||||
}
|
||||
if (false == secure_boot_generate(bin_len)){
|
||||
ESP_LOGE(TAG, "secure boot generate failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
REG_SET_BIT(EFUSE_BLK0_WDATA6_REG, EFUSE_RD_ABS_DONE_0);
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
|
||||
ESP_LOGW(TAG, "burn abstract_done_0");
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
|
||||
ESP_LOGI(TAG, "read EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
|
||||
return true;
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
Bootloader Support Component
|
||||
============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
"Bootloader support" contains APIs which are used by the bootloader but are also needed for the main app.
|
||||
|
||||
Code in this component needs to be aware of being executed in a bootloader environment (no RTOS available, BOOTLOADER_BUILD macro set) or in an esp-idf app environment (RTOS running, need locking support.)
|
|
@ -0,0 +1,35 @@
|
|||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include_priv
|
||||
|
||||
ifdef IS_BOOTLOADER_BUILD
|
||||
# share "private" headers with the bootloader component
|
||||
# eventual goal: all functionality that needs this lives in bootloader_support
|
||||
COMPONENT_ADD_INCLUDEDIRS += include_priv
|
||||
endif
|
||||
|
||||
COMPONENT_SRCDIRS := src
|
||||
|
||||
#
|
||||
# Secure boot signing key support
|
||||
#
|
||||
ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||
|
||||
# this path is created relative to the component build directory
|
||||
SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin)
|
||||
|
||||
$(SECURE_BOOT_SIGNING_KEY):
|
||||
@echo "Need to generate secure boot signing key."
|
||||
@echo "One way is to run this command:"
|
||||
@echo "$(ESPSECUREPY) generate_signing_key $@"
|
||||
@echo "Keep key file safe after generating."
|
||||
@echo "(See secure boot documentation for risks & alternatives.)"
|
||||
@exit 1
|
||||
|
||||
$(SECURE_BOOT_VERIFICATION_KEY): $(SECURE_BOOT_SIGNING_KEY)
|
||||
$(ESPSECUREPY) extract_public_key --keyfile $< $@
|
||||
|
||||
COMPONENT_EXTRA_CLEAN += $(SECURE_BOOT_VERIFICATION_KEY)
|
||||
|
||||
COMPONENT_EMBED_FILES := $(SECURE_BOOT_VERIFICATION_KEY)
|
||||
|
||||
endif
|
|
@ -0,0 +1,132 @@
|
|||
// 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 __ESP32_IMAGE_FORMAT_H
|
||||
#define __ESP32_IMAGE_FORMAT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#define ESP_ERR_IMAGE_BASE 0x2000
|
||||
#define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1)
|
||||
#define ESP_ERR_IMAGE_INVALID (ESP_ERR_IMAGE_BASE + 2)
|
||||
|
||||
/* Support for app/bootloader image parsing
|
||||
Can be compiled as part of app or bootloader code.
|
||||
*/
|
||||
|
||||
/* SPI flash mode, used in esp_image_header_t */
|
||||
typedef enum {
|
||||
ESP_IMAGE_SPI_MODE_QIO,
|
||||
ESP_IMAGE_SPI_MODE_QOUT,
|
||||
ESP_IMAGE_SPI_MODE_DIO,
|
||||
ESP_IMAGE_SPI_MODE_DOUT,
|
||||
ESP_IMAGE_SPI_MODE_FAST_READ,
|
||||
ESP_IMAGE_SPI_MODE_SLOW_READ
|
||||
} esp_image_spi_mode_t;
|
||||
|
||||
/* SPI flash clock frequency */
|
||||
enum {
|
||||
ESP_IMAGE_SPI_SPEED_40M,
|
||||
ESP_IMAGE_SPI_SPEED_26M,
|
||||
ESP_IMAGE_SPI_SPEED_20M,
|
||||
ESP_IMAGE_SPI_SPEED_80M = 0xF
|
||||
} esp_image_spi_freq_t;
|
||||
|
||||
/* Supported SPI flash sizes */
|
||||
typedef enum {
|
||||
ESP_IMAGE_FLASH_SIZE_1MB = 0,
|
||||
ESP_IMAGE_FLASH_SIZE_2MB,
|
||||
ESP_IMAGE_FLASH_SIZE_4MB,
|
||||
ESP_IMAGE_FLASH_SIZE_8MB,
|
||||
ESP_IMAGE_FLASH_SIZE_16MB,
|
||||
ESP_IMAGE_FLASH_SIZE_MAX
|
||||
} esp_image_flash_size_t;
|
||||
|
||||
#define ESP_IMAGE_HEADER_MAGIC 0xE9
|
||||
|
||||
/* Main header of binary image */
|
||||
typedef struct {
|
||||
uint8_t magic;
|
||||
uint8_t segment_count;
|
||||
uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
|
||||
uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
|
||||
uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
|
||||
uint32_t entry_addr;
|
||||
uint8_t encrypt_flag; /* encrypt flag */
|
||||
uint8_t extra_header[15]; /* ESP32 additional header, unused by second bootloader */
|
||||
} esp_image_header_t;
|
||||
|
||||
/* Header of binary image segment */
|
||||
typedef struct {
|
||||
uint32_t load_addr;
|
||||
uint32_t data_len;
|
||||
} esp_image_segment_header_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read an ESP image header from flash.
|
||||
*
|
||||
* @param src_addr Address in flash to load image header. Must be 4 byte aligned.
|
||||
* @param[out] image_header Pointer to an esp_image_header_t struture to be filled with data. If the function fails, contents are undefined.
|
||||
*
|
||||
* @return ESP_OK if image header was loaded, ESP_ERR_IMAGE_FLASH_FAIL
|
||||
* if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header
|
||||
* appears invalid.
|
||||
*/
|
||||
esp_err_t esp_image_load_header(uint32_t src_addr, esp_image_header_t *image_header);
|
||||
|
||||
/**
|
||||
* @brief Read the segment header and data offset of a segment in the image.
|
||||
*
|
||||
* @param index Index of the segment to load information for.
|
||||
* @param src_addr Base address in flash of the image.
|
||||
* @param[in] image_header Pointer to the flash image header, already loaded by @ref esp_image_load_header().
|
||||
* @param[out] segment_header Pointer to a segment header structure to be filled with data. If the function fails, contents are undefined.
|
||||
* @param[out] segment_data_offset Pointer to the data offset of the segment.
|
||||
*
|
||||
* @return ESP_OK if segment_header & segment_data_offset were loaded successfully, ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header appears invalid, ESP_ERR_INVALID_ARG if the index is invalid.
|
||||
*/
|
||||
esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return length of an image in flash. Non-cryptographically validates image integrity in the process.
|
||||
*
|
||||
* If the image has a secure boot signature appended, the signature is not checked and this length is not included in the result.
|
||||
*
|
||||
* Image validation checks:
|
||||
* - Magic byte
|
||||
* - No single segment longer than 16MB
|
||||
* - Total image no longer than 16MB
|
||||
* - 8 bit image checksum is valid
|
||||
*
|
||||
* @param src_addr Offset of the start of the image in flash. Must be 4 byte aligned.
|
||||
* @param[out] length Length of the image, set to a value if the image is valid. Can be null.
|
||||
*
|
||||
* @return ESP_OK if image is valid, ESP_FAIL or ESP_ERR_IMAGE_INVALID on errors.
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_image_basic_verify(uint32_t src_addr, uint32_t *length);
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t drom_addr;
|
||||
uint32_t drom_load_addr;
|
||||
uint32_t drom_size;
|
||||
uint32_t irom_addr;
|
||||
uint32_t irom_load_addr;
|
||||
uint32_t irom_size;
|
||||
} esp_image_flash_mapping_t;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
// 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 __ESP32_SECUREBOOT_H
|
||||
#define __ESP32_SECUREBOOT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <esp_err.h>
|
||||
#include "soc/efuse_reg.h"
|
||||
|
||||
/* Support functions for secure boot features.
|
||||
|
||||
Can be compiled as part of app or bootloader code.
|
||||
*/
|
||||
|
||||
/** @brief Is secure boot currently enabled in hardware?
|
||||
*
|
||||
* Secure boot is enabled if the ABS_DONE_0 efuse is blown. This means
|
||||
* that the ROM bootloader code will only boot a verified secure
|
||||
* bootloader digest from now on.
|
||||
*
|
||||
* @return true if secure boot is enabled.
|
||||
*/
|
||||
static inline bool esp_secure_boot_enabled(void) {
|
||||
return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Enable secure boot if it is not already enabled.
|
||||
*
|
||||
* @important If this function succeeds, secure boot is permanently
|
||||
* enabled on the chip via efuse.
|
||||
*
|
||||
* @important This function is intended to be called from bootloader code only.
|
||||
*
|
||||
* If secure boot is not yet enabled for bootloader, this will
|
||||
* generate the secure boot digest and enable secure boot by blowing
|
||||
* the EFUSE_RD_ABS_DONE_0 efuse.
|
||||
*
|
||||
* This function does not verify secure boot of the bootloader (the
|
||||
* ROM bootloader does this.)
|
||||
*
|
||||
* Will fail if efuses have been part-burned in a way that indicates
|
||||
* secure boot should not or could not be correctly enabled.
|
||||
*
|
||||
*
|
||||
* @return ESP_ERR_INVALID_STATE if efuse state doesn't allow
|
||||
* secure boot to be enabled cleanly. ESP_OK if secure boot
|
||||
* is enabled on this chip from now on.
|
||||
*/
|
||||
esp_err_t esp_secure_boot_permanently_enable(void);
|
||||
|
||||
/** @brief Verify the secure boot signature (determinstic ECDSA w/ SHA256) appended to some binary data in flash.
|
||||
*
|
||||
* Public key is compiled into the calling program. See docs/security/secure-boot.rst for details.
|
||||
*
|
||||
* @param src_addr Starting offset of the data in flash.
|
||||
* @param length Length of data in bytes. Signature is appended -after- length bytes.
|
||||
*
|
||||
* @return ESP_OK if signature is valid, ESP_ERR_INVALID_STATE if
|
||||
* signature fails, ESP_FAIL for other failures (ie can't read flash).
|
||||
*/
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,69 @@
|
|||
// 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 __BOOTLOADER_FLASH_H
|
||||
#define __BOOTLOADER_FLASH_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
/* Provide a Flash API for bootloader_support code,
|
||||
that can be used from bootloader or app code.
|
||||
|
||||
This header is available to source code in the bootloader &
|
||||
bootloader_support components only.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Map a region of flash to data memory
|
||||
*
|
||||
* @important In bootloader code, only one region can be bootloader_mmaped at once. The previous region must be bootloader_munmapped before another region is mapped.
|
||||
*
|
||||
* @important In app code, these functions are not thread safe.
|
||||
*
|
||||
* Call bootloader_munmap once for each successful call to bootloader_mmap.
|
||||
*
|
||||
* In esp-idf app, this function maps directly to spi_flash_mmap.
|
||||
*
|
||||
* @param offset - Starting flash offset to map to memory.
|
||||
* @param length - Length of data to map.
|
||||
*
|
||||
* @return Pointer to mapped data memory (at src_addr), or NULL
|
||||
* if an allocation error occured.
|
||||
*/
|
||||
const void *bootloader_mmap(uint32_t src_addr, uint32_t size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unmap a previously mapped region of flash
|
||||
*
|
||||
* Call bootloader_munmap once for each successful call to bootloader_mmap.
|
||||
*/
|
||||
void bootloader_munmap(const void *mapping);
|
||||
|
||||
/**
|
||||
* @brief Read data from Flash.
|
||||
*
|
||||
* @note Both src and dest have to be 4-byte aligned.
|
||||
*
|
||||
* @param src source address of the data in Flash.
|
||||
* @param dest pointer to the destination buffer
|
||||
* @param size length of data
|
||||
*
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
// 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 <stddef.h>
|
||||
|
||||
#include <bootloader_flash.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_spi_flash.h> /* including in bootloader for error values */
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
/* Normal app version maps to esp_spi_flash.h operations...
|
||||
*/
|
||||
static const char *TAG = "bootloader_mmap";
|
||||
|
||||
static spi_flash_mmap_memory_t map;
|
||||
|
||||
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
|
||||
{
|
||||
if (map) {
|
||||
ESP_LOGE(TAG, "tried to bootloader_mmap twice");
|
||||
return NULL; /* existing mapping in use... */
|
||||
}
|
||||
const void *result = NULL;
|
||||
esp_err_t err = spi_flash_mmap(src_addr, size, SPI_FLASH_MMAP_DATA, &result, &map);
|
||||
if (err != ESP_OK) {
|
||||
result = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void bootloader_munmap(const void *mapping)
|
||||
{
|
||||
if(mapping && map) {
|
||||
spi_flash_munmap(map);
|
||||
}
|
||||
map = 0;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size)
|
||||
{
|
||||
return spi_flash_read(src, dest, size);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Bootloader version, uses ROM functions only */
|
||||
#include <rom/spi_flash.h>
|
||||
#include <rom/cache.h>
|
||||
|
||||
static const char *TAG = "bootloader_flash";
|
||||
|
||||
static bool mapped;
|
||||
|
||||
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
|
||||
{
|
||||
if (mapped) {
|
||||
ESP_LOGE(TAG, "tried to bootloader_mmap twice");
|
||||
return NULL; /* can't map twice */
|
||||
}
|
||||
|
||||
uint32_t src_addr_aligned = src_addr & 0xffff0000;
|
||||
uint32_t count = (size + (src_addr - src_addr_aligned) + 0xffff) / 0x10000;
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", src_addr_aligned, count );
|
||||
cache_flash_mmu_set( 0, 0, 0x3f400000, src_addr_aligned, 64, count );
|
||||
Cache_Read_Enable( 0 );
|
||||
|
||||
mapped = true;
|
||||
|
||||
return (void *)(0x3f400000 + (src_addr - src_addr_aligned));
|
||||
}
|
||||
|
||||
void bootloader_munmap(const void *mapping)
|
||||
{
|
||||
if (mapped) {
|
||||
/* Full MMU reset */
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
mmu_init(0);
|
||||
mapped = false;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size)
|
||||
{
|
||||
if(src_addr & 3) {
|
||||
ESP_LOGE(TAG, "bootloader_flash_read src_addr 0x%x not 4-byte aligned", src_addr);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if((intptr_t)dest & 3) {
|
||||
ESP_LOGE(TAG, "bootloader_flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
SpiFlashOpResult r = SPIRead(src_addr, dest, size);
|
||||
Cache_Read_Enable(0);
|
||||
|
||||
switch(r) {
|
||||
case SPI_FLASH_RESULT_OK:
|
||||
return ESP_OK;
|
||||
case SPI_FLASH_RESULT_ERR:
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
case SPI_FLASH_RESULT_TIMEOUT:
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
default:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,161 @@
|
|||
// 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 <string.h>
|
||||
|
||||
#include <esp_image_format.h>
|
||||
#include <esp_log.h>
|
||||
#include <bootloader_flash.h>
|
||||
|
||||
static const char *TAG = "esp_image";
|
||||
|
||||
#define SIXTEEN_MB 0x1000000
|
||||
#define ESP_ROM_CHECKSUM_INITIAL 0xEF
|
||||
|
||||
esp_err_t esp_image_load_header(uint32_t src_addr, esp_image_header_t *image_header)
|
||||
{
|
||||
esp_err_t err;
|
||||
ESP_LOGD(TAG, "reading image header @ 0x%x", src_addr);
|
||||
|
||||
err = bootloader_flash_read(src_addr, image_header, sizeof(esp_image_header_t));
|
||||
|
||||
if (err == ESP_OK) {
|
||||
if (image_header->magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
ESP_LOGE(TAG, "image at 0x%x has invalid magic byte", src_addr);
|
||||
err = ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
if (image_header->spi_mode > ESP_IMAGE_SPI_MODE_SLOW_READ) {
|
||||
ESP_LOGW(TAG, "image at 0x%x has invalid SPI mode %d", src_addr, image_header->spi_mode);
|
||||
}
|
||||
if (image_header->spi_speed > ESP_IMAGE_SPI_SPEED_80M) {
|
||||
ESP_LOGW(TAG, "image at 0x%x has invalid SPI speed %d", src_addr, image_header->spi_speed);
|
||||
}
|
||||
if (image_header->spi_size > ESP_IMAGE_FLASH_SIZE_MAX) {
|
||||
ESP_LOGW(TAG, "image at 0x%x has invalid SPI size %d", src_addr, image_header->spi_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (err != ESP_OK) {
|
||||
bzero(image_header, sizeof(esp_image_header_t));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
uint32_t next_addr = src_addr + sizeof(esp_image_header_t);
|
||||
|
||||
if(index >= image_header->segment_count) {
|
||||
ESP_LOGE(TAG, "index %d higher than segment count %d", index, image_header->segment_count);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
for(int i = 0; i <= index && err == ESP_OK; i++) {
|
||||
ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
|
||||
err = bootloader_flash_read(next_addr, segment_header, sizeof(esp_image_segment_header_t));
|
||||
if (err == ESP_OK) {
|
||||
if ((segment_header->data_len & 3) != 0
|
||||
|| segment_header->data_len >= SIXTEEN_MB) {
|
||||
ESP_LOGE(TAG, "invalid segment length 0x%x", segment_header->data_len);
|
||||
err = ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
next_addr += sizeof(esp_image_segment_header_t);
|
||||
ESP_LOGV(TAG, "segment data length 0x%x data starts 0x%x", segment_header->data_len, next_addr);
|
||||
*segment_data_offset = next_addr;
|
||||
next_addr += segment_header->data_len;
|
||||
}
|
||||
}
|
||||
|
||||
if (err != ESP_OK) {
|
||||
*segment_data_offset = 0;
|
||||
bzero(segment_header, sizeof(esp_image_segment_header_t));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_image_basic_verify(uint32_t src_addr, uint32_t *p_length)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint8_t buf[16];
|
||||
uint8_t checksum = ESP_ROM_CHECKSUM_INITIAL;
|
||||
esp_image_header_t image_header;
|
||||
esp_image_segment_header_t segment_header = { 0 };
|
||||
uint32_t segment_data_offs = 0;
|
||||
const uint8_t *segment_data;
|
||||
uint32_t end_addr;
|
||||
uint32_t length;
|
||||
|
||||
if (p_length != NULL) {
|
||||
*p_length = 0;
|
||||
}
|
||||
|
||||
err = esp_image_load_header(src_addr, &image_header);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "reading %d image segments", image_header.segment_count);
|
||||
|
||||
/* Checksum each segment's data */
|
||||
for (int i = 0; i < image_header.segment_count; i++) {
|
||||
err = esp_image_load_segment_header(i, src_addr, &image_header,
|
||||
&segment_header, &segment_data_offs);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
segment_data = bootloader_mmap(segment_data_offs, segment_header.data_len);
|
||||
if (segment_data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", segment_data_offs, segment_header.data_len);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
for(int i = 0; i < segment_header.data_len; i++) {
|
||||
checksum ^= segment_data[i];
|
||||
}
|
||||
bootloader_munmap(segment_data);
|
||||
}
|
||||
|
||||
/* End of image, verify checksum */
|
||||
end_addr = segment_data_offs + segment_header.data_len;
|
||||
|
||||
if (end_addr < src_addr) {
|
||||
ESP_LOGE(TAG, "image offset has wrapped");
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
length = end_addr - src_addr;
|
||||
if (length >= SIXTEEN_MB) {
|
||||
ESP_LOGE(TAG, "invalid total length 0x%x", length);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
/* image padded to next full 16 byte block, with checksum byte at very end */
|
||||
ESP_LOGV(TAG, "unpadded image length 0x%x", length);
|
||||
length += 16; /* always pad by at least 1 byte */
|
||||
length = length - (length % 16);
|
||||
ESP_LOGV(TAG, "padded image length 0x%x", length);
|
||||
ESP_LOGD(TAG, "reading checksum block at 0x%x", src_addr + length - 16);
|
||||
bootloader_flash_read(src_addr + length - 16, buf, 16);
|
||||
if (checksum != buf[15]) {
|
||||
ESP_LOGE(TAG, "checksum failed. Calculated 0x%x read 0x%x",
|
||||
checksum, buf[15]);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
if (p_length != NULL) {
|
||||
*p_length = length;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
// 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 <string.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "rom/cache.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/secure_boot.h"
|
||||
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
#define HASH_BLOCK_SIZE 128
|
||||
#define IV_LEN HASH_BLOCK_SIZE
|
||||
#define DIGEST_LEN 64
|
||||
|
||||
/**
|
||||
* @function : secure_boot_generate
|
||||
* @description: generate boot digest (aka "abstract") & iv
|
||||
*
|
||||
* @inputs: image_len - length of image to calculate digest for
|
||||
*/
|
||||
static bool secure_boot_generate(uint32_t image_len){
|
||||
SpiFlashOpResult spiRet;
|
||||
/* buffer is uint32_t not uint8_t to meet ROM SPI API signature */
|
||||
uint32_t buf[IV_LEN / sizeof(uint32_t)];
|
||||
const void *image;
|
||||
|
||||
/* hardware secure boot engine only takes full blocks, so round up the
|
||||
image length. The additional data should all be 0xFF.
|
||||
*/
|
||||
if (image_len % HASH_BLOCK_SIZE != 0) {
|
||||
image_len = (image_len / HASH_BLOCK_SIZE + 1) * HASH_BLOCK_SIZE;
|
||||
}
|
||||
ets_secure_boot_start();
|
||||
ets_secure_boot_rd_iv(buf);
|
||||
ets_secure_boot_hash(NULL);
|
||||
Cache_Read_Disable(0);
|
||||
/* iv stored in sec 0 */
|
||||
spiRet = SPIEraseSector(0);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "SPI erase failed %d", spiRet);
|
||||
return false;
|
||||
}
|
||||
Cache_Read_Enable(0);
|
||||
|
||||
/* write iv to flash, 0x0000, 128 bytes (1024 bits) */
|
||||
ESP_LOGD(TAG, "write iv to flash.");
|
||||
spiRet = SPIWrite(0, buf, IV_LEN);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "SPI write failed %d", spiRet);
|
||||
return false;
|
||||
}
|
||||
bzero(buf, sizeof(buf));
|
||||
|
||||
/* generate digest from image contents */
|
||||
image = bootloader_mmap(0x1000, image_len);
|
||||
if (!image) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x1000, 0x%x) failed", image_len);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < image_len; i+= HASH_BLOCK_SIZE) {
|
||||
ets_secure_boot_hash(image + i/sizeof(void *));
|
||||
}
|
||||
bootloader_munmap(image);
|
||||
|
||||
ets_secure_boot_obtain();
|
||||
ets_secure_boot_rd_abstract(buf);
|
||||
ets_secure_boot_finish();
|
||||
|
||||
ESP_LOGD(TAG, "write digest to flash.");
|
||||
spiRet = SPIWrite(0x80, buf, DIGEST_LEN);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
ESP_LOGE(TAG, "SPI write failed %d", spiRet);
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "write digest to flash.");
|
||||
Cache_Read_Enable(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Burn values written to the efuse write registers */
|
||||
static inline void burn_efuses()
|
||||
{
|
||||
#ifdef CONFIG_SECURE_BOOT_TEST_MODE
|
||||
ESP_LOGE(TAG, "SECURE BOOT TEST MODE. Not really burning any efuses!");
|
||||
#else
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
|
||||
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
|
||||
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
|
||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_permanently_enable(void) {
|
||||
esp_err_t err;
|
||||
uint32_t image_len = 0;
|
||||
if (esp_secure_boot_enabled())
|
||||
{
|
||||
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
err = esp_image_basic_verify(0x1000, &image_len);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
|
||||
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
|
||||
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
|
||||
if (efuse_key_read_protected == false
|
||||
&& efuse_key_write_protected == false
|
||||
&& REG_READ(EFUSE_BLK2_RDATA0_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK2_RDATA1_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK2_RDATA2_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK2_RDATA3_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK2_RDATA4_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK2_RDATA5_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK2_RDATA6_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) {
|
||||
ESP_LOGI(TAG, "Generating new secure boot key...");
|
||||
/* reuse the secure boot IV generation function to generate
|
||||
the key, as this generator uses the hardware RNG. */
|
||||
uint32_t buf[32];
|
||||
ets_secure_boot_start();
|
||||
ets_secure_boot_rd_iv(buf);
|
||||
ets_secure_boot_finish();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ESP_LOGV(TAG, "EFUSE_BLK2_WDATA%d_REG = 0x%08x", i, buf[i]);
|
||||
REG_WRITE(EFUSE_BLK2_WDATA0_REG + 4*i, buf[i]);
|
||||
}
|
||||
bzero(buf, sizeof(buf));
|
||||
burn_efuses();
|
||||
ESP_LOGI(TAG, "Read & write protecting new key...");
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2);
|
||||
burn_efuses();
|
||||
efuse_key_read_protected = true;
|
||||
efuse_key_write_protected = true;
|
||||
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2");
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Generating secure boot digest...");
|
||||
if (false == secure_boot_generate(image_len)){
|
||||
ESP_LOGE(TAG, "secure boot generation failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Digest generation complete.");
|
||||
|
||||
if (!efuse_key_read_protected) {
|
||||
ESP_LOGE(TAG, "Pre-loaded key is not read protected. Refusing to blow secure boot efuse.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (!efuse_key_write_protected) {
|
||||
ESP_LOGE(TAG, "Pre-loaded key is not write protected. Refusing to blow secure boot efuse.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "blowing secure boot efuse...");
|
||||
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
|
||||
|
||||
uint32_t new_wdata6 = EFUSE_RD_ABS_DONE_0;
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_DISABLE_JTAG
|
||||
ESP_LOGI(TAG, "disabling JTAG...");
|
||||
new_wdata6 |= EFUSE_RD_DISABLE_JTAG;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_DISABLE_UART_BOOTLOADER
|
||||
ESP_LOGI(TAG, "disabling UART bootloader...");
|
||||
new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE_S;
|
||||
#endif
|
||||
|
||||
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
|
||||
burn_efuses();
|
||||
uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG);
|
||||
ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA6 %x", after);
|
||||
if (after & EFUSE_RD_ABS_DONE_0) {
|
||||
ESP_LOGI(TAG, "secure boot is now enabled for bootloader image");
|
||||
return ESP_OK;
|
||||
} else {
|
||||
#ifdef CONFIG_SECURE_BOOT_TEST_MODE
|
||||
ESP_LOGE(TAG, "secure boot not enabled due to test mode");
|
||||
#else
|
||||
ESP_LOGE(TAG, "secure boot not enabled for bootloader image, EFUSE_RD_ABS_DONE_0 is probably write protected!");
|
||||
#endif
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
// 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 "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
#include "uECC.h"
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
#include "rom/sha.h"
|
||||
typedef SHA_CTX sha_context;
|
||||
#else
|
||||
#include "hwcrypto/sha.h"
|
||||
typedef esp_sha_context sha_context;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint8_t signature[64];
|
||||
} signature_block_t;
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
sha_context sha;
|
||||
uint8_t digest[32];
|
||||
ptrdiff_t keylen;
|
||||
const uint8_t *data;
|
||||
const signature_block_t *sigblock;
|
||||
bool is_valid;
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
const uint8_t *digest_data;
|
||||
uint32_t digest_len;
|
||||
#endif
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
data = bootloader_mmap(src_addr, length + sizeof(signature_block_t));
|
||||
if(data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(signature_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
sigblock = (const signature_block_t *)(data + length);
|
||||
|
||||
if (sigblock->version != 0) {
|
||||
ESP_LOGE(TAG, "src 0x%x has invalid signature version field 0x%08x", src_addr, sigblock->version);
|
||||
goto unmap_and_fail;
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
/* Use ROM SHA functions directly */
|
||||
ets_sha_enable();
|
||||
ets_sha_init(&sha);
|
||||
digest_len = length * 8;
|
||||
digest_data = data;
|
||||
while (digest_len > 0) {
|
||||
uint32_t chunk_len = (digest_len > 64) ? 64 : digest_len;
|
||||
ets_sha_update(&sha, SHA2_256, digest_data, chunk_len);
|
||||
digest_len -= chunk_len;
|
||||
digest_data += chunk_len / 8;
|
||||
}
|
||||
ets_sha_finish(&sha, SHA2_256, digest);
|
||||
ets_sha_disable();
|
||||
#else
|
||||
/* Use thread-safe esp-idf SHA layer */
|
||||
esp_sha256_init(&sha);
|
||||
esp_sha256_start(&sha, false);
|
||||
esp_sha256_update(&sha, data, length);
|
||||
esp_sha256_finish(&sha, digest);
|
||||
esp_sha256_free(&sha);
|
||||
#endif
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if(keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
goto unmap_and_fail;
|
||||
}
|
||||
|
||||
is_valid = uECC_verify(signature_verification_key_start,
|
||||
digest, sizeof(digest), sigblock->signature,
|
||||
uECC_secp256r1());
|
||||
|
||||
bootloader_munmap(data);
|
||||
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
|
||||
unmap_and_fail:
|
||||
bootloader_munmap(data);
|
||||
return ESP_FAIL;
|
||||
}
|
|
@ -34,7 +34,7 @@ CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-brac
|
|||
|
||||
LIBS := btdm_app
|
||||
|
||||
COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \
|
||||
COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \
|
||||
$(addprefix -l,$(LIBS)) \
|
||||
$(LINKER_SCRIPTS)
|
||||
|
||||
|
@ -75,5 +75,4 @@ include $(IDF_PATH)/make/component_common.mk
|
|||
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
||||
$(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
|
||||
|
||||
# automatically trigger a git submodule update if BT library is missing
|
||||
$(eval $(call SubmoduleCheck,$(ALL_LIB_FILES),$(COMPONENT_PATH)/lib))
|
||||
COMPONENT_SUBMODULES += lib
|
||||
|
|
|
@ -29,37 +29,33 @@ extern "C" {
|
|||
*
|
||||
* This function should be called only once, before any other BT functions are called.
|
||||
*/
|
||||
void bt_controller_init();
|
||||
void bt_controller_init(void);
|
||||
|
||||
/** @brief: vhci_host_callback
|
||||
/** @brief vhci_host_callback
|
||||
* used for vhci call host function to notify what host need to do
|
||||
*
|
||||
* notify_host_send_available: notify host can send packet to controller
|
||||
* notify_host_recv: notify host that controller has packet send to host
|
||||
*/
|
||||
typedef struct vhci_host_callback {
|
||||
|
||||
void (*notify_host_send_available)(void);
|
||||
int (*notify_host_recv)(uint8_t *data, uint16_t len);
|
||||
void (*notify_host_send_available)(void); /*!< callback used to notify that the host can send packet to controller */
|
||||
int (*notify_host_recv)(uint8_t *data, uint16_t len); /*!< callback used to notify that the controller has a packet to send to the host*/
|
||||
} vhci_host_callback_t;
|
||||
|
||||
/** @brief: API_vhci_host_check_send_available
|
||||
/** @brief API_vhci_host_check_send_available
|
||||
* used for check actively if the host can send packet to controller or not.
|
||||
* return true for ready to send, false means cannot send packet
|
||||
* @return true for ready to send, false means cannot send packet
|
||||
*/
|
||||
bool API_vhci_host_check_send_available(void);
|
||||
|
||||
/** @brief: API_vhci_host_send_packet
|
||||
/** @brief API_vhci_host_send_packet
|
||||
* host send packet to controller
|
||||
* param data is the packet point, the param len is the packet length
|
||||
* return void
|
||||
* @param data the packet point
|
||||
*,@param len the packet length
|
||||
*/
|
||||
void API_vhci_host_send_packet(uint8_t *data, uint16_t len);
|
||||
|
||||
/** @brief: API_vhci_host_register_callback
|
||||
/** @brief API_vhci_host_register_callback
|
||||
* register the vhci referece callback, the call back
|
||||
* struct defined by vhci_host_callback structure.
|
||||
* param is the vhci_host_callback type variable
|
||||
* @param callback vhci_host_callback type variable
|
||||
*/
|
||||
void API_vhci_host_register_callback(const vhci_host_callback_t *callback);
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0f11ccac9a5f39e28e5d8904634c54acd4f140fd
|
||||
Subproject commit 5349ca363427758b9ef902f33e9ac0dae2c349e1
|
|
@ -1,14 +1,8 @@
|
|||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.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 SDK documents if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include/driver
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
|
|
@ -18,34 +18,13 @@
|
|||
#include "freertos/xtensa_api.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "soc/soc.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
//TODO: move debug options to menuconfig
|
||||
#define GPIO_DBG_ENABLE (0)
|
||||
#define GPIO_WARNING_ENABLE (0)
|
||||
#define GPIO_ERROR_ENABLE (0)
|
||||
#define GPIO_INFO_ENABLE (0)
|
||||
//DBG INFOR
|
||||
#if GPIO_INFO_ENABLE
|
||||
#define GPIO_INFO ets_printf
|
||||
#else
|
||||
#define GPIO_INFO(...)
|
||||
#endif
|
||||
#if GPIO_WARNING_ENABLE
|
||||
#define GPIO_WARNING(format,...) do{\
|
||||
ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define GPIO_WARNING(...)
|
||||
#endif
|
||||
#if GPIO_ERROR_ENABLE
|
||||
#define GPIO_ERROR(format,...) do{\
|
||||
ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define GPIO_ERROR(...)
|
||||
#endif
|
||||
static const char* GPIO_TAG = "GPIO";
|
||||
#define GPIO_CHECK(a, str, ret_val) if (!(a)) { \
|
||||
ESP_LOGE(GPIO_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret_val); \
|
||||
}
|
||||
|
||||
const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
|
||||
GPIO_PIN_REG_0,
|
||||
|
@ -90,33 +69,85 @@ const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
|
|||
GPIO_PIN_REG_39
|
||||
};
|
||||
|
||||
static int is_valid_gpio(int gpio_num)
|
||||
{
|
||||
if(gpio_num >= GPIO_PIN_COUNT || GPIO_PIN_MUX_REG[gpio_num] == 0) {
|
||||
GPIO_ERROR("GPIO io_num=%d does not exist\n",gpio_num);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT]={
|
||||
{RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M},
|
||||
{PERIPHS_IO_MUX_U0TXD_U, FUN_PU, FUN_PD},
|
||||
{RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M},
|
||||
{PERIPHS_IO_MUX_U0RXD_U, FUN_PU, FUN_PD},
|
||||
{RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M},
|
||||
{PERIPHS_IO_MUX_GPIO5_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_SD_CLK_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_SD_DATA0_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_SD_DATA1_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_SD_DATA2_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_SD_DATA3_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_SD_CMD_U, FUN_PU, FUN_PD},
|
||||
{RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M},
|
||||
{RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M},
|
||||
{RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M},
|
||||
{RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M},
|
||||
{PERIPHS_IO_MUX_GPIO16_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO17_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO18_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO19_U, FUN_PU, FUN_PD},
|
||||
{0,0,0},
|
||||
{PERIPHS_IO_MUX_GPIO21_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO22_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO23_U, FUN_PU, FUN_PD},
|
||||
{0,0,0},
|
||||
{RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M},
|
||||
{RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M},
|
||||
{RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M},
|
||||
{0,0,0},
|
||||
{0,0,0},
|
||||
{0,0,0},
|
||||
{0,0,0},
|
||||
{RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M},
|
||||
{RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M},
|
||||
{PERIPHS_IO_MUX_GPIO34_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO35_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO36_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO37_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO38_U, FUN_PU, FUN_PD},
|
||||
{PERIPHS_IO_MUX_GPIO39_U, FUN_PU, FUN_PD}
|
||||
};
|
||||
|
||||
|
||||
esp_err_t gpio_pullup_en(gpio_num_t gpio_num) {
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gpio_pullup_dis(gpio_num_t gpio_num) {
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gpio_pulldown_en(gpio_num_t gpio_num) {
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num) {
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||
{
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(intr_type >= GPIO_INTR_MAX) {
|
||||
GPIO_ERROR("Unknown GPIO intr:%u\n",intr_type);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
GPIO_CHECK(intr_type < GPIO_INTR_MAX, "GPIO interrupt type error", ESP_ERR_INVALID_ARG);
|
||||
GPIO.pin[gpio_num].int_type = intr_type;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
|
||||
{
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
if(xPortGetCoreID() == 0) {
|
||||
GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr
|
||||
} else {
|
||||
|
@ -127,18 +158,14 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
|
|||
|
||||
esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
GPIO.pin[gpio_num].int_ena = 0; //disable GPIO intr
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
if(gpio_num < 32) {
|
||||
GPIO.enable_w1tc = (0x1 << gpio_num);
|
||||
} else {
|
||||
|
@ -149,13 +176,7 @@ static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
|
|||
|
||||
static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
|
||||
{
|
||||
if(gpio_num >= 34) {
|
||||
GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG);
|
||||
if(gpio_num < 32) {
|
||||
GPIO.enable_w1ts = (0x1 << gpio_num);
|
||||
} else {
|
||||
|
@ -166,9 +187,7 @@ static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
|
|||
|
||||
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
|
||||
{
|
||||
if(!GPIO_IS_VALID_GPIO(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
if(level) {
|
||||
if(gpio_num < 32) {
|
||||
GPIO.out_w1ts = (1 << gpio_num);
|
||||
|
@ -196,29 +215,28 @@ int gpio_get_level(gpio_num_t gpio_num)
|
|||
|
||||
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
|
||||
{
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
GPIO_CHECK(pull <= GPIO_FLOATING, "GPIO pull mode error", ESP_ERR_INVALID_ARG);
|
||||
esp_err_t ret = ESP_OK;
|
||||
switch(pull) {
|
||||
case GPIO_PULLUP_ONLY:
|
||||
PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]);
|
||||
PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]);
|
||||
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
|
||||
break;
|
||||
case GPIO_PULLDOWN_ONLY:
|
||||
PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]);
|
||||
PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
|
||||
break;
|
||||
case GPIO_PULLUP_PULLDOWN:
|
||||
PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]);
|
||||
PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]);
|
||||
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
|
||||
break;
|
||||
case GPIO_FLOATING:
|
||||
PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]);
|
||||
PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
|
||||
break;
|
||||
default:
|
||||
GPIO_ERROR("Unknown pull up/down mode,gpio_num=%u,pull=%u\n",gpio_num,pull);
|
||||
ESP_LOGE(GPIO_TAG, "Unknown pull up/down mode,gpio_num=%u,pull=%u",gpio_num,pull);
|
||||
ret = ESP_ERR_INVALID_ARG;
|
||||
break;
|
||||
}
|
||||
|
@ -227,11 +245,9 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
|
|||
|
||||
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
|
||||
{
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
if(gpio_num >= 34 && (mode & (GPIO_MODE_DEF_OUTPUT))) {
|
||||
GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
|
||||
ESP_LOGE(GPIO_TAG, "io_num=%d can only be input",gpio_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
@ -266,54 +282,56 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
|
|||
uint64_t gpio_pin_mask = (pGPIOConfig->pin_bit_mask);
|
||||
uint32_t io_reg = 0;
|
||||
uint32_t io_num = 0;
|
||||
uint64_t bit_valid = 0;
|
||||
uint8_t input_en = 0;
|
||||
uint8_t output_en = 0;
|
||||
uint8_t od_en = 0;
|
||||
uint8_t pu_en = 0;
|
||||
uint8_t pd_en = 0;
|
||||
if(pGPIOConfig->pin_bit_mask == 0 || pGPIOConfig->pin_bit_mask >= (((uint64_t) 1) << GPIO_PIN_COUNT)) {
|
||||
GPIO_ERROR("GPIO_PIN mask error \n");
|
||||
ESP_LOGE(GPIO_TAG, "GPIO_PIN mask error ");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if((pGPIOConfig->mode) & (GPIO_MODE_DEF_OUTPUT)) {
|
||||
//GPIO 34/35/36/37/38/39 can only be used as input mode;
|
||||
if((gpio_pin_mask & ( GPIO_SEL_34 | GPIO_SEL_35 | GPIO_SEL_36 | GPIO_SEL_37 | GPIO_SEL_38 | GPIO_SEL_39))) {
|
||||
GPIO_ERROR("GPIO34-39 can only be used as input mode\n");
|
||||
ESP_LOGE(GPIO_TAG, "GPIO34-39 can only be used as input mode");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
do {
|
||||
io_reg = GPIO_PIN_MUX_REG[io_num];
|
||||
if(((gpio_pin_mask >> io_num) & BIT(0)) && io_reg) {
|
||||
GPIO_INFO("Gpio%02d |Mode:",io_num);
|
||||
if((pGPIOConfig->mode) & GPIO_MODE_DEF_INPUT) {
|
||||
GPIO_INFO("INPUT ");
|
||||
input_en = 1;
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_num]);
|
||||
} else {
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[io_num]);
|
||||
}
|
||||
if((pGPIOConfig->mode) & GPIO_MODE_DEF_OD) {
|
||||
GPIO_INFO("OD ");
|
||||
od_en = 1;
|
||||
GPIO.pin[io_num].pad_driver = 1; /*0x01 Open-drain */
|
||||
} else {
|
||||
GPIO.pin[io_num].pad_driver = 0; /*0x00 Normal gpio output */
|
||||
}
|
||||
if((pGPIOConfig->mode) & GPIO_MODE_DEF_OUTPUT) {
|
||||
GPIO_INFO("OUTPUT ");
|
||||
output_en = 1;
|
||||
gpio_output_enable(io_num);
|
||||
} else {
|
||||
gpio_output_disable(io_num);
|
||||
}
|
||||
GPIO_INFO("|");
|
||||
if(pGPIOConfig->pull_up_en) {
|
||||
GPIO_INFO("PU ");
|
||||
PIN_PULLUP_EN(io_reg);
|
||||
pu_en = 1;
|
||||
REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pu);
|
||||
} else {
|
||||
PIN_PULLUP_DIS(io_reg);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pu);
|
||||
}
|
||||
if(pGPIOConfig->pull_down_en) {
|
||||
GPIO_INFO("PD ");
|
||||
PIN_PULLDWN_EN(io_reg);
|
||||
pd_en = 1;
|
||||
REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
|
||||
} else {
|
||||
PIN_PULLDWN_DIS(io_reg);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
|
||||
}
|
||||
GPIO_INFO("Intr:%d |\n",pGPIOConfig->intr_type);
|
||||
ESP_LOGI(GPIO_TAG, "GPIO[%d]| InputEn: %d| OutputEn: %d| OpenDrain: %d| Pullup: %d| Pulldown: %d| Intr:%d ", io_num, input_en, output_en, od_en, pu_en, pd_en, pGPIOConfig->intr_type);
|
||||
gpio_set_intr_type(io_num, pGPIOConfig->intr_type);
|
||||
if(pGPIOConfig->intr_type) {
|
||||
gpio_intr_enable(io_num);
|
||||
|
@ -321,8 +339,6 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
|
|||
gpio_intr_disable(io_num);
|
||||
}
|
||||
PIN_FUNC_SELECT(io_reg, PIN_FUNC_GPIO); /*function number 2 is GPIO_FUNC for each pin */
|
||||
} else if(bit_valid && (io_reg == 0)) {
|
||||
GPIO_WARNING("io_num=%d does not exist\n",io_num);
|
||||
}
|
||||
io_num++;
|
||||
} while(io_num < GPIO_PIN_COUNT);
|
||||
|
@ -331,9 +347,7 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
|
|||
|
||||
esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg)
|
||||
{
|
||||
if(fn == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG);
|
||||
ESP_INTR_DISABLE(gpio_intr_num);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num);
|
||||
xt_set_interrupt_handler(gpio_intr_num, fn, arg);
|
||||
|
@ -344,15 +358,13 @@ esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * ar
|
|||
/*only level interrupt can be used for wake-up function*/
|
||||
esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||
{
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
esp_err_t ret = ESP_OK;
|
||||
if((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) {
|
||||
GPIO.pin[gpio_num].int_type = intr_type;
|
||||
GPIO.pin[gpio_num].wakeup_enable = 0x1;
|
||||
} else {
|
||||
GPIO_ERROR("GPIO wakeup only support Level mode,but edge mode set. gpio_num:%u\n",gpio_num);
|
||||
ESP_LOGE(GPIO_TAG, "GPIO wakeup only support Level mode,but edge mode set. gpio_num:%u",gpio_num);
|
||||
ret = ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return ret;
|
||||
|
@ -360,9 +372,7 @@ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
|||
|
||||
esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
if(!is_valid_gpio(gpio_num)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
GPIO.pin[gpio_num].wakeup_enable = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "soc/gpio_struct.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
|
@ -27,43 +28,43 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GPIO_SEL_0 (BIT(0)) /* Pin 0 selected */
|
||||
#define GPIO_SEL_1 (BIT(1)) /* Pin 1 selected */
|
||||
#define GPIO_SEL_2 (BIT(2)) /* Pin 2 selected */
|
||||
#define GPIO_SEL_3 (BIT(3)) /* Pin 3 selected */
|
||||
#define GPIO_SEL_4 (BIT(4)) /* Pin 4 selected */
|
||||
#define GPIO_SEL_5 (BIT(5)) /* Pin 5 selected */
|
||||
#define GPIO_SEL_6 (BIT(6)) /* Pin 6 selected */
|
||||
#define GPIO_SEL_7 (BIT(7)) /* Pin 7 selected */
|
||||
#define GPIO_SEL_8 (BIT(8)) /* Pin 8 selected */
|
||||
#define GPIO_SEL_9 (BIT(9)) /* Pin 9 selected */
|
||||
#define GPIO_SEL_10 (BIT(10)) /* Pin 10 selected */
|
||||
#define GPIO_SEL_11 (BIT(11)) /* Pin 11 selected */
|
||||
#define GPIO_SEL_12 (BIT(12)) /* Pin 12 selected */
|
||||
#define GPIO_SEL_13 (BIT(13)) /* Pin 13 selected */
|
||||
#define GPIO_SEL_14 (BIT(14)) /* Pin 14 selected */
|
||||
#define GPIO_SEL_15 (BIT(15)) /* Pin 15 selected */
|
||||
#define GPIO_SEL_16 (BIT(16)) /* Pin 16 selected */
|
||||
#define GPIO_SEL_17 (BIT(17)) /* Pin 17 selected */
|
||||
#define GPIO_SEL_18 (BIT(18)) /* Pin 18 selected */
|
||||
#define GPIO_SEL_19 (BIT(19)) /* Pin 19 selected */
|
||||
#define GPIO_SEL_0 (BIT(0)) /*!< Pin 0 selected */
|
||||
#define GPIO_SEL_1 (BIT(1)) /*!< Pin 1 selected */
|
||||
#define GPIO_SEL_2 (BIT(2)) /*!< Pin 2 selected */
|
||||
#define GPIO_SEL_3 (BIT(3)) /*!< Pin 3 selected */
|
||||
#define GPIO_SEL_4 (BIT(4)) /*!< Pin 4 selected */
|
||||
#define GPIO_SEL_5 (BIT(5)) /*!< Pin 5 selected */
|
||||
#define GPIO_SEL_6 (BIT(6)) /*!< Pin 6 selected */
|
||||
#define GPIO_SEL_7 (BIT(7)) /*!< Pin 7 selected */
|
||||
#define GPIO_SEL_8 (BIT(8)) /*!< Pin 8 selected */
|
||||
#define GPIO_SEL_9 (BIT(9)) /*!< Pin 9 selected */
|
||||
#define GPIO_SEL_10 (BIT(10)) /*!< Pin 10 selected */
|
||||
#define GPIO_SEL_11 (BIT(11)) /*!< Pin 11 selected */
|
||||
#define GPIO_SEL_12 (BIT(12)) /*!< Pin 12 selected */
|
||||
#define GPIO_SEL_13 (BIT(13)) /*!< Pin 13 selected */
|
||||
#define GPIO_SEL_14 (BIT(14)) /*!< Pin 14 selected */
|
||||
#define GPIO_SEL_15 (BIT(15)) /*!< Pin 15 selected */
|
||||
#define GPIO_SEL_16 (BIT(16)) /*!< Pin 16 selected */
|
||||
#define GPIO_SEL_17 (BIT(17)) /*!< Pin 17 selected */
|
||||
#define GPIO_SEL_18 (BIT(18)) /*!< Pin 18 selected */
|
||||
#define GPIO_SEL_19 (BIT(19)) /*!< Pin 19 selected */
|
||||
|
||||
#define GPIO_SEL_21 (BIT(21)) /* Pin 21 selected */
|
||||
#define GPIO_SEL_22 (BIT(22)) /* Pin 22 selected */
|
||||
#define GPIO_SEL_23 (BIT(23)) /* Pin 23 selected */
|
||||
#define GPIO_SEL_21 (BIT(21)) /*!< Pin 21 selected */
|
||||
#define GPIO_SEL_22 (BIT(22)) /*!< Pin 22 selected */
|
||||
#define GPIO_SEL_23 (BIT(23)) /*!< Pin 23 selected */
|
||||
|
||||
#define GPIO_SEL_25 (BIT(25)) /* Pin 25 selected */
|
||||
#define GPIO_SEL_26 (BIT(26)) /* Pin 26 selected */
|
||||
#define GPIO_SEL_27 (BIT(27)) /* Pin 27 selected */
|
||||
#define GPIO_SEL_25 (BIT(25)) /*!< Pin 25 selected */
|
||||
#define GPIO_SEL_26 (BIT(26)) /*!< Pin 26 selected */
|
||||
#define GPIO_SEL_27 (BIT(27)) /*!< Pin 27 selected */
|
||||
|
||||
#define GPIO_SEL_32 ((uint64_t)(((uint64_t)1)<<32)) /* Pin 32 selected */
|
||||
#define GPIO_SEL_33 ((uint64_t)(((uint64_t)1)<<33)) /* Pin 33 selected */
|
||||
#define GPIO_SEL_34 ((uint64_t)(((uint64_t)1)<<34)) /* Pin 34 selected */
|
||||
#define GPIO_SEL_35 ((uint64_t)(((uint64_t)1)<<35)) /* Pin 35 selected */
|
||||
#define GPIO_SEL_36 ((uint64_t)(((uint64_t)1)<<36)) /* Pin 36 selected */
|
||||
#define GPIO_SEL_37 ((uint64_t)(((uint64_t)1)<<37)) /* Pin 37 selected */
|
||||
#define GPIO_SEL_38 ((uint64_t)(((uint64_t)1)<<38)) /* Pin 38 selected */
|
||||
#define GPIO_SEL_39 ((uint64_t)(((uint64_t)1)<<39)) /* Pin 39 selected */
|
||||
#define GPIO_SEL_32 ((uint64_t)(((uint64_t)1)<<32)) /*!< Pin 32 selected */
|
||||
#define GPIO_SEL_33 ((uint64_t)(((uint64_t)1)<<33)) /*!< Pin 33 selected */
|
||||
#define GPIO_SEL_34 ((uint64_t)(((uint64_t)1)<<34)) /*!< Pin 34 selected */
|
||||
#define GPIO_SEL_35 ((uint64_t)(((uint64_t)1)<<35)) /*!< Pin 35 selected */
|
||||
#define GPIO_SEL_36 ((uint64_t)(((uint64_t)1)<<36)) /*!< Pin 36 selected */
|
||||
#define GPIO_SEL_37 ((uint64_t)(((uint64_t)1)<<37)) /*!< Pin 37 selected */
|
||||
#define GPIO_SEL_38 ((uint64_t)(((uint64_t)1)<<38)) /*!< Pin 38 selected */
|
||||
#define GPIO_SEL_39 ((uint64_t)(((uint64_t)1)<<39)) /*!< Pin 39 selected */
|
||||
|
||||
#define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U
|
||||
#define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U
|
||||
|
@ -116,223 +117,223 @@ extern const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT];
|
|||
#define GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0)) //to decide whether it is a valid GPIO number
|
||||
#define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) ((GPIO_IS_VALID_GPIO(gpio_num)) && (gpio_num < 34)) //to decide whether it can be a valid GPIO number of output mode
|
||||
|
||||
/**
|
||||
* @brief Pullup/pulldown information for a single GPIO pad
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t reg; /*!< Register to modify to enable or disable pullups or pulldowns */
|
||||
uint32_t pu; /*!< Bit to set or clear in the above register to enable or disable the pullup, respectively */
|
||||
uint32_t pd; /*!< Bit to set or clear in the above register to enable or disable the pulldown, respectively */
|
||||
} gpio_pu_pd_desc_t;
|
||||
|
||||
|
||||
/**
|
||||
* Per-GPIO pullup/pulldown information
|
||||
* On the ESP32, some GPIOs need their pullups and pulldowns enabled and disabled in the RTC
|
||||
* peripheral instead of in the GPIO peripheral. This array documents for every GPIO what bit
|
||||
* to set or clear.
|
||||
*
|
||||
* This array is non-static, so if you need a very quick way of toggling the pull-up/downs, you can just
|
||||
* do e.g. REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); inline.
|
||||
*
|
||||
* ToDo: Functions using the contents of this array will do a read/modify/write on GPIO as well as RTC
|
||||
* registers. We may need to look into muxes/locks for other code that accesses these RTC registers when we
|
||||
* write drivers for the RTC stuff.
|
||||
*/
|
||||
extern const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT];
|
||||
|
||||
|
||||
typedef enum {
|
||||
GPIO_NUM_0 = 0,
|
||||
GPIO_NUM_1 = 1,
|
||||
GPIO_NUM_2 = 2,
|
||||
GPIO_NUM_3 = 3,
|
||||
GPIO_NUM_4 = 4,
|
||||
GPIO_NUM_5 = 5,
|
||||
GPIO_NUM_6 = 6,
|
||||
GPIO_NUM_7 = 7,
|
||||
GPIO_NUM_8 = 8,
|
||||
GPIO_NUM_9 = 9,
|
||||
GPIO_NUM_10 = 10,
|
||||
GPIO_NUM_11 = 11,
|
||||
GPIO_NUM_12 = 12,
|
||||
GPIO_NUM_13 = 13,
|
||||
GPIO_NUM_14 = 14,
|
||||
GPIO_NUM_15 = 15,
|
||||
GPIO_NUM_16 = 16,
|
||||
GPIO_NUM_17 = 17,
|
||||
GPIO_NUM_18 = 18,
|
||||
GPIO_NUM_19 = 19,
|
||||
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
|
||||
GPIO_NUM_1 = 1, /*!< GPIO1, input and output */
|
||||
GPIO_NUM_2 = 2, /*!< GPIO2, input and output */
|
||||
GPIO_NUM_3 = 3, /*!< GPIO3, input and output */
|
||||
GPIO_NUM_4 = 4, /*!< GPIO4, input and output */
|
||||
GPIO_NUM_5 = 5, /*!< GPIO5, input and output */
|
||||
GPIO_NUM_6 = 6, /*!< GPIO6, input and output */
|
||||
GPIO_NUM_7 = 7, /*!< GPIO7, input and output */
|
||||
GPIO_NUM_8 = 8, /*!< GPIO8, input and output */
|
||||
GPIO_NUM_9 = 9, /*!< GPIO9, input and output */
|
||||
GPIO_NUM_10 = 10, /*!< GPIO10, input and output */
|
||||
GPIO_NUM_11 = 11, /*!< GPIO11, input and output */
|
||||
GPIO_NUM_12 = 12, /*!< GPIO12, input and output */
|
||||
GPIO_NUM_13 = 13, /*!< GPIO13, input and output */
|
||||
GPIO_NUM_14 = 14, /*!< GPIO14, input and output */
|
||||
GPIO_NUM_15 = 15, /*!< GPIO15, input and output */
|
||||
GPIO_NUM_16 = 16, /*!< GPIO16, input and output */
|
||||
GPIO_NUM_17 = 17, /*!< GPIO17, input and output */
|
||||
GPIO_NUM_18 = 18, /*!< GPIO18, input and output */
|
||||
GPIO_NUM_19 = 19, /*!< GPIO19, input and output */
|
||||
|
||||
GPIO_NUM_21 = 21,
|
||||
GPIO_NUM_22 = 22,
|
||||
GPIO_NUM_23 = 23,
|
||||
GPIO_NUM_21 = 21, /*!< GPIO21, input and output */
|
||||
GPIO_NUM_22 = 22, /*!< GPIO22, input and output */
|
||||
GPIO_NUM_23 = 23, /*!< GPIO23, input and output */
|
||||
|
||||
GPIO_NUM_25 = 25,
|
||||
GPIO_NUM_26 = 26,
|
||||
GPIO_NUM_27 = 27,
|
||||
GPIO_NUM_25 = 25, /*!< GPIO25, input and output */
|
||||
GPIO_NUM_26 = 26, /*!< GPIO26, input and output */
|
||||
GPIO_NUM_27 = 27, /*!< GPIO27, input and output */
|
||||
|
||||
GPIO_NUM_32 = 32,
|
||||
GPIO_NUM_33 = 33,
|
||||
GPIO_NUM_34 = 34, /*input mode only */
|
||||
GPIO_NUM_35 = 35, /*input mode only */
|
||||
GPIO_NUM_36 = 36, /*input mode only */
|
||||
GPIO_NUM_37 = 37, /*input mode only */
|
||||
GPIO_NUM_38 = 38, /*input mode only */
|
||||
GPIO_NUM_39 = 39, /*input mode only */
|
||||
GPIO_NUM_32 = 32, /*!< GPIO32, input and output */
|
||||
GPIO_NUM_33 = 33, /*!< GPIO32, input and output */
|
||||
GPIO_NUM_34 = 34, /*!< GPIO34, input mode only */
|
||||
GPIO_NUM_35 = 35, /*!< GPIO35, input mode only */
|
||||
GPIO_NUM_36 = 36, /*!< GPIO36, input mode only */
|
||||
GPIO_NUM_37 = 37, /*!< GPIO37, input mode only */
|
||||
GPIO_NUM_38 = 38, /*!< GPIO38, input mode only */
|
||||
GPIO_NUM_39 = 39, /*!< GPIO39, input mode only */
|
||||
} gpio_num_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_INTR_DISABLE = 0, /* disable GPIO interrupt */
|
||||
GPIO_INTR_POSEDGE = 1, /* GPIO interrupt type : rising edge */
|
||||
GPIO_INTR_NEGEDGE = 2, /* GPIO interrupt type : falling edge */
|
||||
GPIO_INTR_ANYEDGE = 3, /* GPIO interrupt type : both rising and falling edge */
|
||||
GPIO_INTR_LOW_LEVEL = 4, /* GPIO interrupt type : input low level trigger */
|
||||
GPIO_INTR_HIGH_LEVEL = 5, /* GPIO interrupt type : input high level trigger */
|
||||
GPIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */
|
||||
GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */
|
||||
GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */
|
||||
GPIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */
|
||||
GPIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */
|
||||
GPIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */
|
||||
GPIO_INTR_MAX,
|
||||
} gpio_int_type_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /* GPIO mode : input only */
|
||||
GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /* GPIO mode : output only mode */
|
||||
GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /* GPIO mode : output only with open-drain mode */
|
||||
GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /* GPIO mode : output and input with open-drain mode*/
|
||||
GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)), /* GPIO mode : output and input mode */
|
||||
GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /*!< GPIO mode : input only */
|
||||
GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /*!< GPIO mode : output only mode */
|
||||
GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /*!< GPIO mode : output only with open-drain mode */
|
||||
GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /*!< GPIO mode : output and input with open-drain mode*/
|
||||
GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)), /*!< GPIO mode : output and input mode */
|
||||
} gpio_mode_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_PULLUP_DISABLE = 0x0, /* disable GPIO pull-up resistor */
|
||||
GPIO_PULLUP_ENABLE = 0x1, /* enable GPIO pull-up resistor */
|
||||
GPIO_PULLUP_DISABLE = 0x0, /*!< Disable GPIO pull-up resistor */
|
||||
GPIO_PULLUP_ENABLE = 0x1, /*!< Enable GPIO pull-up resistor */
|
||||
} gpio_pullup_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_PULLDOWN_DISABLE = 0x0, /* disable GPIO pull-down resistor */
|
||||
GPIO_PULLDOWN_ENABLE = 0x1, /* enable GPIO pull-down resistor */
|
||||
GPIO_PULLDOWN_DISABLE = 0x0, /*!< Disable GPIO pull-down resistor */
|
||||
GPIO_PULLDOWN_ENABLE = 0x1, /*!< Enable GPIO pull-down resistor */
|
||||
} gpio_pulldown_t;
|
||||
|
||||
/**
|
||||
* @brief Configuration parameters of GPIO pad for gpio_config function
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t pin_bit_mask; /* GPIO pin: set with bit mask, each bit maps to a GPIO */
|
||||
gpio_mode_t mode; /* GPIO mode: set input/output mode */
|
||||
gpio_pullup_t pull_up_en; /* GPIO pull-up */
|
||||
gpio_pulldown_t pull_down_en; /* GPIO pull-down */
|
||||
gpio_int_type_t intr_type; /* GPIO interrupt type */
|
||||
uint64_t pin_bit_mask; /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
|
||||
gpio_mode_t mode; /*!< GPIO mode: set input/output mode */
|
||||
gpio_pullup_t pull_up_en; /*!< GPIO pull-up */
|
||||
gpio_pulldown_t pull_down_en; /*!< GPIO pull-down */
|
||||
gpio_int_type_t intr_type; /*!< GPIO interrupt type */
|
||||
} gpio_config_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_LOW_LEVEL = 0,
|
||||
GPIO_HIGH_LEVEL = 1,
|
||||
GPIO_LEVEL_ERR,
|
||||
} gpio_level_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_PULLUP_ONLY, /* Pad pull up */
|
||||
GPIO_PULLDOWN_ONLY, /* Pad pull down */
|
||||
GPIO_PULLUP_PULLDOWN, /* Pad pull up + pull down*/
|
||||
GPIO_FLOATING, /* Pad floating */
|
||||
GPIO_PULLUP_ONLY, /*!< Pad pull up */
|
||||
GPIO_PULLDOWN_ONLY, /*!< Pad pull down */
|
||||
GPIO_PULLUP_PULLDOWN, /*!< Pad pull up + pull down*/
|
||||
GPIO_FLOATING, /*!< Pad floating */
|
||||
} gpio_pull_mode_t;
|
||||
|
||||
typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num);
|
||||
|
||||
/** \defgroup Driver_APIs Driver APIs
|
||||
* @brief Driver APIs
|
||||
*/
|
||||
|
||||
/** @addtogroup Driver_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \defgroup GPIO_Driver_APIs GPIO Driver APIs
|
||||
* @brief GPIO APIs
|
||||
*/
|
||||
|
||||
/** @addtogroup GPIO_Driver_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief GPIO common configuration
|
||||
* @brief GPIO common configuration
|
||||
*
|
||||
* Use this Function ,Configure GPIO's Mode,pull-up,PullDown,IntrType
|
||||
* Configure GPIO's Mode,pull-up,PullDown,IntrType
|
||||
*
|
||||
* @parameter[in] pGPIOConfig
|
||||
* pGPIOConfig.pin_bit_mask : Configure GPIO pins bits,set this parameter with bit mask.
|
||||
* If you want to configure GPIO34 and GPIO16, pin_bit_mask=GPIO_Pin_16|GPIO_Pin_34;
|
||||
* pGPIOConfig.mode : Configure GPIO mode,such as output ,input...
|
||||
* pGPIOConfig.pull_up_en : Enable or Disable pull-up
|
||||
* pGPIOConfig.pull_down_en : Enable or Disable pull-down
|
||||
* pGPIOConfig.intr_type : Configure GPIO interrupt trigger type
|
||||
* @return ESP_OK: success ;
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* ESP_FAIL : GPIO error
|
||||
* @param pGPIOConfig Pointer to GPIO configure struct
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*
|
||||
*/
|
||||
esp_err_t gpio_config(gpio_config_t *pGPIOConfig);
|
||||
|
||||
|
||||
/**
|
||||
* @brief GPIO set interrupt trigger type
|
||||
* @brief GPIO set interrupt trigger type
|
||||
*
|
||||
* @parameter[in] gpio_num : GPIO number.
|
||||
* If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @parameter[in] intr_type: interrupt type, select from gpio_int_type_t
|
||||
* @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @param intr_type Interrupt type, select from gpio_int_type_t
|
||||
*
|
||||
* @return ESP_OK : success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*
|
||||
*/
|
||||
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type);
|
||||
|
||||
/**
|
||||
* @brief enable GPIO module interrupt signal
|
||||
* @brief Enable GPIO module interrupt signal
|
||||
*
|
||||
* @parameter[in] gpio_num : GPIO number.
|
||||
* If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @param gpio_num GPIO number. If you want to enable an interrupt on e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
*
|
||||
* @return ESP_OK : success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*
|
||||
*/
|
||||
esp_err_t gpio_intr_enable(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief disable GPIO module interrupt signal
|
||||
* @brief Disable GPIO module interrupt signal
|
||||
*
|
||||
* @parameter[in] gpio_num : GPIO number.
|
||||
* If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
*
|
||||
* @return ESP_OK : success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*
|
||||
*/
|
||||
esp_err_t gpio_intr_disable(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief GPIO set output level
|
||||
* @brief GPIO set output level
|
||||
*
|
||||
* @parameter[in] gpio_num : GPIO number.
|
||||
* If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @parameter[in] level : Output level. 0: low ; 1: high
|
||||
* @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @param level Output level. 0: low ; 1: high
|
||||
*
|
||||
* @return ESP_OK : success
|
||||
* ESP_FAIL : GPIO error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - GPIO_IS_VALID_GPIO GPIO number error
|
||||
*
|
||||
*/
|
||||
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);
|
||||
|
||||
/**
|
||||
* @brief GPIO get input level
|
||||
* @brief GPIO get input level
|
||||
*
|
||||
* @parameter[in] gpio_num : GPIO number.
|
||||
* If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
*
|
||||
* @return 0 : the GPIO input level is 0
|
||||
* 1 : the GPIO input level is 1
|
||||
* @return
|
||||
* - 0 the GPIO input level is 0
|
||||
* - 1 the GPIO input level is 1
|
||||
*
|
||||
*/
|
||||
int gpio_get_level(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief GPIO set direction
|
||||
* @brief GPIO set direction
|
||||
*
|
||||
* Configure GPIO direction,such as output_only,input_only,output_and_input
|
||||
*
|
||||
* @parameter[in] gpio_num : Configure GPIO pins number,it should be GPIO number.
|
||||
* If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @parameter[in] mode : Configure GPIO direction,such as output_only,input_only,...
|
||||
* @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @param mode GPIO direction
|
||||
*
|
||||
* @return ESP_OK : success
|
||||
* ESP_ERR_INVALID_ARG : fail
|
||||
* ESP_FAIL : GPIO error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG GPIO error
|
||||
*
|
||||
*/
|
||||
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief GPIO set pull
|
||||
* @brief GPIO set pull
|
||||
*
|
||||
* User this Function,configure GPIO pull mode,such as pull-up,pull-down
|
||||
*
|
||||
* @parameter[in] gpio_num : Configure GPIO pins number,it should be GPIO number.
|
||||
* If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16);
|
||||
* @parameter[in] pull : Configure GPIO pull up/down mode,such as pullup_only,pulldown_only,pullup_and_pulldown,...
|
||||
* @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @param pull GPIO pull up/down mode.
|
||||
*
|
||||
* @return ESP_OK : success
|
||||
* ESP_ERR_INVALID_ARG : fail
|
||||
* ESP_FAIL : GPIO error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG : Parameter error
|
||||
*
|
||||
*/
|
||||
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
|
||||
|
@ -340,121 +341,187 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
|
|||
/**
|
||||
* @brief enable GPIO wake-up function.
|
||||
*
|
||||
* @param gpio_num_t gpio_num : GPIO number.
|
||||
* @param gpio_num GPIO number.
|
||||
*
|
||||
* @param gpio_int_type_t intr_type : only GPIO_INTR_LOLEVEL\GPIO_INTR_HILEVEL can be used
|
||||
* @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used.
|
||||
*
|
||||
* @return ESP_OK: success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
|
||||
|
||||
/**
|
||||
* @brief disable GPIO wake-up function.
|
||||
* @brief Disable GPIO wake-up function.
|
||||
*
|
||||
* @param gpio_num_t gpio_num: GPIO number
|
||||
* @param gpio_num GPIO number
|
||||
*
|
||||
* @return ESP_OK: success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief register GPIO interrupt handler, the handler is an ISR.
|
||||
* The handler will be attached to the same CPU core that this function is running on.
|
||||
* @note
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
* TODO: to move INUM options to menu_config
|
||||
* @parameter uint32_t gpio_intr_num : GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details
|
||||
* @parameter void (* fn)(void* ) : interrupt handler function.
|
||||
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
* @parameter void * arg : parameter for handler function
|
||||
*
|
||||
* @return ESP_OK : success ;
|
||||
* ESP_FAIL: gpio error
|
||||
* @param gpio_intr_num GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details
|
||||
* @param fn Interrupt handler function.
|
||||
*
|
||||
* @note
|
||||
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
*
|
||||
* @param arg Parameter for handler function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success ;
|
||||
* - ESP_ERR_INVALID_ARG GPIO error
|
||||
*/
|
||||
esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable pull-up on GPIO.
|
||||
*
|
||||
* @param gpio_num GPIO number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t gpio_pullup_en(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief Disable pull-up on GPIO.
|
||||
*
|
||||
* @param gpio_num GPIO number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t gpio_pullup_dis(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief Enable pull-down on GPIO.
|
||||
*
|
||||
* @param gpio_num GPIO number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t gpio_pulldown_en(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief Disable pull-down on GPIO.
|
||||
*
|
||||
* @param gpio_num GPIO number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
|
||||
|
||||
|
||||
/**
|
||||
* *************** ATTENTION ********************/
|
||||
/**
|
||||
*
|
||||
* Each GPIO has its own separate configuration register, so we do not use
|
||||
* a lock to serialize access to them. This works under the assumption that
|
||||
* no situation will occur where two tasks try to configure the same GPIO
|
||||
* pin simultaneously. It is up to the application developer to guarantee this.
|
||||
*@attention
|
||||
* Each GPIO has its own separate configuration register, so we do not use
|
||||
* a lock to serialize access to them. This works under the assumption that
|
||||
* no situation will occur where two tasks try to configure the same GPIO
|
||||
* pin simultaneously. It is up to the application developer to guarantee this.
|
||||
*/
|
||||
|
||||
|
||||
/*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ */
|
||||
/* gpio_config_t io_conf;
|
||||
/**
|
||||
*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ *
|
||||
* @code{c}
|
||||
* gpio_config_t io_conf;
|
||||
* io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
|
||||
* io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode
|
||||
* io_conf.pin_bit_mask = GPIO_SEL_18 | GPIO_SEL_19; //bit mask of the pins that you want to set,e.g.GPIO18/19
|
||||
* io_conf.pull_down_en = 0; //disable pull-down mode
|
||||
* io_conf.pull_up_en = 0; //disable pull-up mode
|
||||
* gpio_config(&io_conf); //configure GPIO with the given settings
|
||||
* @endcode
|
||||
**/
|
||||
/*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ */
|
||||
/* io_conf.intr_type = GPIO_INTR_POSEDGE; //set posedge interrupt
|
||||
|
||||
/**
|
||||
*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ *
|
||||
* @code{c}
|
||||
* io_conf.intr_type = GPIO_INTR_POSEDGE; //set posedge interrupt
|
||||
* io_conf.mode = GPIO_MODE_INPUT; //set as input
|
||||
* io_conf.pin_bit_mask = GPIO_SEL_4 | GPIO_SEL_5; //bit mask of the pins that you want to set, e.g.,GPIO4/5
|
||||
* io_conf.pull_down_en = 0; //disable pull-down mode
|
||||
* io_conf.pull_up_en = 1; //enable pull-up mode
|
||||
* gpio_config(&io_conf); //configure GPIO with the given settings
|
||||
*----------EXAMPLE TO SET ISR HANDLER ----------------------*/
|
||||
/* gpio_isr_register(18,gpio_intr_test,NULL); //hook the isr handler for GPIO interrupt
|
||||
* //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
|
||||
* //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt.
|
||||
* //NOTE2:do not pick the INUM that already occupied by the system.
|
||||
* //NOTE3:refer to soc.h to check which INUMs that can be used.
|
||||
*-------------EXAMPLE OF HANDLER FUNCTION-------------------*/
|
||||
/*#include "esp_attr.h"
|
||||
* @endcode
|
||||
*/
|
||||
/**
|
||||
*----------EXAMPLE TO SET ISR HANDLER ----------------------
|
||||
* @code{c}
|
||||
* //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
|
||||
* gpio_isr_register(18,gpio_intr_test,NULL); //hook the isr handler for GPIO interrupt
|
||||
* @endcode
|
||||
* @note
|
||||
* 1. user should arrange the INUMs that used, better not to use a same INUM for different interrupt.
|
||||
* 2. do not pick the INUM that already occupied by the system.
|
||||
* 3. refer to soc.h to check which INUMs that can be used.
|
||||
*/
|
||||
/**
|
||||
*-------------EXAMPLE OF HANDLER FUNCTION-------------------*
|
||||
* @code{c}
|
||||
* #include "esp_attr.h"
|
||||
* void IRAM_ATTR gpio_intr_test(void* arg)
|
||||
*{
|
||||
* //GPIO intr process
|
||||
* ets_printf("in gpio_intr\n");
|
||||
* uint32_t gpio_num = 0;
|
||||
* uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); //read status to get interrupt status for GPIO0-31
|
||||
* uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39
|
||||
* SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status); //Clear intr for gpio0-gpio31
|
||||
* SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39
|
||||
* do {
|
||||
* if(gpio_num < 32) {
|
||||
* if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
|
||||
* ets_printf("Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num));
|
||||
* //This is an isr handler, you should post an event to process it in RTOS queue.
|
||||
* }
|
||||
* } else {
|
||||
* if(gpio_intr_status_h & BIT(gpio_num - 32)) {
|
||||
* ets_printf("Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num));
|
||||
* //This is an isr handler, you should post an event to process it in RTOS queue.
|
||||
* }
|
||||
* }
|
||||
* } while(++gpio_num < GPIO_PIN_COUNT);
|
||||
*}
|
||||
*----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---*/
|
||||
/* gpio_config_t io_conf;
|
||||
* io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
|
||||
* io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD; //set as output mode
|
||||
* io_conf.pin_bit_mask = GPIO_SEL_21 | GPIO_SEL_22; //bit mask of the pins that you want to set,e.g.GPIO21/22
|
||||
* io_conf.pull_down_en = 0; //disable pull-down mode
|
||||
* io_conf.pull_up_en = 1; //enable pull-up mode
|
||||
* gpio_config(&io_conf); //configure GPIO with the given settings
|
||||
* gpio_matrix_out(21, EXT_I2C_SCL_O_IDX, 0, 0); //set output signal for io_matrix
|
||||
* gpio_matrix_out(22, EXT_I2C_SDA_O_IDX, 0, 0); //set output signal for io_matrix
|
||||
* gpio_matrix_in( 22, EXT_I2C_SDA_I_IDX, 0); //set input signal for io_matrix
|
||||
* {
|
||||
* //GPIO intr process
|
||||
* ets_printf("in gpio_intr\n");
|
||||
* uint32_t gpio_num = 0;
|
||||
* uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); //read status to get interrupt status for GPIO0-31
|
||||
* uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39
|
||||
* SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status); //Clear intr for gpio0-gpio31
|
||||
* SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39
|
||||
* do {
|
||||
* if(gpio_num < 32) {
|
||||
* if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
|
||||
* ets_printf("Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num));
|
||||
* //This is an isr handler, you should post an event to process it in RTOS queue.
|
||||
* }
|
||||
* } else {
|
||||
* if(gpio_intr_status_h & BIT(gpio_num - 32)) {
|
||||
* ets_printf("Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num));
|
||||
* //This is an isr handler, you should post an event to process it in RTOS queue.
|
||||
* }
|
||||
* }
|
||||
* } while(++gpio_num < GPIO_PIN_COUNT);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
*----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---*
|
||||
* @code{c}
|
||||
* gpio_config_t io_conf;
|
||||
* io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
|
||||
* io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD; //set as output mode
|
||||
* io_conf.pin_bit_mask = GPIO_SEL_21 | GPIO_SEL_22; //bit mask of the pins that you want to set,e.g.GPIO21/22
|
||||
* io_conf.pull_down_en = 0; //disable pull-down mode
|
||||
* io_conf.pull_up_en = 1; //enable pull-up mode
|
||||
* gpio_config(&io_conf); //configure GPIO with the given settings
|
||||
* gpio_matrix_out(21, EXT_I2C_SCL_O_IDX, 0, 0); //set output signal for io_matrix
|
||||
* gpio_matrix_out(22, EXT_I2C_SDA_O_IDX, 0, 0); //set output signal for io_matrix
|
||||
* gpio_matrix_in( 22, EXT_I2C_SDA_I_IDX, 0); //set input signal for io_matrix
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -30,68 +30,74 @@ extern "C" {
|
|||
#define LEDC_REF_CLK_HZ (1*1000000)
|
||||
|
||||
typedef enum {
|
||||
LEDC_HIGH_SPEED_MODE = 0, /*LEDC high speed speed_mode */
|
||||
LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */
|
||||
//in this version, we only support high speed speed_mode. We will access low speed speed_mode later
|
||||
//LEDC_LOW_SPEED_MODE, /*LEDC low speed speed_mode */
|
||||
LEDC_SPEED_MODE_MAX,
|
||||
//LEDC_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */
|
||||
LEDC_SPEED_MODE_MAX, /*!< LEDC speed limit */
|
||||
} ledc_mode_t;
|
||||
|
||||
typedef enum {
|
||||
LEDC_INTR_DISABLE = 0, /*Disable LEDC interrupt */
|
||||
LEDC_INTR_FADE_END, /*Enable LEDC interrupt */
|
||||
LEDC_INTR_DISABLE = 0, /*!< Disable LEDC interrupt */
|
||||
LEDC_INTR_FADE_END, /*!< Enable LEDC interrupt */
|
||||
} ledc_intr_type_t;
|
||||
|
||||
typedef enum {
|
||||
LEDC_DUTY_DIR_DECREASE = 0, /*LEDC duty decrease direction */
|
||||
LEDC_DUTY_DIR_INCREASE = 1, /*LEDC duty increase direction */
|
||||
LEDC_DUTY_DIR_DECREASE = 0, /*!< LEDC duty decrease direction */
|
||||
LEDC_DUTY_DIR_INCREASE = 1, /*!< LEDC duty increase direction */
|
||||
} ledc_duty_direction_t;
|
||||
|
||||
typedef enum {
|
||||
LEDC_REF_TICK = 0, /*LEDC timer clock divided from reference tick(1Mhz) */
|
||||
LEDC_APB_CLK, /*LEDC timer clock divided from APB clock(80Mhz)*/
|
||||
LEDC_REF_TICK = 0, /*!< LEDC timer clock divided from reference tick(1Mhz) */
|
||||
LEDC_APB_CLK, /*!< LEDC timer clock divided from APB clock(80Mhz)*/
|
||||
} ledc_clk_src_t;
|
||||
|
||||
typedef enum {
|
||||
LEDC_TIMER_0 = 0, /*LEDC source timer TIMER0 */
|
||||
LEDC_TIMER_1, /*LEDC source timer TIMER1 */
|
||||
LEDC_TIMER_2, /*LEDC source timer TIMER2 */
|
||||
LEDC_TIMER_3, /*LEDC source timer TIMER3 */
|
||||
LEDC_TIMER_0 = 0, /*!< LEDC source timer TIMER0 */
|
||||
LEDC_TIMER_1, /*!< LEDC source timer TIMER1 */
|
||||
LEDC_TIMER_2, /*!< LEDC source timer TIMER2 */
|
||||
LEDC_TIMER_3, /*!< LEDC source timer TIMER3 */
|
||||
} ledc_timer_t;
|
||||
|
||||
typedef enum {
|
||||
LEDC_CHANNEL_0 = 0, /*LEDC channel 0 */
|
||||
LEDC_CHANNEL_1, /*LEDC channel 1 */
|
||||
LEDC_CHANNEL_2, /*LEDC channel 2 */
|
||||
LEDC_CHANNEL_3, /*LEDC channel 3 */
|
||||
LEDC_CHANNEL_4, /*LEDC channel 4 */
|
||||
LEDC_CHANNEL_5, /*LEDC channel 5 */
|
||||
LEDC_CHANNEL_6, /*LEDC channel 6 */
|
||||
LEDC_CHANNEL_7, /*LEDC channel 7 */
|
||||
LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */
|
||||
LEDC_CHANNEL_1, /*!< LEDC channel 1 */
|
||||
LEDC_CHANNEL_2, /*!< LEDC channel 2 */
|
||||
LEDC_CHANNEL_3, /*!< LEDC channel 3 */
|
||||
LEDC_CHANNEL_4, /*!< LEDC channel 4 */
|
||||
LEDC_CHANNEL_5, /*!< LEDC channel 5 */
|
||||
LEDC_CHANNEL_6, /*!< LEDC channel 6 */
|
||||
LEDC_CHANNEL_7, /*!< LEDC channel 7 */
|
||||
} ledc_channel_t;
|
||||
|
||||
typedef enum {
|
||||
LEDC_TIMER_10_BIT = 10, /*LEDC PWM depth 10Bit */
|
||||
LEDC_TIMER_11_BIT = 11, /*LEDC PWM depth 11Bit */
|
||||
LEDC_TIMER_12_BIT = 12, /*LEDC PWM depth 12Bit */
|
||||
LEDC_TIMER_13_BIT = 13, /*LEDC PWM depth 13Bit */
|
||||
LEDC_TIMER_14_BIT = 14, /*LEDC PWM depth 14Bit */
|
||||
LEDC_TIMER_15_BIT = 15, /*LEDC PWM depth 15Bit */
|
||||
LEDC_TIMER_10_BIT = 10, /*!< LEDC PWM depth 10Bit */
|
||||
LEDC_TIMER_11_BIT = 11, /*!< LEDC PWM depth 11Bit */
|
||||
LEDC_TIMER_12_BIT = 12, /*!< LEDC PWM depth 12Bit */
|
||||
LEDC_TIMER_13_BIT = 13, /*!< LEDC PWM depth 13Bit */
|
||||
LEDC_TIMER_14_BIT = 14, /*!< LEDC PWM depth 14Bit */
|
||||
LEDC_TIMER_15_BIT = 15, /*!< LEDC PWM depth 15Bit */
|
||||
} ledc_timer_bit_t;
|
||||
|
||||
/**
|
||||
* @brief Configuration parameters of LEDC channel for ledc_channel_config function
|
||||
*/
|
||||
typedef struct {
|
||||
int gpio_num; /*the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/
|
||||
ledc_mode_t speed_mode; /*LEDC speed speed_mode, high-speed mode or low-speed mode*/
|
||||
ledc_channel_t channel; /*LEDC channel(0 - 7)*/
|
||||
ledc_intr_type_t intr_type; /*configure interrupt, Fade interrupt enable or Fade interrupt disable*/
|
||||
ledc_timer_t timer_sel; /*Select the timer source of channel (0 - 3)*/
|
||||
uint32_t duty; /*LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */
|
||||
int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/
|
||||
ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/
|
||||
ledc_channel_t channel; /*!< LEDC channel(0 - 7)*/
|
||||
ledc_intr_type_t intr_type; /*!< configure interrupt, Fade interrupt enable or Fade interrupt disable*/
|
||||
ledc_timer_t timer_sel; /*!< Select the timer source of channel (0 - 3)*/
|
||||
uint32_t duty; /*!< LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */
|
||||
} ledc_channel_config_t;
|
||||
|
||||
/**
|
||||
* @brief Configuration parameters of LEDC Timer timer for ledc_timer_config function
|
||||
*/
|
||||
typedef struct {
|
||||
ledc_mode_t speed_mode; /*LEDC speed speed_mode, high-speed mode or low-speed mode*/
|
||||
ledc_timer_bit_t bit_num; /*LEDC channel duty depth*/
|
||||
ledc_timer_t timer_num; /*The timer source of channel (0 - 3)*/
|
||||
uint32_t freq_hz; /*LEDC timer frequency(Hz)*/
|
||||
ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/
|
||||
ledc_timer_bit_t bit_num; /*!< LEDC channel duty depth*/
|
||||
ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3)*/
|
||||
uint32_t freq_hz; /*!< LEDC timer frequency(Hz)*/
|
||||
} ledc_timer_config_t;
|
||||
|
||||
|
||||
|
@ -100,15 +106,10 @@ typedef struct {
|
|||
*
|
||||
* User this Function, configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC depth
|
||||
*
|
||||
* @param[in] ledc_channel_config_t
|
||||
* ledc_channel_config_t.speed_mode : LEDC speed speed_mode
|
||||
* ledc_channel_config_t.gpio_num : LEDC output gpio_num, if you want to use gpio16, ledc_channel_config_t.gpio_num = 16
|
||||
* ledc_channel_config_t.channel : LEDC channel(0 - 7)
|
||||
* ledc_channel_config_t.intr_type : configure interrupt, Fade interrupt enable or Fade interrupt disable
|
||||
* ledc_channel_config_t.timer_sel : Select the timer source of channel (0 - 3), high speed channel must bind with high speed timer.
|
||||
* ledc_channel_config_t.duty : LEDC channel duty, the duty range is [0, (2**timer_bit_num) - 1],
|
||||
* @return ESP_OK: success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @param ledc_conf Pointer of LEDC channel configure struct
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf);
|
||||
|
@ -118,14 +119,13 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf);
|
|||
*
|
||||
* User this Function, configure LEDC timer with the given source timer/frequency(Hz)/bit_num
|
||||
*
|
||||
* @param[in] ledc_timer_config_t
|
||||
* ledc_timer_config_t.speed_mode : LEDC speed speed_mode
|
||||
* ledc_timer_config_t.timer_num : Select the timer source of channel (0 - 3)
|
||||
* ledc_timer_config_t.freq_hz : LEDC channel frequency(Hz),
|
||||
* ledc_timer_config_t.bit_num : LEDC channel duty depth
|
||||
* @return ESP_OK: success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num.
|
||||
* @param timer_conf Pointer of LEDC timer configure struct
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current bit_num.
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf);
|
||||
|
@ -136,12 +136,13 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf);
|
|||
* Call this function to activate the LEDC updated parameters.
|
||||
* After ledc_set_duty, ledc_set_fade, we need to call this function to update the settings.
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] channel : LEDC channel(0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel(0-7), select from ledc_channel_t
|
||||
*
|
||||
* @return ESP_OK: success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||
|
@ -151,12 +152,15 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
|||
*
|
||||
* Disable LEDC output, and set idle level
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] channel : LEDC channel(0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel(0-7), select from ledc_channel_t
|
||||
*
|
||||
* @return ESP_OK: success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @param idle_level Set output idle level after LEDC stops.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level);
|
||||
|
||||
|
@ -165,27 +169,29 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl
|
|||
*
|
||||
* Set LEDC frequency(Hz)
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] timer_num : LEDC timer index(0-3), select from ledc_timer_t
|
||||
* @param timer_num LEDC timer index(0-3), select from ledc_timer_t
|
||||
*
|
||||
* @param[in] freq_hz : set the LEDC frequency
|
||||
* @param freq_hz Set the LEDC frequency
|
||||
*
|
||||
* @return ESP_OK: success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current bit_num.
|
||||
*/
|
||||
esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz);
|
||||
|
||||
/**
|
||||
* @brief LEDC get channel frequency(Hz)
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] timer_num : LEDC timer index(0-3), select from ledc_timer_t
|
||||
* @param timer_num LEDC timer index(0-3), select from ledc_timer_t
|
||||
*
|
||||
* @return 0 : error
|
||||
* others : current LEDC frequency
|
||||
* @return
|
||||
* - 0 error
|
||||
* - Others Current LEDC frequency
|
||||
*
|
||||
*/
|
||||
uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
|
||||
|
@ -195,27 +201,29 @@ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
|
|||
*
|
||||
* Set LEDC duty, After the function calls the ledc_update_duty function, the function can take effect.
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] channel : LEDC channel(0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel(0-7), select from ledc_channel_t
|
||||
*
|
||||
* @param[in] duty : set the LEDC duty, the duty range is [0, (2**bit_num) - 1]
|
||||
* @param duty Set the LEDC duty, the duty range is [0, (2**bit_num) - 1]
|
||||
*
|
||||
* @return ESP_OK: success
|
||||
* ESP_ERR_INVALID_ARG: parameter error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty);
|
||||
|
||||
/**
|
||||
* @brief LEDC get duty
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] channel : LEDC channel(0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel(0-7), select from ledc_channel_t
|
||||
*
|
||||
*
|
||||
* @return -1: parameter error
|
||||
* other value: current LEDC duty
|
||||
* @return
|
||||
* - (-1) parameter error
|
||||
* - Others Current LEDC duty
|
||||
*
|
||||
*/
|
||||
int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||
|
@ -225,22 +233,23 @@ int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
|||
*
|
||||
* Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect.
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] channel : LEDC channel(0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel(0-7), select from ledc_channel_t
|
||||
*
|
||||
* @param[in] duty : set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1]
|
||||
* @param duty Set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1]
|
||||
*
|
||||
* @param[in] gradule_direction : set the direction of the gradient
|
||||
* @param gradule_direction Set the direction of the gradient
|
||||
*
|
||||
* @param[in] step_num : set the number of the gradient
|
||||
* @param step_num Set the number of the gradient
|
||||
*
|
||||
* @param[in] duty_cyle_num : set how many LEDC tick each time the gradient lasts
|
||||
* @param duty_cyle_num Set how many LEDC tick each time the gradient lasts
|
||||
*
|
||||
* @param[in] duty_scale : set gradient change amplitude
|
||||
* @param duty_scale Set gradient change amplitude
|
||||
*
|
||||
* @return ESP_OK : success
|
||||
* ESP_ERR_INVALID_ARG : parameter error
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t gradule_direction,
|
||||
uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale);
|
||||
|
@ -248,34 +257,37 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty,
|
|||
/**
|
||||
* @brief register LEDC interrupt handler, the handler is an ISR.
|
||||
* The handler will be attached to the same CPU core that this function is running on.
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
* TODO: to move INUM options to menu_config
|
||||
* @param[in] uint32_t ledc_intr_num : LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details
|
||||
* @param[in] void (* fn)(void* ) : interrupt handler function.
|
||||
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
* @param[in] void * arg : parameter for handler function
|
||||
* @note
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
* @param ledc_intr_num LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details
|
||||
* @param fn Interrupt handler function.
|
||||
* @note
|
||||
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
* @param arg Parameter for handler function
|
||||
*
|
||||
* @return ESP_OK : success ;
|
||||
* ESP_ERR_INVALID_ARG : function ptr error.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Function pointer error.
|
||||
*/
|
||||
esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg);
|
||||
|
||||
/**
|
||||
* @brief configure LEDC settings
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] timer_sel : timer index(0-3), there are 4 timers in LEDC module
|
||||
* @param timer_sel Timer index(0-3), there are 4 timers in LEDC module
|
||||
*
|
||||
* @param[in] div_num : timer clock divide number, the timer clock is divided from the selected clock source
|
||||
* @param div_num Timer clock divide number, the timer clock is divided from the selected clock source
|
||||
*
|
||||
* @param[in] bit_num : the count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1)
|
||||
* @param bit_num The count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1)
|
||||
*
|
||||
* @param[in] clk_src : select LEDC source clock.
|
||||
* @param clk_src Select LEDC source clock.
|
||||
*
|
||||
* @return -1: parameter error
|
||||
* other value: current LEDC duty
|
||||
* @return
|
||||
* - (-1) Parameter error
|
||||
* - Other Current LEDC duty
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src);
|
||||
|
@ -283,13 +295,14 @@ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_
|
|||
/**
|
||||
* @brief reset LEDC timer
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t
|
||||
* @param timer_sel LEDC timer index(0-3), select from ledc_timer_t
|
||||
*
|
||||
*
|
||||
* @return ESP_ERR_INVALID_ARG: parameter error
|
||||
* ESP_OK: success
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
|
||||
|
@ -297,13 +310,14 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
|
|||
/**
|
||||
* @brief pause LEDC timer counter
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t
|
||||
* @param timer_sel LEDC timer index(0-3), select from ledc_timer_t
|
||||
*
|
||||
*
|
||||
* @return ESP_ERR_INVALID_ARG: parameter error
|
||||
* ESP_OK: success
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
|
||||
|
@ -311,13 +325,14 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
|
|||
/**
|
||||
* @brief pause LEDC timer resume
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t
|
||||
* @param timer_sel LEDC timer index(0-3), select from ledc_timer_t
|
||||
*
|
||||
*
|
||||
* @return ESP_ERR_INVALID_ARG: parameter error
|
||||
* ESP_OK: success
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
|
||||
|
@ -325,15 +340,16 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
|
|||
/**
|
||||
* @brief bind LEDC channel with the selected timer
|
||||
*
|
||||
* @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
|
||||
*
|
||||
* @param[in] channel : LEDC channel index(0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel index(0-7), select from ledc_channel_t
|
||||
*
|
||||
* @param[in] timer_idx : LEDC timer index(0-3), select from ledc_timer_t
|
||||
* @param timer_idx LEDC timer index(0-3), select from ledc_timer_t
|
||||
*
|
||||
*
|
||||
* @return ESP_ERR_INVALID_ARG: parameter error
|
||||
* ESP_OK: success
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx);
|
||||
|
@ -342,44 +358,56 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint
|
|||
*
|
||||
*
|
||||
* ----------------EXAMPLE OF LEDC SETTING ---------------------
|
||||
* //1. enable LEDC
|
||||
* periph_module_enable(PERIPH_LEDC_MODULE); //enable LEDC module, or you can not set any register of it.
|
||||
* @code{c}
|
||||
* //1. enable LEDC
|
||||
* //enable LEDC module, or you can not set any register of it.
|
||||
* periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
* @endcode
|
||||
*
|
||||
* //2. set LEDC timer
|
||||
* ledc_timer_config_t timer_conf = {
|
||||
* .bit_num = LEDC_TIMER_12_BIT, //set timer counter bit number
|
||||
* .freq_hz = 1000, //set frequency of pwm, here, 1000Hz
|
||||
* .speed_mode = LEDC_HIGH_SPEED_MODE //timer mode,
|
||||
* .timer_num = LEDC_TIMER_0, //timer number
|
||||
* };
|
||||
* ledc_timer_config(&timer_conf); //setup timer.
|
||||
* @code{c}
|
||||
* //2. set LEDC timer
|
||||
* ledc_timer_config_t timer_conf = {
|
||||
* .bit_num = LEDC_TIMER_12_BIT, //set timer counter bit number
|
||||
* .freq_hz = 1000, //set frequency of pwm, here, 1000Hz
|
||||
* .speed_mode = LEDC_HIGH_SPEED_MODE, //timer mode,
|
||||
* .timer_num = LEDC_TIMER_0, //timer number
|
||||
* };
|
||||
* ledc_timer_config(&timer_conf); //setup timer.
|
||||
* @endcode
|
||||
*
|
||||
* //3. set LEDC channel
|
||||
* ledc_channel_config_t ledc_conf = {
|
||||
* .channel = LEDC_CHANNEL_0; //set LEDC channel 0
|
||||
* .duty = 1000; //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
|
||||
* .gpio_num = 16; //GPIO number
|
||||
* .intr_type = LEDC_INTR_FADE_END; //GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
|
||||
* .speed_mode = LEDC_HIGH_SPEED_MODE; //set LEDC mode, from ledc_mode_t
|
||||
* .timer_sel = LEDC_TIMER_0; //set LEDC timer source, if different channel use one timer, the frequency and bit_num of these channels should be the same
|
||||
* }
|
||||
* ledc_channel_config(&ledc_conf); //setup the configuration
|
||||
* @code{c}
|
||||
* //3. set LEDC channel
|
||||
* ledc_channel_config_t ledc_conf = {
|
||||
* .channel = LEDC_CHANNEL_0; //set LEDC channel 0
|
||||
* .duty = 1000; //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
|
||||
* .gpio_num = 16; //GPIO number
|
||||
* .intr_type = LEDC_INTR_FADE_END; //GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
|
||||
* .speed_mode = LEDC_HIGH_SPEED_MODE; //set LEDC mode, from ledc_mode_t
|
||||
* .timer_sel = LEDC_TIMER_0; //set LEDC timer source, if different channel use one timer, the frequency and bit_num of these channels should be the same
|
||||
* }
|
||||
* ledc_channel_config(&ledc_conf); //setup the configuration
|
||||
*
|
||||
* ----------------EXAMPLE OF SETTING DUTY --- -----------------
|
||||
* uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73)
|
||||
* uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1)
|
||||
* LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty.
|
||||
* ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel); //after set duty, we need to call ledc_update_duty to update the settings.
|
||||
*
|
||||
* @code{c}
|
||||
* uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73)
|
||||
* uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1)
|
||||
* LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty.
|
||||
* ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel); //after set duty, we need to call ledc_update_duty to update the settings.
|
||||
* @endcode
|
||||
*
|
||||
* ----------------EXAMPLE OF LEDC INTERRUPT ------------------
|
||||
* //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here.
|
||||
* ledc_isr_register(18, ledc_isr_handler, NULL); //hook the isr handler for LEDC interrupt
|
||||
* //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
|
||||
* //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
|
||||
* //NOTE2:do not pick the INUM that already occupied by the system.
|
||||
* //NOTE3:refer to soc.h to check which INUMs that can be used.
|
||||
* @code{c}
|
||||
* //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here.
|
||||
* ledc_isr_register(18, ledc_isr_handler, NULL); //hook the isr handler for LEDC interrupt
|
||||
* @endcode
|
||||
* @note
|
||||
* 1. the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
|
||||
* 2. user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
|
||||
* 3. do not pick the INUM that already occupied by the system.
|
||||
* 4. refer to soc.h to check which INUMs that can be used.
|
||||
*
|
||||
* ----------------EXAMPLE OF INTERRUPT HANDLER ---------------
|
||||
* @code{c}
|
||||
* #include "esp_attr.h"
|
||||
* void IRAM_ATTR ledc_isr_handler(void* arg) //we should add 'IRAM_ATTR' attribution when we declare the isr function
|
||||
* {
|
||||
|
@ -391,7 +419,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint
|
|||
*
|
||||
* LEDC.int_clr.val = intr_st; //clear LEDC interrupt status.
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
*--------------------------END OF EXAMPLE --------------------------
|
||||
*/
|
||||
|
|
|
@ -39,6 +39,7 @@ typedef enum {
|
|||
PERIPH_PWM3_MODULE,
|
||||
PERIPH_UHCI0_MODULE,
|
||||
PERIPH_UHCI1_MODULE,
|
||||
PERIPH_RMT_MODULE,
|
||||
} periph_module_t;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,794 @@
|
|||
// 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 _DRIVER_RMT_CTRL_H_
|
||||
#define _DRIVER_RMT_CTRL_H_
|
||||
#include "esp_err.h"
|
||||
#include "soc/rmt_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RMT_MEM_BLOCK_BYTE_NUM (256)
|
||||
#define RMT_MEM_ITEM_NUM (RMT_MEM_BLOCK_BYTE_NUM/4)
|
||||
|
||||
typedef enum {
|
||||
RMT_CHANNEL_0=0, /*!< RMT Channel0 */
|
||||
RMT_CHANNEL_1, /*!< RMT Channel1 */
|
||||
RMT_CHANNEL_2, /*!< RMT Channel2 */
|
||||
RMT_CHANNEL_3, /*!< RMT Channel3 */
|
||||
RMT_CHANNEL_4, /*!< RMT Channel4 */
|
||||
RMT_CHANNEL_5, /*!< RMT Channel5 */
|
||||
RMT_CHANNEL_6, /*!< RMT Channel6 */
|
||||
RMT_CHANNEL_7, /*!< RMT Channel7 */
|
||||
RMT_CHANNEL_MAX
|
||||
} rmt_channel_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_MEM_OWNER_TX = 0, /*!< RMT RX mode, RMT transmitter owns the memory block*/
|
||||
RMT_MEM_OWNER_RX = 1, /*!< RMT RX mode, RMT receiver owns the memory block*/
|
||||
RMT_MEM_OWNER_MAX,
|
||||
}rmt_mem_owner_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_BASECLK_REF = 0, /*!< RMT source clock system reference tick, 1MHz by default(Not supported in this version) */
|
||||
RMT_BASECLK_APB, /*!< RMT source clock is APB CLK, 80Mhz by default */
|
||||
RMT_BASECLK_MAX,
|
||||
} rmt_source_clk_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_DATA_MODE_FIFO = 0, /*<! RMT memory access in FIFO mode */
|
||||
RMT_DATA_MODE_MEM = 1, /*<! RMT memory access in memory mode */
|
||||
RMT_DATA_MODE_MAX,
|
||||
} rmt_data_mode_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_MODE_TX=0, /*!< RMT TX mode */
|
||||
RMT_MODE_RX, /*!< RMT RX mode */
|
||||
RMT_MODE_MAX
|
||||
} rmt_mode_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_IDLE_LEVEL_LOW=0, /*!< RMT TX idle level: low Level */
|
||||
RMT_IDLE_LEVEL_HIGH, /*!< RMT TX idle level: high Level */
|
||||
RMT_IDLE_LEVEL_MAX,
|
||||
} rmt_idle_level_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_CARRIER_LEVEL_LOW=0, /*!< RMT carrier wave is modulated for low Level output */
|
||||
RMT_CARRIER_LEVEL_HIGH, /*!< RMT carrier wave is modulated for high Level output */
|
||||
RMT_CARRIER_LEVEL_MAX
|
||||
} rmt_carrier_level_t;
|
||||
|
||||
/**
|
||||
* @brief Data struct of RMT TX configure parameters
|
||||
*/
|
||||
typedef struct {
|
||||
bool loop_en; /*!< RMT loop output mode*/
|
||||
uint32_t carrier_freq_hz; /*!< RMT carrier frequency */
|
||||
uint8_t carrier_duty_percent; /*!< RMT carrier duty (%) */
|
||||
rmt_carrier_level_t carrier_level; /*!< RMT carrier level */
|
||||
bool carrier_en; /*!< RMT carrier enable */
|
||||
rmt_idle_level_t idle_level; /*!< RMT idle level */
|
||||
bool idle_output_en; /*!< RMT idle level output enable*/
|
||||
}rmt_tx_config_t;
|
||||
|
||||
/**
|
||||
* @brief Data struct of RMT RX configure parameters
|
||||
*/
|
||||
typedef struct {
|
||||
bool filter_en; /*!< RMT receiver filer enable*/
|
||||
uint8_t filter_ticks_thresh; /*!< RMT filter tick number */
|
||||
uint16_t idle_threshold; /*!< RMT RX idle threshold */
|
||||
}rmt_rx_config_t;
|
||||
|
||||
/**
|
||||
* @brief Data struct of RMT configure parameters
|
||||
*/
|
||||
typedef struct {
|
||||
rmt_mode_t rmt_mode; /*!< RMT mode: transmitter or receiver */
|
||||
rmt_channel_t channel; /*!< RMT channel */
|
||||
uint8_t clk_div; /*!< RMT channel counter divider */
|
||||
gpio_num_t gpio_num; /*!< RMT GPIO number */
|
||||
uint8_t mem_block_num; /*!< RMT memory block number */
|
||||
union{
|
||||
rmt_tx_config_t tx_config; /*!< RMT TX parameter */
|
||||
rmt_rx_config_t rx_config; /*!< RMT RX parameter */
|
||||
};
|
||||
} rmt_config_t;
|
||||
|
||||
/**
|
||||
* @brief Set RMT clock divider, channel clock is divided from source clock.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param div_cnt RMT counter clock divider
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_clk_div(rmt_channel_t channel, uint8_t div_cnt);
|
||||
|
||||
/**
|
||||
* @brief Get RMT clock divider, channel clock is divided from source clock.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param div_cnt pointer to accept RMT counter divider
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_clk_div(rmt_channel_t channel, uint8_t* div_cnt);
|
||||
|
||||
/**
|
||||
* @brief Set RMT RX idle threshold value
|
||||
*
|
||||
* In receive mode, when no edge is detected on the input signal
|
||||
* for longer than idle_thres channel clock cycles,
|
||||
* the receive process is finished.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param thresh RMT RX idle threshold
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_rx_idle_thresh(rmt_channel_t channel, uint16_t thresh);
|
||||
|
||||
/**
|
||||
* @brief Get RMT idle threshold value.
|
||||
*
|
||||
* In receive mode, when no edge is detected on the input signal
|
||||
* for longer than idle_thres channel clock cycles,
|
||||
* the receive process is finished.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param thresh pointer to accept RMT RX idle threshold value
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_rx_idle_thresh(rmt_channel_t channel, uint16_t *thresh);
|
||||
|
||||
/**
|
||||
* @brief Set RMT memory block number for RMT channel
|
||||
*
|
||||
* This function is used to configure the amount of memory blocks allocated to channel n
|
||||
* The 8 channels share a 512x32-bit RAM block which can be read and written
|
||||
* by the processor cores over the APB bus, as well as read by the transmitters
|
||||
* and written by the receivers.
|
||||
* The RAM address range for channel n is start_addr_CHn to end_addr_CHn, which are defined by:
|
||||
* Memory block start address is RMT_CHANNEL_MEM(n) (in soc/rmt_reg.h),
|
||||
* that is, start_addr_chn = RMT base address + 0x800 + 64 ∗ 4 ∗ n, and
|
||||
* end_addr_chn = RMT base address + 0x800 + 64 ∗ 4 ∗ n + 64 ∗ 4 ∗ RMT_MEM_SIZE_CHn mod 512 ∗ 4
|
||||
* @note
|
||||
* If memory block number of one channel is set to a value greater than 1, this channel will occupy the memory
|
||||
* block of the next channel.
|
||||
* Channel0 can use at most 8 blocks of memory, accordingly channel7 can only use one memory block.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param rmt_mem_num RMT RX memory block number, one block has 64 * 32 bits.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_mem_block_num(rmt_channel_t channel, uint8_t rmt_mem_num);
|
||||
|
||||
/**
|
||||
* @brief Get RMT memory block number
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param rmt_mem_num Pointer to accept RMT RX memory block number
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_mem_block_num(rmt_channel_t channel, uint8_t* rmt_mem_num);
|
||||
|
||||
/**
|
||||
* @brief Configure RMT carrier for TX signal.
|
||||
*
|
||||
* Set different values for carrier_high and carrier_low to set different frequency of carrier.
|
||||
* The unit of carrier_high/low is the source clock tick, not the divided channel counter clock.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param carrier_en Whether to enable output carrier.
|
||||
*
|
||||
* @param high_level High level duration of carrier
|
||||
*
|
||||
* @param low_level Low level duration of carrier.
|
||||
*
|
||||
* @param carrier_level Configure the way carrier wave is modulated for channel0-7.
|
||||
*
|
||||
* 1'b1:transmit on low output level
|
||||
*
|
||||
* 1'b0:transmit on high output level
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_tx_carrier(rmt_channel_t channel, bool carrier_en, uint16_t high_level, uint16_t low_level, rmt_carrier_level_t carrier_level);
|
||||
|
||||
/**
|
||||
* @brief Set RMT memory in low power mode.
|
||||
*
|
||||
* Reduce power consumed by memory. 1:memory is in low power state.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param pd_en RMT memory low power enable.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en);
|
||||
|
||||
/**
|
||||
* @brief Get RMT memory low power mode.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param pd_en Pointer to accept RMT memory low power mode.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool* pd_en);
|
||||
|
||||
/**
|
||||
* @brief Set RMT start sending data from memory.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param tx_idx_rst Set true to reset memory index for TX.
|
||||
* Otherwise, transmitter will continue sending from the last index in memory.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_tx_start(rmt_channel_t channel, bool tx_idx_rst);
|
||||
|
||||
/**
|
||||
* @brief Set RMT stop sending.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_tx_stop(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Set RMT start receiving data.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param rx_idx_rst Set true to reset memory index for receiver.
|
||||
* Otherwise, receiver will continue receiving data to the last index in memory.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_rx_start(rmt_channel_t channel, bool rx_idx_rst);
|
||||
|
||||
/**
|
||||
* @brief Set RMT stop receiving data.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_rx_stop(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Reset RMT TX/RX memory index.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_memory_rw_rst(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Set RMT memory owner.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param owner To set when the transmitter or receiver can process the memory of channel.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_memory_owner(rmt_channel_t channel, rmt_mem_owner_t owner);
|
||||
|
||||
/**
|
||||
* @brief Get RMT memory owner.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param owner Pointer to get memory owner.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_memory_owner(rmt_channel_t channel, rmt_mem_owner_t* owner);
|
||||
|
||||
/**
|
||||
* @brief Set RMT tx loop mode.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param loop_en To enable RMT transmitter loop sending mode.
|
||||
*
|
||||
* If set true, transmitter will continue sending from the first data
|
||||
* to the last data in channel0-7 again and again.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_tx_loop_mode(rmt_channel_t channel, bool loop_en);
|
||||
|
||||
/**
|
||||
* @brief Get RMT tx loop mode.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param loop_en Pointer to accept RMT transmitter loop sending mode.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_tx_loop_mode(rmt_channel_t channel, bool* loop_en);
|
||||
|
||||
/**
|
||||
* @brief Set RMT RX filter.
|
||||
*
|
||||
* In receive mode, channel0-7 will ignore input pulse when the pulse width is smaller than threshold.
|
||||
* Counted in source clock, not divided counter clock.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param rx_filter_en To enable RMT receiver filter.
|
||||
*
|
||||
* @param thresh Threshold of pulse width for receiver.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_rx_filter(rmt_channel_t channel, bool rx_filter_en, uint8_t thresh);
|
||||
|
||||
/**
|
||||
* @brief Set RMT source clock
|
||||
*
|
||||
* RMT module has two source clock:
|
||||
* 1. APB clock which is 80Mhz
|
||||
* 2. REF tick clock, which would be 1Mhz( not supported in this version).
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param base_clk To choose source clock for RMT module.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk);
|
||||
|
||||
/**
|
||||
* @brief Get RMT source clock
|
||||
*
|
||||
* RMT module has two source clock:
|
||||
* 1. APB clock which is 80Mhz
|
||||
* 2. REF tick clock, which would be 1Mhz( not supported in this version).
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param src_clk Pointer to accept source clock for RMT module.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_source_clk(rmt_channel_t channel, rmt_source_clk_t* src_clk);
|
||||
|
||||
/**
|
||||
* @brief Set RMT idle output level for transmitter
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param idle_out_en To enable idle level output.
|
||||
*
|
||||
* @param level To set the output signal's level for channel0-7 in idle state.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_idle_level(rmt_channel_t channel, bool idle_out_en, rmt_idle_level_t level);
|
||||
|
||||
/**
|
||||
* @brief Get RMT status
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param status Pointer to accept channel status.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_status(rmt_channel_t channel, uint32_t* status);
|
||||
|
||||
/**
|
||||
* @brief Set mask value to RMT interrupt enable register.
|
||||
*
|
||||
* @param mask Bit mask to set to the register
|
||||
*
|
||||
*/
|
||||
void rmt_set_intr_enable_mask(uint32_t mask);
|
||||
|
||||
/**
|
||||
* @brief Clear mask value to RMT interrupt enable register.
|
||||
*
|
||||
* @param mask Bit mask to clear the register
|
||||
*
|
||||
*/
|
||||
void rmt_clr_intr_enable_mask(uint32_t mask);
|
||||
|
||||
/**
|
||||
* @brief Set RMT RX interrupt enable
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param en enable or disable RX interrupt.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_rx_intr_en(rmt_channel_t channel, bool en);
|
||||
|
||||
/**
|
||||
* @brief Set RMT RX error interrupt enable
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param en enable or disable RX err interrupt.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_err_intr_en(rmt_channel_t channel, bool en);
|
||||
|
||||
/**
|
||||
* @brief Set RMT TX interrupt enable
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param en enable or disable TX interrupt.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en);
|
||||
|
||||
/**
|
||||
* @brief Set RMT TX event interrupt enable
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param en enable or disable TX event interrupt.
|
||||
*
|
||||
* @param evt_thresh RMT event interrupt threshold value
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_evt_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh);
|
||||
|
||||
/**
|
||||
* @brief Set RMT pins
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param mode TX or RX mode for RMT
|
||||
*
|
||||
* @param gpio_num GPIO number to transmit or receive the signal.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief Configure RMT parameters
|
||||
*
|
||||
* @param rmt_param RMT parameter structor
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_config(rmt_config_t* rmt_param);
|
||||
|
||||
/**
|
||||
* @brief register RMT interrupt handler, the handler is an ISR.
|
||||
*
|
||||
* The handler will be attached to the same CPU core that this function is running on.
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
* @note
|
||||
* If you already called rmt_driver_install to use system RMT driver,
|
||||
* please do not register ISR handler again.
|
||||
*
|
||||
* @param rmt_intr_num RMT interrupt number, check the info in soc.h, and please see the core-isa.h for more details
|
||||
*
|
||||
* @param fn Interrupt handler function.
|
||||
*
|
||||
* @note
|
||||
* the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
*
|
||||
* @param arg Parameter for handler function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Function pointer error.
|
||||
* - ESP_FAIL System driver installed, can not register ISR handler for RMT
|
||||
*/
|
||||
esp_err_t rmt_isr_register(uint8_t rmt_intr_num, void (* fn)(void* ), void * arg);
|
||||
|
||||
/**
|
||||
* @brief Fill memory data of channel with given RMT items.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param item Pointer of items.
|
||||
*
|
||||
* @param item_num RMT sending items number.
|
||||
*
|
||||
* @param mem_offset Index offset of memory.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_fill_tx_items(rmt_channel_t channel, rmt_item32_t* item, uint16_t item_num, uint16_t mem_offset);
|
||||
|
||||
/**
|
||||
* @brief Initialize RMT driver
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param rx_buf_size Size of RMT RX ringbuffer.
|
||||
*
|
||||
* @note
|
||||
* If we do not need RX ringbuffer, just set rx_buf_size to 0.
|
||||
*
|
||||
* @note
|
||||
* When we call rmt_driver_install function, it will register a driver ISR handler,
|
||||
* DO NOT REGISTER ISR HANDLER AGAIN.
|
||||
*
|
||||
* @param rmt_intr_num RMT interrupt number.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num);
|
||||
|
||||
/**
|
||||
* @brief Uninstall RMT driver.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_driver_uninstall(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief RMT send waveform from rmt_item array.
|
||||
*
|
||||
* This API allows user to send waveform with any length.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param rmt_item head point of RMT items array.
|
||||
*
|
||||
* @param item_num RMT data item number.
|
||||
*
|
||||
* @param wait_tx_done If set 1, it will block the task and wait for sending done.
|
||||
*
|
||||
* If set 0, it will not wait and return immediately.
|
||||
*
|
||||
* @note
|
||||
* This function will not copy data, instead, it will point to the original items,
|
||||
* and send the waveform items.
|
||||
* If wait_tx_done is set to true, this function will block and will not return until
|
||||
* all items have been sent out.
|
||||
* If wait_tx_done is set to false, this function will return immediately, and the driver
|
||||
* interrupt will continue sending the items. We must make sure the item data will not be
|
||||
* damaged when the driver is still sending items in driver interrupt.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_write_items(rmt_channel_t channel, rmt_item32_t* rmt_item, int item_num, bool wait_tx_done);
|
||||
|
||||
/**
|
||||
* @brief Wait RMT TX finished.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_wait_tx_done(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Get ringbuffer from UART.
|
||||
*
|
||||
* Users can get the RMT RX ringbuffer handler, and process the RX data.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param buf_handler Pointer to buffer handler to accept RX ringbuffer handler.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_ringbuf_handler(rmt_channel_t channel, RingbufHandle_t* buf_handler);
|
||||
|
||||
/***************************EXAMPLE**********************************
|
||||
*
|
||||
* @note
|
||||
* You can also refer to example/09_rmt_nec_tx_rx to have more information about how to use RMT module.
|
||||
*
|
||||
* ----------------EXAMPLE OF RMT SETTING ---------------------
|
||||
* @code{c}
|
||||
* //1. enable RMT
|
||||
* //enable RMT module, or you can not set any register of it.
|
||||
* //this will be done in rmt_config API.
|
||||
* periph_module_enable(PERIPH_RMT_MODULE);
|
||||
* @endcode
|
||||
*
|
||||
* @code{c}
|
||||
* //2. set RMT transmitter
|
||||
* void rmt_tx_init()
|
||||
* {
|
||||
* rmt_config_t rmt_tx;
|
||||
* rmt_tx.channel = 0;
|
||||
* rmt_tx.gpio_num = 16;
|
||||
* rmt_tx.mem_block_num = 1;
|
||||
* rmt_tx.clk_div = 100;
|
||||
* rmt_tx.tx_config.loop_en = false;
|
||||
* rmt_tx.tx_config.carrier_duty_percent = 50;
|
||||
* rmt_tx.tx_config.carrier_freq_hz = 38000;
|
||||
* rmt_tx.tx_config.carrier_level = 1;
|
||||
* rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN;
|
||||
* rmt_tx.tx_config.idle_level = 0;
|
||||
* rmt_tx.tx_config.idle_output_en = true;
|
||||
* rmt_tx.rmt_mode = 0;
|
||||
* rmt_config(&rmt_tx);
|
||||
*
|
||||
* //install system RMT driver, disable rx ringbuffer for transmitter.
|
||||
* rmt_driver_install(rmt_tx.channel, 0, RMT_INTR_NUM);
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
* @code{c}
|
||||
* //3. set RMT receiver
|
||||
* void rmt_rx_init()
|
||||
* {
|
||||
* rmt_config_t rmt_rx;
|
||||
* rmt_rx.channel = 1;
|
||||
* rmt_rx.gpio_num = 19;
|
||||
* rmt_rx.clk_div = 100;
|
||||
* rmt_rx.mem_block_num = 1;
|
||||
* rmt_rx.rmt_mode = RMT_MODE_RX;
|
||||
* rmt_rx.rx_config.filter_en = true;
|
||||
* rmt_rx.rx_config.filter_ticks_thresh = 100;
|
||||
* rmt_rx.rx_config.idle_threshold = 0xffff;
|
||||
* rmt_config(&rmt_rx);
|
||||
*
|
||||
* //install system RMT driver.
|
||||
* rmt_driver_install(rmt_rx.channel, 1000, RMT_INTR_NUM);
|
||||
* }
|
||||
*
|
||||
* ----------------EXAMPLE OF RMT INTERRUPT ------------------
|
||||
* @code{c}
|
||||
*
|
||||
* rmt_isr_register(RMT_INTR_NUM, rmt_isr, NULL); //hook the ISR handler for RMT interrupt
|
||||
* @endcode
|
||||
* @note
|
||||
* 0. If you have called rmt_driver_install, you don't need to set ISR handler any more.
|
||||
* 1. the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
|
||||
* 2. user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
|
||||
* 3. do not pick the INUM that already occupied by the system.
|
||||
* 4. refer to soc.h to check which INUMs that can be used.
|
||||
*
|
||||
* ----------------EXAMPLE OF INTERRUPT HANDLER ---------------
|
||||
* @code{c}
|
||||
* #include "esp_attr.h"
|
||||
* //we should add 'IRAM_ATTR' attribution when we declare the isr function
|
||||
* void IRAM_ATTR rmt_isr_handler(void* arg)
|
||||
* {
|
||||
* //read RMT interrupt status.
|
||||
* uint32_t intr_st = RMT.int_st.val;
|
||||
*
|
||||
* //you will find which channels have triggered fade_end interrupt here,
|
||||
* //then, you can post some event to RTOS queue to process the event.
|
||||
* //later we will add a queue in the driver code.
|
||||
*
|
||||
* //clear RMT interrupt status.
|
||||
* RMT.int_clr.val = intr_st;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*--------------------------END OF EXAMPLE --------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DRIVER_RMT_CTRL_H_ */
|
|
@ -0,0 +1,748 @@
|
|||
// 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 _DRIVER_UART_H_
|
||||
#define _DRIVER_UART_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "esp_err.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include <esp_types.h>
|
||||
|
||||
#define UART_FIFO_LEN (128) /*!< Length of the hardware FIFO buffers */
|
||||
#define UART_INTR_MASK 0x1ff /*!< mask of all UART interrupts */
|
||||
#define UART_LINE_INV_MASK (0x3f << 19) /*!< TBD */
|
||||
#define UART_BITRATE_MAX 5000000 /*!< Max bit rate supported by UART */
|
||||
#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */
|
||||
|
||||
#define UART_INVERSE_DISABLE (0x0) /*!< Disable UART signal inverse*/
|
||||
#define UART_INVERSE_RXD (UART_RXD_INV_M) /*!< UART RXD input inverse*/
|
||||
#define UART_INVERSE_CTS (UART_CTS_INV_M) /*!< UART CTS input inverse*/
|
||||
#define UART_INVERSE_TXD (UART_TXD_INV_M) /*!< UART TXD output inverse*/
|
||||
#define UART_INVERSE_RTS (UART_RTS_INV_M) /*!< UART RTS output inverse*/
|
||||
|
||||
/**
|
||||
* @brief UART word length constants
|
||||
*/
|
||||
typedef enum {
|
||||
UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/
|
||||
UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/
|
||||
UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/
|
||||
UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/
|
||||
UART_DATA_BITS_MAX = 0X4,
|
||||
} uart_word_length_t;
|
||||
|
||||
/**
|
||||
* @brief UART stop bits number
|
||||
*/
|
||||
typedef enum {
|
||||
UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/
|
||||
UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/
|
||||
UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/
|
||||
UART_STOP_BITS_MAX = 0x4,
|
||||
} uart_stop_bits_t;
|
||||
|
||||
/**
|
||||
* @brief UART peripheral number
|
||||
*/
|
||||
typedef enum {
|
||||
UART_NUM_0 = 0x0, /*!< UART base address 0x3ff40000*/
|
||||
UART_NUM_1 = 0x1, /*!< UART base address 0x3ff50000*/
|
||||
UART_NUM_2 = 0x2, /*!< UART base address 0x3ff6E000*/
|
||||
UART_NUM_MAX,
|
||||
} uart_port_t;
|
||||
|
||||
/**
|
||||
* @brief UART parity constants
|
||||
*/
|
||||
typedef enum {
|
||||
UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/
|
||||
UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/
|
||||
UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/
|
||||
} uart_parity_t;
|
||||
|
||||
/**
|
||||
* @brief UART hardware flow control modes
|
||||
*/
|
||||
typedef enum {
|
||||
UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/
|
||||
UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/
|
||||
UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/
|
||||
UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/
|
||||
UART_HW_FLOWCTRL_MAX = 0x4,
|
||||
} uart_hw_flowcontrol_t;
|
||||
|
||||
/**
|
||||
* @brief UART configuration parameters for uart_param_config function
|
||||
*/
|
||||
typedef struct {
|
||||
int baud_rate; /*!< UART baudrate*/
|
||||
uart_word_length_t data_bits; /*!< UART byte size*/
|
||||
uart_parity_t parity; /*!< UART parity mode*/
|
||||
uart_stop_bits_t stop_bits; /*!< UART stop bits*/
|
||||
uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode(cts/rts)*/
|
||||
uint8_t rx_flow_ctrl_thresh ; /*!< UART HW RTS threshold*/
|
||||
} uart_config_t;
|
||||
|
||||
/**
|
||||
* @brief UART interrupt configuration parameters for uart_intr_config function
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t intr_enable_mask; /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/
|
||||
uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold(unit: time of sending one byte)*/
|
||||
uint8_t txfifo_empty_intr_thresh; /*!< UART TX empty interrupt threshold.*/
|
||||
uint8_t rxfifo_full_thresh; /*!< UART RX full interrupt threshold.*/
|
||||
} uart_intr_config_t;
|
||||
|
||||
/**
|
||||
* @brief UART event types used in the ringbuffer
|
||||
*/
|
||||
typedef enum {
|
||||
UART_DATA, /*!< UART data event*/
|
||||
UART_BREAK, /*!< UART break event*/
|
||||
UART_BUFFER_FULL, /*!< UART RX buffer full event*/
|
||||
UART_FIFO_OVF, /*!< UART FIFO overflow event*/
|
||||
UART_FRAME_ERR, /*!< UART RX frame error event*/
|
||||
UART_PARITY_ERR, /*!< UART RX parity event*/
|
||||
UART_DATA_BREAK, /*!< UART TX data and break event*/
|
||||
UART_EVENT_MAX, /*!< UART event max index*/
|
||||
} uart_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief Event structure used in UART event queue
|
||||
*/
|
||||
typedef struct {
|
||||
uart_event_type_t type; /*!< UART event type */
|
||||
size_t size; /*!< UART data size for UART_DATA event*/
|
||||
} uart_event_t;
|
||||
|
||||
/**
|
||||
* @brief Set UART data bits.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param data_bit UART data bits
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit);
|
||||
|
||||
/**
|
||||
* @brief Get UART data bits.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param data_bit Pointer to accept value of UART data bits.
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success, result will be put in (*data_bit)
|
||||
*/
|
||||
esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit);
|
||||
|
||||
/**
|
||||
* @brief Set UART stop bits.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param bit_num UART stop bits
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Fail
|
||||
*/
|
||||
esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t bit_num);
|
||||
|
||||
/**
|
||||
* @brief Set UART stop bits.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param stop_bit Pointer to accept value of UART stop bits.
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success, result will be put in (*stop_bit)
|
||||
*/
|
||||
esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit);
|
||||
|
||||
/**
|
||||
* @brief Set UART parity.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param parity_mode the enum of uart parity configuration
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode);
|
||||
|
||||
/**
|
||||
* @brief Get UART parity mode.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param parity_mode Pointer to accept value of UART parity mode.
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success, result will be put in (*parity_mode)
|
||||
*
|
||||
*/
|
||||
esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode);
|
||||
|
||||
/**
|
||||
* @brief Set UART baud rate.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param baud_rate UART baud-rate.
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate);
|
||||
|
||||
/**
|
||||
* @brief Get UART bit-rate.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param baudrate Pointer to accept value of UART baud rate
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success, result will be put in (*baudrate)
|
||||
*
|
||||
*/
|
||||
esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);
|
||||
|
||||
/**
|
||||
* @brief Set UART line inverse mode
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param inverse_mask Choose the wires that need to be inversed.
|
||||
* Inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR operation.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask);
|
||||
|
||||
/**
|
||||
* @brief Set hardware flow control.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param flow_ctrl Hardware flow control mode
|
||||
* @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN).
|
||||
* Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);
|
||||
|
||||
/**
|
||||
* @brief Get hardware flow control mode
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param flow_ctrl Option for different flow control mode.
|
||||
*
|
||||
* @return
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_OK Success, result will be put in (*flow_ctrl)
|
||||
*/
|
||||
esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl);
|
||||
|
||||
/**
|
||||
* @brief Clear UART interrupt status
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param clr_mask Bit mask of the status that to be cleared.
|
||||
* enable_mask should be chosen from the fields of register UART_INT_CLR_REG.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask);
|
||||
|
||||
/**
|
||||
* @brief Set UART interrupt enable
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param enable_mask Bit mask of the enable bits.
|
||||
* enable_mask should be chosen from the fields of register UART_INT_ENA_REG.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);
|
||||
|
||||
/**
|
||||
* @brief Clear UART interrupt enable bits
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param disable_mask Bit mask of the disable bits.
|
||||
* disable_mask should be chosen from the fields of register UART_INT_ENA_REG.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_enable_rx_intr(uart_port_t uart_num);
|
||||
|
||||
/**
|
||||
* @brief Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_disable_rx_intr(uart_port_t uart_num);
|
||||
|
||||
/**
|
||||
* @brief Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_disable_tx_intr(uart_port_t uart_num);
|
||||
|
||||
/**
|
||||
* @brief Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param enable 1: enable; 0: disable
|
||||
* @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
|
||||
|
||||
/**
|
||||
* @brief register UART interrupt handler(ISR).
|
||||
*
|
||||
* @note UART ISR handler will be attached to the same CPU core that this function is running on.
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
*
|
||||
* @attention The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details
|
||||
* @param fn Interrupt handler function.
|
||||
* @param arg parameter for handler function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg);
|
||||
|
||||
/**
|
||||
* @brief Set UART pin number
|
||||
*
|
||||
* @note Internal signal can be output to multiple GPIO pads.
|
||||
* Only one GPIO pad can connect with input signal.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param tx_io_num UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
|
||||
* @param rx_io_num UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
|
||||
* @param rts_io_num UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
|
||||
* @param cts_io_num UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num);
|
||||
|
||||
/**
|
||||
* @brief UART set RTS level (before inverse)
|
||||
* UART rx hardware flow control should not be set.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param level 1: RTS output low(active); 0: RTS output high(block)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_set_rts(uart_port_t uart_num, int level);
|
||||
|
||||
/**
|
||||
* @brief UART set DTR level (before inverse)
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param level 1: DTR output low; 0: DTR output high
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_set_dtr(uart_port_t uart_num, int level);
|
||||
|
||||
/**
|
||||
* @brief UART parameter configure
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param uart_config UART parameter settings
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);
|
||||
|
||||
/**
|
||||
* @brief UART interrupt configure
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param intr_conf UART interrupt settings
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf);
|
||||
|
||||
/**
|
||||
* @brief Install UART driver.
|
||||
*
|
||||
* UART ISR handler will be attached to the same CPU core that this function is running on.
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param rx_buffer_size UART RX ring buffer size
|
||||
* @param tx_buffer_size UART TX ring buffer size.
|
||||
* If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..
|
||||
* @param queue_size UART event queue size/depth.
|
||||
* @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details
|
||||
* @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, int uart_intr_num, void* uart_queue);
|
||||
|
||||
/**
|
||||
* @brief Uninstall UART driver.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_driver_delete(uart_port_t uart_num);
|
||||
|
||||
/**
|
||||
* @brief Wait UART TX FIFO empty
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param ticks_to_wait Timeout, count in RTOS ticks
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
* - ESP_ERR_TIMEOUT Timeout
|
||||
*/
|
||||
esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Send data to the UART port from a given buffer and length.
|
||||
*
|
||||
* This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full.
|
||||
* @note This function should only be used when UART TX buffer is not enabled.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param buffer data buffer address
|
||||
* @param len data length to send
|
||||
*
|
||||
* @return
|
||||
* - (-1) Parameter error
|
||||
* - OTHERS(>=0) The number of data that pushed to the TX FIFO
|
||||
*/
|
||||
int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Send data to the UART port from a given buffer and length,
|
||||
*
|
||||
* If parameter tx_buffer_size is set to zero:
|
||||
* This function will not return until all the data have been sent out, or at least pushed into TX FIFO.
|
||||
*
|
||||
* Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,
|
||||
* then, UART ISR will move data from ring buffer to TX FIFO gradually.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param src data buffer address
|
||||
* @param size data length to send
|
||||
*
|
||||
* @return
|
||||
* - (-1) Parameter error
|
||||
* - OTHERS(>=0) The number of data that pushed to the TX FIFO
|
||||
*/
|
||||
int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Send data to the UART port from a given buffer and length,
|
||||
*
|
||||
* If parameter tx_buffer_size is set to zero:
|
||||
* This function will not return until all the data and the break signal have been sent out.
|
||||
* After all data send out, send a break signal.
|
||||
*
|
||||
* Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,
|
||||
* then, UART ISR will move data from ring buffer to TX FIFO gradually.
|
||||
* After all data send out, send a break signal.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param src data buffer address
|
||||
* @param size data length to send
|
||||
* @param brk_len break signal length (unit: time of one data bit at current_baudrate)
|
||||
*
|
||||
* @return
|
||||
* - (-1) Parameter error
|
||||
* - OTHERS(>=0) The number of data that pushed to the TX FIFO
|
||||
*/
|
||||
|
||||
int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len);
|
||||
|
||||
/**
|
||||
* @brief UART read bytes from UART buffer
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param buf pointer to the buffer.
|
||||
* @param length data length
|
||||
* @param ticks_to_wait sTimeout, count in RTOS ticks
|
||||
*
|
||||
* @return
|
||||
* - (-1) Error
|
||||
* - Others return a char data from uart fifo.
|
||||
*/
|
||||
int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief UART ring buffer flush
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t uart_flush(uart_port_t uart_num);
|
||||
|
||||
/***************************EXAMPLE**********************************
|
||||
*
|
||||
*
|
||||
* ----------------EXAMPLE OF UART SETTING ---------------------
|
||||
* @code{c}
|
||||
* //1. Setup UART
|
||||
* #include "freertos/queue.h"
|
||||
* #define UART_INTR_NUM 17 //choose one interrupt number from soc.h
|
||||
* //a. Set UART parameter
|
||||
* int uart_num = 0; //uart port number
|
||||
* uart_config_t uart_config = {
|
||||
* .baud_rate = UART_BITRATE_115200, //baudrate
|
||||
* .data_bits = UART_DATA_8_BITS, //data bit mode
|
||||
* .parity = UART_PARITY_DISABLE, //parity mode
|
||||
* .stop_bits = UART_STOP_BITS_1, //stop bit mode
|
||||
* .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, //hardware flow control(cts/rts)
|
||||
* .rx_flow_ctrl_thresh = 120, //flow control threshold
|
||||
* };
|
||||
* uart_param_config(uart_num, &uart_config);
|
||||
* //b1. Setup UART driver(with UART queue)
|
||||
* QueueHandle_t uart_queue;
|
||||
* //parameters here are just an example, tx buffer size is 2048
|
||||
* uart_driver_install(uart_num, 1024 * 2, 1024 * 2, 10, UART_INTR_NUM, &uart_queue);
|
||||
* //b2. Setup UART driver(without UART queue)
|
||||
* //parameters here are just an example, tx buffer size is 0
|
||||
* uart_driver_install(uart_num, 1024 * 2, 0, 10, UART_INTR_NUM, NULL);
|
||||
*@endcode
|
||||
*-----------------------------------------------------------------------------*
|
||||
* @code{c}
|
||||
* //2. Set UART pin
|
||||
* //set UART pin, not needed if use default pins.
|
||||
* uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 15, 13);
|
||||
* @endcode
|
||||
*-----------------------------------------------------------------------------*
|
||||
* @code{c}
|
||||
* //3. Read data from UART.
|
||||
* uint8_t data[128];
|
||||
* int length = 0;
|
||||
* length = uart_read_bytes(uart_num, data, sizeof(data), 100);
|
||||
* @endcode
|
||||
*-----------------------------------------------------------------------------*
|
||||
* @code{c}
|
||||
* //4. Write data to UART.
|
||||
* char* test_str = "This is a test string.\n"
|
||||
* uart_write_bytes(uart_num, (const char*)test_str, strlen(test_str));
|
||||
* @endcode
|
||||
*-----------------------------------------------------------------------------*
|
||||
* @code{c}
|
||||
* //5. Write data to UART, end with a break signal.
|
||||
* uart_write_bytes_with_break(0, "test break\n",strlen("test break\n"), 100);
|
||||
* @endcode
|
||||
*-----------------------------------------------------------------------------*
|
||||
* @code{c}
|
||||
* //6. an example of echo test with hardware flow control on UART1
|
||||
* void uart_loop_back_test()
|
||||
* {
|
||||
* int uart_num = 1;
|
||||
* uart_config_t uart_config = {
|
||||
* .baud_rate = 115200,
|
||||
* .data_bits = UART_DATA_8_BITS,
|
||||
* .parity = UART_PARITY_DISABLE,
|
||||
* .stop_bits = UART_STOP_BITS_1,
|
||||
* .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
|
||||
* .rx_flow_ctrl_thresh = 122,
|
||||
* };
|
||||
* //Configure UART1 parameters
|
||||
* uart_param_config(uart_num, &uart_config);
|
||||
* //Set UART1 pins(TX: IO16, RX: IO17, RTS: IO18, CTS: IO19)
|
||||
* uart_set_pin(uart_num, 16, 17, 18, 19);
|
||||
* //Install UART driver( We don't need an event queue here)
|
||||
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, NULL, RINGBUF_TYPE_BYTEBUF);
|
||||
* uint8_t data[1000];
|
||||
* while(1) {
|
||||
* //Read data from UART
|
||||
* int len = uart_read_bytes(uart_num, data, sizeof(data), 10);
|
||||
* //Write data back to UART
|
||||
* uart_write_bytes(uart_num, (const char*)data, len);
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*-----------------------------------------------------------------------------*
|
||||
* @code{c}
|
||||
* //7. An example of using UART event queue on UART0.
|
||||
* #include "freertos/queue.h"
|
||||
* //A queue to handle UART event.
|
||||
* QueueHandle_t uart0_queue;
|
||||
* static const char *TAG = "uart_example";
|
||||
* void uart_task(void *pvParameters)
|
||||
* {
|
||||
* int uart_num = (int)pvParameters;
|
||||
* uart_event_t event;
|
||||
* size_t size = 1024;
|
||||
* uint8_t* dtmp = (uint8_t*)malloc(size);
|
||||
* for(;;) {
|
||||
* //Waiting for UART event.
|
||||
* if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
|
||||
* ESP_LOGI(TAG, "uart[%d] event:", uart_num);
|
||||
* switch(event.type) {
|
||||
* memset(dtmp, 0, size);
|
||||
* //Event of UART receving data
|
||||
* case UART_DATA:
|
||||
* ESP_LOGI(TAG,"data, len: %d", event.size);
|
||||
* int len = uart_read_bytes(uart_num, dtmp, event.size, 10);
|
||||
* ESP_LOGI(TAG, "uart read: %d", len);
|
||||
uart_write_bytes(uart_num, (const char*)dtmp, len);
|
||||
* break;
|
||||
* //Event of HW FIFO overflow detected
|
||||
* case UART_FIFO_OVF:
|
||||
* ESP_LOGI(TAG, "hw fifo overflow\n");
|
||||
* break;
|
||||
* //Event of UART ring buffer full
|
||||
* case UART_BUFFER_FULL:
|
||||
* ESP_LOGI(TAG, "ring buffer full\n");
|
||||
* break;
|
||||
* //Event of UART RX break detected
|
||||
* case UART_BREAK:
|
||||
* ESP_LOGI(TAG, "uart rx break\n");
|
||||
* break;
|
||||
* //Event of UART parity check error
|
||||
* case UART_PARITY_ERR:
|
||||
* ESP_LOGI(TAG, "uart parity error\n");
|
||||
* break;
|
||||
* //Event of UART frame error
|
||||
* case UART_FRAME_ERR:
|
||||
* ESP_LOGI(TAG, "uart frame error\n");
|
||||
* break;
|
||||
* //Others
|
||||
* default:
|
||||
* ESP_LOGI(TAG, "uart event type: %d\n", event.type);
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* free(dtmp);
|
||||
* dtmp = NULL;
|
||||
* vTaskDelete(NULL);
|
||||
* }
|
||||
*
|
||||
* void uart_queue_test()
|
||||
* {
|
||||
* int uart_num = 0;
|
||||
* uart_config_t uart_config = {
|
||||
* .baud_rate = 115200,
|
||||
* .data_bits = UART_DATA_8_BITS,
|
||||
* .parity = UART_PARITY_DISABLE,
|
||||
* .stop_bits = UART_STOP_BITS_1,
|
||||
* .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
* .rx_flow_ctrl_thresh = 122,
|
||||
* };
|
||||
* //Set UART parameters
|
||||
* uart_param_config(uart_num, &uart_config);
|
||||
* //Set UART pins,(-1: default pin, no change.)
|
||||
* uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
* //Set UART log level
|
||||
* esp_log_level_set(TAG, ESP_LOG_INFO);
|
||||
* //Install UART driver, and get the queue.
|
||||
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, &uart0_queue);
|
||||
* //Create a task to handler UART event from ISR
|
||||
* xTaskCreate(uart_task, "uTask", 1024, (void*)uart_num, 10, NULL);
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
***************************END OF EXAMPLE**********************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_DRIVER_UART_H_*/
|
|
@ -18,86 +18,19 @@
|
|||
#include "freertos/xtensa_api.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
//TODO: to use APIs in esp_log.h.
|
||||
#define LEDC_DBG_WARING_ENABLE (0)
|
||||
#define LEDC_DBG_ERROR_ENABLE (0)
|
||||
#define LEDC_INFO_ENABLE (0)
|
||||
#define LEDC_DBG_ENABLE (0)
|
||||
|
||||
//DBG INFOR
|
||||
#if LEDC_DBG_ENABLE
|
||||
#define LEDC_DBG(format,...) do{\
|
||||
ets_printf("[dbg][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define LEDC_DBG(...)
|
||||
#endif
|
||||
|
||||
#if LEDC_INFO_ENABLE
|
||||
#define LEDC_INFO(format,...) do{\
|
||||
ets_printf("[info][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define LEDC_INFO(...)
|
||||
#endif
|
||||
|
||||
#if LEDC_DBG_WARING_ENABLE
|
||||
#define LEDC_WARING(format,...) do{\
|
||||
ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define LEDC_WARING(...)
|
||||
#endif
|
||||
#if LEDC_DBG_ERROR_ENABLE
|
||||
#define LEDC_ERROR(format,...) do{\
|
||||
ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\
|
||||
ets_printf(format,##__VA_ARGS__);\
|
||||
}while(0)
|
||||
#else
|
||||
#define LEDC_ERROR(...)
|
||||
#endif
|
||||
|
||||
static const char* LEDC_TAG = "LEDC";
|
||||
static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static bool ledc_is_valid_channel(uint32_t channel)
|
||||
{
|
||||
if(channel > LEDC_CHANNEL_7) {
|
||||
LEDC_ERROR("LEDC CHANNEL ERR: %d\n",channel);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ledc_is_valid_mode(uint32_t mode)
|
||||
{
|
||||
if(mode >= LEDC_SPEED_MODE_MAX) {
|
||||
LEDC_ERROR("LEDC MODE ERR: %d\n",mode);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ledc_is_valid_timer(int timer)
|
||||
{
|
||||
if(timer > LEDC_TIMER_3) {
|
||||
LEDC_ERROR("LEDC TIMER ERR: %d\n", timer);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#define LEDC_CHECK(a, str, ret_val) if (!(a)) { \
|
||||
ESP_LOGE(LEDC_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret_val); \
|
||||
}
|
||||
|
||||
esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_timer(timer_sel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.div_num = div_num;
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src;
|
||||
|
@ -125,12 +58,8 @@ static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, uint32_t channel_num,
|
|||
|
||||
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_timer(timer_idx)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_idx <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx;
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
|
@ -139,12 +68,8 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint
|
|||
|
||||
esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_timer(timer_sel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 1;
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
|
||||
|
@ -154,12 +79,8 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
|
|||
|
||||
esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_timer(timer_sel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
|
@ -168,12 +89,8 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
|
|||
|
||||
esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_timer(timer_sel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
|
@ -182,9 +99,7 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
|
|||
|
||||
static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
uint32_t value;
|
||||
uint32_t intr_type = type;
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
|
@ -200,9 +115,7 @@ static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel,
|
|||
|
||||
esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg)
|
||||
{
|
||||
if(fn == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(fn, "ledc isr null", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
ESP_INTR_DISABLE(ledc_intr_num);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_LEDC_INTR_SOURCE, ledc_intr_num);
|
||||
|
@ -218,16 +131,13 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
|
|||
int bit_num = timer_conf->bit_num;
|
||||
int timer_num = timer_conf->timer_num;
|
||||
int speed_mode = timer_conf->speed_mode;
|
||||
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
if(freq_hz == 0 || bit_num == 0 || bit_num > LEDC_TIMER_15_BIT) {
|
||||
LEDC_ERROR("freq_hz=%u bit_num=%u\n", freq_hz, bit_num);
|
||||
ESP_LOGE(LEDC_TAG, "freq_hz=%u bit_num=%u", freq_hz, bit_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(timer_num > LEDC_TIMER_3) {
|
||||
LEDC_ERROR("Time Select %u\n", timer_num);
|
||||
ESP_LOGE(LEDC_TAG, "Time Select %u", timer_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
@ -239,7 +149,7 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
|
|||
/*Selet the reference tick*/
|
||||
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||
if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
LEDC_ERROR("div param err,div_param=%u\n", div_param);
|
||||
ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", (uint32_t)div_param);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
timer_clk_src = LEDC_REF_TICK;
|
||||
|
@ -254,6 +164,21 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
|
|||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel)
|
||||
{
|
||||
LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
if(speed_mode == LEDC_HIGH_SPEED_MODE) {
|
||||
gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0);
|
||||
} else {
|
||||
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
||||
{
|
||||
uint32_t speed_mode = ledc_conf->speed_mode;
|
||||
|
@ -262,21 +187,10 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
|||
uint32_t timer_select = ledc_conf->timer_sel;
|
||||
uint32_t intr_type = ledc_conf->intr_type;
|
||||
uint32_t duty = ledc_conf->duty;
|
||||
|
||||
if(!ledc_is_valid_channel(ledc_channel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)) {
|
||||
LEDC_ERROR("GPIO number error: IO%d\n ", gpio_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(timer_select > LEDC_TIMER_3) {
|
||||
LEDC_ERROR("Time Select %u\n", timer_select);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_select <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
esp_err_t ret = ESP_OK;
|
||||
/*set channel parameters*/
|
||||
/* channel parameters decide how the waveform looks like in one period*/
|
||||
|
@ -288,7 +202,7 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
|||
ledc_bind_channel_timer(speed_mode, ledc_channel, timer_select);
|
||||
/*set interrupt type*/
|
||||
ledc_enable_intr_type(speed_mode, ledc_channel, intr_type);
|
||||
LEDC_INFO("LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u\n",
|
||||
ESP_LOGI(LEDC_TAG, "LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u",
|
||||
ledc_channel, gpio_num, duty, timer_select
|
||||
);
|
||||
/*set LEDC signal in gpio matrix*/
|
||||
|
@ -300,12 +214,8 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
|||
|
||||
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_channel(channel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1;
|
||||
|
@ -315,12 +225,8 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
|||
|
||||
esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_channel(channel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.idle_lv = idle_level & 0x1;
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 0;
|
||||
|
@ -331,18 +237,11 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl
|
|||
esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t fade_direction,
|
||||
uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_channel(channel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(fade_direction > LEDC_DUTY_DIR_INCREASE) {
|
||||
LEDC_ERROR("Duty direction err\n");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(fade_direction <= LEDC_DUTY_DIR_INCREASE, "ledc fade direction error", ESP_ERR_INVALID_ARG);
|
||||
if(step_num > LEDC_DUTY_NUM_HSCH0_V || duty_cyle_num > LEDC_DUTY_CYCLE_HSCH0_V || duty_scale > LEDC_DUTY_SCALE_HSCH0_V) {
|
||||
LEDC_ERROR("step_num=%u duty_cyle_num=%u duty_scale=%u\n", step_num, duty_cyle_num, duty_scale);
|
||||
ESP_LOGE(LEDC_TAG, "step_num=%u duty_cyle_num=%u duty_scale=%u", step_num, duty_cyle_num, duty_scale);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ledc_duty_config(speed_mode,
|
||||
|
@ -359,12 +258,8 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty,
|
|||
|
||||
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(!ledc_is_valid_channel(channel)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
ledc_duty_config(speed_mode,
|
||||
channel, //uint32_t chan_num,
|
||||
0, //uint32_t hpoint_val,
|
||||
|
@ -379,18 +274,14 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
|
|||
|
||||
int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return -1;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (-1));
|
||||
uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4);
|
||||
return duty;
|
||||
}
|
||||
|
||||
esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t div_num = 0;
|
||||
|
@ -403,7 +294,7 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t
|
|||
div_num = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||
}
|
||||
if(div_num <= 256 || div_num > LEDC_DIV_NUM_HSTIMER0) {
|
||||
LEDC_ERROR("div param err,div_param=%u\n", div_num);
|
||||
ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", div_num);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num = div_num;
|
||||
|
@ -413,9 +304,7 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t
|
|||
|
||||
uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)
|
||||
{
|
||||
if(!ledc_is_valid_mode(speed_mode)) {
|
||||
return 0;
|
||||
}
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (0));
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
uint32_t freq = 0;
|
||||
uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;
|
||||
|
|
|
@ -25,6 +25,10 @@ void periph_module_enable(periph_module_t periph)
|
|||
{
|
||||
portENTER_CRITICAL(&periph_spinlock);
|
||||
switch(periph) {
|
||||
case PERIPH_RMT_MODULE:
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST);
|
||||
break;
|
||||
case PERIPH_LEDC_MODULE:
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
|
||||
|
|
|
@ -0,0 +1,717 @@
|
|||
// 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 <esp_types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "esp_intr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "driver/rmt.h"
|
||||
|
||||
#define RMT_SOUCCE_CLK_APB (APB_CLK_FREQ) /*!< RMT source clock is APB_CLK */
|
||||
#define RMT_SOURCE_CLK_REF (1 * 1000000) /*!< not used yet */
|
||||
#define RMT_SOURCE_CLK(select) ((select == RMT_BASECLK_REF) ? (RMT_SOURCE_CLK_REF) : (RMT_SOUCCE_CLK_APB)) /*! RMT source clock frequency */
|
||||
|
||||
#define RMT_CHANNEL_ERROR_STR "RMT CHANNEL ERR"
|
||||
#define RMT_ADDR_ERROR_STR "RMT ADDRESS ERR"
|
||||
#define RMT_MEM_CNT_ERROR_STR "RMT MEM BLOCK NUM ERR"
|
||||
#define RMT_CARRIER_ERROR_STR "RMT CARRIER LEVEL ERR"
|
||||
#define RMT_MEM_OWNER_ERROR_STR "RMT MEM OWNER_ERR"
|
||||
#define RMT_BASECLK_ERROR_STR "RMT BASECLK ERR"
|
||||
#define RMT_WR_MEM_OVF_ERROR_STR "RMT WR MEM OVERFLOW"
|
||||
#define RMT_GPIO_ERROR_STR "RMT GPIO ERROR"
|
||||
#define RMT_MODE_ERROR_STR "RMT MODE ERROR"
|
||||
#define RMT_CLK_DIV_ERROR_STR "RMT CLK DIV ERR"
|
||||
#define RMT_DRIVER_ERROR_STR "RMT DRIVER ERR"
|
||||
#define RMT_DRIVER_LENGTH_ERROR_STR "RMT PARAM LEN ERROR"
|
||||
|
||||
static const char* RMT_TAG = "RMT";
|
||||
static bool s_rmt_driver_installed = false;
|
||||
|
||||
#define RMT_CHECK(a, str, ret) if (!(a)) { \
|
||||
ESP_LOGE(RMT_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret); \
|
||||
}
|
||||
static portMUX_TYPE rmt_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
typedef struct {
|
||||
int tx_offset;
|
||||
int tx_len_rem;
|
||||
int tx_sub_len;
|
||||
rmt_channel_t channel;
|
||||
rmt_item32_t* tx_data;
|
||||
xSemaphoreHandle tx_sem;
|
||||
RingbufHandle_t tx_buf;
|
||||
RingbufHandle_t rx_buf;
|
||||
} rmt_obj_t;
|
||||
|
||||
rmt_obj_t* p_rmt_obj[RMT_CHANNEL_MAX] = {0};
|
||||
|
||||
static void rmt_set_tx_wrap_en(rmt_channel_t channel, bool en)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.apb_conf.mem_tx_wrap_en = en;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
}
|
||||
|
||||
static void rmt_set_data_mode(rmt_data_mode_t data_mode)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.apb_conf.fifo_mask = data_mode;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_clk_div(rmt_channel_t channel, uint8_t div_cnt)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.conf_ch[channel].conf0.div_cnt = div_cnt;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_clk_div(rmt_channel_t channel, uint8_t* div_cnt)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(div_cnt != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*div_cnt = RMT.conf_ch[channel].conf0.div_cnt;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_rx_idle_thresh(rmt_channel_t channel, uint16_t thresh)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.conf_ch[channel].conf0.idle_thres = thresh;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_rx_idle_thresh(rmt_channel_t channel, uint16_t *thresh)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(thresh != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*thresh = RMT.conf_ch[channel].conf0.idle_thres;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_mem_block_num(rmt_channel_t channel, uint8_t rmt_mem_num)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(rmt_mem_num < 16, RMT_MEM_CNT_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.conf_ch[channel].conf0.mem_size = rmt_mem_num;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_mem_block_num(rmt_channel_t channel, uint8_t* rmt_mem_num)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(rmt_mem_num != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*rmt_mem_num = RMT.conf_ch[channel].conf0.mem_size;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_tx_carrier(rmt_channel_t channel, bool carrier_en, uint16_t high_level, uint16_t low_level,
|
||||
rmt_carrier_level_t carrier_level)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(carrier_level < RMT_CARRIER_LEVEL_MAX, RMT_CARRIER_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.carrier_duty_ch[channel].high = high_level;
|
||||
RMT.carrier_duty_ch[channel].low = low_level;
|
||||
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
|
||||
RMT.conf_ch[channel].conf0.carrier_en = carrier_en;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.conf_ch[channel].conf0.mem_pd = pd_en;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool* pd_en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*pd_en = (bool) RMT.conf_ch[channel].conf0.mem_pd;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_tx_start(rmt_channel_t channel, bool tx_idx_rst)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
if(tx_idx_rst) {
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
}
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX;
|
||||
RMT.conf_ch[channel].conf1.tx_start = 1;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_tx_stop(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.tx_start = 0;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_rx_start(rmt_channel_t channel, bool rx_idx_rst)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
if(rx_idx_rst) {
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
}
|
||||
RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX;
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_rx_stop(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_memory_rw_rst(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_memory_owner(rmt_channel_t channel, rmt_mem_owner_t owner)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(owner < RMT_MEM_OWNER_MAX, RMT_MEM_OWNER_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.mem_owner = owner;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_memory_owner(rmt_channel_t channel, rmt_mem_owner_t* owner)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(owner != NULL, RMT_MEM_OWNER_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*owner = (rmt_mem_owner_t) RMT.conf_ch[channel].conf1.mem_owner;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_tx_loop_mode(rmt_channel_t channel, bool loop_en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = loop_en;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_tx_loop_mode(rmt_channel_t channel, bool* loop_en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*loop_en = (bool) RMT.conf_ch[channel].conf1.tx_conti_mode;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_rx_filter(rmt_channel_t channel, bool rx_filter_en, uint8_t thresh)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.rx_filter_en = rx_filter_en;
|
||||
RMT.conf_ch[channel].conf1.rx_filter_thres = thresh;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(base_clk < RMT_BASECLK_MAX, RMT_BASECLK_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = base_clk;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_source_clk(rmt_channel_t channel, rmt_source_clk_t* src_clk)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*src_clk = (rmt_source_clk_t) (RMT.conf_ch[channel].conf1.ref_always_on);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_idle_level(rmt_channel_t channel, bool idle_out_en, rmt_idle_level_t level)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(level < RMT_IDLE_LEVEL_MAX, "RMT IDLE LEVEL ERR", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.idle_out_en = idle_out_en;
|
||||
RMT.conf_ch[channel].conf1.idle_out_lv = level;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_status(rmt_channel_t channel, uint32_t* status)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*status = RMT.status_ch[channel];
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
rmt_data_mode_t rmt_get_data_mode()
|
||||
{
|
||||
return (rmt_data_mode_t) (RMT.apb_conf.fifo_mask);
|
||||
}
|
||||
|
||||
void rmt_set_intr_enable_mask(uint32_t mask)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.int_ena.val |= mask;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
}
|
||||
|
||||
void rmt_clr_intr_enable_mask(uint32_t mask)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.int_ena.val &= (~mask);
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_rx_intr_en(rmt_channel_t channel, bool en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(en) {
|
||||
rmt_set_intr_enable_mask(BIT(channel * 3 + 1));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel * 3 + 1));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_err_intr_en(rmt_channel_t channel, bool en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(en) {
|
||||
rmt_set_intr_enable_mask(BIT(channel * 3 + 2));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel * 3 + 2));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(en) {
|
||||
rmt_set_intr_enable_mask(BIT(channel * 3));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel * 3));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_evt_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(evt_thresh < 256, "RMT EVT THRESH ERR", ESP_ERR_INVALID_ARG);
|
||||
if(en) {
|
||||
RMT.tx_lim_ch[channel].limit = evt_thresh;
|
||||
rmt_set_tx_wrap_en(channel, true);
|
||||
rmt_set_intr_enable_mask(BIT(channel + 24));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel + 24));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(mode < RMT_MODE_MAX, RMT_MODE_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(((GPIO_IS_VALID_GPIO(gpio_num) && (mode == RMT_MODE_RX)) || (GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) && (mode == RMT_MODE_TX))),
|
||||
RMT_GPIO_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], 2);
|
||||
if(mode == RMT_MODE_TX) {
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
gpio_matrix_out(gpio_num, RMT_SIG_OUT0_IDX + channel, 0, 0);
|
||||
} else {
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
|
||||
gpio_matrix_in(gpio_num, RMT_SIG_IN0_IDX + channel, 0);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_config(rmt_config_t* rmt_param)
|
||||
{
|
||||
uint8_t mode = rmt_param->rmt_mode;
|
||||
uint8_t channel = rmt_param->channel;
|
||||
uint8_t gpio_num = rmt_param->gpio_num;
|
||||
uint8_t mem_cnt = rmt_param->mem_block_num;
|
||||
int clk_div = rmt_param->clk_div;
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(GPIO_IS_VALID_GPIO(gpio_num), RMT_GPIO_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK((mem_cnt + channel <= 8 && mem_cnt > 0), RMT_MEM_CNT_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK((clk_div > 0), RMT_CLK_DIV_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
periph_module_enable(PERIPH_RMT_MODULE);
|
||||
|
||||
RMT.conf_ch[channel].conf0.div_cnt = clk_div;
|
||||
/*Visit data use memory not FIFO*/
|
||||
rmt_set_data_mode(RMT_DATA_MODE_MEM);
|
||||
/*Reset tx/rx memory index */
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
|
||||
if(mode == RMT_MODE_TX) {
|
||||
uint32_t rmt_source_clk_hz = 0;
|
||||
uint32_t carrier_freq_hz = rmt_param->tx_config.carrier_freq_hz;
|
||||
uint16_t carrier_duty_percent = rmt_param->tx_config.carrier_duty_percent;
|
||||
uint8_t carrier_level = rmt_param->tx_config.carrier_level;
|
||||
uint8_t idle_level = rmt_param->tx_config.idle_level;
|
||||
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = rmt_param->tx_config.loop_en;
|
||||
/*Memory set block number*/
|
||||
RMT.conf_ch[channel].conf0.mem_size = mem_cnt;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX;
|
||||
/*We use APB clock in this version, which is 80Mhz, later we will release system reference clock*/
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = RMT_BASECLK_APB;
|
||||
rmt_source_clk_hz = RMT_SOURCE_CLK(RMT_BASECLK_APB);
|
||||
/*Set idle level */
|
||||
RMT.conf_ch[channel].conf1.idle_out_en = rmt_param->tx_config.idle_output_en;
|
||||
RMT.conf_ch[channel].conf1.idle_out_lv = idle_level;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
|
||||
/*Set carrier*/
|
||||
uint32_t duty_div, duty_h, duty_l;
|
||||
duty_div = rmt_source_clk_hz / carrier_freq_hz;
|
||||
duty_h = duty_div * carrier_duty_percent / 100;
|
||||
duty_l = duty_div - duty_h;
|
||||
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
|
||||
RMT.carrier_duty_ch[channel].high = duty_h;
|
||||
RMT.carrier_duty_ch[channel].low = duty_l;
|
||||
RMT.conf_ch[channel].conf0.carrier_en = rmt_param->tx_config.carrier_en;
|
||||
ESP_LOGD(RMT_TAG, "Rmt Tx Channel %u|Gpio %u|Sclk_Hz %u|Div %u|Carrier_Hz %u|Duty %u",
|
||||
channel, gpio_num, rmt_source_clk_hz, clk_div, carrier_freq_hz, carrier_duty_percent);
|
||||
}
|
||||
else if(RMT_MODE_RX == mode) {
|
||||
uint8_t filter_cnt = rmt_param->rx_config.filter_ticks_thresh;
|
||||
uint16_t threshold = rmt_param->rx_config.idle_threshold;
|
||||
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
/*clock init*/
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = RMT_BASECLK_APB;
|
||||
uint32_t rmt_source_clk_hz = RMT_SOURCE_CLK(RMT_BASECLK_APB);
|
||||
/*memory set block number and owner*/
|
||||
RMT.conf_ch[channel].conf0.mem_size = mem_cnt;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX;
|
||||
/*Set idle threshold*/
|
||||
RMT.conf_ch[channel].conf0.idle_thres = threshold;
|
||||
/* Set RX filter */
|
||||
RMT.conf_ch[channel].conf1.rx_filter_thres = filter_cnt;
|
||||
RMT.conf_ch[channel].conf1.rx_filter_en = rmt_param->rx_config.filter_en;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
|
||||
ESP_LOGD(RMT_TAG, "Rmt Rx Channel %u|Gpio %u|Sclk_Hz %u|Div %u|Thresold %u|Filter %u",
|
||||
channel, gpio_num, rmt_source_clk_hz, clk_div, threshold, filter_cnt);
|
||||
}
|
||||
rmt_set_pin(channel, mode, gpio_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR rmt_fill_memory(rmt_channel_t channel, rmt_item32_t* item, uint16_t item_num, uint16_t mem_offset)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.apb_conf.fifo_mask = RMT_DATA_MODE_MEM;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
int i;
|
||||
for(i = 0; i < item_num; i++) {
|
||||
RMTMEM.chan[channel].data32[i + mem_offset].val = item[i].val;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t rmt_fill_tx_items(rmt_channel_t channel, rmt_item32_t* item, uint16_t item_num, uint16_t mem_offset)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, (0));
|
||||
RMT_CHECK((item != NULL), RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK((item_num > 0), RMT_DRIVER_LENGTH_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
/*Each block has 64 x 32 bits of data*/
|
||||
uint8_t mem_cnt = RMT.conf_ch[channel].conf0.mem_size;
|
||||
RMT_CHECK((mem_cnt * RMT_MEM_ITEM_NUM >= item_num), RMT_WR_MEM_OVF_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
rmt_fill_memory(channel, item, item_num, mem_offset);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_isr_register(uint8_t rmt_intr_num, void (*fn)(void*), void * arg)
|
||||
{
|
||||
RMT_CHECK((fn != NULL), RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(s_rmt_driver_installed == false, "RMT DRIVER INSTALLED, CAN NOT REG ISR HANDLER", ESP_FAIL);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
ESP_INTR_DISABLE(rmt_intr_num);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_RMT_INTR_SOURCE, rmt_intr_num);
|
||||
xt_set_interrupt_handler(rmt_intr_num, fn, arg);
|
||||
ESP_INTR_ENABLE(rmt_intr_num);
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR rmt_get_mem_len(rmt_channel_t channel)
|
||||
{
|
||||
int block_num = RMT.conf_ch[channel].conf0.mem_size;
|
||||
int item_block_len = block_num * RMT_MEM_ITEM_NUM;
|
||||
volatile rmt_item32_t* data = RMTMEM.chan[channel].data32;
|
||||
int idx;
|
||||
for(idx = 0; idx < item_block_len; idx++) {
|
||||
if(data[idx].duration0 == 0) {
|
||||
return idx;
|
||||
} else if(data[idx].duration1 == 0) {
|
||||
return idx + 1;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR rmt_driver_isr_default(void* arg)
|
||||
{
|
||||
uint32_t intr_st = RMT.int_st.val;
|
||||
uint32_t i = 0;
|
||||
uint8_t channel;
|
||||
portBASE_TYPE HPTaskAwoken = 0;
|
||||
for(i = 0; i < 32; i++) {
|
||||
if(i < 24) {
|
||||
if(intr_st & (BIT(i))) {
|
||||
channel = i / 3;
|
||||
rmt_obj_t* p_rmt = p_rmt_obj[channel];
|
||||
switch(i % 3) {
|
||||
//TX END
|
||||
case 0:
|
||||
ESP_EARLY_LOGD(RMT_TAG, "RMT INTR : TX END\n");
|
||||
xSemaphoreGiveFromISR(p_rmt->tx_sem, &HPTaskAwoken);
|
||||
if(HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
p_rmt->tx_data = NULL;
|
||||
p_rmt->tx_len_rem = 0;
|
||||
p_rmt->tx_offset = 0;
|
||||
p_rmt->tx_sub_len = 0;
|
||||
break;
|
||||
//RX_END
|
||||
case 1:
|
||||
ESP_EARLY_LOGD(RMT_TAG, "RMT INTR : RX END");
|
||||
RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
int item_len = rmt_get_mem_len(channel);
|
||||
//change memory owner to protect data.
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX;
|
||||
if(p_rmt->rx_buf) {
|
||||
BaseType_t res = xRingbufferSendFromISR(p_rmt->rx_buf, (void*) RMTMEM.chan[channel].data32, item_len * 4, &HPTaskAwoken);
|
||||
if(res == pdFALSE) {
|
||||
ESP_LOGE(RMT_TAG, "RMT RX BUFFER FULL");
|
||||
} else {
|
||||
|
||||
}
|
||||
if(HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
} else {
|
||||
ESP_EARLY_LOGE(RMT_TAG, "RMT RX BUFFER ERROR\n");
|
||||
}
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX;
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
break;
|
||||
//ERR
|
||||
case 2:
|
||||
ESP_EARLY_LOGE(RMT_TAG, "RMT[%d] ERR", channel);
|
||||
ESP_EARLY_LOGE(RMT_TAG, "status: 0x%08x", RMT.status_ch[channel]);
|
||||
RMT.int_ena.val &= (~(BIT(i)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
RMT.int_clr.val = BIT(i);
|
||||
}
|
||||
} else {
|
||||
if(intr_st & (BIT(i))) {
|
||||
channel = i - 24;
|
||||
rmt_obj_t* p_rmt = p_rmt_obj[channel];
|
||||
RMT.int_clr.val = BIT(i);
|
||||
ESP_EARLY_LOGD(RMT_TAG, "RMT CH[%d]: EVT INTR", channel);
|
||||
if(p_rmt->tx_data == NULL) {
|
||||
//skip
|
||||
} else {
|
||||
rmt_item32_t* pdata = p_rmt->tx_data;
|
||||
int len_rem = p_rmt->tx_len_rem;
|
||||
if(len_rem >= p_rmt->tx_sub_len) {
|
||||
rmt_fill_memory(channel, pdata, p_rmt->tx_sub_len, p_rmt->tx_offset);
|
||||
p_rmt->tx_data += p_rmt->tx_sub_len;
|
||||
p_rmt->tx_len_rem -= p_rmt->tx_sub_len;
|
||||
} else if(len_rem == 0) {
|
||||
RMTMEM.chan[channel].data32[p_rmt->tx_offset].val = 0;
|
||||
} else {
|
||||
rmt_fill_memory(channel, pdata, len_rem, p_rmt->tx_offset);
|
||||
RMTMEM.chan[channel].data32[p_rmt->tx_offset + len_rem].val = 0;
|
||||
p_rmt->tx_data += len_rem;
|
||||
p_rmt->tx_len_rem -= len_rem;
|
||||
}
|
||||
if(p_rmt->tx_offset == 0) {
|
||||
p_rmt->tx_offset = p_rmt->tx_sub_len;
|
||||
} else {
|
||||
p_rmt->tx_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t rmt_driver_uninstall(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(p_rmt_obj[channel] == NULL) {
|
||||
return ESP_OK;
|
||||
}
|
||||
xSemaphoreTake(p_rmt_obj[channel]->tx_sem, portMAX_DELAY);
|
||||
rmt_set_rx_intr_en(channel, 0);
|
||||
rmt_set_err_intr_en(channel, 0);
|
||||
rmt_set_tx_intr_en(channel, 0);
|
||||
rmt_set_evt_intr_en(channel, 0, 0xffff);
|
||||
if(p_rmt_obj[channel]->tx_sem) {
|
||||
vSemaphoreDelete(p_rmt_obj[channel]->tx_sem);
|
||||
p_rmt_obj[channel]->tx_sem = NULL;
|
||||
}
|
||||
if(p_rmt_obj[channel]->rx_buf) {
|
||||
vRingbufferDelete(p_rmt_obj[channel]->rx_buf);
|
||||
p_rmt_obj[channel]->rx_buf = NULL;
|
||||
}
|
||||
free(p_rmt_obj[channel]);
|
||||
p_rmt_obj[channel] = NULL;
|
||||
s_rmt_driver_installed = false;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(p_rmt_obj[channel] != NULL) {
|
||||
ESP_LOGD(RMT_TAG, "RMT DRIVER ALREADY INSTALLED");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_INTR_DISABLE(rmt_intr_num);
|
||||
p_rmt_obj[channel] = (rmt_obj_t*) malloc(sizeof(rmt_obj_t));
|
||||
|
||||
if(p_rmt_obj[channel] == NULL) {
|
||||
ESP_LOGE(RMT_TAG, "RMT driver malloc error");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
memset(p_rmt_obj[channel], 0, sizeof(rmt_obj_t));
|
||||
|
||||
p_rmt_obj[channel]->tx_len_rem = 0;
|
||||
p_rmt_obj[channel]->tx_data = NULL;
|
||||
p_rmt_obj[channel]->channel = channel;
|
||||
p_rmt_obj[channel]->tx_offset = 0;
|
||||
p_rmt_obj[channel]->tx_sub_len = 0;
|
||||
|
||||
if(p_rmt_obj[channel]->tx_sem == NULL) {
|
||||
p_rmt_obj[channel]->tx_sem = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(p_rmt_obj[channel]->tx_sem);
|
||||
}
|
||||
if(p_rmt_obj[channel]->rx_buf == NULL && rx_buf_size > 0) {
|
||||
p_rmt_obj[channel]->rx_buf = xRingbufferCreate(rx_buf_size, RINGBUF_TYPE_NOSPLIT);
|
||||
rmt_set_rx_intr_en(channel, 1);
|
||||
rmt_set_err_intr_en(channel, 1);
|
||||
}
|
||||
if(s_rmt_driver_installed == false) {
|
||||
rmt_isr_register(rmt_intr_num, rmt_driver_isr_default, NULL);
|
||||
s_rmt_driver_installed = true;
|
||||
}
|
||||
rmt_set_tx_intr_en(channel, 1);
|
||||
ESP_INTR_ENABLE(rmt_intr_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_write_items(rmt_channel_t channel, rmt_item32_t* rmt_item, int item_num, bool wait_tx_done)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL);
|
||||
RMT_CHECK(rmt_item != NULL, RMT_ADDR_ERROR_STR, ESP_FAIL);
|
||||
RMT_CHECK(item_num > 0, RMT_DRIVER_LENGTH_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
rmt_obj_t* p_rmt = p_rmt_obj[channel];
|
||||
int block_num = RMT.conf_ch[channel].conf0.mem_size;
|
||||
int item_block_len = block_num * RMT_MEM_ITEM_NUM;
|
||||
int item_sub_len = block_num * RMT_MEM_ITEM_NUM / 2;
|
||||
int len_rem = item_num;
|
||||
xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY);
|
||||
// fill the memory block first
|
||||
if(item_num >= item_block_len) {
|
||||
rmt_fill_memory(channel, rmt_item, item_block_len, 0);
|
||||
RMT.tx_lim_ch[channel].limit = item_sub_len;
|
||||
RMT.apb_conf.mem_tx_wrap_en = 1;
|
||||
len_rem -= item_block_len;
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = 0;
|
||||
rmt_set_evt_intr_en(channel, 1, item_sub_len);
|
||||
p_rmt->tx_data = rmt_item + item_block_len;
|
||||
p_rmt->tx_len_rem = len_rem;
|
||||
p_rmt->tx_offset = 0;
|
||||
p_rmt->tx_sub_len = item_sub_len;
|
||||
} else {
|
||||
rmt_fill_memory(channel, rmt_item, len_rem, 0);
|
||||
RMTMEM.chan[channel].data32[len_rem].val = 0;
|
||||
len_rem = 0;
|
||||
}
|
||||
rmt_tx_start(channel, true);
|
||||
if(wait_tx_done) {
|
||||
xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY);
|
||||
xSemaphoreGive(p_rmt->tx_sem);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_wait_tx_done(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL);
|
||||
xSemaphoreTake(p_rmt_obj[channel]->tx_sem, portMAX_DELAY);
|
||||
xSemaphoreGive(p_rmt_obj[channel]->tx_sem);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_ringbuf_handler(rmt_channel_t channel, RingbufHandle_t* buf_handler)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL);
|
||||
RMT_CHECK(buf_handler != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*buf_handler = p_rmt_obj[channel]->rx_buf;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
Plik diff jest za duży
Load Diff
|
@ -319,6 +319,88 @@ config BROWNOUT_DET_RESETDELAY
|
|||
before trying to restart the chip. You can set the delay here.
|
||||
|
||||
|
||||
choice ESP32_TIME_SYSCALL
|
||||
prompt "Timers used for gettimeofday function"
|
||||
default ESP32_TIME_SYSCALL_USE_RTC_FRC1
|
||||
help
|
||||
This setting defines which hardware timers are used to
|
||||
implement 'gettimeofday' and 'time' functions in C library.
|
||||
|
||||
- If only FRC1 timer is used, gettimeofday will provide time at
|
||||
microsecond resolution. Time will not be preserved when going
|
||||
into deep sleep mode.
|
||||
- If both FRC1 and RTC timers are used, timekeeping will
|
||||
continue in deep sleep. Time will be reported at 1 microsecond
|
||||
resolution.
|
||||
- If only RTC timer is used, timekeeping will continue in
|
||||
deep sleep, but time will be measured at 6.(6) microsecond
|
||||
resolution. Also the gettimeofday function itself may take
|
||||
longer to run.
|
||||
- If no timers are used, gettimeofday and time functions
|
||||
return -1 and set errno to ENOSYS.
|
||||
|
||||
config ESP32_TIME_SYSCALL_USE_RTC
|
||||
bool "RTC"
|
||||
config ESP32_TIME_SYSCALL_USE_RTC_FRC1
|
||||
bool "RTC and FRC1"
|
||||
config ESP32_TIME_SYSCALL_USE_FRC1
|
||||
bool "FRC1"
|
||||
config ESP32_TIME_SYSCALL_USE_NONE
|
||||
bool "None"
|
||||
endchoice
|
||||
|
||||
choice ESP32_RTC_CLOCK_SOURCE
|
||||
prompt "RTC clock source"
|
||||
default ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
|
||||
help
|
||||
Choose which clock is used as RTC clock source.
|
||||
The only available option for now is to use internal
|
||||
150kHz RC oscillator.
|
||||
|
||||
config ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC
|
||||
bool "Internal RC"
|
||||
config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||
bool "External 32kHz crystal"
|
||||
depends on DOCUMENTATION_FOR_RTC_CNTL
|
||||
endchoice
|
||||
|
||||
|
||||
config ESP32_PHY_AUTO_INIT
|
||||
bool "Initialize PHY in startup code"
|
||||
default y
|
||||
help
|
||||
If enabled, PHY will be initialized in startup code, before
|
||||
app_main function runs.
|
||||
If this is undesired, disable this option and call esp_phy_init
|
||||
from the application before enabling WiFi or BT.
|
||||
|
||||
If this option is enabled, startup code will also initialize
|
||||
NVS prior to initializing PHY.
|
||||
|
||||
If unsure, choose 'y'.
|
||||
|
||||
config ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
bool "Use a partition to store PHY init data"
|
||||
default n
|
||||
help
|
||||
If enabled, PHY init data will be loaded from a partition.
|
||||
When using a custom partition table, make sure that PHY data
|
||||
partition is included (type: 'data', subtype: 'phy').
|
||||
With default partition tables, this is done automatically.
|
||||
If PHY init data is stored in a partition, it has to be flashed there,
|
||||
otherwise runtime error will occur.
|
||||
|
||||
If this option is not enabled, PHY init data will be embedded
|
||||
into the application binary.
|
||||
|
||||
If unsure, choose 'n'.
|
||||
|
||||
config ESP32_PHY_MAX_TX_POWER
|
||||
int "Max TX power (dBm)"
|
||||
range 0 20
|
||||
default 20
|
||||
help
|
||||
Set maximum transmit power. Actual transmit power for high
|
||||
data rates may be lower than this setting.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
ifdef CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
|
||||
PHY_INIT_DATA_OBJ = $(BUILD_DIR_BASE)/phy_init_data.o
|
||||
PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin
|
||||
|
||||
# Command to flash PHY init data partition
|
||||
PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN)
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN)
|
||||
|
||||
ESP32_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||
|
||||
$(PHY_INIT_DATA_OBJ): $(ESP32_COMPONENT_PATH)/phy_init_data.h $(BUILD_DIR_BASE)/include/sdkconfig.h
|
||||
$(summary) CC $(notdir $@)
|
||||
printf "#include \"phy_init_data.h\"\n" | $(CC) -I $(BUILD_DIR_BASE)/include -I $(ESP32_COMPONENT_PATH) -I $(ESP32_COMPONENT_PATH)/include -c -o $@ -xc -
|
||||
|
||||
$(PHY_INIT_DATA_BIN): $(PHY_INIT_DATA_OBJ)
|
||||
$(summary) BIN $(notdir $@)
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
|
||||
phy_init_data: $(PHY_INIT_DATA_BIN)
|
||||
|
||||
phy_init_data-flash: $(BUILD_DIR_BASE)/phy_init_data.bin
|
||||
@echo "Flashing PHY init data..."
|
||||
$(PHY_INIT_DATA_FLASH_CMD)
|
||||
|
||||
phy_init_data-clean:
|
||||
rm -f $(PHY_INIT_DATA_BIN) $(PHY_INIT_DATA_OBJ)
|
||||
|
||||
all: phy_init_data
|
||||
flash: phy_init_data
|
||||
|
||||
endif # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
|
@ -1,33 +1,23 @@
|
|||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
-include include/config/auto.conf
|
||||
|
||||
COMPONENT_SRCDIRS := . hwcrypto
|
||||
|
||||
LIBS := crypto core net80211 phy rtc pp wpa smartconfig coexist
|
||||
LIBS := core net80211 phy rtc pp wpa smartconfig coexist wps
|
||||
|
||||
LINKER_SCRIPTS += -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld
|
||||
|
||||
COMPONENT_ADD_LDFLAGS := -lesp32 \
|
||||
$(abspath libhal.a) \
|
||||
-L$(abspath lib) \
|
||||
$(COMPONENT_PATH)/libhal.a \
|
||||
-L$(COMPONENT_PATH)/lib \
|
||||
$(addprefix -l,$(LIBS)) \
|
||||
-L $(abspath ld) \
|
||||
-L $(COMPONENT_PATH)/ld \
|
||||
$(LINKER_SCRIPTS)
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
||||
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
||||
|
||||
# automatically trigger a git submodule update
|
||||
# if any libraries are missing
|
||||
$(eval $(call SubmoduleCheck,$(ALL_LIB_FILES),$(COMPONENT_PATH)/lib))
|
||||
COMPONENT_SUBMODULES += lib
|
||||
|
||||
# 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
|
||||
|
@ -44,8 +34,6 @@ $(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
|
|||
# saves us from having to add the target to a Makefile.projbuild
|
||||
$(COMPONENT_LIBRARY): esp32_out.ld
|
||||
|
||||
# .. is BUILD_DIR_BASE here, as component makefiles
|
||||
# are evaluated with CWD=component build dir
|
||||
esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h
|
||||
$(CC) -I ../include -C -P -x c -E $< -o $@
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/uart.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "rom/cache.h"
|
||||
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/dport_reg.h"
|
||||
|
@ -48,6 +50,7 @@
|
|||
#include "esp_brownout.h"
|
||||
#include "esp_int_wdt.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "trax.h"
|
||||
|
||||
void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
|
||||
|
@ -60,11 +63,14 @@ static bool app_cpu_started = false;
|
|||
#endif //!CONFIG_FREERTOS_UNICORE
|
||||
|
||||
static void do_global_ctors(void);
|
||||
static void do_phy_init();
|
||||
static void main_task(void* args);
|
||||
extern void app_main(void);
|
||||
|
||||
extern int _bss_start;
|
||||
extern int _bss_end;
|
||||
extern int _rtc_bss_start;
|
||||
extern int _rtc_bss_end;
|
||||
extern int _init_start;
|
||||
extern void (*__init_array_start)(void);
|
||||
extern void (*__init_array_end)(void);
|
||||
|
@ -95,6 +101,11 @@ void IRAM_ATTR call_start_cpu0()
|
|||
|
||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
||||
|
||||
/* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */
|
||||
if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) {
|
||||
memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start));
|
||||
}
|
||||
|
||||
// Initialize heap allocator
|
||||
heap_alloc_caps_init();
|
||||
|
||||
|
@ -102,7 +113,9 @@ void IRAM_ATTR call_start_cpu0()
|
|||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
|
||||
|
||||
//Flush and enable icache for APP CPU
|
||||
Cache_Flush(1);
|
||||
Cache_Read_Enable(1);
|
||||
//Un-stall the app cpu; the panic handler may have stalled it.
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M);
|
||||
|
@ -161,13 +174,14 @@ void start_cpu0_default(void)
|
|||
#if CONFIG_TASK_WDT
|
||||
esp_task_wdt_init();
|
||||
#endif
|
||||
esp_setup_syscalls();
|
||||
esp_setup_syscall_table();
|
||||
esp_setup_time_syscalls();
|
||||
esp_vfs_dev_uart_register();
|
||||
esp_reent_init(_GLOBAL_REENT);
|
||||
const char* default_uart_dev = "/dev/uart/0";
|
||||
_GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r");
|
||||
_GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w");
|
||||
_GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w");
|
||||
_GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r");
|
||||
do_global_ctors();
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
esp_crosscore_int_init();
|
||||
|
@ -175,6 +189,11 @@ void start_cpu0_default(void)
|
|||
esp_ipc_init();
|
||||
spi_flash_init();
|
||||
|
||||
#if CONFIG_ESP32_PHY_AUTO_INIT
|
||||
nvs_flash_init();
|
||||
do_phy_init();
|
||||
#endif
|
||||
|
||||
xTaskCreatePinnedToCore(&main_task, "main",
|
||||
ESP_TASK_MAIN_STACK, NULL,
|
||||
ESP_TASK_MAIN_PRIO, NULL, 0);
|
||||
|
@ -212,3 +231,36 @@ static void main_task(void* args)
|
|||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void do_phy_init()
|
||||
{
|
||||
esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL;
|
||||
if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
|
||||
calibration_mode = PHY_RF_CAL_NONE;
|
||||
}
|
||||
const esp_phy_init_data_t* init_data = esp_phy_get_init_data();
|
||||
if (init_data == NULL) {
|
||||
ESP_LOGE(TAG, "failed to obtain PHY init data");
|
||||
abort();
|
||||
}
|
||||
esp_phy_calibration_data_t* cal_data =
|
||||
(esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1);
|
||||
if (cal_data == NULL) {
|
||||
ESP_LOGE(TAG, "failed to allocate memory for RF calibration data");
|
||||
abort();
|
||||
}
|
||||
esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration");
|
||||
calibration_mode = PHY_RF_CAL_FULL;
|
||||
}
|
||||
|
||||
esp_phy_init(init_data, calibration_mode, cal_data);
|
||||
|
||||
if (calibration_mode != PHY_RF_CAL_NONE) {
|
||||
err = esp_phy_store_cal_data_to_nvs(cal_data);
|
||||
} else {
|
||||
err = ESP_OK;
|
||||
}
|
||||
esp_phy_release_init_data(init_data);
|
||||
free(cal_data); // PHY maintains a copy of calibration data, so we can free this
|
||||
}
|
||||
|
|
|
@ -45,14 +45,9 @@ the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably
|
|||
*/
|
||||
static void esp_crosscore_isr(void *arg) {
|
||||
uint32_t myReasonVal;
|
||||
#if 0
|
||||
//A pointer to the correct reason array item is passed to this ISR.
|
||||
volatile uint32_t *myReason=arg;
|
||||
#else
|
||||
//The previous line does not work yet, the interrupt code needs work to understand two separate interrupt and argument
|
||||
//tables... this is a valid but slightly less optimal replacement.
|
||||
volatile uint32_t *myReason=&reason[xPortGetCoreID()];
|
||||
#endif
|
||||
|
||||
//Clear the interrupt first.
|
||||
if (xPortGetCoreID()==0) {
|
||||
WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0);
|
||||
|
|
|
@ -40,8 +40,7 @@ void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub)
|
|||
}
|
||||
|
||||
void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) {
|
||||
//
|
||||
//mmu_init(0);
|
||||
/* Clear MMU for CPU 0 */
|
||||
REG_SET_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR);
|
||||
REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wifi_internal.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_event_loop.h"
|
||||
#include "esp_task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
@ -66,6 +68,10 @@ static system_event_handle_t g_system_event_handle_table[] = {
|
|||
{SYSTEM_EVENT_STA_DISCONNECTED, system_event_sta_disconnected_handle_default},
|
||||
{SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
|
||||
{SYSTEM_EVENT_STA_GOT_IP, system_event_sta_got_ip_default},
|
||||
{SYSTEM_EVENT_STA_WPS_ER_SUCCESS, NULL},
|
||||
{SYSTEM_EVENT_STA_WPS_ER_FAILED, NULL},
|
||||
{SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, NULL},
|
||||
{SYSTEM_EVENT_STA_WPS_ER_PIN, NULL},
|
||||
{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},
|
||||
|
@ -76,8 +82,7 @@ static system_event_handle_t g_system_event_handle_table[] = {
|
|||
|
||||
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);
|
||||
WIFI_API_CALL_CHECK("esp_wifi_internal_set_sta_ip", esp_wifi_internal_set_sta_ip(), ESP_OK);
|
||||
|
||||
ESP_LOGI(TAG, "ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR,
|
||||
IP2STR(&event->event_info.got_ip.ip_info.ip),
|
||||
|
@ -92,7 +97,7 @@ esp_err_t system_event_ap_start_handle_default(system_event_t *event)
|
|||
tcpip_adapter_ip_info_t ap_ip;
|
||||
uint8_t ap_mac[6];
|
||||
|
||||
WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_AP, (wifi_rxcb_t)tcpip_adapter_ap_input), ESP_OK);
|
||||
WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(WIFI_IF_AP, (wifi_rxcb_t)tcpip_adapter_ap_input), ESP_OK);
|
||||
WIFI_API_CALL_CHECK("esp_wifi_mac_get", esp_wifi_get_mac(WIFI_IF_AP, ap_mac), ESP_OK);
|
||||
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ap_ip);
|
||||
|
@ -103,7 +108,7 @@ esp_err_t system_event_ap_start_handle_default(system_event_t *event)
|
|||
|
||||
esp_err_t system_event_ap_stop_handle_default(system_event_t *event)
|
||||
{
|
||||
WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_AP, NULL), ESP_OK);
|
||||
WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(WIFI_IF_AP, NULL), ESP_OK);
|
||||
|
||||
tcpip_adapter_stop(TCPIP_ADAPTER_IF_AP);
|
||||
|
||||
|
@ -133,7 +138,7 @@ 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);
|
||||
WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(WIFI_IF_STA, (wifi_rxcb_t)tcpip_adapter_sta_input), ESP_OK);
|
||||
|
||||
tcpip_adapter_up(TCPIP_ADAPTER_IF_STA);
|
||||
|
||||
|
@ -165,7 +170,7 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event)
|
|||
esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event)
|
||||
{
|
||||
tcpip_adapter_down(TCPIP_ADAPTER_IF_STA);
|
||||
WIFI_API_CALL_CHECK("esp_wifi_reg_rxcb", esp_wifi_reg_rxcb(WIFI_IF_STA, NULL), ESP_OK);
|
||||
WIFI_API_CALL_CHECK("esp_wifi_internal_reg_rxcb", esp_wifi_internal_reg_rxcb(WIFI_IF_STA, NULL), ESP_OK);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -196,16 +201,14 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
|
|||
}
|
||||
case SYSTEM_EVENT_STA_CONNECTED: {
|
||||
system_event_sta_connected_t *connected = &event->event_info.connected;
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_CONNECTED, ssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d", \
|
||||
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);
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_CONNECTED, ssid:%s, ssid_len:%d, bssid:" MACSTR ", channel:%d, authmode:%d", \
|
||||
connected->ssid, connected->ssid_len, MAC2STR(connected->bssid), connected->channel, connected->authmode);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED: {
|
||||
system_event_sta_disconnected_t *disconnected = &event->event_info.disconnected;
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_DISCONNECTED, ssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d", \
|
||||
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);
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_DISCONNECTED, ssid:%s, ssid_len:%d, bssid:" MACSTR ", reason:%d", \
|
||||
disconnected->ssid, disconnected->ssid_len, MAC2STR(disconnected->bssid), disconnected->reason);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: {
|
||||
|
@ -221,6 +224,22 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
|
|||
IP2STR(&got_ip->ip_info.gw));
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS: {
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_SUCCESS");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_WPS_ER_FAILED: {
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_FAILED");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT: {
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_TIMEOUT");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_STA_WPS_ER_PIN: {
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PIN");
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_AP_START: {
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START");
|
||||
break;
|
||||
|
@ -231,23 +250,21 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
|
|||
}
|
||||
case SYSTEM_EVENT_AP_STACONNECTED: {
|
||||
system_event_ap_staconnected_t *staconnected = &event->event_info.sta_connected;
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STACONNECTED, mac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d", \
|
||||
staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \
|
||||
staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid);
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STACONNECTED, mac:" MACSTR ", aid:%d", \
|
||||
MAC2STR(staconnected->mac), staconnected->aid);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_AP_STADISCONNECTED: {
|
||||
system_event_ap_stadisconnected_t *stadisconnected = &event->event_info.sta_disconnected;
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED, mac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d", \
|
||||
stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \
|
||||
stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid);
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED, mac:" MACSTR ", aid:%d", \
|
||||
MAC2STR(stadisconnected->mac), stadisconnected->aid);
|
||||
break;
|
||||
}
|
||||
case SYSTEM_EVENT_AP_PROBEREQRECVED: {
|
||||
system_event_ap_probe_req_rx_t *ap_probereqrecved = &event->event_info.ap_probereqrecved;
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_PROBEREQRECVED, rssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x", \
|
||||
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]);
|
||||
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_PROBEREQRECVED, rssi:%d, mac:" MACSTR, \
|
||||
ap_probereqrecved->rssi, \
|
||||
MAC2STR(ap_probereqrecved->mac));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
// 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
|
||||
//We use just a static array here because it's not expected many components will need
|
||||
//an idle or tick hook.
|
||||
#define MAX_HOOKS 8
|
||||
|
||||
static esp_freertos_idle_cb_t idle_cb[MAX_HOOKS]={0};
|
||||
static esp_freertos_tick_cb_t tick_cb[MAX_HOOKS]={0};
|
||||
|
||||
void IRAM_ATTR esp_vApplicationTickHook()
|
||||
{
|
||||
int n;
|
||||
for (n=0; n<MAX_HOOKS; n++) {
|
||||
if (tick_cb[n]!=NULL) {
|
||||
tick_cb[n]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void esp_vApplicationIdleHook()
|
||||
{
|
||||
bool doWait=true;
|
||||
bool r;
|
||||
int n;
|
||||
for (n=0; n<MAX_HOOKS; n++) {
|
||||
if (idle_cb[n]!=NULL) {
|
||||
r=idle_cb[n]();
|
||||
if (!r) doWait=false;
|
||||
}
|
||||
}
|
||||
if (doWait) {
|
||||
//Wait for whatever interrupt comes next... this should save some power.
|
||||
asm("waiti 0");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)
|
||||
{
|
||||
int n;
|
||||
for (n=0; n<MAX_HOOKS; n++) {
|
||||
if (idle_cb[n]==NULL) {
|
||||
idle_cb[n]=new_idle_cb;
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)
|
||||
{
|
||||
int n;
|
||||
for (n=0; n<MAX_HOOKS; n++) {
|
||||
if (tick_cb[n]==NULL) {
|
||||
tick_cb[n]=new_tick_cb;
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)
|
||||
{
|
||||
int n;
|
||||
for (n=0; n<MAX_HOOKS; n++) {
|
||||
if (idle_cb[n]==old_idle_cb) idle_cb[n]=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)
|
||||
{
|
||||
int n;
|
||||
for (n=0; n<MAX_HOOKS; n++) {
|
||||
if (tick_cb[n]==old_tick_cb) tick_cb[n]=NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
#include "soc/io_mux_reg.h"
|
||||
|
||||
#include "esp_gdbstub.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
|
||||
//implies a minimum size of about 320 bytes.
|
||||
|
@ -351,10 +352,10 @@ static int gdbReadCommand() {
|
|||
|
||||
|
||||
|
||||
void gdbstubPanicHandler(XtExcFrame *frame) {
|
||||
void esp_gdbstub_panic_handler(XtExcFrame *frame) {
|
||||
dumpHwToRegfile(frame);
|
||||
//Make sure txd/rxd are enabled
|
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
|
||||
gpio_pullup_dis(1);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
|
||||
|
||||
|
|
|
@ -20,22 +20,25 @@
|
|||
//and all variables in shared RAM. These macros can be used to redirect
|
||||
//particular functions/variables to other memory regions.
|
||||
|
||||
// Forces code into IRAM instead of flash
|
||||
// Forces code into IRAM instead of flash.
|
||||
#define IRAM_ATTR __attribute__((section(".iram1")))
|
||||
|
||||
// Forces data into DRAM instead of flash
|
||||
#define DRAM_ATTR __attribute__((section(".dram1")))
|
||||
|
||||
// Forces code into RTC fast memory
|
||||
// Forces a string into DRAM instrad of flash
|
||||
// Use as ets_printf(DRAM_STR("Hello world!\n"));
|
||||
#define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;}))
|
||||
|
||||
// Forces code into RTC fast memory. See "docs/deep-sleep-stub.rst"
|
||||
#define RTC_IRAM_ATTR __attribute__((section(".rtc.text")))
|
||||
|
||||
// Forces data into RTC slow memory
|
||||
// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst"
|
||||
// Any variable marked with this attribute will keep its value
|
||||
// during a deep sleep / wake cycle.
|
||||
#define RTC_DATA_ATTR __attribute__((section(".rtc.data")))
|
||||
|
||||
// Forces read-only data into RTC slow memory
|
||||
// Makes constant data available to RTC wake stubs (see esp_deepsleep.h)
|
||||
// Forces read-only data into RTC slow memory. See "docs/deep-sleep-stub.rst"
|
||||
#define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata")))
|
||||
|
||||
#endif /* __ESP_ATTR_H__ */
|
||||
|
|
|
@ -54,37 +54,7 @@ void system_deep_sleep(uint64_t time_in_us);
|
|||
* to run code immediately when the chip wakes from
|
||||
* sleep.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
|
||||
* esp_default_wake_deep_sleep();
|
||||
* // Add additional functionality here
|
||||
* }
|
||||
*
|
||||
* (Implementing this function is not required for normal operation,
|
||||
* in the usual case your app will start normally when waking from
|
||||
* deep sleep.)
|
||||
*
|
||||
* esp_wake_deep_sleep() functionality is limited:
|
||||
*
|
||||
* - Runs immediately on wake, so most of the SoC is freshly reset -
|
||||
* flash is unmapped and hardware is otherwise uninitialised.
|
||||
*
|
||||
* - Can only call functions implemented in ROM, or marked RTC_IRAM_ATTR.
|
||||
*
|
||||
* - Static variables marked RTC_DATA_ATTR will have initial values on
|
||||
* cold boot, and maintain these values between sleep/wake cycles.
|
||||
*
|
||||
* - Read-only data should be marked RTC_RODATA_ATTR. Strings must be
|
||||
* declared as variables also using RTC_RODATA_ATTR, like this:
|
||||
* RTC_RODATA_ATTR const char message[] = "Hello from very early boot!\n";
|
||||
*
|
||||
* - Any other static memory will not be initialised (either to zero,
|
||||
* or to any predefined value).
|
||||
*
|
||||
*
|
||||
* - If you implement your own stub, the first call the stub makes
|
||||
should be to esp_default_wake_deep_sleep().
|
||||
* See docs/deep-sleep-stub.rst for details.
|
||||
*/
|
||||
void esp_wake_deep_sleep(void);
|
||||
|
||||
|
@ -115,9 +85,7 @@ esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void);
|
|||
|
||||
/* The default esp-idf-provided esp_wake_deep_sleep() stub.
|
||||
|
||||
If you replace esp_wake_deep_sleep() in your program, or use
|
||||
esp_set_deep_sleep_wake_stub(), then it is recommended you call
|
||||
esp_default_wake_deep_sleep() as the first function in your stub.
|
||||
See docs/deep-sleep-stub.rst for details.
|
||||
*/
|
||||
void esp_default_wake_deep_sleep(void);
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ typedef int32_t esp_err_t;
|
|||
#define ESP_ERR_INVALID_STATE 0x103
|
||||
#define ESP_ERR_INVALID_SIZE 0x104
|
||||
#define ESP_ERR_NOT_FOUND 0x105
|
||||
#define ESP_ERR_NOT_SUPPORTED 0x106
|
||||
#define ESP_ERR_TIMEOUT 0x107
|
||||
|
||||
|
||||
#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */
|
||||
|
||||
/**
|
||||
* Macro which can be used to check the error code,
|
||||
|
|
|
@ -35,11 +35,16 @@ typedef enum {
|
|||
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_GOT_IP, /**< ESP32 station got IP from connected AP */
|
||||
SYSTEM_EVENT_STA_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */
|
||||
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 from ESP32 soft-AP */
|
||||
SYSTEM_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */
|
||||
SYSTEM_EVENT_AP_STA_GOT_IP6, /**< ESP32 station or ap interface v6IP addr is preferred */
|
||||
SYSTEM_EVENT_MAX
|
||||
} system_event_id_t;
|
||||
|
||||
|
@ -73,6 +78,14 @@ typedef struct {
|
|||
tcpip_adapter_ip_info_t ip_info;
|
||||
} system_event_sta_got_ip_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */
|
||||
} system_event_sta_wps_er_pin_t;
|
||||
|
||||
typedef struct {
|
||||
tcpip_adapter_ip6_info_t ip6_info;
|
||||
} system_event_ap_sta_got_ip6_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */
|
||||
uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */
|
||||
|
@ -94,9 +107,11 @@ typedef union {
|
|||
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; /**< ESP32 station got IP */
|
||||
system_event_sta_wps_er_pin_t sta_er_pin; /**< ESP32 station WPS enrollee mode PIN code received */
|
||||
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 soft-AP receive probe request packet */
|
||||
system_event_ap_sta_got_ip6_t got_ip6; /**< ESP32 station or ap ipv6 addr state change to preferred */
|
||||
} system_event_info_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -21,57 +21,9 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
#define ESP_PARTITION_TABLE_ADDR 0x4000
|
||||
#define ESP_PARTITION_TABLE_ADDR 0x8000
|
||||
#define ESP_PARTITION_MAGIC 0x50AA
|
||||
|
||||
/* SPI flash mode, used in esp_image_header_t */
|
||||
typedef enum {
|
||||
ESP_IMAGE_SPI_MODE_QIO,
|
||||
ESP_IMAGE_SPI_MODE_QOUT,
|
||||
ESP_IMAGE_SPI_MODE_DIO,
|
||||
ESP_IMAGE_SPI_MODE_DOUT,
|
||||
ESP_IMAGE_SPI_MODE_FAST_READ,
|
||||
ESP_IMAGE_SPI_MODE_SLOW_READ
|
||||
} esp_image_spi_mode_t;
|
||||
|
||||
/* SPI flash clock frequency */
|
||||
enum {
|
||||
ESP_IMAGE_SPI_SPEED_40M,
|
||||
ESP_IMAGE_SPI_SPEED_26M,
|
||||
ESP_IMAGE_SPI_SPEED_20M,
|
||||
ESP_IMAGE_SPI_SPEED_80M = 0xF
|
||||
} esp_image_spi_freq_t;
|
||||
|
||||
/* Supported SPI flash sizes */
|
||||
typedef enum {
|
||||
ESP_IMAGE_FLASH_SIZE_1MB = 0,
|
||||
ESP_IMAGE_FLASH_SIZE_2MB,
|
||||
ESP_IMAGE_FLASH_SIZE_4MB,
|
||||
ESP_IMAGE_FLASH_SIZE_8MB,
|
||||
ESP_IMAGE_FLASH_SIZE_16MB,
|
||||
ESP_IMAGE_FLASH_SIZE_MAX
|
||||
} esp_image_flash_size_t;
|
||||
|
||||
/* Main header of binary image */
|
||||
typedef struct {
|
||||
uint8_t magic;
|
||||
uint8_t blocks;
|
||||
uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
|
||||
uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
|
||||
uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
|
||||
uint32_t entry_addr;
|
||||
uint8_t encrypt_flag; /* encrypt flag */
|
||||
uint8_t secure_boot_flag; /* secure boot flag */
|
||||
uint8_t extra_header[14]; /* ESP32 additional header, unused by second bootloader */
|
||||
} esp_image_header_t;
|
||||
|
||||
/* Header of binary image segment */
|
||||
typedef struct {
|
||||
uint32_t load_addr;
|
||||
uint32_t data_len;
|
||||
} esp_image_section_header_t;
|
||||
|
||||
|
||||
/* OTA selection structure (two copies in the OTA data partition.)
|
||||
Size of 32 bytes is friendly to flash encryption */
|
||||
typedef struct {
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
// 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_FREERTOS_HOOKS_H__
|
||||
#define __ESP_FREERTOS_HOOKS_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*
|
||||
Definitions for the tickhook and idlehook callbacks
|
||||
*/
|
||||
typedef bool (*esp_freertos_idle_cb_t)();
|
||||
typedef void (*esp_freertos_tick_cb_t)();
|
||||
|
||||
/**
|
||||
* @brief Register a callback to be called on the freertos idle hook
|
||||
* The callback should return true if it's okay for the core to
|
||||
* sleep until an interrupt (or FreeRTOS tick) happens and false
|
||||
* if it should be called again as fast as possible.
|
||||
*
|
||||
* @warning Idle callbacks MUST NOT, UNDER ANY CIRCUMSTANCES, CALL
|
||||
* A FUNCTION THAT MIGHT BLOCK.
|
||||
*
|
||||
* @param esp_freertos_idle_cb_t new_idle_cb : Callback to be called
|
||||
*
|
||||
* @return ESP_OK : Callback registered
|
||||
* @return ESP_ERR_NO_MEM : No more space to register hook
|
||||
*/
|
||||
esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb);
|
||||
|
||||
/**
|
||||
* @brief Register a callback to be called on the freertos tick hook
|
||||
*
|
||||
* @param esp_freertos_tick_cb_t new_tick_cb : Callback to be called
|
||||
*
|
||||
* @return ESP_OK : Callback registered
|
||||
* @return ESP_ERR_NO_MEM : No more space to register hook
|
||||
*/
|
||||
esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t tick_cb);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unregister an idle callback registered earlier
|
||||
*
|
||||
* @param esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unregister a tick callback registered earlier
|
||||
*
|
||||
* @param esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -41,9 +41,6 @@ This uses the TIMERG1 WDT.
|
|||
* @brief Initialize the interrupt watchdog. This is called in the init code if
|
||||
* the interrupt watchdog is enabled in menuconfig.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
void esp_int_wdt_init();
|
||||
|
||||
|
|
|
@ -82,126 +82,6 @@ extern "C" {
|
|||
#define ESP_INTR_DISABLE(inum) \
|
||||
xt_ints_off((1<<inum))
|
||||
|
||||
#define ESP_CCOMPARE_INTR_ENBALE() \
|
||||
ESP_INTR_ENABLE(ETS_CCOMPARE_INUM)
|
||||
|
||||
#define ESP_CCOMPARE_INTR_DISBALE() \
|
||||
ESP_INTR_DISABLE(ETS_CCOMPARE_INUM)
|
||||
|
||||
#define ESP_SPI1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI1_INUM)
|
||||
|
||||
#define ESP_SPI1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI1_INUM)
|
||||
|
||||
#define ESP_SPI2_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI2_INUM)
|
||||
|
||||
#define ESP_PWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_PWM_INUM)
|
||||
|
||||
#define ESP_PWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_PWM_INUM)
|
||||
|
||||
#define ESP_SPI2_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI2_INUM)
|
||||
|
||||
#define ESP_SPI3_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI3_INUM)
|
||||
|
||||
#define ESP_SPI3_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI3_INUM)
|
||||
|
||||
#define ESP_I2S0_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_I2S0_INUM)
|
||||
|
||||
#define ESP_I2S0_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_I2S0_INUM)
|
||||
|
||||
#define ESP_I2S1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_I2S1_INUM)
|
||||
|
||||
#define ESP_I2S1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_I2S1_INUM)
|
||||
|
||||
#define ESP_MPWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_MPWM_INUM)
|
||||
|
||||
#define ESP_EPWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_EPWM_INUM)
|
||||
|
||||
#define ESP_MPWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_MPWM_INUM)
|
||||
|
||||
#define ESP_EPWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_EPWM_INUM)
|
||||
|
||||
#define ESP_BB_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_BB_INUM)
|
||||
|
||||
#define ESP_BB_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_BB_INUM)
|
||||
|
||||
#define ESP_UART0_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_UART0_INUM)
|
||||
|
||||
#define ESP_UART0_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_UART0_INUM)
|
||||
|
||||
#define ESP_LEDC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_LEDC_INUM)
|
||||
|
||||
#define ESP_LEDC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_LEDC_INUM)
|
||||
|
||||
#define ESP_GPIO_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_GPIO_INUM)
|
||||
|
||||
#define ESP_GPIO_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_GPIO_INUM)
|
||||
|
||||
#define ESP_WDT_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_WDT_INUM)
|
||||
|
||||
#define ESP_WDT_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_WDT_INUM)
|
||||
|
||||
#define ESP_FRC1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_FRC_TIMER1_INUM)
|
||||
|
||||
#define ESP_FRC1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_FRC_TIMER1_INUM)
|
||||
|
||||
#define ESP_FRC2_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_FRC_TIMER2_INUM)
|
||||
|
||||
#define ESP_FRC2_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_FRC_TIMER2_INUM)
|
||||
|
||||
#define ESP_RTC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_RTC_INUM)
|
||||
|
||||
#define ESP_RTC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_RTC_INUM)
|
||||
|
||||
#define ESP_SLC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SLC_INUM)
|
||||
|
||||
#define ESP_SLC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SLC_INUM)
|
||||
|
||||
#define ESP_PCNT_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_PCNT_INUM)
|
||||
|
||||
#define ESP_PCNT_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_PCNT_INUM)
|
||||
|
||||
#define ESP_RMT_CTRL_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_RMT_CTRL_INUM)
|
||||
|
||||
#define ESP_RMT_CTRL_DIABLE() \
|
||||
ESP_INTR_DISABLE(ETS_RMT_CTRL_INUM)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file PHY init parameters and API
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Structure holding PHY init parameters
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t param_ver_id; /*!< init_data structure version */
|
||||
uint8_t crystal_select; /*!< 0: 40MHz, 1: 26 MHz, 2: 24 MHz, 3: auto */
|
||||
uint8_t wifi_rx_gain_swp_step_1; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_2; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_3; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_4; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_5; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_6; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_7; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_8; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_9; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_10; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_11; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_12; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_13; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_14; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_15; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_1; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_2; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_3; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_4; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_5; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_6; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_7; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_8; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_9; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_10; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_11; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_12; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_13; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_14; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_15; /*!< do not change */
|
||||
uint8_t gain_cmp_1; /*!< do not change */
|
||||
uint8_t gain_cmp_6; /*!< do not change */
|
||||
uint8_t gain_cmp_11; /*!< do not change */
|
||||
uint8_t gain_cmp_ext2_1; /*!< do not change */
|
||||
uint8_t gain_cmp_ext2_6; /*!< do not change */
|
||||
uint8_t gain_cmp_ext2_11; /*!< do not change */
|
||||
uint8_t gain_cmp_ext3_1; /*!< do not change */
|
||||
uint8_t gain_cmp_ext3_6; /*!< do not change */
|
||||
uint8_t gain_cmp_ext3_11; /*!< do not change */
|
||||
uint8_t gain_cmp_bt_ofs_1; /*!< do not change */
|
||||
uint8_t gain_cmp_bt_ofs_6; /*!< do not change */
|
||||
uint8_t gain_cmp_bt_ofs_11; /*!< do not change */
|
||||
uint8_t target_power_qdb_0; /*!< 78 means target power is 78/4=19.5dbm */
|
||||
uint8_t target_power_qdb_1; /*!< 76 means target power is 76/4=19dbm */
|
||||
uint8_t target_power_qdb_2; /*!< 74 means target power is 74/4=18.5dbm */
|
||||
uint8_t target_power_qdb_3; /*!< 68 means target power is 68/4=17dbm */
|
||||
uint8_t target_power_qdb_4; /*!< 64 means target power is 64/4=16dbm */
|
||||
uint8_t target_power_qdb_5; /*!< 52 means target power is 52/4=13dbm */
|
||||
uint8_t target_power_index_mcs0; /*!< target power index is 0, means target power is target_power_qdb_0 19.5dbm; (1m,2m,5.5m,11m,6m,9m) */
|
||||
uint8_t target_power_index_mcs1; /*!< target power index is 0, means target power is target_power_qdb_0 19.5dbm; (12m) */
|
||||
uint8_t target_power_index_mcs2; /*!< target power index is 1, means target power is target_power_qdb_1 19dbm; (18m) */
|
||||
uint8_t target_power_index_mcs3; /*!< target power index is 1, means target power is target_power_qdb_1 19dbm; (24m) */
|
||||
uint8_t target_power_index_mcs4; /*!< target power index is 2, means target power is target_power_qdb_2 18.5dbm; (36m) */
|
||||
uint8_t target_power_index_mcs5; /*!< target power index is 3, means target power is target_power_qdb_3 17dbm; (48m) */
|
||||
uint8_t target_power_index_mcs6; /*!< target power index is 4, means target power is target_power_qdb_4 16dbm; (54m) */
|
||||
uint8_t target_power_index_mcs7; /*!< target power index is 5, means target power is target_power_qdb_5 13dbm */
|
||||
uint8_t pwr_ind_11b_en; /*!< 0: 11b power is same as mcs0 and 6m, 1: 11b power different with OFDM */
|
||||
uint8_t pwr_ind_11b_0; /*!< 1m, 2m power index [0~5] */
|
||||
uint8_t pwr_ind_11b_1; /*!< 5.5m, 11m power index [0~5] */
|
||||
uint8_t chan_backoff_en; /*!< 0: channel backoff disable, 1:channel backoff enable */
|
||||
uint8_t chan1_power_backoff_qdb; /*!< 4 means backoff is 1db */
|
||||
uint8_t chan2_power_backoff_qdb; /*!< see chan1_power_backoff_qdb */
|
||||
uint8_t chan3_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan4_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan5_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan6_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan7_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan8_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan9_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan10_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan11_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan12_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan13_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan14_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan1_rate_backoff_index; /*!< if bit i is set, backoff data rate is target_power_qdb_i */
|
||||
uint8_t chan2_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan3_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan4_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan5_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan6_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan7_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan8_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan9_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan10_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan11_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan12_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan13_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan14_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t spur_freq_cfg_msb_1; /*!< first spur: */
|
||||
uint8_t spur_freq_cfg_1; /*!< spur_freq_cfg = (spur_freq_cfg_msb_1 <<8) | spur_freq_cfg_1 */
|
||||
uint8_t spur_freq_cfg_div_1; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_1 */
|
||||
uint8_t spur_freq_en_h_1; /*!< the seventh bit for total enable */
|
||||
uint8_t spur_freq_en_l_1; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority */
|
||||
uint8_t spur_freq_cfg_msb_2; /*!< second spur: */
|
||||
uint8_t spur_freq_cfg_2; /*!< spur_freq_cfg = (spur_freq_cfg_msb_2 <<8) | spur_freq_cfg_2 */
|
||||
uint8_t spur_freq_cfg_div_2; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_2 */
|
||||
uint8_t spur_freq_en_h_2; /*!< the seventh bit for total enable */
|
||||
uint8_t spur_freq_en_l_2; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority */
|
||||
uint8_t spur_freq_cfg_msb_3; /*!< third spur: */
|
||||
uint8_t spur_freq_cfg_3; /*!< spur_freq_cfg = (spur_freq_cfg_msb_3 <<8) | spur_freq_cfg_3 */
|
||||
uint8_t spur_freq_cfg_div_3; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_3 */
|
||||
uint8_t spur_freq_en_h_3; /*!< the seventh bit for total enable */
|
||||
uint8_t spur_freq_en_l_3; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority, */
|
||||
uint8_t reserved[23]; /*!< reserved for future expansion */
|
||||
} esp_phy_init_data_t;
|
||||
|
||||
/**
|
||||
* @brief Opaque PHY calibration data
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t opaque[1904]; /*!< calibration data */
|
||||
} esp_phy_calibration_data_t;
|
||||
|
||||
typedef enum {
|
||||
PHY_RF_CAL_PARTIAL = 0x00000000, /*!< Do part of RF calibration. This should be used after power-on reset. */
|
||||
PHY_RF_CAL_NONE = 0x00000001, /*!< Don't do any RF calibration. This mode is only suggested to be used after deep sleep reset. */
|
||||
PHY_RF_CAL_FULL = 0x00000002 /*!< Do full RF calibration. Produces best results, but also consumes a lot of time and current. Suggested to be used once. */
|
||||
} esp_phy_calibration_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Get PHY init data
|
||||
*
|
||||
* If "Use a partition to store PHY init data" option is set in menuconfig,
|
||||
* This function will load PHY init data from a partition. Otherwise,
|
||||
* PHY init data will be compiled into the application itself, and this function
|
||||
* will return a pointer to PHY init data located in read-only memory (DROM).
|
||||
*
|
||||
* If "Use a partition to store PHY init data" option is enabled, this function
|
||||
* may return NULL if the data loaded from flash is not valid.
|
||||
*
|
||||
* @note Call esp_phy_release_init_data to release the pointer obtained using
|
||||
* this function after the call to esp_wifi_init.
|
||||
*
|
||||
* @return pointer to PHY init data structure
|
||||
*/
|
||||
const esp_phy_init_data_t* esp_phy_get_init_data();
|
||||
|
||||
/**
|
||||
* @brief Release PHY init data
|
||||
* @param data pointer to PHY init data structure obtained from
|
||||
* esp_phy_get_init_data function
|
||||
*/
|
||||
void esp_phy_release_init_data(const esp_phy_init_data_t* data);
|
||||
|
||||
/**
|
||||
* @brief Function called by esp_phy_init to load PHY calibration data
|
||||
*
|
||||
* This is a convenience function which can be used to load PHY calibration
|
||||
* data from NVS. Data can be stored to NVS using esp_phy_store_cal_data_to_nvs
|
||||
* function.
|
||||
*
|
||||
* If calibration data is not present in the NVS, or
|
||||
* data is not valid (was obtained for a chip with a different MAC address,
|
||||
* or obtained for a different version of software), this function will
|
||||
* return an error.
|
||||
*
|
||||
* If "Initialize PHY in startup code" option is set in menuconfig, this
|
||||
* function will be used to load calibration data. To provide a different
|
||||
* mechanism for loading calibration data, disable
|
||||
* "Initialize PHY in startup code" option in menuconfig and call esp_phy_init
|
||||
* function from the application. For an example usage of esp_phy_init and
|
||||
* this function, see do_phy_init function in cpu_start.c
|
||||
*
|
||||
* @param out_cal_data pointer to calibration data structure to be filled with
|
||||
* loaded data.
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data);
|
||||
|
||||
/**
|
||||
* @brief Function called by esp_phy_init to store PHY calibration data
|
||||
*
|
||||
* This is a convenience function which can be used to store PHY calibration
|
||||
* data to the NVS. Calibration data is returned by esp_phy_init function.
|
||||
* Data saved using this function to the NVS can later be loaded using
|
||||
* esp_phy_store_cal_data_to_nvs function.
|
||||
*
|
||||
* If "Initialize PHY in startup code" option is set in menuconfig, this
|
||||
* function will be used to store calibration data. To provide a different
|
||||
* mechanism for storing calibration data, disable
|
||||
* "Initialize PHY in startup code" option in menuconfig and call esp_phy_init
|
||||
* function from the application.
|
||||
*
|
||||
* @param cal_data pointer to calibration data which has to be saved.
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data);
|
||||
|
||||
/**
|
||||
* @brief Initialize PHY module
|
||||
*
|
||||
* PHY module should be initialized in order to use WiFi or BT.
|
||||
* If "Initialize PHY in startup code" option is set in menuconfig,
|
||||
* this function will be called automatically before app_main is called,
|
||||
* using parameters obtained from esp_phy_get_init_data.
|
||||
*
|
||||
* Applications which don't need to enable PHY on every start up should
|
||||
* disable this menuconfig option and call esp_phy_init before calling
|
||||
* esp_wifi_init or bt_controller_init. See do_phy_init function in
|
||||
* cpu_start.c for an example of using this function.
|
||||
*
|
||||
* @param init_data PHY parameters. Default set of parameters can
|
||||
* be obtained by calling esp_phy_get_default_init_data
|
||||
* function.
|
||||
* @param mode Calibration mode (Full, partial, or no calibration)
|
||||
* @param[inout] calibration_data
|
||||
* @return ESP_OK on success.
|
||||
*/
|
||||
esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data,
|
||||
esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -32,6 +32,13 @@ extern "C" {
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @attention application don't need to call this function anymore. It do nothing and will
|
||||
* be removed in future version.
|
||||
*/
|
||||
void system_init(void) __attribute__ ((deprecated));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get information of the SDK version.
|
||||
*
|
||||
|
@ -169,8 +176,6 @@ bool system_rtc_mem_write(uint16_t dst, const void *src, uint16_t n);
|
|||
esp_err_t system_efuse_read_mac(uint8_t mac[6]);
|
||||
|
||||
|
||||
void system_init(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -42,9 +42,6 @@ This uses the TIMERG0 WDT.
|
|||
* @brief Initialize the task watchdog. This is called in the init code, if the
|
||||
* task watchdog is enabled in menuconfig.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
void esp_task_wdt_init();
|
||||
|
||||
|
@ -52,9 +49,6 @@ void esp_task_wdt_init();
|
|||
* @brief Feed the watchdog. After the first feeding session, the watchdog will expect the calling
|
||||
* task to keep feeding the watchdog until task_wdt_delete() is called.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
|
||||
void esp_task_wdt_feed();
|
||||
|
@ -63,9 +57,6 @@ void esp_task_wdt_feed();
|
|||
/**
|
||||
* @brief Delete the watchdog for the current task.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
void esp_task_wdt_delete();
|
||||
|
||||
|
|
|
@ -70,6 +70,27 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_ERR_WIFI_OK ESP_OK /*!< No error */
|
||||
#define ESP_ERR_WIFI_FAIL ESP_FAIL /*!< General fail code */
|
||||
#define ESP_ERR_WIFI_NO_MEM ESP_ERR_NO_MEM /*!< Out of memory */
|
||||
#define ESP_ERR_WIFI_ARG ESP_ERR_INVALID_ARG /*!< Invalid argument */
|
||||
#define ESP_ERR_WIFI_NOT_SUPPORT ESP_ERR_NOT_SUPPORTED /*!< Indicates that API is not supported yet */
|
||||
|
||||
#define ESP_ERR_WIFI_NOT_INIT (ESP_ERR_WIFI_BASE + 1) /*!< WiFi driver is not installed by esp_wifi_init */
|
||||
#define ESP_ERR_WIFI_NOT_START (ESP_ERR_WIFI_BASE + 2) /*!< WiFi driver is not started by esp_wifi_start */
|
||||
#define ESP_ERR_WIFI_IF (ESP_ERR_WIFI_BASE + 3) /*!< WiFi interface error */
|
||||
#define ESP_ERR_WIFI_MODE (ESP_ERR_WIFI_BASE + 4) /*!< WiFi mode error */
|
||||
#define ESP_ERR_WIFI_STATE (ESP_ERR_WIFI_BASE + 5) /*!< WiFi internal state error */
|
||||
#define ESP_ERR_WIFI_CONN (ESP_ERR_WIFI_BASE + 6) /*!< WiFi internal control block of station or soft-AP error */
|
||||
#define ESP_ERR_WIFI_NVS (ESP_ERR_WIFI_BASE + 7) /*!< WiFi internal NVS module error */
|
||||
#define ESP_ERR_WIFI_MAC (ESP_ERR_WIFI_BASE + 8) /*!< MAC address is invalid */
|
||||
#define ESP_ERR_WIFI_SSID (ESP_ERR_WIFI_BASE + 9) /*!< SSID is invalid */
|
||||
#define ESP_ERR_WIFI_PASSWORD (ESP_ERR_WIFI_BASE + 10) /*!< Passord is invalid */
|
||||
#define ESP_ERR_WIFI_TIMEOUT (ESP_ERR_WIFI_BASE + 11) /*!< Timeout error */
|
||||
|
||||
/**
|
||||
* @brief WiFi stack configuration parameters passed to esp_wifi_init call.
|
||||
*/
|
||||
typedef struct {
|
||||
system_event_handler_t event_handler; /**< WiFi event handler */
|
||||
} wifi_init_config_t;
|
||||
|
@ -90,10 +111,12 @@ typedef struct {
|
|||
* will post station connected event to this queue. If the queue is not initialized, WiFi
|
||||
* will not post any events
|
||||
*
|
||||
* @param wifi_init_config_t *config : provide WiFi init configuration
|
||||
* @param config provide WiFi init configuration
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NO_MEM: out of memory
|
||||
* - others: refer to error code esp_err.h
|
||||
*/
|
||||
esp_err_t esp_wifi_init(wifi_init_config_t *config);
|
||||
|
||||
|
@ -103,8 +126,7 @@ esp_err_t esp_wifi_init(wifi_init_config_t *config);
|
|||
*
|
||||
* @attention 1. This API should be called if you want to remove WiFi driver from the system
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return ESP_OK: succeed
|
||||
*/
|
||||
esp_err_t esp_wifi_deinit(void);
|
||||
|
||||
|
@ -114,20 +136,25 @@ esp_err_t esp_wifi_deinit(void);
|
|||
* 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:
|
||||
* @param mode WiFi operating mode
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - others: refer to error code in esp_err.h
|
||||
*/
|
||||
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
|
||||
* @param[out] mode store current WiFi mode
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_get_mode(wifi_mode_t *mode);
|
||||
|
||||
|
@ -137,23 +164,25 @@ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode);
|
|||
* 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
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_NO_MEM: out of memory
|
||||
* - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong
|
||||
* - ESP_ERR_WIFI_FAIL: other WiFi internal errors
|
||||
*/
|
||||
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_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
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
*/
|
||||
esp_err_t esp_wifi_stop(void);
|
||||
|
||||
|
@ -163,40 +192,47 @@ esp_err_t esp_wifi_stop(void);
|
|||
* @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
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
|
||||
* - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong
|
||||
* - ESP_ERR_WIFI_SSID: SSID of AP which station connects is invalid
|
||||
*/
|
||||
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
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
|
||||
* - ESP_ERR_WIFI_FAIL: other WiFi internal errors
|
||||
*/
|
||||
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
|
||||
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t esp_wifi_clear_fast_connect(void);
|
||||
|
||||
/**
|
||||
* @brief deauthenticate all stations or associated id equals to aid
|
||||
*
|
||||
* @param uint16_t aid : when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid
|
||||
* @param aid when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_MODE: WiFi mode is wrong
|
||||
*/
|
||||
esp_err_t esp_wifi_deauth_sta(uint16_t aid);
|
||||
|
||||
|
@ -207,76 +243,87 @@ esp_err_t esp_wifi_deauth_sta(uint16_t aid);
|
|||
* 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
|
||||
* @param config configuration of scanning
|
||||
* @param 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
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
|
||||
* - ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout
|
||||
* - others: refer to error code in esp_err.h
|
||||
*/
|
||||
esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf, bool block);
|
||||
esp_err_t esp_wifi_scan_start(wifi_scan_config_t *config, bool block);
|
||||
|
||||
/**
|
||||
* @brief Stop the scan in process
|
||||
*
|
||||
* @param null
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
|
||||
*/
|
||||
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
|
||||
* @param[out] 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
|
||||
* @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
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number);
|
||||
|
||||
/**
|
||||
* @brief Get AP list found in last scan
|
||||
*
|
||||
* @param uint16_t *number : as input param, it stores max AP number ap_records can hold, as output param, it store
|
||||
the actual AP number this API returns
|
||||
* @param wifi_ap_record_t *ap_records: wifi_ap_record_t array to hold the found APs
|
||||
* @param[inout] number As input param, it stores max AP number ap_records can hold.
|
||||
* As output param, it receives the actual AP number this API returns.
|
||||
* @param ap_records wifi_ap_record_t array to hold the found APs
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_NO_MEM: out of memory
|
||||
*/
|
||||
esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get information of AP associated with ESP32 station
|
||||
* @brief Get information of AP which the ESP32 station is associated with
|
||||
*
|
||||
* @param wifi_ap_record_t *ap_info: the wifi_ap_record_t to hold station assocated AP
|
||||
* @param ap_info the wifi_ap_record_t to hold AP information
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t esp_wifi_sta_get_ap_info(wifi_ap_record_t *ap_info);
|
||||
|
||||
/**
|
||||
* @brief Set current power save type
|
||||
*
|
||||
* @param wifi_ps_type_t type : power save type
|
||||
* @param type power save type
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return ESP_ERR_WIFI_NOT_SUPPORT: not supported yet
|
||||
*/
|
||||
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
|
||||
* @param[out] type: store current power save type
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return ESP_ERR_WIFI_NOT_SUPPORT: not supported yet
|
||||
*/
|
||||
esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
|
||||
|
||||
|
@ -286,36 +333,47 @@ esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
|
|||
*
|
||||
* @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
|
||||
* @param ifx interfaces
|
||||
* @param protocol_bitmap WiFi protocol bitmap
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
* - others: refer to error codes in esp_err.h
|
||||
*/
|
||||
esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap);
|
||||
|
||||
/**
|
||||
* @brief Get the current protocol bitmap of specified ifx
|
||||
* @brief Get the current protocol bitmap of the specified interface
|
||||
*
|
||||
* @param wifi_interface_t ifx : interfaces
|
||||
* @param uint8_t protocol : store current WiFi protocol bitmap of interface ifx
|
||||
* @param ifx interface
|
||||
* @param[out] protocol_bitmap store current WiFi protocol bitmap of interface ifx
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - others: refer to error codes in esp_err.h
|
||||
*/
|
||||
esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
|
||||
|
||||
/**
|
||||
* @brief Set the bandwidth of ESP32 specified interface
|
||||
*
|
||||
* @attention 1. API return false if try to configure a interface that is not enable
|
||||
* @attention 1. API return false if try to configure an interface that is not enabled
|
||||
* @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
|
||||
* @param ifx interface to be configured
|
||||
* @param bw bandwidth
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - others: refer to error codes in esp_err.h
|
||||
*/
|
||||
esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
|
||||
|
||||
|
@ -324,37 +382,45 @@ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
|
|||
*
|
||||
* @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
|
||||
* @param ifx interface to be configured
|
||||
* @param[out] bw store bandwidth of interface ifx
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw);
|
||||
|
||||
/**
|
||||
* @brief Set primary/second channel of ESP32
|
||||
* @brief Set primary/secondary 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
|
||||
* @param primary for HT20, primary is the channel number, for HT40, primary is the primary channel
|
||||
* @param second for HT20, second is ignored, for HT40, second is the second channel
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second);
|
||||
|
||||
/**
|
||||
* @brief Get the primary/second channel of ESP32
|
||||
* @brief Get the primary/secondary 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
|
||||
* @param primary store current primary channel
|
||||
* @param[out] second store current second channel
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second);
|
||||
|
||||
|
@ -362,20 +428,25 @@ 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
|
||||
* @param country country type
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - others: refer to error code in esp_err.h
|
||||
*/
|
||||
esp_err_t esp_wifi_set_country(wifi_country_t country);
|
||||
|
||||
/**
|
||||
* @brief Get country code
|
||||
*
|
||||
* @param wifi_country_t country : store current country
|
||||
* @param country store current country
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_get_country(wifi_country_t *country);
|
||||
|
||||
|
@ -384,69 +455,82 @@ esp_err_t esp_wifi_get_country(wifi_country_t *country);
|
|||
*
|
||||
* @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
|
||||
* @attention 3. The bit 0 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.
|
||||
* @param ifx interface
|
||||
* @param mac the MAC address
|
||||
*
|
||||
* @return true : succeed
|
||||
* @return false : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
* - ESP_ERR_WIFI_MAC: invalid mac address
|
||||
* - ESP_ERR_WIFI_MODE: WiFi mode is wrong
|
||||
* - others: refer to error codes in esp_err.h
|
||||
*/
|
||||
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
|
||||
* @param ifx interface
|
||||
* @param[out] mac store mac of the interface ifx
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
*/
|
||||
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.
|
||||
* Each time a packet is received, the callback function will be called.
|
||||
*
|
||||
* @param void *buf : the data received
|
||||
* @param uint16_t len : data length
|
||||
* @param buf the data received
|
||||
* @param len data length
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return none
|
||||
*/
|
||||
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.
|
||||
* Each time a packet is received, the registered callback function will be called.
|
||||
*
|
||||
* @param wifi_promiscuous_cb_t cb : callback
|
||||
* @param cb callback
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
*/
|
||||
esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
|
||||
|
||||
/**
|
||||
* @brief Enable the promiscuous mode.
|
||||
*
|
||||
* @param bool promiscuous : false - disable / true - enable
|
||||
* @param en false - disable, true - enable
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
*/
|
||||
esp_err_t esp_wifi_set_promiscuous(bool en);
|
||||
|
||||
/**
|
||||
* @brief Get the promiscuous mode.
|
||||
*
|
||||
* @param bool *enable : store the current status of promiscuous mode
|
||||
* @param[out] en store the current status of promiscuous mode
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_get_promiscuous(bool *en);
|
||||
|
||||
|
@ -458,22 +542,32 @@ esp_err_t esp_wifi_get_promiscuous(bool *en);
|
|||
* @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
|
||||
* @param ifx interface
|
||||
* @param conf station or soft-AP configuration
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
* - ESP_ERR_WIFI_MODE: invalid mode
|
||||
* - ESP_ERR_WIFI_PASSWORD: invalid password
|
||||
* - ESP_ERR_WIFI_NVS: WiFi internal NVS error
|
||||
* - others: refer to the erro code in esp_err.h
|
||||
*/
|
||||
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
|
||||
* @param ifx interface
|
||||
* @param[out] conf station or soft-AP configuration
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_IF: invalid interface
|
||||
*/
|
||||
esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
|
||||
|
||||
|
@ -482,10 +576,14 @@ esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
|
|||
*
|
||||
* @attention SSC only API
|
||||
*
|
||||
* @param wifi_sta_list_t *sta: station list
|
||||
* @param[out] sta station list
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_MODE: WiFi mode is wrong
|
||||
* - ESP_ERR_WIFI_CONN: WiFi internal error, the station/soft-AP control block is invalid
|
||||
*/
|
||||
esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta);
|
||||
|
||||
|
@ -495,97 +593,76 @@ esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta);
|
|||
*
|
||||
* @attention 1. The default value is WIFI_STORAGE_FLASH
|
||||
*
|
||||
* @param wifi_storage_t storage : storage type
|
||||
* @param storage : storage type
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_set_storage(wifi_storage_t storage);
|
||||
|
||||
/**
|
||||
* @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 en : true - enable auto connect / false - disable auto connect
|
||||
*
|
||||
* @param bool en : true - enable auto connect / false - disable auto connect
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_MODE: WiFi internal error, the station/soft-AP control block is invalid
|
||||
* - others: refer to error code in esp_err.h
|
||||
*/
|
||||
esp_err_t esp_wifi_set_auto_connect(bool en);
|
||||
|
||||
/**
|
||||
* @brief Get the auto connect flag
|
||||
*
|
||||
* @param bool *en : store current auto connect configuration
|
||||
* @param[out] en store current auto connect configuration
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_get_auto_connect(bool *en);
|
||||
|
||||
/**
|
||||
* @brief Set vendor specific element
|
||||
*
|
||||
* @param bool enable : enable or not
|
||||
* @param wifi_vendor_ie_type_t type : 0 - WIFI_VND_IE_TYPE_BEACON
|
||||
* 1 - WIFI_VND_IE_TYPE_PROBE_REQ
|
||||
* 2 - WIFI_VND_IE_TYPE_PROBE_RESP
|
||||
* 3 - WIFI_VND_IE_TYPE_ASSOC_REQ
|
||||
* 4 - WIFI_VND_IE_TYPE_ASSOC_RESP
|
||||
* @param wifi_vendor_ie_id_t idx : 0 - WIFI_VND_IE_ID_0
|
||||
1 - WIFI_VND_IE_ID_1
|
||||
* @param uint8_t *vnd_ie : pointer to a vendor specific element
|
||||
* @param enable enable or not
|
||||
* @param type information element type
|
||||
* @param idx information element index
|
||||
* @param vnd_ie pointer to a vendor specific element
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
* - ESP_ERR_WIFI_NO_MEM: out of memory
|
||||
*/
|
||||
esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, uint8_t *vnd_ie);
|
||||
|
||||
/**
|
||||
* @brief Define function pointer for vendor specific element callback
|
||||
* @param void *ctx : reserved
|
||||
* @param wifi_vendor_ie_type_t type : 0 - WIFI_VND_IE_TYPE_BEACON
|
||||
* 1 - WIFI_VND_IE_TYPE_PROBE_REQ
|
||||
* 2 - WIFI_VND_IE_TYPE_PROBE_RESP
|
||||
* 3 - WIFI_VND_IE_TYPE_ASSOC_REQ
|
||||
* 4 - WIFI_VND_IE_TYPE_ASSOC_RESP
|
||||
* @param const uint8_t sa[6] : source address
|
||||
* @param const uint8_t *vnd_ie : pointer to a vendor specific element
|
||||
* @param int rssi : received signal strength indication
|
||||
* @param ctx reserved
|
||||
* @param type information element type
|
||||
* @param sa source address
|
||||
* @param vnd_ie pointer to a vendor specific element
|
||||
* @param rssi received signal strength indication
|
||||
*/
|
||||
typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const uint8_t *vnd_ie, int rssi);
|
||||
|
||||
/**
|
||||
* @brief Set vendor specific element callback
|
||||
*
|
||||
* @param esp_vendor_ie_cb_t cb : callback function
|
||||
* @param void *ctx : reserved
|
||||
* @param cb callback function
|
||||
* @param ctx reserved
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
*/
|
||||
esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx);
|
||||
|
||||
|
|
|
@ -62,16 +62,48 @@ void esp_wifi_internal_free_rx_buffer(void* buffer);
|
|||
/**
|
||||
* @brief transmit the buffer via wifi driver
|
||||
*
|
||||
* @attention1 TODO should modify the return type from bool to int
|
||||
*
|
||||
* @param wifi_interface_t wifi_if : wifi interface id
|
||||
* @param void *buffer : the buffer to be tansmit
|
||||
* @param u16_t len : the length of buffer
|
||||
*
|
||||
* @return True : success transmit the buffer to wifi driver
|
||||
* False : failed to transmit the buffer to wifi driver
|
||||
* @return
|
||||
* - ERR_OK : Successfully transmit the buffer to wifi driver
|
||||
* - ERR_MEM : Out of memory
|
||||
* - ERR_IF : WiFi driver error
|
||||
* - ERR_ARG : Invalid argument
|
||||
*/
|
||||
bool esp_wifi_internal_tx(wifi_interface_t wifi_if, void *buffer, u16_t len);
|
||||
int esp_wifi_internal_tx(wifi_interface_t wifi_if, void *buffer, u16_t len);
|
||||
|
||||
/**
|
||||
* @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_internal_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn);
|
||||
|
||||
/**
|
||||
* @brief Notify WIFI driver that the station got ip successfully
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
*/
|
||||
esp_err_t esp_wifi_internal_set_sta_ip(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
// 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_WPS_H__
|
||||
#define __ESP_WPS_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup WiFi_APIs WiFi Related APIs
|
||||
* @brief WiFi APIs
|
||||
*/
|
||||
|
||||
/** @addtogroup WiFi_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \defgroup WPS_APIs WPS APIs
|
||||
* @brief ESP32 WPS APIs
|
||||
*
|
||||
* WPS can only be used when ESP32 station is enabled.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @addtogroup WPS_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define ESP_ERR_WIFI_REGISTRAR (ESP_ERR_WIFI_BASE + 51) /*!< WPS registrar is not supported */
|
||||
#define ESP_ERR_WIFI_WPS_TYPE (ESP_ERR_WIFI_BASE + 52) /*!< WPS type error */
|
||||
#define ESP_ERR_WIFI_WPS_SM (ESP_ERR_WIFI_BASE + 53) /*!< WPS state machine is not initialized */
|
||||
|
||||
typedef enum wps_type {
|
||||
WPS_TYPE_DISABLE = 0,
|
||||
WPS_TYPE_PBC,
|
||||
WPS_TYPE_PIN,
|
||||
WPS_TYPE_MAX,
|
||||
} wps_type_t;
|
||||
|
||||
/**
|
||||
* @brief Enable Wi-Fi WPS function.
|
||||
*
|
||||
* @attention WPS can only be used when ESP32 station is enabled.
|
||||
*
|
||||
* @param wps_type_t wps_type : WPS type, so far only WPS_TYPE_PBC and WPS_TYPE_PIN is supported
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : succeed
|
||||
* - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid
|
||||
* - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
|
||||
* - ESP_ERR_WIFI_FAIL : wps initialization fails
|
||||
*/
|
||||
esp_err_t esp_wifi_wps_enable(wps_type_t wps_type);
|
||||
|
||||
/**
|
||||
* @brief Disable Wi-Fi WPS function and release resource it taken.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : succeed
|
||||
* - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
|
||||
*/
|
||||
esp_err_t esp_wifi_wps_disable(void);
|
||||
|
||||
/**
|
||||
* @brief WPS starts to work.
|
||||
*
|
||||
* @attention WPS can only be used when ESP32 station is enabled.
|
||||
*
|
||||
* @param timeout_ms : maximum blocking time before API return.
|
||||
* - 0 : non-blocking
|
||||
* - 1~120000 : blocking time (not supported in IDF v1.0)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : succeed
|
||||
* - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid
|
||||
* - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
|
||||
* - ESP_ERR_WIFI_WPS_SM : wps state machine is not initialized
|
||||
* - ESP_ERR_WIFI_FAIL : wps initialization fails
|
||||
*/
|
||||
esp_err_t esp_wifi_wps_start(int timeout_ms);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ESP_WPS_H__ */
|
|
@ -25,7 +25,7 @@ void ets_secure_boot_start(void);
|
|||
|
||||
void ets_secure_boot_finish(void);
|
||||
|
||||
void ets_secure_boot_hash(uint32_t *buf);
|
||||
void ets_secure_boot_hash(const uint32_t *buf);
|
||||
|
||||
void ets_secure_boot_obtain(void);
|
||||
|
||||
|
|
|
@ -1028,6 +1028,7 @@
|
|||
#define DPORT_WIFI_RST_EN_REG (DR_REG_DPORT_BASE + 0x0D0)
|
||||
/* DPORT_WIFI_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
|
||||
/*description: */
|
||||
#define DPORT_MAC_RST (BIT(2))
|
||||
#define DPORT_WIFI_RST 0xFFFFFFFF
|
||||
#define DPORT_WIFI_RST_M ((DPORT_WIFI_RST_V)<<(DPORT_WIFI_RST_S))
|
||||
#define DPORT_WIFI_RST_V 0xFFFFFFFF
|
||||
|
|
|
@ -29,6 +29,16 @@
|
|||
#define EFUSE_RD_EFUSE_RD_DIS_M ((EFUSE_RD_EFUSE_RD_DIS_V)<<(EFUSE_RD_EFUSE_RD_DIS_S))
|
||||
#define EFUSE_RD_EFUSE_RD_DIS_V 0xF
|
||||
#define EFUSE_RD_EFUSE_RD_DIS_S 16
|
||||
|
||||
/* Read disable bits for efuse blocks 1-3 */
|
||||
#define EFUSE_RD_DIS_BLK1 (1<<16)
|
||||
#define EFUSE_RD_DIS_BLK2 (1<<17)
|
||||
#define EFUSE_RD_DIS_BLK3 (1<<18)
|
||||
/* Read disable FLASH_CRYPT_CONFIG, CODING_SCHEME & KEY_STATUS
|
||||
in efuse block 0
|
||||
*/
|
||||
#define EFUSE_RD_DIS_BLK0_PARTIAL (1<<19)
|
||||
|
||||
/* EFUSE_RD_EFUSE_WR_DIS : RO ;bitpos:[15:0] ;default: 16'b0 ; */
|
||||
/*description: read for efuse_wr_disable*/
|
||||
#define EFUSE_RD_EFUSE_WR_DIS 0x0000FFFF
|
||||
|
@ -36,6 +46,22 @@
|
|||
#define EFUSE_RD_EFUSE_WR_DIS_V 0xFFFF
|
||||
#define EFUSE_RD_EFUSE_WR_DIS_S 0
|
||||
|
||||
/* Write disable bits */
|
||||
#define EFUSE_WR_DIS_RD_DIS (1<<0) /*< disable writing read disable reg */
|
||||
#define EFUSE_WR_DIS_WR_DIS (1<<1) /*< disable writing write disable reg */
|
||||
#define EFUSE_WR_DIS_FLASH_CRYPT_CNT (1<<2)
|
||||
#define EFUSE_WR_DIS_MAC_SPI_CONFIG_HD (1<<3) /*< disable writing MAC & SPI config hd efuses */
|
||||
#define EFUSE_WR_DIS_XPD_SDIO (1<<5) /*< disable writing SDIO config efuses */
|
||||
#define EFUSE_WR_DIS_SPI_PAD_CONFIG (1<<6) /*< disable writing SPI_PAD_CONFIG efuses */
|
||||
#define EFUSE_WR_DIS_BLK1 (1<<7) /*< disable writing BLK1 efuses */
|
||||
#define EFUSE_WR_DIS_BLK2 (1<<8) /*< disable writing BLK2 efuses */
|
||||
#define EFUSE_WR_DIS_BLK3 (1<<9) /*< disable writing BLK3 efuses */
|
||||
#define EFUSE_WR_DIS_FLASH_CRYPT_CODING_SCHEME (1<<10) /*< disable writing FLASH_CRYPT_CONFIG and CODING_SCHEME efuses */
|
||||
#define EFUSE_WR_DIS_ABS_DONE_0 (1<<12) /*< disable writing ABS_DONE_0 efuse */
|
||||
#define EFUSE_WR_DIS_ABS_DONE_1 (1<<13) /*< disable writing ABS_DONE_1 efuse */
|
||||
#define EFUSE_WR_DIS_JTAG_DISABLE (1<<14) /*< disable writing JTAG_DISABLE efuse */
|
||||
#define EFUSE_WR_DIS_CONSOLE_DL_DISABLE (1<<15) /*< disable writing CONSOLE_DEBUG_DISABLE, DISABLE_DL_ENCRYPT, DISABLE_DL_DECRYPT and DISABLE_DL_CACHE efuses */
|
||||
|
||||
#define EFUSE_BLK0_RDATA1_REG (DR_REG_EFUSE_BASE + 0x004)
|
||||
/* EFUSE_RD_WIFI_MAC_CRC_LOW : RO ;bitpos:[31:0] ;default: 32'b0 ; */
|
||||
/*description: read for low 32bit WIFI_MAC_Address*/
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// 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 _SOC_FRC_TIMER_REG_H_
|
||||
#define _SOC_FRC_TIMER_REG_H_
|
||||
|
||||
#include "soc.h"
|
||||
|
||||
/**
|
||||
* These are the register definitions for "legacy" timers
|
||||
*/
|
||||
|
||||
#define REG_FRC_TIMER_BASE(i) (DR_REG_FRC_TIMER_BASE + i*0x20)
|
||||
|
||||
#define FRC_TIMER_LOAD_REG(i) (REG_FRC_TIMER_BASE(i) + 0x0) // timer load value (23 bit for i==0, 32 bit for i==1)
|
||||
#define FRC_TIMER_LOAD_VALUE(i) ((i == 0)?0x007FFFFF:0xffffffff)
|
||||
#define FRC_TIMER_LOAD_VALUE_S 0
|
||||
|
||||
#define FRC_TIMER_COUNT_REG(i) (REG_FRC_TIMER_BASE(i) + 0x4) // timer count value (23 bit for i==0, 32 bit for i==1)
|
||||
#define FRC_TIMER_COUNT ((i == 0)?0x007FFFFF:0xffffffff)
|
||||
#define FRC_TIMER_COUNT_S 0
|
||||
|
||||
#define FRC_TIMER_CTRL_REG(i) (REG_FRC_TIMER_BASE(i) + 0x8)
|
||||
#define FRC_TIMER_INT_ENABLE (BIT(8)) // enable interrupt
|
||||
#define FRC_TIMER_ENABLE (BIT(7)) // enable timer
|
||||
#define FRC_TIMER_AUTOLOAD (BIT(6)) // enable autoload
|
||||
#define FRC_TIMER_PRESCALER 0x00000007 // 0: divide by 1, 2: divide by 16, 4: divide by 256
|
||||
#define FRC_TIMER_PRESCALER_S 1
|
||||
#define FRC_TIMER_EDGE_INT (BIT(0)) // 0: level, 1: edge
|
||||
|
||||
#define FRC_TIMER_INT_REG(i) (REG_FRC_TIMER_BASE(i) + 0xC)
|
||||
#define FRC_TIMER_INT_CLR (BIT(0)) // clear interrupt
|
||||
|
||||
#define FRC_TIMER_ALARM_REG(i) (REG_FRC_TIMER_BASE(i) + 0x10) // timer alarm value; register only present for i == 1
|
||||
#define FRC_TIMER_ALARM 0xFFFFFFFF
|
||||
#define FRC_TIMER_ALARM_S 0
|
||||
|
||||
#endif //_SOC_FRC_TIMER_REG_H_
|
|
@ -0,0 +1,37 @@
|
|||
// 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 __HWCRYPTO_REG_H__
|
||||
#define __HWCRYPTO_REG_H__
|
||||
|
||||
#include "soc.h"
|
||||
|
||||
/* registers for RSA acceleration via Multiple Precision Integer ops */
|
||||
#define RSA_MEM_M_BLOCK_BASE ((DR_REG_RSA_BASE)+0x000)
|
||||
/* RB & Z use the same memory block, depending on phase of operation */
|
||||
#define RSA_MEM_RB_BLOCK_BASE ((DR_REG_RSA_BASE)+0x200)
|
||||
#define RSA_MEM_Z_BLOCK_BASE ((DR_REG_RSA_BASE)+0x200)
|
||||
#define RSA_MEM_Y_BLOCK_BASE ((DR_REG_RSA_BASE)+0x400)
|
||||
#define RSA_MEM_X_BLOCK_BASE ((DR_REG_RSA_BASE)+0x600)
|
||||
|
||||
#define RSA_M_DASH_REG (DR_REG_RSA_BASE + 0x800)
|
||||
#define RSA_MODEXP_MODE_REG (DR_REG_RSA_BASE + 0x804)
|
||||
#define RSA_START_MODEXP_REG (DR_REG_RSA_BASE + 0x808)
|
||||
#define RSA_MULT_MODE_REG (DR_REG_RSA_BASE + 0x80c)
|
||||
#define RSA_MULT_START_REG (DR_REG_RSA_BASE + 0x810)
|
||||
|
||||
#define RSA_INTERRUPT_REG (DR_REG_RSA_BASE + 0X814)
|
||||
|
||||
#define RSA_CLEAN_ADDR (DR_REG_RSA_BASE + 0X818)
|
||||
|
||||
#endif
|
|
@ -34,10 +34,41 @@
|
|||
#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE)
|
||||
#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE)
|
||||
#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv));
|
||||
#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU)
|
||||
#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU)
|
||||
#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD)
|
||||
#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD)
|
||||
|
||||
/*
|
||||
* @attention
|
||||
* The PIN_PULL[UP|DWN]_[EN|DIS]() functions used to exist as macros in previous SDK versions.
|
||||
* Unfortunately, however, they do not work for some GPIOs on the ESP32 chip, which needs pullups
|
||||
* and -downs turned on and off through RTC registers. The functions still exist for compatibility
|
||||
* with older code, but are marked as deprecated in order to generate a warning.
|
||||
* Please replace them in this fashion: (make sure to include driver/gpio.h as well)
|
||||
* PIN_PULLUP_EN(GPIO_PIN_MUX_REG[x]) -> gpio_pullup_en(x)
|
||||
* PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[x]) -> gpio_pullup_dis(x)
|
||||
* PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[x]) -> gpio_pulldown_en(x)
|
||||
* PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[x]) -> gpio_pulldown_dis(x)
|
||||
*
|
||||
*/
|
||||
static inline void __attribute__ ((deprecated)) PIN_PULLUP_DIS(uint32_t PIN_NAME)
|
||||
{
|
||||
REG_CLR_BIT(PIN_NAME, FUN_PU);
|
||||
}
|
||||
|
||||
static inline void __attribute__ ((deprecated)) PIN_PULLUP_EN(uint32_t PIN_NAME)
|
||||
{
|
||||
REG_SET_BIT(PIN_NAME, FUN_PU);
|
||||
}
|
||||
|
||||
static inline void __attribute__ ((deprecated)) PIN_PULLDWN_DIS(uint32_t PIN_NAME)
|
||||
{
|
||||
REG_CLR_BIT(PIN_NAME, FUN_PD);
|
||||
}
|
||||
|
||||
static inline void __attribute__ ((deprecated)) PIN_PULLDWN_EN(uint32_t PIN_NAME)
|
||||
{
|
||||
REG_SET_BIT(PIN_NAME, FUN_PD);
|
||||
}
|
||||
|
||||
|
||||
#define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC)
|
||||
|
||||
#define PIN_FUNC_GPIO 2
|
||||
|
|
|
@ -2163,7 +2163,8 @@
|
|||
#define RMT_DATE_V 0xFFFFFFFF
|
||||
#define RMT_DATE_S 0
|
||||
|
||||
|
||||
/* RMT memory block address */
|
||||
#define RMT_CHANNEL_MEM(i) (DR_REG_RMT_BASE + 0x800 + 64 * 4 * (i))
|
||||
|
||||
|
||||
#endif /*_SOC_RMT_REG_H_ */
|
||||
|
|
|
@ -226,19 +226,35 @@ typedef volatile struct {
|
|||
} rmt_dev_t;
|
||||
extern rmt_dev_t RMT;
|
||||
|
||||
//Allow access to RMT memory using RMTMEM.chan[0].data[8]
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t duration0 :15;
|
||||
uint32_t level0 :1;
|
||||
uint32_t duration1 :15;
|
||||
uint32_t level1 :1;
|
||||
};
|
||||
uint32_t val;
|
||||
};
|
||||
} rmt_item32_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint16_t duration :15;
|
||||
uint16_t level :1;
|
||||
};
|
||||
uint16_t val;
|
||||
};
|
||||
} rmt_item16_t;
|
||||
|
||||
//Allow access to RMT memory using RMTMEM.chan[0].data32[8]
|
||||
typedef volatile struct {
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t level1: 1;
|
||||
uint32_t duration1: 15;
|
||||
uint32_t level0: 1;
|
||||
uint32_t duration0: 15;
|
||||
|
||||
};
|
||||
uint32_t val;
|
||||
} data[64];
|
||||
rmt_item32_t data32[64];
|
||||
rmt_item16_t data16[128];
|
||||
};
|
||||
} chan[8];
|
||||
} rmt_mem_t;
|
||||
extern rmt_mem_t RMTMEM;
|
||||
|
|
|
@ -239,6 +239,9 @@
|
|||
#define RTC_CNTL_TIME_VALID_V 0x1
|
||||
#define RTC_CNTL_TIME_VALID_S 30
|
||||
|
||||
/* frequency of RTC slow clock, Hz */
|
||||
#define RTC_CTNL_SLOWCLK_FREQ 150000
|
||||
|
||||
#define RTC_CNTL_TIME0_REG (DR_REG_RTCCNTL_BASE + 0x10)
|
||||
/* RTC_CNTL_TIME_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */
|
||||
/*description: RTC timer low 32 bits*/
|
||||
|
|
|
@ -141,6 +141,7 @@
|
|||
//}}
|
||||
|
||||
#define DR_REG_DPORT_BASE 0x3ff00000
|
||||
#define DR_REG_RSA_BASE 0x3ff02000
|
||||
#define DR_REG_UART_BASE 0x3ff40000
|
||||
#define DR_REG_SPI1_BASE 0x3ff42000
|
||||
#define DR_REG_SPI0_BASE 0x3ff43000
|
||||
|
@ -148,6 +149,7 @@
|
|||
#define DR_REG_GPIO_SD_BASE 0x3ff44f00
|
||||
#define DR_REG_FE2_BASE 0x3ff45000
|
||||
#define DR_REG_FE_BASE 0x3ff46000
|
||||
#define DR_REG_FRC_TIMER_BASE 0x3ff47000
|
||||
#define DR_REG_RTCCNTL_BASE 0x3ff48000
|
||||
#define DR_REG_RTCIO_BASE 0x3ff48400
|
||||
#define DR_REG_SARADC_BASE 0x3ff48800
|
||||
|
@ -281,9 +283,9 @@
|
|||
* 19 2 extern level
|
||||
* 20 2 extern level
|
||||
* 21 2 extern level
|
||||
* 22 3 extern edge
|
||||
* 22 3 extern edge FRC1 timer
|
||||
* 23 3 extern level
|
||||
* 24 4 extern level
|
||||
* 24 4 extern level TG1_WDT
|
||||
* 25 4 extern level Reserved Reserved
|
||||
* 26 5 extern level Reserved Reserved
|
||||
* 27 3 extern level Reserved Reserved
|
||||
|
@ -301,8 +303,10 @@
|
|||
#define ETS_T0_WDT_INUM 3
|
||||
#define ETS_WBB_INUM 4
|
||||
#define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/
|
||||
#define ETS_FRC1_INUM 22
|
||||
#define ETS_T1_WDT_INUM 24
|
||||
|
||||
//CPU0 Intrrupt number used in ROM, should be cancelled in SDK
|
||||
//CPU0 Interrupt number used in ROM, should be cancelled in SDK
|
||||
#define ETS_SLC_INUM 1
|
||||
#define ETS_UART0_INUM 5
|
||||
#define ETS_UART1_INUM 5
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
#include "soc.h"
|
||||
|
||||
#define REG_UART_BASE( i ) (DR_REG_UART_BASE + (i) * 0x10000 + ( i > 1 ? 0xe000 : 0 ) )
|
||||
|
||||
#define REG_UART_AHB_BASE(i) (0x60000000 + (i) * 0x10000 + ( i > 1 ? 0xe000 : 0 ) )
|
||||
#define UART_FIFO_AHB_REG(i) (REG_UART_AHB_BASE(i) + 0x0)
|
||||
#define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0)
|
||||
|
||||
/* UART_RXFIFO_RD_BYTE : RO ;bitpos:[7:0] ;default: 8'b0 ; */
|
||||
/*description: This register stores one byte data read by rx fifo.*/
|
||||
#define UART_RXFIFO_RD_BYTE 0x000000FF
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "esp_err.h"
|
||||
#include "esp_intr.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
|
||||
|
@ -36,6 +37,38 @@
|
|||
#define WDT_INT_NUM 24
|
||||
|
||||
|
||||
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
|
||||
#if CONFIG_INT_WDT_CHECK_CPU1
|
||||
//Not static; the ISR assembly checks this.
|
||||
bool int_wdt_app_cpu_ticked=false;
|
||||
|
||||
static void IRAM_ATTR tick_hook(void) {
|
||||
if (xPortGetCoreID()!=0) {
|
||||
int_wdt_app_cpu_ticked=true;
|
||||
} else {
|
||||
//Only feed wdt if app cpu also ticked.
|
||||
if (int_wdt_app_cpu_ticked) {
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
|
||||
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
int_wdt_app_cpu_ticked=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void IRAM_ATTR tick_hook(void) {
|
||||
if (xPortGetCoreID()!=0) return;
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
|
||||
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void esp_int_wdt_init() {
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS
|
||||
|
@ -53,6 +86,7 @@ void esp_int_wdt_init() {
|
|||
TIMERG1.wdt_wprotect=0;
|
||||
TIMERG1.int_clr_timers.wdt=1;
|
||||
TIMERG1.int_ena.wdt=1;
|
||||
esp_register_freertos_tick_hook(tick_hook);
|
||||
ESP_INTR_DISABLE(WDT_INT_NUM);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
|
||||
//We do not register a handler for the interrupt because it is interrupt level 4 which
|
||||
|
@ -62,35 +96,5 @@ void esp_int_wdt_init() {
|
|||
}
|
||||
|
||||
|
||||
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
|
||||
#if CONFIG_INT_WDT_CHECK_CPU1
|
||||
//Not static; the ISR assembly checks this.
|
||||
bool int_wdt_app_cpu_ticked=false;
|
||||
|
||||
void IRAM_ATTR vApplicationTickHook(void) {
|
||||
if (xPortGetCoreID()!=0) {
|
||||
int_wdt_app_cpu_ticked=true;
|
||||
} else {
|
||||
//Only feed wdt if app cpu also ticked.
|
||||
if (int_wdt_app_cpu_ticked) {
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
|
||||
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
int_wdt_app_cpu_ticked=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void IRAM_ATTR vApplicationTickHook(void) {
|
||||
if (xPortGetCoreID()!=0) return;
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
|
||||
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -3,8 +3,38 @@ ENTRY(call_start_cpu0);
|
|||
|
||||
SECTIONS
|
||||
{
|
||||
/* RTC fast memory holds RTC wake stub code,
|
||||
including from any source file named rtc_wake_stub*.c
|
||||
*/
|
||||
.rtc.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.rtc.literal .rtc.text)
|
||||
*rtc_wake_stub*.o(.literal .text .literal.* .text.*)
|
||||
} >rtc_iram_seg
|
||||
|
||||
/* RTC slow memory holds RTC wake stub
|
||||
data/rodata, including from any source file
|
||||
named rtc_wake_stub*.c
|
||||
*/
|
||||
.rtc.data :
|
||||
{
|
||||
*(.rtc.data)
|
||||
*(.rtc.rodata)
|
||||
*rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*)
|
||||
} > rtc_slow_seg
|
||||
|
||||
/* RTC bss, from any source file named rtc_wake_stub*.c */
|
||||
.rtc.bss (NOLOAD) :
|
||||
{
|
||||
_rtc_bss_start = ABSOLUTE(.);
|
||||
*rtc_wake_stub*.o(.bss .bss.*)
|
||||
*rtc_wake_stub*.o(COMMON)
|
||||
_rtc_bss_end = ABSOLUTE(.);
|
||||
} > rtc_slow_seg
|
||||
|
||||
/* Send .iram0 code to iram */
|
||||
.iram0.vectors :
|
||||
.iram0.vectors :
|
||||
{
|
||||
/* Vectors go to IRAM */
|
||||
_init_start = ABSOLUTE(.);
|
||||
|
@ -155,16 +185,4 @@ SECTIONS
|
|||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} >iram0_2_seg
|
||||
|
||||
.rtc.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.rtc.literal .rtc.text)
|
||||
} >rtc_iram_seg
|
||||
|
||||
.rtc.data :
|
||||
{
|
||||
*(.rtc.data)
|
||||
*(.rtc.rodata)
|
||||
} > rtc_slow_seg
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 2afb6bb13ec50bf46128331fa7b6835d672c0414
|
||||
Subproject commit e2e5781dc27e638c5e63f85bc23590dd21af1619
|
|
@ -0,0 +1,64 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include "esp_phy_init.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file phy.h
|
||||
* @brief Declarations for functions provided by libphy.a
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize function pointer table in PHY library.
|
||||
* @note This function should be called before register_chipv7_phy.
|
||||
*/
|
||||
void phy_get_romfunc_addr(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize PHY module and do RF calibration
|
||||
* @param[in] init_data Initialization parameters to be used by the PHY
|
||||
* @param[inout] cal_data As input, calibration data previously obtained. As output, will contain new calibration data.
|
||||
* @param[in] cal_mode RF calibration mode
|
||||
* @return reserved for future use
|
||||
*/
|
||||
int register_chipv7_phy(const esp_phy_init_data_t* init_data, esp_phy_calibration_data_t *cal_data, esp_phy_calibration_mode_t cal_mode);
|
||||
|
||||
/**
|
||||
* @brief Get the format version of calibration data used by PHY library.
|
||||
* @return Format version number, OR'ed with BIT(16) if PHY is in WIFI only mode.
|
||||
*/
|
||||
uint32_t phy_get_rf_cal_version();
|
||||
|
||||
/**
|
||||
* @brief Set RF/BB for only WIFI mode or coexist(WIFI & BT) mode
|
||||
* @param[in] true is for only WIFI mode, false is for coexist mode. default is 0.
|
||||
* @return NULL
|
||||
*/
|
||||
void phy_set_wifi_mode_only(bool wifi_only);
|
||||
|
||||
/**
|
||||
* @brief Set BT the highest priority in coexist mode.
|
||||
* @return NULL
|
||||
*/
|
||||
void coex_bt_high_prio(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
// 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 <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rom/ets_sys.h"
|
||||
#include "soc/dport_reg.h"
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "esp_system.h"
|
||||
#include "phy.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "phy_init_data.h"
|
||||
|
||||
static const char* TAG = "phy_init";
|
||||
|
||||
|
||||
esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data,
|
||||
esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data)
|
||||
{
|
||||
assert(init_data);
|
||||
assert(calibration_data);
|
||||
// Initialize PHY pointer table
|
||||
phy_get_romfunc_addr();
|
||||
REG_SET_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST);
|
||||
REG_CLR_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST);
|
||||
// Enable WiFi peripheral clock
|
||||
SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf);
|
||||
ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d",
|
||||
init_data, calibration_data, mode);
|
||||
phy_set_wifi_mode_only(0);
|
||||
register_chipv7_phy(init_data, calibration_data, mode);
|
||||
coex_bt_high_prio();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// PHY init data handling functions
|
||||
#if CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
#include "esp_partition.h"
|
||||
|
||||
const esp_phy_init_data_t* esp_phy_get_init_data()
|
||||
{
|
||||
const esp_partition_t* partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL);
|
||||
if (partition == NULL) {
|
||||
ESP_LOGE(TAG, "PHY data partition not found");
|
||||
return NULL;
|
||||
}
|
||||
ESP_LOGD(TAG, "loading PHY init data from partition at offset 0x%x", partition->address);
|
||||
size_t init_data_store_length = sizeof(phy_init_magic_pre) +
|
||||
sizeof(esp_phy_init_data_t) + sizeof(phy_init_magic_post);
|
||||
uint8_t* init_data_store = (uint8_t*) malloc(init_data_store_length);
|
||||
if (init_data_store == NULL) {
|
||||
ESP_LOGE(TAG, "failed to allocate memory for PHY init data");
|
||||
return NULL;
|
||||
}
|
||||
esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to read PHY data partition (%d)", err);
|
||||
return NULL;
|
||||
}
|
||||
if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 ||
|
||||
memcmp(init_data_store + init_data_store_length - sizeof(phy_init_magic_post),
|
||||
PHY_INIT_MAGIC, sizeof(phy_init_magic_post)) != 0) {
|
||||
ESP_LOGE(TAG, "failed to validate PHY data partition");
|
||||
return NULL;
|
||||
}
|
||||
ESP_LOGE(TAG, "PHY data partition validated");
|
||||
return (const esp_phy_init_data_t*) (init_data_store + sizeof(phy_init_magic_pre));
|
||||
}
|
||||
|
||||
void esp_phy_release_init_data(const esp_phy_init_data_t* init_data)
|
||||
{
|
||||
free((uint8_t*) init_data - sizeof(phy_init_magic_pre));
|
||||
}
|
||||
|
||||
#else // CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
|
||||
// phy_init_data.h will declare static 'phy_init_data' variable initialized with default init data
|
||||
|
||||
const esp_phy_init_data_t* esp_phy_get_init_data()
|
||||
{
|
||||
ESP_LOGD(TAG, "loading PHY init data from application binary");
|
||||
return &phy_init_data;
|
||||
}
|
||||
|
||||
void esp_phy_release_init_data(const esp_phy_init_data_t* init_data)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
#endif // CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
|
||||
|
||||
// PHY calibration data handling functions
|
||||
static const char* PHY_NAMESPACE = "phy";
|
||||
static const char* PHY_CAL_VERSION_KEY = "cal_version";
|
||||
static const char* PHY_CAL_MAC_KEY = "cal_mac";
|
||||
static const char* PHY_CAL_DATA_KEY = "cal_data";
|
||||
|
||||
static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle,
|
||||
esp_phy_calibration_data_t* out_cal_data);
|
||||
|
||||
static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle,
|
||||
const esp_phy_calibration_data_t* cal_data);
|
||||
|
||||
esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data)
|
||||
{
|
||||
nvs_handle handle;
|
||||
esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
err = load_cal_data_from_nvs_handle(handle, out_cal_data);
|
||||
nvs_close(handle);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data)
|
||||
{
|
||||
nvs_handle handle;
|
||||
esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
err = store_cal_data_to_nvs_handle(handle, cal_data);
|
||||
nvs_close(handle);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle,
|
||||
esp_phy_calibration_data_t* out_cal_data)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t cal_data_version;
|
||||
err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: failed to get cal_version (%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16));
|
||||
ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version);
|
||||
if (cal_data_version != cal_format_version) {
|
||||
ESP_LOGD(TAG, "%s: expected calibration data format %d, found %d",
|
||||
__func__, cal_format_version, cal_data_version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uint8_t cal_data_mac[6];
|
||||
size_t length = sizeof(cal_data_mac);
|
||||
err = nvs_get_blob(handle, PHY_CAL_MAC_KEY, cal_data_mac, &length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: failed to get cal_mac (%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
if (length != sizeof(cal_data_mac)) {
|
||||
ESP_LOGD(TAG, "%s: invalid length of cal_mac (%d)", __func__, length);
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
uint8_t sta_mac[6];
|
||||
system_efuse_read_mac(sta_mac);
|
||||
if (memcmp(sta_mac, cal_data_mac, sizeof(sta_mac)) != 0) {
|
||||
ESP_LOGE(TAG, "%s: calibration data MAC check failed: expected " \
|
||||
MACSTR ", found " MACSTR,
|
||||
__func__, MAC2STR(sta_mac), MAC2STR(cal_data_mac));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
length = sizeof(*out_cal_data);
|
||||
err = nvs_get_blob(handle, PHY_CAL_DATA_KEY, out_cal_data, &length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: failed to get cal_data(%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
if (length != sizeof(*out_cal_data)) {
|
||||
ESP_LOGD(TAG, "%s: invalid length of cal_data (%d)", __func__, length);
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle,
|
||||
const esp_phy_calibration_data_t* cal_data)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16));
|
||||
ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version);
|
||||
err = nvs_set_u32(handle, PHY_CAL_VERSION_KEY, cal_format_version);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
uint8_t sta_mac[6];
|
||||
system_efuse_read_mac(sta_mac);
|
||||
err = nvs_set_blob(handle, PHY_CAL_MAC_KEY, sta_mac, sizeof(sta_mac));
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
err = nvs_set_blob(handle, PHY_CAL_DATA_KEY, cal_data, sizeof(*cal_data));
|
||||
return err;
|
||||
}
|
||||
|
||||
void register_chipv7_phy_stub()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
// Copyright 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.
|
||||
|
||||
#pragma once
|
||||
#include "esp_phy_init.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// constrain a value between 'low' and 'high', inclusive
|
||||
#define LIMIT(val, low, high) ((val < low) ? low : (val > high) ? high : val)
|
||||
|
||||
#define PHY_INIT_MAGIC "PHYINIT"
|
||||
|
||||
static const char phy_init_magic_pre[] = PHY_INIT_MAGIC;
|
||||
|
||||
/**
|
||||
* @brief Structure containing default recommended PHY initialization parameters.
|
||||
*/
|
||||
static const esp_phy_init_data_t phy_init_data= {
|
||||
.param_ver_id = 0,
|
||||
.crystal_select = 3,
|
||||
.wifi_rx_gain_swp_step_1 = 0x05,
|
||||
.wifi_rx_gain_swp_step_2 = 0x04,
|
||||
.wifi_rx_gain_swp_step_3 = 0x06,
|
||||
.wifi_rx_gain_swp_step_4 = 0x05,
|
||||
.wifi_rx_gain_swp_step_5 = 0x01,
|
||||
.wifi_rx_gain_swp_step_6 = 0x06,
|
||||
.wifi_rx_gain_swp_step_7 = 0x05,
|
||||
.wifi_rx_gain_swp_step_8 = 0x04,
|
||||
.wifi_rx_gain_swp_step_9 = 0x06,
|
||||
.wifi_rx_gain_swp_step_10 = 0x04,
|
||||
.wifi_rx_gain_swp_step_11 = 0x05,
|
||||
.wifi_rx_gain_swp_step_12 = 0x00,
|
||||
.wifi_rx_gain_swp_step_13 = 0x00,
|
||||
.wifi_rx_gain_swp_step_14 = 0x00,
|
||||
.wifi_rx_gain_swp_step_15 = 0x00,
|
||||
.bt_rx_gain_swp_step_1 = 0x05,
|
||||
.bt_rx_gain_swp_step_2 = 0x04,
|
||||
.bt_rx_gain_swp_step_3 = 0x06,
|
||||
.bt_rx_gain_swp_step_4 = 0x05,
|
||||
.bt_rx_gain_swp_step_5 = 0x01,
|
||||
.bt_rx_gain_swp_step_6 = 0x06,
|
||||
.bt_rx_gain_swp_step_7 = 0x05,
|
||||
.bt_rx_gain_swp_step_8 = 0x00,
|
||||
.bt_rx_gain_swp_step_9 = 0x00,
|
||||
.bt_rx_gain_swp_step_10 = 0x00,
|
||||
.bt_rx_gain_swp_step_11 = 0x00,
|
||||
.bt_rx_gain_swp_step_12 = 0x00,
|
||||
.bt_rx_gain_swp_step_13 = 0x00,
|
||||
.bt_rx_gain_swp_step_14 = 0x00,
|
||||
.bt_rx_gain_swp_step_15 = 0x00,
|
||||
.gain_cmp_1 = 0x0a,
|
||||
.gain_cmp_6 = 0x0a,
|
||||
.gain_cmp_11 = 0x0c,
|
||||
.gain_cmp_ext2_1 = 0xf0,
|
||||
.gain_cmp_ext2_6 = 0xf0,
|
||||
.gain_cmp_ext2_11 = 0xf0,
|
||||
.gain_cmp_ext3_1 = 0xe0,
|
||||
.gain_cmp_ext3_6 = 0xe0,
|
||||
.gain_cmp_ext3_11 = 0xe0,
|
||||
.gain_cmp_bt_ofs_1 = 0x18,
|
||||
.gain_cmp_bt_ofs_6 = 0x18,
|
||||
.gain_cmp_bt_ofs_11 = 0x18,
|
||||
.target_power_qdb_0 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 78),
|
||||
.target_power_qdb_1 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 76),
|
||||
.target_power_qdb_2 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 74),
|
||||
.target_power_qdb_3 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 68),
|
||||
.target_power_qdb_4 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 64),
|
||||
.target_power_qdb_5 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 52),
|
||||
.target_power_index_mcs0 = 0,
|
||||
.target_power_index_mcs1 = 0,
|
||||
.target_power_index_mcs2 = 1,
|
||||
.target_power_index_mcs3 = 1,
|
||||
.target_power_index_mcs4 = 2,
|
||||
.target_power_index_mcs5 = 3,
|
||||
.target_power_index_mcs6 = 4,
|
||||
.target_power_index_mcs7 = 5,
|
||||
.pwr_ind_11b_en = 0,
|
||||
.pwr_ind_11b_0 = 0,
|
||||
.pwr_ind_11b_1 = 0,
|
||||
.chan_backoff_en = 0,
|
||||
.chan1_power_backoff_qdb = 0,
|
||||
.chan2_power_backoff_qdb = 0,
|
||||
.chan3_power_backoff_qdb = 0,
|
||||
.chan4_power_backoff_qdb = 0,
|
||||
.chan5_power_backoff_qdb = 0,
|
||||
.chan6_power_backoff_qdb = 0,
|
||||
.chan7_power_backoff_qdb = 0,
|
||||
.chan8_power_backoff_qdb = 0,
|
||||
.chan9_power_backoff_qdb = 0,
|
||||
.chan10_power_backoff_qdb = 0,
|
||||
.chan11_power_backoff_qdb = 0,
|
||||
.chan12_power_backoff_qdb = 0,
|
||||
.chan13_power_backoff_qdb = 0,
|
||||
.chan14_power_backoff_qdb = 0,
|
||||
.chan1_rate_backoff_index = 0,
|
||||
.chan2_rate_backoff_index = 0,
|
||||
.chan3_rate_backoff_index = 0,
|
||||
.chan4_rate_backoff_index = 0,
|
||||
.chan5_rate_backoff_index = 0,
|
||||
.chan6_rate_backoff_index = 0,
|
||||
.chan7_rate_backoff_index = 0,
|
||||
.chan8_rate_backoff_index = 0,
|
||||
.chan9_rate_backoff_index = 0,
|
||||
.chan10_rate_backoff_index = 0,
|
||||
.chan11_rate_backoff_index = 0,
|
||||
.chan12_rate_backoff_index = 0,
|
||||
.chan13_rate_backoff_index = 0,
|
||||
.chan14_rate_backoff_index = 0,
|
||||
.spur_freq_cfg_msb_1 = 0,
|
||||
.spur_freq_cfg_1 = 0,
|
||||
.spur_freq_cfg_div_1 = 0,
|
||||
.spur_freq_en_h_1 = 0,
|
||||
.spur_freq_en_l_1 = 0,
|
||||
.spur_freq_cfg_msb_2 = 0,
|
||||
.spur_freq_cfg_2 = 0,
|
||||
.spur_freq_cfg_div_2 = 0,
|
||||
.spur_freq_en_h_2 = 0,
|
||||
.spur_freq_en_l_2 = 0,
|
||||
.spur_freq_cfg_msb_3 = 0,
|
||||
.spur_freq_cfg_3 = 0,
|
||||
.spur_freq_cfg_div_3 = 0,
|
||||
.spur_freq_en_h_3 = 0,
|
||||
.spur_freq_en_l_3 = 0,
|
||||
.reserved = {0}
|
||||
};
|
||||
|
||||
static const char phy_init_magic_post[] = PHY_INIT_MAGIC;
|
||||
|
|
@ -22,10 +22,13 @@
|
|||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include <esp_types.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "esp_log.h"
|
||||
|
@ -44,6 +47,8 @@ struct wdt_task_t {
|
|||
};
|
||||
|
||||
static wdt_task_t *wdt_task_list=NULL;
|
||||
static portMUX_TYPE taskwdt_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
|
||||
static void IRAM_ATTR task_wdt_isr(void *arg) {
|
||||
wdt_task_t *wdttask;
|
||||
|
@ -54,24 +59,35 @@ static void IRAM_ATTR task_wdt_isr(void *arg) {
|
|||
TIMERG0.wdt_wprotect=0;
|
||||
//Ack interrupt
|
||||
TIMERG0.int_clr_timers.wdt=1;
|
||||
//We are taking a spinlock while doing I/O (ets_printf) here. Normally, that is a pretty
|
||||
//bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case,
|
||||
//something bad already happened and reporting this is considered more important
|
||||
//than the badness caused by a spinlock here.
|
||||
portENTER_CRITICAL(&taskwdt_spinlock);
|
||||
if (!wdt_task_list) {
|
||||
//No task on list. Maybe none registered yet.
|
||||
portEXIT_CRITICAL(&taskwdt_spinlock);
|
||||
return;
|
||||
}
|
||||
//Watchdog got triggered because at least one task did not report in.
|
||||
ets_printf("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n");
|
||||
ets_printf(DRAM_STR("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n"));
|
||||
for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
|
||||
if (!wdttask->fed_watchdog) {
|
||||
cpu=xTaskGetAffinity(wdttask->task_handle)==0?"CPU 0":"CPU 1";
|
||||
if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu="CPU 0/1";
|
||||
printf(" - %s (%s)\n", pcTaskGetTaskName(wdttask->task_handle), cpu);
|
||||
cpu=xTaskGetAffinity(wdttask->task_handle)==0?DRAM_STR("CPU 0"):DRAM_STR("CPU 1");
|
||||
if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu=DRAM_STR("CPU 0/1");
|
||||
ets_printf(DRAM_STR(" - %s (%s)\n"), pcTaskGetTaskName(wdttask->task_handle), cpu);
|
||||
}
|
||||
}
|
||||
ets_printf("Tasks currently running:\n");
|
||||
ets_printf(DRAM_STR("Tasks currently running:\n"));
|
||||
for (int x=0; x<portNUM_PROCESSORS; x++) {
|
||||
ets_printf("CPU %d: %s\n", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
|
||||
ets_printf(DRAM_STR("CPU %d: %s\n"), x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
|
||||
}
|
||||
|
||||
#if CONFIG_TASK_WDT_PANIC
|
||||
ets_printf("Aborting.\n");
|
||||
ets_printf(DRAM_STR("Aborting.\n"));
|
||||
abort();
|
||||
#endif
|
||||
portEXIT_CRITICAL(&taskwdt_spinlock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,6 +95,8 @@ void esp_task_wdt_feed() {
|
|||
wdt_task_t *wdttask=wdt_task_list;
|
||||
bool found_task=false, do_feed_wdt=true;
|
||||
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
|
||||
portENTER_CRITICAL(&taskwdt_spinlock);
|
||||
|
||||
//Walk the linked list of wdt tasks to find this one, as well as see if we need to feed
|
||||
//the real watchdog timer.
|
||||
for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
|
||||
|
@ -113,14 +131,18 @@ void esp_task_wdt_feed() {
|
|||
//Reset fed_watchdog status
|
||||
for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) wdttask->fed_watchdog=false;
|
||||
}
|
||||
portEXIT_CRITICAL(&taskwdt_spinlock);
|
||||
}
|
||||
|
||||
void esp_task_wdt_delete() {
|
||||
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
|
||||
wdt_task_t *wdttask=wdt_task_list;
|
||||
portENTER_CRITICAL(&taskwdt_spinlock);
|
||||
|
||||
//Wdt task list can't be empty
|
||||
if (!wdt_task_list) {
|
||||
ESP_LOGE(TAG, "task_wdt_delete: No tasks in list?");
|
||||
portEXIT_CRITICAL(&taskwdt_spinlock);
|
||||
return;
|
||||
}
|
||||
if (handle==wdt_task_list) {
|
||||
|
@ -129,17 +151,39 @@ void esp_task_wdt_delete() {
|
|||
free(wdttask);
|
||||
} else {
|
||||
//Find current task in list
|
||||
if (wdt_task_list->task_handle==handle) {
|
||||
//Task is the very first one.
|
||||
wdt_task_t *freeme=wdt_task_list;
|
||||
wdt_task_list=wdt_task_list->next;
|
||||
free(freeme);
|
||||
portEXIT_CRITICAL(&taskwdt_spinlock);
|
||||
return;
|
||||
}
|
||||
while (wdttask->next!=NULL && wdttask->next->task_handle!=handle) wdttask=wdttask->next;
|
||||
if (!wdttask->next) {
|
||||
ESP_LOGE(TAG, "task_wdt_delete: Task never called task_wdt_feed!");
|
||||
portEXIT_CRITICAL(&taskwdt_spinlock);
|
||||
return;
|
||||
}
|
||||
wdt_task_t *freeme=wdttask->next;
|
||||
wdttask->next=wdttask->next->next;
|
||||
free(freeme);
|
||||
}
|
||||
portEXIT_CRITICAL(&taskwdt_spinlock);
|
||||
}
|
||||
|
||||
|
||||
#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
|
||||
static bool idle_hook(void) {
|
||||
#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
|
||||
if (xPortGetCoreID()!=0) return true;
|
||||
#endif
|
||||
esp_task_wdt_feed();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void esp_task_wdt_init() {
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
|
||||
|
@ -153,6 +197,9 @@ void esp_task_wdt_init() {
|
|||
TIMERG0.wdt_config0.en=1;
|
||||
TIMERG0.wdt_feed=1;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
|
||||
esp_register_freertos_idle_hook(idle_hook);
|
||||
#endif
|
||||
ESP_INTR_DISABLE(ETS_T0_WDT_INUM);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM);
|
||||
xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL);
|
||||
|
@ -161,13 +208,5 @@ void esp_task_wdt_init() {
|
|||
ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
|
||||
}
|
||||
|
||||
#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
|
||||
void vApplicationIdleHook(void) {
|
||||
#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
|
||||
if (xPortGetCoreID()!=0) return;
|
||||
#endif
|
||||
esp_task_wdt_feed();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
menu "TESTS"
|
||||
|
||||
config FP_TEST_ENABLE
|
||||
bool "Enable test fp"
|
||||
default "y"
|
||||
help
|
||||
For FPGA single core CPU which has no floating point support, floating point test should be disabled.
|
||||
|
||||
endmenu
|
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
#Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
|
||||
COMPONENT_SRCDIRS := . test_vectors
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
||||
test_tjpgd.o: test_tjpgd_logo.h
|
||||
|
||||
test_tjpgd_logo.h: $(COMPONENT_PATH)/logo.jpg
|
||||
$(summary) XXD logo.jpg
|
||||
$(Q) cd $(COMPONENT_PATH); xxd -i logo.jpg $(COMPONENT_BUILD_DIR)/test_tjpgd_logo.h
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 7.4 KiB |
|
@ -0,0 +1,293 @@
|
|||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/lldesc.h"
|
||||
#include "rom/gpio.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
|
||||
|
||||
#define DPORT_I2S0_CLK_EN (BIT(4))
|
||||
#define DPORT_I2S0_RST (BIT(4))
|
||||
|
||||
|
||||
/*
|
||||
This test tests the s32c1i instruction when the AHB bus is also used. To create some AHB traffic, we use the I2S interface
|
||||
to copy bytes over from one memory location to another. DO NOT USE the i2s routines inhere, they've been trial-and-error'ed until
|
||||
the point where they happened to do what I want.
|
||||
*/
|
||||
|
||||
static void lcdIfaceInit()
|
||||
{
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
|
||||
//Init pins to i2s functions
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
|
||||
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO20_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
|
||||
|
||||
WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
|
||||
// WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
|
||||
|
||||
//GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
|
||||
|
||||
//Reset I2S subsystem
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_SIG_LOOPBACK);
|
||||
WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
|
||||
|
||||
WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
|
||||
(16 << I2S_RX_BITS_MOD_S) |
|
||||
(16 << I2S_TX_BITS_MOD_S) |
|
||||
(1 << I2S_RX_BCK_DIV_NUM_S) |
|
||||
(1 << I2S_TX_BCK_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
|
||||
I2S_CLKA_ENA | I2S_CLK_EN |
|
||||
(1 << I2S_CLKM_DIV_A_S) |
|
||||
(1 << I2S_CLKM_DIV_B_S) |
|
||||
(1 << I2S_CLKM_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
|
||||
(32 << I2S_TX_DATA_NUM_S) | //Low watermark for IRQ
|
||||
(32 << I2S_RX_DATA_NUM_S));
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
|
||||
|
||||
//Invert WS to active-low
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
|
||||
WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
|
||||
}
|
||||
|
||||
|
||||
static volatile lldesc_t dmaDesc[2];
|
||||
|
||||
static void finishDma()
|
||||
{
|
||||
//No need to finish if no DMA transfer going on
|
||||
if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Wait till fifo done
|
||||
while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
|
||||
//Wait for last bytes to leave i2s xmit thing
|
||||
//ToDo: poll bit in next hw
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
|
||||
|
||||
//Reset I2S for next transfer
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This is a very, very, very hacked up LCD routine which ends up basically doing a memcpy from sbuf to rbuf.
|
||||
*/
|
||||
static void sendRecvBufDma(uint16_t *sbuf, uint16_t *rbuf, int len)
|
||||
{
|
||||
//Fill DMA descriptor
|
||||
dmaDesc[0].length = len * 2;
|
||||
dmaDesc[0].size = len * 2;
|
||||
dmaDesc[0].owner = 1;
|
||||
dmaDesc[0].sosf = 0;
|
||||
dmaDesc[0].buf = (uint8_t *)sbuf;
|
||||
dmaDesc[0].offset = 0; //unused in hw
|
||||
dmaDesc[0].empty = 0;
|
||||
dmaDesc[0].eof = 1;
|
||||
dmaDesc[1].length = len * 2;
|
||||
dmaDesc[1].size = len * 2;
|
||||
dmaDesc[1].owner = 1;
|
||||
dmaDesc[1].sosf = 0;
|
||||
dmaDesc[1].buf = (uint8_t *)rbuf;
|
||||
dmaDesc[1].offset = 0; //unused in hw
|
||||
dmaDesc[1].empty = 0;
|
||||
dmaDesc[1].eof = 1;
|
||||
|
||||
//Reset DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
|
||||
//Reset I2S FIFO
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
//Set desc addr
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
|
||||
CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
|
||||
|
||||
WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
|
||||
|
||||
//Enable and configure DMA
|
||||
WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN |
|
||||
I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
|
||||
I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
//Clear int flags
|
||||
WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
#define DMALEN (2048-2)
|
||||
|
||||
static void tskLcd(void *pvParameters)
|
||||
{
|
||||
uint16_t *sbuf = malloc(DMALEN * 2);
|
||||
uint16_t *rbuf = malloc(DMALEN * 2);
|
||||
uint16_t xorval = 0;
|
||||
int x;
|
||||
lcdIfaceInit();
|
||||
// lcdFlush();
|
||||
while (1) {
|
||||
for (x = 0; x < DMALEN; x++) {
|
||||
sbuf[x] = x ^ xorval;
|
||||
}
|
||||
for (x = 0; x < DMALEN; x++) {
|
||||
rbuf[x] = 0; //clear rbuf
|
||||
}
|
||||
sendRecvBufDma(sbuf, rbuf, DMALEN);
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
finishDma();
|
||||
for (x = 0; x < DMALEN; x++) if (rbuf[x] != (x ^ xorval)) {
|
||||
printf("Rxbuf err! pos %d val %x xor %x", x, (int)rbuf[x], (int)xorval);
|
||||
}
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
xorval++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_s32c1i_lock(volatile int *lockvar, int lockval, int unlockval, volatile int *ctr);
|
||||
|
||||
static volatile int ctr = 0, state = 0;
|
||||
static volatile int lock = 0;
|
||||
|
||||
static void tskOne(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int err = 0, run = 0;
|
||||
while (1) {
|
||||
ctr = 0; lock = 0;
|
||||
state = 1;
|
||||
for (x = 0; x < 16 * 1024; x++) {
|
||||
test_s32c1i_lock(&lock, 1, 0, &ctr);
|
||||
}
|
||||
vTaskDelay(60 / portTICK_PERIOD_MS);
|
||||
state = 2;
|
||||
if (ctr != 16 * 1024 * 2) {
|
||||
printf("Lock malfunction detected! Ctr=0x%x instead of %x\n", ctr, 16 * 1024 * 2);
|
||||
err++;
|
||||
}
|
||||
run++;
|
||||
printf("Run %d err %d\n", run, err);
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
#define FB2ADDR 0x40098000
|
||||
|
||||
static void tskTwo(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int *p = (int *)FB2ADDR;
|
||||
int *s = (int *)test_s32c1i_lock;
|
||||
void (*test_s32c1i_lock2)(volatile int * lockvar, int lockval, int unlockval, volatile int * ctr) = (void *)FB2ADDR;
|
||||
volatile int w;
|
||||
int delay;
|
||||
for (x = 0; x < 100; x++) {
|
||||
*p++ = *s++; //copy routine to different pool
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (state != 1) ;
|
||||
for (x = 0; x < 16 * 1024; x++) {
|
||||
test_s32c1i_lock2(&lock, 2, 0, &ctr);
|
||||
//Some random delay to increase chance of weirdness
|
||||
if ((x & 0x1f) == 0) {
|
||||
delay = rand() & 0x1f;
|
||||
for (w = 0; w < delay; w++);
|
||||
}
|
||||
}
|
||||
while (state != 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("S32C1I vs AHB test (needs I2S)", "[hw]")
|
||||
{
|
||||
int i;
|
||||
TaskHandle_t th[3];
|
||||
state = 0;
|
||||
|
||||
printf("Creating tasks\n");
|
||||
xTaskCreatePinnedToCore(tskTwo , "tsktwo" , 2048, NULL, 3, &th[1], 1);
|
||||
xTaskCreatePinnedToCore(tskOne , "tskone" , 2048, NULL, 3, &th[0], 0);
|
||||
xTaskCreatePinnedToCore(tskLcd , "tsklcd" , 2048, NULL, 3, &th[2], 0);
|
||||
|
||||
// Let stuff run for 20s
|
||||
while (1) {
|
||||
vTaskDelay(20000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
//Shut down all the tasks
|
||||
for (i = 0; i < 3; i++) {
|
||||
vTaskDelete(th[i]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
This little bit of code is executed in-place by one CPU, but copied to a different memory region
|
||||
by the other CPU. Make sure it stays position-independent.
|
||||
*/
|
||||
.text
|
||||
.align 4
|
||||
.global test_s32c1i_lock
|
||||
.type test_s32c1i_lock,@function
|
||||
//Args:
|
||||
//a2 - lock addr
|
||||
//a3 - val to lock with
|
||||
//a4 - val to unlock with
|
||||
//a5 - addr to increase
|
||||
test_s32c1i_lock:
|
||||
entry a1, 64
|
||||
wsr a4, SCOMPARE1
|
||||
lockloop:
|
||||
mov a6, a3
|
||||
s32c1i a6, a2, 0
|
||||
bne a4, a6, lockloop
|
||||
|
||||
l32i a6, a5, 0
|
||||
//Give other CPU the time to mess up the inc if the lock somehow malfunctions
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
addi a6, a6, 1
|
||||
s32i a6, a5, 0
|
||||
|
||||
|
||||
//No need to actually let this loop but hey, a hang indicates an error, right?
|
||||
wsr a3, SCOMPARE1
|
||||
unlockloop:
|
||||
mov a6, a4
|
||||
s32c1i a6, a2, 0
|
||||
bne a3, a6, unlockloop
|
||||
|
||||
retw
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
|
||||
/*
|
||||
This test tests the 'fast' peripherial bus at 0x3ff40000. This bus is connected directly to the core, and as such
|
||||
can receive 'speculative' reads, that is, reads that may or may not actually be executed in the code flow. This
|
||||
may mess with any FIFOs mapped in the region: if a byte gets dropped due to a missed speculative read, the fifo
|
||||
may advance to the next byte anyway.
|
||||
|
||||
This code tests reading/writing from the UART1 FIFO, using both cores. For this to work, it's required that the
|
||||
UARTs RX and TX lines are connected.
|
||||
*/
|
||||
|
||||
|
||||
void test_fastbus_cp(int fifo_addr, unsigned char *buf, int len, int *dummy);
|
||||
|
||||
static volatile int state = 0;
|
||||
static volatile int xor = 0;
|
||||
static unsigned char res[128];
|
||||
|
||||
static void tskOne(void *pvParameters)
|
||||
{
|
||||
int run = 0, err = 0;
|
||||
int x;
|
||||
int ct[256];
|
||||
volatile int w;
|
||||
int dummy;
|
||||
while (1) {
|
||||
state = 1;
|
||||
for (x = 0; x < 64; x++) {
|
||||
WRITE_PERI_REG(UART_FIFO_REG(1), x ^ xor);
|
||||
}
|
||||
for (w = 0; w < (1 << 14); w++); //delay
|
||||
state = 2;
|
||||
test_fastbus_cp(UART_FIFO_REG(1), &res[0], 64, &dummy);
|
||||
for (w = 0; w < (1 << 10); w++); //delay
|
||||
for (x = 0; x < 255; x++) {
|
||||
ct[x] = 0; //zero ctrs
|
||||
}
|
||||
for (x = 0; x < 128; x++) {
|
||||
ct[(int)res[x]^xor]++; //count values
|
||||
}
|
||||
for (x = 0; x < 255; x++) { //check counts
|
||||
if (ct[x] != (x < 128 ? 1 : 0)) {
|
||||
//Disregard first few loops; there may be crap in the fifo.
|
||||
if (run > 2) {
|
||||
err++;
|
||||
printf("Error! Received value %d %d times!\n", x, ct[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
run++;
|
||||
if ((run & 255) == 0) {
|
||||
printf("Loop %d errct %d\n", run, err);
|
||||
}
|
||||
xor = (xor + 1) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
#define FB2ADDR 0x40098000
|
||||
|
||||
static void tskTwo(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int dummy;
|
||||
int *p = (int *)FB2ADDR;
|
||||
int *s = (int *)test_fastbus_cp;
|
||||
for (x = 0; x < 100; x++) {
|
||||
*p++ = *s++;
|
||||
}
|
||||
void (*test_fastbus_cp2)(int fifo_addr, unsigned char * buf, int len, int * dummy) = (void *)FB2ADDR;
|
||||
|
||||
|
||||
while (1) {
|
||||
while (state != 1) ;
|
||||
for (x = 64; x < 128; x++) {
|
||||
WRITE_PERI_REG(UART_FIFO_REG(1), x ^ xor);
|
||||
}
|
||||
while (state != 2);
|
||||
test_fastbus_cp2(UART_FIFO_REG(1), &res[64], 64, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: split this thing into separate orthogonal tests
|
||||
TEST_CASE("Fast I/O bus test", "[hw]")
|
||||
{
|
||||
int i;
|
||||
if ((REG_UART_BASE(0) >> 16) != 0x3ff4) {
|
||||
printf("Error! Uart base isn't on fast bus.\n");
|
||||
TEST_ASSERT(0);
|
||||
}
|
||||
|
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_SD_DATA3_U);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, FUNC_SD_DATA2_U1RXD);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, FUNC_SD_DATA3_U1TXD);
|
||||
|
||||
int reg_val = (1 << UART_RXFIFO_FULL_THRHD_S);
|
||||
WRITE_PERI_REG(UART_CONF1_REG(1), reg_val);
|
||||
WRITE_PERI_REG(UART_CLKDIV_REG(1), 0x30); //semi-random
|
||||
// CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(1), UART_TXFIFO_EMPTY_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
|
||||
|
||||
TaskHandle_t th[2];
|
||||
printf("Creating tasks\n");
|
||||
xTaskCreatePinnedToCore(tskOne , "tskone" , 2048, NULL, 3, &th[0], 0);
|
||||
xTaskCreatePinnedToCore(tskTwo , "tsktwo" , 2048, NULL, 3, &th[1], 1);
|
||||
|
||||
// Let stuff run for 20s
|
||||
while (1) {
|
||||
vTaskDelay(20000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
//Shut down all the tasks
|
||||
for (i = 0; i < 2; i++) {
|
||||
vTaskDelete(th[i]);
|
||||
}
|
||||
xt_ints_off(1 << ETS_UART0_INUM);
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
This little bit of code is executed in-place by one CPU, but copied to a different memory region
|
||||
by the other CPU. Make sure it stays position-independent.
|
||||
*/
|
||||
.text
|
||||
.align 4
|
||||
.global test_fastbus_cp
|
||||
.type test_fastbus_cp,@function
|
||||
//Args:
|
||||
//a2 - fifo addr
|
||||
//a3 - buf addr
|
||||
//a4 - len
|
||||
//a5 - ptr to int to use
|
||||
test_fastbus_cp:
|
||||
entry a1,64
|
||||
back:
|
||||
beqi a4, 0, out //check if loop done
|
||||
s32i a4, a5, 0 //store value, for shits and/or giggles
|
||||
memw //make sure write happens
|
||||
l32i a4, a5, 0 //load value again, to thwart any prediction in the pipeline
|
||||
bbsi a4, 0, pred //Random jump to check predictive reads. Both branches should do the same.
|
||||
l32i a6, a2, 0 //read from fifo 1
|
||||
j predout
|
||||
pred:
|
||||
l32i a6, a2, 0 //read from fifo 2
|
||||
predout:
|
||||
s8i a6, a3, 0 //store result
|
||||
addi a3, a3, 1 //inc ptr
|
||||
addi a4, a4, -1 //next
|
||||
j back //loop again
|
||||
out:
|
||||
retw //and we are done
|
|
@ -0,0 +1,195 @@
|
|||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
|
||||
#if CONFIG_FP_TEST_ENABLE
|
||||
static float addsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"add.s f2, f0, f1\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float mulsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"mul.s f2, f0, f1\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float divsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"div0.s f3, f1 \n"
|
||||
"nexp01.s f4, f1 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"maddn.s f5, f4, f3 \n"
|
||||
"mov.s f6, f3 \n"
|
||||
"mov.s f7, f1 \n"
|
||||
"nexp01.s f8, f0 \n"
|
||||
"maddn.s f6, f5, f3 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"const.s f2, 0 \n"
|
||||
"neg.s f9, f8 \n"
|
||||
"maddn.s f5,f4,f6 \n"
|
||||
"maddn.s f2, f0, f3 \n"
|
||||
"mkdadj.s f7, f0 \n"
|
||||
"maddn.s f6,f5,f6 \n"
|
||||
"maddn.s f9,f4,f2 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"maddn.s f5,f4,f6 \n"
|
||||
"maddn.s f2,f9,f6 \n"
|
||||
"neg.s f9, f8 \n"
|
||||
"maddn.s f6,f5,f6 \n"
|
||||
"maddn.s f9,f4,f2 \n"
|
||||
"addexpm.s f2, f7 \n"
|
||||
"addexp.s f6, f7 \n"
|
||||
"divn.s f2,f9,f6\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float sqrtsf(float a)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"sqrt0.s f2, f0\n"
|
||||
"const.s f5, 0\n"
|
||||
"maddn.s f5, f2, f2\n"
|
||||
"nexp01.s f3, f0\n"
|
||||
"const.s f4, 3\n"
|
||||
"addexp.s f3, f4\n"
|
||||
"maddn.s f4, f5, f3\n"
|
||||
"nexp01.s f5, f0\n"
|
||||
"neg.s f6, f5\n"
|
||||
"maddn.s f2, f4, f2\n"
|
||||
"const.s f1, 0\n"
|
||||
"const.s f4, 0\n"
|
||||
"const.s f7, 0\n"
|
||||
"maddn.s f1, f6, f2\n"
|
||||
"maddn.s f4, f2, f3\n"
|
||||
"const.s f6, 3\n"
|
||||
"maddn.s f7, f6, f2\n"
|
||||
"maddn.s f5, f1, f1\n"
|
||||
"maddn.s f6, f4, f2\n"
|
||||
"neg.s f3, f7\n"
|
||||
"maddn.s f1, f5, f3\n"
|
||||
"maddn.s f7, f6, f7\n"
|
||||
"mksadj.s f2, f0\n"
|
||||
"nexp01.s f5, f0\n"
|
||||
"maddn.s f5, f1, f1\n"
|
||||
"neg.s f3, f7\n"
|
||||
"addexpm.s f1, f2\n"
|
||||
"addexp.s f3, f2\n"
|
||||
"divn.s f1, f5, f3\n"
|
||||
"rfr %0, f1\n"
|
||||
:"=r"(result):"r"(a)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST_CASE("test FP add", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 0.5f;
|
||||
float c = addsf(a, b);
|
||||
float eps = c - 100.5f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP mul", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 0.05f;
|
||||
float c = mulsf(a, b);
|
||||
float eps = c - 5.0f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP div", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 5.0f;
|
||||
float c = divsf(a, b);
|
||||
float eps = c - 20.0f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP sqrt", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float c = sqrtsf(a);
|
||||
float eps = c - 10.0f;
|
||||
printf("a=%g c=%g eps=%g\r\n", a, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
|
||||
struct TestFPState {
|
||||
int fail;
|
||||
int done;
|
||||
};
|
||||
|
||||
static const int testFpIter = 100000;
|
||||
|
||||
static void tskTestFP(void *pvParameters)
|
||||
{
|
||||
struct TestFPState *state = (struct TestFPState *) pvParameters;
|
||||
for (int i = 0; i < testFpIter; ++i) {
|
||||
// calculate zero in a slightly obscure way
|
||||
float y = sqrtsf(addsf(1.0f, divsf(mulsf(sqrtsf(2), sqrtsf(2)), 2.0f)));
|
||||
y = mulsf(y, y);
|
||||
y = addsf(y, -2.0f);
|
||||
// check that result is not far from zero
|
||||
float eps = fabs(y);
|
||||
if (eps > 1e-6f) {
|
||||
state->fail++;
|
||||
printf("%s: i=%d y=%f eps=%f\r\n", __func__, i, y, eps);
|
||||
}
|
||||
}
|
||||
state->done++;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("context switch saves FP registers", "[fp]")
|
||||
{
|
||||
struct TestFPState state;
|
||||
state.done = 0;
|
||||
state.fail = 0;
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk1", 2048, &state, 3, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk2", 2048, &state, 3, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk3", 2048, &state, 3, NULL, 1);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk4", 2048, &state, 3, NULL, 0);
|
||||
while (state.done != 4) {
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
if (state.fail) {
|
||||
const int total = testFpIter * 4;
|
||||
printf("Failed: %d, total: %d\r\n", state.fail, total);
|
||||
}
|
||||
TEST_ASSERT(state.fail == 0);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "rom/miniz.h"
|
||||
#include "unity.h"
|
||||
|
||||
|
||||
#define DATASIZE (1024*64)
|
||||
|
||||
TEST_CASE("Test miniz compression/decompression", "[miniz]")
|
||||
{
|
||||
int x;
|
||||
char b;
|
||||
char *inbuf, *outbuf;
|
||||
tdefl_compressor *comp;
|
||||
tinfl_decompressor *decomp;
|
||||
tdefl_status status;
|
||||
size_t inbytes = 0, outbytes = 0, inpos = 0, outpos = 0, compsz;
|
||||
printf("Allocating data buffer and filling it with semi-random data\n");
|
||||
inbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(inbuf != NULL);
|
||||
srand(0);
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
inbuf[x] = (x & 1) ? rand() & 0xff : 0;
|
||||
}
|
||||
printf("Allocating compressor & outbuf (%d bytes)\n", sizeof(tdefl_compressor));
|
||||
comp = malloc(sizeof(tdefl_compressor));
|
||||
TEST_ASSERT(comp != NULL);
|
||||
outbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(outbuf != NULL);
|
||||
printf("Compressing...\n");
|
||||
status = tdefl_init(comp, NULL, NULL, TDEFL_WRITE_ZLIB_HEADER | 1500);
|
||||
TEST_ASSERT(status == TDEFL_STATUS_OKAY);
|
||||
while (inbytes != DATASIZE) {
|
||||
outbytes = DATASIZE - outpos;
|
||||
inbytes = DATASIZE - inpos;
|
||||
tdefl_compress(comp, &inbuf[inpos], &inbytes, &outbuf[outpos], &outbytes, TDEFL_FINISH);
|
||||
printf("...Compressed %d into %d bytes\n", inbytes, outbytes);
|
||||
inpos += inbytes; outpos += outbytes;
|
||||
}
|
||||
compsz = outpos;
|
||||
free(comp);
|
||||
//Kill inbuffer
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
inbuf[x] = 0;
|
||||
}
|
||||
free(inbuf);
|
||||
|
||||
inbuf = outbuf;
|
||||
outbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(outbuf != NULL);
|
||||
printf("Reinflating...\n");
|
||||
decomp = malloc(sizeof(tinfl_decompressor));
|
||||
TEST_ASSERT(decomp != NULL);
|
||||
tinfl_init(decomp);
|
||||
inpos = 0; outpos = 0;
|
||||
while (inbytes != compsz) {
|
||||
outbytes = DATASIZE - outpos;
|
||||
inbytes = compsz - inpos;
|
||||
tinfl_decompress(decomp, (const mz_uint8 *)&inbuf[inpos], &inbytes, (uint8_t *)outbuf, (mz_uint8 *)&outbuf[outpos], &outbytes, TINFL_FLAG_PARSE_ZLIB_HEADER);
|
||||
printf("...Decompressed %d into %d bytes\n", inbytes, outbytes);
|
||||
inpos += inbytes; outpos += outbytes;
|
||||
}
|
||||
printf("Checking if same...\n");
|
||||
srand(0);
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
b = (x & 1) ? rand() & 0xff : 0;
|
||||
if (outbuf[x] != b) {
|
||||
printf("Pos %x: %hhx!=%hhx\n", x, outbuf[x], b);
|
||||
TEST_ASSERT(0);
|
||||
}
|
||||
}
|
||||
printf("Great Success!\n");
|
||||
free(inbuf);
|
||||
free(outbuf);
|
||||
free(decomp);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "rom/tjpgd.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "unity.h"
|
||||
|
||||
#include "test_tjpgd_logo.h"
|
||||
|
||||
typedef struct {
|
||||
const unsigned char *inData;
|
||||
int inPos;
|
||||
unsigned char *outData;
|
||||
int outW;
|
||||
int outH;
|
||||
} JpegDev;
|
||||
|
||||
|
||||
static UINT infunc(JDEC *decoder, BYTE *buf, UINT len)
|
||||
{
|
||||
JpegDev *jd = (JpegDev *)decoder->device;
|
||||
printf("Reading %d bytes from pos %d\n", len, jd->inPos);
|
||||
if (buf != NULL) {
|
||||
memcpy(buf, jd->inData + jd->inPos, len);
|
||||
}
|
||||
jd->inPos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect)
|
||||
{
|
||||
unsigned char *in = (unsigned char *)bitmap;
|
||||
unsigned char *out;
|
||||
int y;
|
||||
printf("Rect %d,%d - %d,%d\n", rect->top, rect->left, rect->bottom, rect->right);
|
||||
JpegDev *jd = (JpegDev *)decoder->device;
|
||||
for (y = rect->top; y <= rect->bottom; y++) {
|
||||
out = jd->outData + ((jd->outW * y) + rect->left) * 3;
|
||||
memcpy(out, in, ((rect->right - rect->left) + 1) * 3);
|
||||
in += ((rect->right - rect->left) + 1) * 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define TESTW 48
|
||||
#define TESTH 48
|
||||
#define WORKSZ 3100
|
||||
|
||||
TEST_CASE("Test JPEG decompression library", "[tjpgd]")
|
||||
{
|
||||
char aapix[] = " .:;+=xX$$";
|
||||
unsigned char *decoded, *p;
|
||||
char *work;
|
||||
int r;
|
||||
int x, y, v;
|
||||
JDEC decoder;
|
||||
JpegDev jd;
|
||||
decoded = malloc(48 * 48 * 3);
|
||||
for (x = 0; x < 48 * 48 * 3; x += 2) {
|
||||
decoded[x] = 0; decoded[x + 1] = 0xff;
|
||||
}
|
||||
work = malloc(WORKSZ);
|
||||
memset(work, 0, WORKSZ);
|
||||
|
||||
jd.inData = logo_jpg;
|
||||
jd.inPos = 0;
|
||||
jd.outData = decoded;
|
||||
jd.outW = TESTW;
|
||||
jd.outH = TESTH;
|
||||
|
||||
r = jd_prepare(&decoder, infunc, work, WORKSZ, (void *)&jd);
|
||||
TEST_ASSERT_EQUAL(r, JDR_OK);
|
||||
r = jd_decomp(&decoder, outfunc, 0);
|
||||
TEST_ASSERT_EQUAL(r, JDR_OK);
|
||||
|
||||
p = decoded + 2;
|
||||
for (y = 0; y < TESTH; y++) {
|
||||
for (x = 0; x < TESTH; x++) {
|
||||
v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;
|
||||
printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]);
|
||||
p += 3;
|
||||
}
|
||||
printf("%c%c", ' ', '\n');
|
||||
}
|
||||
|
||||
free(work);
|
||||
free(decoded);
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/lldesc.h"
|
||||
#include "rom/gpio.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
|
||||
|
||||
#define DPORT_I2S0_CLK_EN (BIT(4))
|
||||
#define DPORT_I2S0_RST (BIT(4))
|
||||
|
||||
static volatile lldesc_t dmaDesc[2];
|
||||
|
||||
|
||||
//hacked up routine to essentially do a memcpy() using dma. Supports max 4K-1 bytes.
|
||||
static void dmaMemcpy(void *in, void *out, int len)
|
||||
{
|
||||
volatile int i;
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
|
||||
//Init pins to i2s functions
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
|
||||
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO20_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
|
||||
|
||||
WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
|
||||
// WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
|
||||
|
||||
//GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
|
||||
|
||||
//Reset I2S subsystem
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_I2S_SIG_LOOPBACK);
|
||||
WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
|
||||
|
||||
WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
|
||||
(16 << I2S_RX_BITS_MOD_S) |
|
||||
(16 << I2S_TX_BITS_MOD_S) |
|
||||
(1 << I2S_RX_BCK_DIV_NUM_S) |
|
||||
(1 << I2S_TX_BCK_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
|
||||
I2S_CLKA_ENA | I2S_CLK_EN |
|
||||
(1 << I2S_CLKM_DIV_A_S) |
|
||||
(1 << I2S_CLKM_DIV_B_S) |
|
||||
(1 << I2S_CLKM_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
|
||||
(32 << I2S_TX_DATA_NUM_S) | //Low watermark for IRQ
|
||||
(32 << I2S_RX_DATA_NUM_S));
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
|
||||
|
||||
//Invert WS to active-low
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
|
||||
WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
|
||||
|
||||
//--
|
||||
//Fill DMA descriptor
|
||||
dmaDesc[0].length = len;
|
||||
dmaDesc[0].size = len;
|
||||
dmaDesc[0].owner = 1;
|
||||
dmaDesc[0].sosf = 0;
|
||||
dmaDesc[0].buf = (uint8_t *)in;
|
||||
dmaDesc[0].offset = 0; //unused in hw
|
||||
dmaDesc[0].empty = 0;
|
||||
dmaDesc[0].eof = 1;
|
||||
dmaDesc[1].length = len;
|
||||
dmaDesc[1].size = len;
|
||||
dmaDesc[1].owner = 1;
|
||||
dmaDesc[1].sosf = 0;
|
||||
dmaDesc[1].buf = (uint8_t *)out;
|
||||
dmaDesc[1].offset = 0; //unused in hw
|
||||
dmaDesc[1].empty = 0;
|
||||
dmaDesc[1].eof = 1;
|
||||
|
||||
//Reset DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
|
||||
//Reset I2S FIFO
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
//Set desc addr
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
|
||||
CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
|
||||
|
||||
WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
|
||||
|
||||
//Enable and configure DMA
|
||||
WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN |
|
||||
I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
|
||||
I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
//Clear int flags
|
||||
WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
|
||||
//--
|
||||
//No need to finish if no DMA transfer going on
|
||||
if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Wait till fifo done
|
||||
while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
|
||||
//Wait for last bytes to leave i2s xmit thing
|
||||
//ToDo: poll bit in next hw
|
||||
for (i = 0; i < (1 << 8); i++);
|
||||
while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
|
||||
|
||||
//Reset I2S for next transfer
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
|
||||
|
||||
}
|
||||
|
||||
|
||||
int mymemcmp(char *a, char *b, int len)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < len; x++) {
|
||||
if (a[x] != b[x]) {
|
||||
printf("Not equal at byte %d. a=%x, b=%x\n", x, (int)a[x], (int)b[x]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("Unaligned DMA test (needs I2S)", "[hw]")
|
||||
{
|
||||
int x;
|
||||
char src[2049], dest[2049];
|
||||
for (x = 0; x < sizeof(src); x++) {
|
||||
src[x] = x & 0xff;
|
||||
}
|
||||
|
||||
printf("Aligned dma\n");
|
||||
memset(dest, 0, 2049);
|
||||
dmaMemcpy(src, dest, 2048 + 1);
|
||||
TEST_ASSERT(mymemcmp(src, dest, 2048) == 0);
|
||||
printf("Src unaligned\n");
|
||||
dmaMemcpy(src + 1, dest, 2048 + 1);
|
||||
TEST_ASSERT(mymemcmp(src + 1, dest, 2048) == 0);
|
||||
printf("Dst unaligned\n");
|
||||
dmaMemcpy(src, dest + 1, 2048 + 2);
|
||||
TEST_ASSERT(mymemcmp(src, dest + 1, 2048) == 0);
|
||||
}
|
||||
|
|
@ -11,27 +11,49 @@ PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
|
|||
# two commands that can be used from other components
|
||||
# to invoke esptool.py (with or without serial port args)
|
||||
#
|
||||
# NB: esptool.py lives in the sdk/bin directory not the component directory
|
||||
ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py
|
||||
ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
|
||||
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
|
||||
|
||||
# Supporting esptool command line tools
|
||||
ESPEFUSEPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espefuse.py
|
||||
ESPSECUREPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espsecure.py
|
||||
export ESPSECUREPY # is used in bootloader_support component
|
||||
|
||||
ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE)
|
||||
|
||||
# the no-stub argument is temporary until esptool.py fully supports compressed uploads
|
||||
ESPTOOL_ELF2IMAGE_OPTIONS :=
|
||||
|
||||
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS)
|
||||
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
|
||||
|
||||
$(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC)
|
||||
$(Q) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) -o $@ $<
|
||||
ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
# for secure boot, add a signing step to get from unsiged app to signed app
|
||||
APP_BIN_UNSIGNED := $(APP_BIN:.bin=-unsigned.bin)
|
||||
|
||||
$(APP_BIN): $(APP_BIN_UNSIGNED)
|
||||
$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $^ # signed in-place
|
||||
endif
|
||||
endif
|
||||
# non-secure boot (or bootloader), both these files are the same
|
||||
APP_BIN_UNSIGNED ?= $(APP_BIN)
|
||||
|
||||
$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC)
|
||||
$(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
|
||||
|
||||
flash: all_binaries $(ESPTOOLPY_SRC)
|
||||
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..."
|
||||
$(Q) $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
|
||||
ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
|
||||
endif
|
||||
$(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
|
||||
|
||||
app-flash: $(APP_BIN) $(ESPTOOLPY_SRC)
|
||||
@echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..."
|
||||
$(Q) $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN)
|
||||
$(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN)
|
||||
|
||||
$(eval $(call SubmoduleCheck,$(ESPTOOLPY_SRC),$(COMPONENT_PATH)/esptool))
|
||||
# Submodules normally added in component.mk, but can be added
|
||||
# at the project level as long as qualified path
|
||||
COMPONENT_SUBMODULES += $(COMPONENT_PATH)/esptool
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. 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 SDK documents if you need to do this.
|
||||
#
|
||||
COMPONENT_ADD_INCLUDEDIRS := port/include include/expat
|
||||
|
||||
COMPONENT_SRCDIRS := library port
|
||||
|
||||
CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
|
|
@ -108,44 +108,45 @@ add_failure(SRunner *runner, int verbosity)
|
|||
}
|
||||
}
|
||||
|
||||
static void run_test(SRunner *runner, int verbosity, TCase *tc, int i)
|
||||
{
|
||||
if (tc->setup != NULL) {
|
||||
/* setup */
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
return;
|
||||
}
|
||||
tc->setup();
|
||||
}
|
||||
/* test */
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
return;
|
||||
}
|
||||
(tc->tests[i])();
|
||||
|
||||
/* teardown */
|
||||
if (tc->teardown != NULL) {
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
return;
|
||||
}
|
||||
tc->teardown();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
srunner_run_all(SRunner *runner, int verbosity)
|
||||
{
|
||||
Suite *suite;
|
||||
TCase *tc;
|
||||
assert(runner != NULL);
|
||||
suite = runner->suite;
|
||||
tc = suite->tests;
|
||||
assert(runner->suite != NULL);
|
||||
TCase *tc = runner->suite->tests;
|
||||
while (tc != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < tc->ntests; ++i) {
|
||||
for (int i = 0; i < tc->ntests; ++i) {
|
||||
runner->nchecks++;
|
||||
|
||||
if (tc->setup != NULL) {
|
||||
/* setup */
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
continue;
|
||||
}
|
||||
tc->setup();
|
||||
}
|
||||
/* test */
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
continue;
|
||||
}
|
||||
(tc->tests[i])();
|
||||
|
||||
/* teardown */
|
||||
if (tc->teardown != NULL) {
|
||||
if (setjmp(env)) {
|
||||
add_failure(runner, verbosity);
|
||||
continue;
|
||||
}
|
||||
tc->teardown();
|
||||
}
|
||||
run_test(runner, verbosity, tc, i);
|
||||
tc = tc->next_tcase;
|
||||
}
|
||||
tc = tc->next_tcase;
|
||||
}
|
||||
if (verbosity) {
|
||||
int passed = runner->nchecks - runner->nfailures;
|
||||
|
|
|
@ -141,6 +141,35 @@ config FREERTOS_ISR_STACKSIZE
|
|||
The interrupt handlers have their own stack. The size of the stack can be defined here.
|
||||
Each processor has its own stack, so the total size occupied will be twice this.
|
||||
|
||||
config FREERTOS_LEGACY_HOOKS
|
||||
bool "Use FreeRTOS legacy hooks"
|
||||
default n
|
||||
help
|
||||
FreeRTOS offers a number of hooks/callback functions that are called when a timer
|
||||
tick happens, the idle thread runs etc. esp-idf replaces these by runtime registerable
|
||||
hooks using the esp_register_freertos_xxx_hook system, but for legacy reasons the old
|
||||
hooks can also still be enabled. Please enable this only if you have code that for some
|
||||
reason can't be migrated to the esp_register_freertos_xxx_hook system.
|
||||
|
||||
if FREERTOS_LEGACY_HOOKS
|
||||
|
||||
config FREERTOS_LEGACY_IDLE_HOOK
|
||||
bool "Enable legacy idle hook"
|
||||
default n
|
||||
help
|
||||
If enabled, FreeRTOS will call a function called vApplicationIdleHook when the idle thread
|
||||
on a CPU is running. Please make sure your code defines such a function.
|
||||
|
||||
config FREERTOS_LEGACY_TICK_HOOK
|
||||
bool "Enable legacy tick hook"
|
||||
default n
|
||||
help
|
||||
If enabled, FreeRTOS will call a function called vApplicationTickHook when a FreeRTOS
|
||||
tick is executed. Please make sure your code defines such a function.
|
||||
|
||||
endif #FREERTOS_LEGACY_HOOKS
|
||||
|
||||
|
||||
menuconfig FREERTOS_DEBUG_INTERNALS
|
||||
bool "Debug FreeRTOS internals"
|
||||
default n
|
||||
|
|
|
@ -6,4 +6,3 @@ COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) -Wl,--undefined=uxTopUsedPriority
|
|||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include/freertos
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
|
|
@ -895,7 +895,8 @@ typedef struct xSTATIC_TCB
|
|||
uint32_t ulDummy18;
|
||||
uint32_t ucDummy19;
|
||||
#endif
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
#if( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) \
|
||||
|| ( portUSING_MPU_WRAPPERS == 1 ) )
|
||||
uint8_t uxDummy20;
|
||||
#endif
|
||||
|
||||
|
@ -927,7 +928,6 @@ typedef struct xSTATIC_QUEUE
|
|||
|
||||
StaticList_t xDummy3[ 2 ];
|
||||
UBaseType_t uxDummy4[ 3 ];
|
||||
BaseType_t ucDummy5[ 2 ];
|
||||
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
uint8_t ucDummy6;
|
||||
|
@ -943,12 +943,12 @@ typedef struct xSTATIC_QUEUE
|
|||
#endif
|
||||
|
||||
struct {
|
||||
volatile uint32_t mux;
|
||||
volatile uint32_t ucDummy10;
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
const char *lastLockedFn;
|
||||
int lastLockedLine;
|
||||
void *pvDummy8;
|
||||
UBaseType_t uxDummy11;
|
||||
#endif
|
||||
} mux;
|
||||
} sDummy12;
|
||||
|
||||
} StaticQueue_t;
|
||||
typedef StaticQueue_t StaticSemaphore_t;
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
|
||||
/* configASSERT behaviour */
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <stdlib.h> /* for abort() */
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#if defined(CONFIG_FREERTOS_ASSERT_DISABLE)
|
||||
|
@ -126,8 +127,6 @@
|
|||
#endif
|
||||
|
||||
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
|
||||
#include <stdlib.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#define UNTESTED_FUNCTION() { ets_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
|
||||
#else
|
||||
#define UNTESTED_FUNCTION()
|
||||
|
@ -152,9 +151,9 @@
|
|||
*----------------------------------------------------------*/
|
||||
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_IDLE_HOOK ( CONFIG_TASK_WDT_CHECK_IDLE_TASK )
|
||||
#define configUSE_IDLE_HOOK ( CONFIG_FREERTOS_LEGACY_IDLE_HOOK )
|
||||
|
||||
#define configUSE_TICK_HOOK ( CONFIG_INT_WDT )
|
||||
#define configUSE_TICK_HOOK ( CONFIG_FREERTOS_LEGACY_TICK_HOOK )
|
||||
|
||||
#define configTICK_RATE_HZ ( CONFIG_FREERTOS_HZ )
|
||||
|
||||
|
@ -265,12 +264,6 @@
|
|||
#define INCLUDE_eTaskGetState 1
|
||||
#define configUSE_QUEUE_SETS 1
|
||||
|
||||
#if (!defined XT_INTEXC_HOOKS)
|
||||
#define configXT_INTEXC_HOOKS 1 /* Exception hooks used by certain tests */
|
||||
#if configUSE_TRACE_FACILITY_2
|
||||
#define configASSERT_2 1 /* Specific to Xtensa port */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define configXT_BOARD 1 /* Board mode */
|
||||
#define configXT_SIMULATOR 0
|
||||
|
|
|
@ -190,6 +190,10 @@ struct xLIST_ITEM
|
|||
};
|
||||
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticListItem_t) == sizeof(ListItem_t), "StaticListItem_t != ListItem_t");
|
||||
#endif
|
||||
|
||||
struct xMINI_LIST_ITEM
|
||||
{
|
||||
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
|
@ -199,6 +203,11 @@ struct xMINI_LIST_ITEM
|
|||
};
|
||||
typedef struct xMINI_LIST_ITEM MiniListItem_t;
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticMiniListItem_t) == sizeof(MiniListItem_t), "StaticMiniListItem_t != MiniListItem_t");
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Definition of the type of queue used by the scheduler.
|
||||
*/
|
||||
|
@ -211,6 +220,10 @@ typedef struct xLIST
|
|||
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
} List_t;
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticList_t) == sizeof(List_t), "StaticList_t != List_t");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Access macro to set the owner of a list item. The owner of a list item
|
||||
* is the object (usually a TCB) that contains the list item.
|
||||
|
|
|
@ -18,22 +18,34 @@ to this bit of memory will block.
|
|||
|
||||
The requirement for items to be contiguous is slightly problematic when the only way to place
|
||||
the next item would involve a wraparound from the end to the beginning of the ringbuffer. This can
|
||||
be solved in two ways:
|
||||
- allow_split_items = pdTRUE: The insertion code will split the item in two items; one which fits
|
||||
be solved (or not) in a few ways:
|
||||
- type = RINGBUF_TYPE_ALLOWSPLIT: The insertion code will split the item in two items; one which fits
|
||||
in the space left at the end of the ringbuffer, one that contains the remaining data which is placed
|
||||
in the beginning. Two xRingbufferReceive calls will be needed to retrieve the data.
|
||||
- allow_split_items = pdFALSE: The insertion code will leave the room at the end of the ringbuffer
|
||||
- type = RINGBUF_TYPE_NOSPLIT: The insertion code will leave the room at the end of the ringbuffer
|
||||
unused and instead will put the entire item at the start of the ringbuffer, as soon as there is
|
||||
enough free space.
|
||||
- type = RINGBUF_TYPE_BYTEBUF: This is your conventional byte-based ringbuffer. It does have no
|
||||
overhead, but it has no item contiguousness either: a read will just give you the entire written
|
||||
buffer space, or the space up to the end of the buffer, and writes can be broken up in any way
|
||||
possible. Note that this type cannot do a 2nd read before returning the memory of the 1st.
|
||||
|
||||
The maximum size of an item will be affected by this decision. When split items are allowed, it's
|
||||
acceptable to push items of (buffer_size)-16 bytes into the buffer. When it's not allowed, the
|
||||
maximum size is (buffer_size/2)-8 bytes.
|
||||
maximum size is (buffer_size/2)-8 bytes. The bytebuf can fill the entire buffer with data, it has
|
||||
no overhead.
|
||||
*/
|
||||
|
||||
//An opaque handle for a ringbuff object.
|
||||
typedef void * RingbufHandle_t;
|
||||
|
||||
//The various types of buffer
|
||||
typedef enum {
|
||||
RINGBUF_TYPE_NOSPLIT = 0,
|
||||
RINGBUF_TYPE_ALLOWSPLIT,
|
||||
RINGBUF_TYPE_BYTEBUF
|
||||
} ringbuf_type_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a ring buffer
|
||||
|
@ -45,7 +57,7 @@ typedef void * RingbufHandle_t;
|
|||
*
|
||||
* @return A RingbufHandle_t handle to the created ringbuffer, or NULL in case of error.
|
||||
*/
|
||||
RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_items);
|
||||
RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -120,6 +132,34 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t
|
|||
void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes
|
||||
* to return
|
||||
*
|
||||
* @param ringbuf - Ring buffer to retrieve the item from
|
||||
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
|
||||
* @param xTicksToWait - Ticks to wait for items in the ringbuffer.
|
||||
*
|
||||
* @return Pointer to the retrieved item on success; *item_size filled with the length of the
|
||||
* item. NULL on timeout, *item_size is untouched in that case.
|
||||
*/
|
||||
void *xRingbufferReceiveUpTo(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait, size_t wanted_size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes
|
||||
* to return. Call this from an ISR.
|
||||
*
|
||||
* @param ringbuf - Ring buffer to retrieve the item from
|
||||
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
|
||||
*
|
||||
* @return Pointer to the retrieved item on success; *item_size filled with the length of the
|
||||
* item. NULL when the ringbuffer is empty, *item_size is untouched in that case.
|
||||
*/
|
||||
void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size, size_t wanted_size);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a previously-retrieved item to the ringbuffer
|
||||
*
|
||||
|
|
|
@ -42,7 +42,8 @@ typedef void (*xt_exc_handler)(XtExcFrame *);
|
|||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to set a handler for the specified exception.
|
||||
Call this function to set a handler for the specified exception. The handler
|
||||
will be installed on the core that calls this function.
|
||||
|
||||
n - Exception number (type)
|
||||
f - Handler function address, NULL to uninstall handler.
|
||||
|
@ -61,7 +62,8 @@ extern xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f);
|
|||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to set a handler for the specified interrupt.
|
||||
Call this function to set a handler for the specified interrupt. The handler
|
||||
will be installed on the core that calls this function.
|
||||
|
||||
n - Interrupt number.
|
||||
f - Handler function address, NULL to uninstall handler.
|
||||
|
@ -73,7 +75,8 @@ extern xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg);
|
|||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to enable the specified interrupts.
|
||||
Call this function to enable the specified interrupts on the core that runs
|
||||
this code.
|
||||
|
||||
mask - Bit mask of interrupts to be enabled.
|
||||
-------------------------------------------------------------------------------
|
||||
|
@ -83,7 +86,8 @@ extern void xt_ints_on(unsigned int mask);
|
|||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to disable the specified interrupts.
|
||||
Call this function to disable the specified interrupts on the core that runs
|
||||
this code.
|
||||
|
||||
mask - Bit mask of interrupts to be disabled.
|
||||
-------------------------------------------------------------------------------
|
||||
|
|
|
@ -179,6 +179,11 @@ typedef struct QueueDefinition
|
|||
name below to enable the use of older kernel aware debuggers. */
|
||||
typedef xQUEUE Queue_t;
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticQueue_t) == sizeof(Queue_t), "StaticQueue_t != Queue_t");
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue