mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'master' into feature/bignum_rsa
This commit is contained in:
commit
cf8c9770a0
3
.gitignore
vendored
3
.gitignore
vendored
@ -19,6 +19,3 @@ GPATH
|
|||||||
examples/*/sdkconfig
|
examples/*/sdkconfig
|
||||||
examples/*/sdkconfig.old
|
examples/*/sdkconfig.old
|
||||||
examples/*/build
|
examples/*/build
|
||||||
|
|
||||||
# Bootloader files
|
|
||||||
components/bootloader/src/sdkconfig.old
|
|
359
.gitlab-ci.yml
359
.gitlab-ci.yml
@ -1,6 +1,8 @@
|
|||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
|
- unit_test
|
||||||
- test
|
- test
|
||||||
|
- test_report
|
||||||
- deploy
|
- deploy
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
@ -37,6 +39,12 @@ build_template_app:
|
|||||||
# branch
|
# branch
|
||||||
- git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..."
|
- git checkout ${CI_BUILD_REF_NAME} || echo "Using esp-idf-template default branch..."
|
||||||
- make defconfig
|
- make defconfig
|
||||||
|
# Test debug build (default)
|
||||||
|
- make all V=1
|
||||||
|
# Now test release build
|
||||||
|
- make clean
|
||||||
|
- sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig
|
||||||
|
- make defconfig
|
||||||
- make all V=1
|
- make all V=1
|
||||||
|
|
||||||
|
|
||||||
@ -62,13 +70,30 @@ build_ssc:
|
|||||||
expire_in: 6 mos
|
expire_in: 6 mos
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- git clone ssh://git@gitlab.espressif.cn:27227/yinling/SSC.git
|
- git clone $GITLAB_SSH_SERVER/yinling/SSC.git
|
||||||
- cd SSC
|
- cd SSC
|
||||||
- git checkout ${CI_BUILD_REF_NAME} || echo "Using SSC default branch..."
|
- git checkout ${CI_BUILD_REF_NAME} || echo "Using SSC default branch..."
|
||||||
- make defconfig
|
- make defconfig
|
||||||
- chmod +x gen_misc_ng.sh
|
- chmod +x gen_misc_ng.sh
|
||||||
- ./gen_misc_ng.sh
|
- ./gen_misc_ng.sh
|
||||||
|
|
||||||
|
build_esp_idf_tests:
|
||||||
|
<<: *build_template
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- ./esp-idf-tests/build/*.bin
|
||||||
|
- ./esp-idf-tests/build/*.elf
|
||||||
|
- ./esp-idf-tests/build/*.map
|
||||||
|
- ./esp-idf-tests/build/bootloader/*.bin
|
||||||
|
expire_in: 6 mos
|
||||||
|
|
||||||
|
script:
|
||||||
|
- git clone $GITLAB_SSH_SERVER/idf/esp-idf-tests.git
|
||||||
|
- cd esp-idf-tests
|
||||||
|
- git checkout ${CI_BUILD_REF_NAME} || echo "Using default branch..."
|
||||||
|
- make defconfig
|
||||||
|
- make
|
||||||
|
|
||||||
build_examples:
|
build_examples:
|
||||||
<<: *build_template
|
<<: *build_template
|
||||||
artifacts:
|
artifacts:
|
||||||
@ -86,6 +111,20 @@ build_examples:
|
|||||||
- cd build_examples
|
- cd build_examples
|
||||||
- ${IDF_PATH}/make/build_examples.sh
|
- ${IDF_PATH}/make/build_examples.sh
|
||||||
|
|
||||||
|
build_docs:
|
||||||
|
stage: build
|
||||||
|
image: espressif/esp32-ci-env
|
||||||
|
tags:
|
||||||
|
- build_docs
|
||||||
|
script:
|
||||||
|
- cd docs
|
||||||
|
- make html
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- docs/_build/html
|
||||||
|
expire_in: 1 mos
|
||||||
|
|
||||||
|
|
||||||
test_nvs_on_host:
|
test_nvs_on_host:
|
||||||
stage: test
|
stage: test
|
||||||
image: espressif/esp32-ci-env
|
image: espressif/esp32-ci-env
|
||||||
@ -105,43 +144,28 @@ test_build_system:
|
|||||||
script:
|
script:
|
||||||
- ./make/test_build_system.sh
|
- ./make/test_build_system.sh
|
||||||
|
|
||||||
|
test_report:
|
||||||
|
stage: test_report
|
||||||
# template for test jobs
|
|
||||||
.test_template: &test_template
|
|
||||||
stage: test
|
|
||||||
when: on_success
|
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
- triggers
|
- triggers
|
||||||
|
tags:
|
||||||
|
- test_report
|
||||||
variables:
|
variables:
|
||||||
# need user to set SDK_NAME and CONFIG_FILE (may need to set BIN_PATH and APP_NAME later) in before_script
|
LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
|
||||||
SCRIPT_PATH: /home/gitlab-runner/auto_test_script
|
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test"
|
||||||
BIN_PATH: ${CI_PROJECT_DIR}/SSC/build/
|
REPORT_PATH: "$CI_PROJECT_DIR/CI_Test_Report"
|
||||||
APP_NAME: ssc
|
|
||||||
LOG_PATH: $CI_PROJECT_DIR/$CI_BUILD_REF
|
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
paths:
|
paths:
|
||||||
- $LOG_PATH
|
- $REPORT_PATH
|
||||||
expire_in: 6 mos
|
expire_in: 12 mos
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cd $SCRIPT_PATH
|
# clone test bench
|
||||||
- python CIRunner.py -l $LOG_PATH -c $SDK_NAME/$CONFIG_FILE bin_path $APP_NAME $BIN_PATH
|
- git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git
|
||||||
|
- cd auto_test_script
|
||||||
sanity_test:
|
# generate report
|
||||||
<<: *test_template
|
- python CITestReport.py -l $LOG_PATH -t $TEST_CASE_FILE_PATH -p $REPORT_PATH
|
||||||
tags:
|
|
||||||
- ESP32
|
|
||||||
- SSC_T1_1
|
|
||||||
- SSC_T2_1
|
|
||||||
- SSC_T1_WAN
|
|
||||||
before_script:
|
|
||||||
- SDK_NAME=ESP32_IDF
|
|
||||||
- CONFIG_FILE=sanity_test.yml
|
|
||||||
|
|
||||||
|
|
||||||
push_master_to_github:
|
push_master_to_github:
|
||||||
@ -165,3 +189,278 @@ push_master_to_github:
|
|||||||
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||||
- git remote add github git@github.com:espressif/esp-idf.git
|
- git remote add github git@github.com:espressif/esp-idf.git
|
||||||
- git push --follow-tags github HEAD:master
|
- 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
|
||||||
|
stage: test
|
||||||
|
when: on_success
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- triggers
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
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/"
|
||||||
|
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/integration_test"
|
||||||
|
# jobs MUST set CONFIG_FILE in before_script, and overwrite the variables above if necessary
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- $LOG_PATH
|
||||||
|
expire_in: 6 mos
|
||||||
|
|
||||||
|
script:
|
||||||
|
# add gitlab ssh key
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- chmod 700 ~/.ssh
|
||||||
|
- echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64
|
||||||
|
- base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa
|
||||||
|
- chmod 600 ~/.ssh/id_rsa
|
||||||
|
- echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||||
|
# clone test bench
|
||||||
|
- git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git
|
||||||
|
- cd auto_test_script
|
||||||
|
# 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 overnight test jobs
|
||||||
|
.test_template_night: &test_template_night
|
||||||
|
<<: *test_template
|
||||||
|
only:
|
||||||
|
# can only be triggered
|
||||||
|
- triggers
|
||||||
|
script:
|
||||||
|
# must be night build triggers, otherwise exit without test
|
||||||
|
- test $NIGHT_BUILD = "Yes" || exit 0
|
||||||
|
# add gitlab ssh key
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- chmod 700 ~/.ssh
|
||||||
|
- echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64
|
||||||
|
- base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa
|
||||||
|
- chmod 600 ~/.ssh/id_rsa
|
||||||
|
- echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||||
|
# clone test bench
|
||||||
|
- git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git
|
||||||
|
- cd auto_test_script
|
||||||
|
# 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:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_SYS_01.yml
|
||||||
|
|
||||||
|
IT_Function_WIFI_01:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_01.yml
|
||||||
|
|
||||||
|
IT_Function_WIFI_02:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_02.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_01:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_01.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_02:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_02.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_03:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_03.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_04:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_04.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_05:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_05.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_06:
|
||||||
|
<<: *test_template_night
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_06.yml
|
||||||
|
|
||||||
|
IT_Function_WIFI_03:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T3_PhyMode
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_03.yml
|
||||||
|
|
||||||
|
IT_Function_WIFI_04:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_APC
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_04.yml
|
||||||
|
|
||||||
|
IT_Function_WIFI_05:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_WEP
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_05.yml
|
||||||
|
|
||||||
|
IT_Function_WIFI_06:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T2_PhyMode
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_WIFI_06.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_07:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T1_2
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_07.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_08:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_08.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_09:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_09.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_10:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T1_2
|
||||||
|
- SSC_T2_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_10.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_11:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
- SSC_T1_2
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_11.yml
|
||||||
|
|
||||||
|
IT_Function_TCPIP_12:
|
||||||
|
<<: *test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- SSC_T1_1
|
||||||
|
before_script:
|
||||||
|
- CONFIG_FILE=$TEST_CASE_FILE_PATH/CIConfigs/IT_Function_TCPIP_12.yml
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -7,3 +7,6 @@
|
|||||||
[submodule "components/bt/lib"]
|
[submodule "components/bt/lib"]
|
||||||
path = components/bt/lib
|
path = components/bt/lib
|
||||||
url = https://github.com/espressif/esp32-bt-lib.git
|
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,12 +1,15 @@
|
|||||||
# Contributions Guide
|
Contributions Guide
|
||||||
|
===================
|
||||||
|
|
||||||
We welcome contributions to the esp-idf project!
|
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:
|
Before sending us a Pull Request, please consider this list of points:
|
||||||
|
|
||||||
@ -16,15 +19,16 @@ Before sending us a Pull Request, please consider this list of points:
|
|||||||
|
|
||||||
* Is the code adequately commented for people to understand how it is structured?
|
* 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?
|
* 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.
|
* 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.
|
After you open the Pull Request, there will probably be some discussion in the comments field of the request itself.
|
||||||
|
|
||||||
@ -32,6 +36,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.
|
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.
|
|
20
Kconfig
20
Kconfig
@ -23,6 +23,26 @@ endmenu
|
|||||||
|
|
||||||
source "$COMPONENT_KCONFIGS_PROJBUILD"
|
source "$COMPONENT_KCONFIGS_PROJBUILD"
|
||||||
|
|
||||||
|
choice OPTIMIZATION_LEVEL
|
||||||
|
prompt "Optimization level"
|
||||||
|
default OPTIMIZATION_LEVEL_DEBUG
|
||||||
|
help
|
||||||
|
This option sets optimization level.
|
||||||
|
|
||||||
|
- for "Release" setting, -Os flag is added to CFLAGS,
|
||||||
|
and -DNDEBUG flag is added to CPPFLAGS.
|
||||||
|
|
||||||
|
- for "Debug" setting, -Og flag is added to CFLAGS.
|
||||||
|
|
||||||
|
To override any of these settings, set CFLAGS and/or CPPFLAGS
|
||||||
|
in project makefile, before including $(IDF_PATH)/make/project.mk.
|
||||||
|
|
||||||
|
config OPTIMIZATION_LEVEL_DEBUG
|
||||||
|
bool "Debug"
|
||||||
|
config OPTIMIZATION_LEVEL_RELEASE
|
||||||
|
bool "Release"
|
||||||
|
endchoice
|
||||||
|
|
||||||
menu "Component config"
|
menu "Component config"
|
||||||
source "$COMPONENT_KCONFIGS"
|
source "$COMPONENT_KCONFIGS"
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Using Espressif IoT Development Framework with the ESP32
|
# 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
|
# Setting Up ESP-IDF
|
||||||
|
|
||||||
In the [docs](docs) directory you will find per-platform setup guides:
|
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.
|
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
|
# 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.
|
* 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.
|
* [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
|
endchoice
|
||||||
|
|
||||||
config LOG_BOOTLOADER_LEVEL
|
config LOG_BOOTLOADER_LEVEL
|
||||||
int
|
int
|
||||||
default 0 if LOG_BOOTLOADER_LEVEL_NONE
|
default 0 if LOG_BOOTLOADER_LEVEL_NONE
|
||||||
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
|
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
|
||||||
default 2 if LOG_BOOTLOADER_LEVEL_WARN
|
default 2 if LOG_BOOTLOADER_LEVEL_WARN
|
||||||
default 3 if LOG_BOOTLOADER_LEVEL_INFO
|
default 3 if LOG_BOOTLOADER_LEVEL_INFO
|
||||||
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
|
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
|
||||||
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
|
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
|
endmenu
|
@ -8,42 +8,113 @@
|
|||||||
# basically runs Make in the src/ directory but it needs to zero some variables
|
# basically runs Make in the src/ directory but it needs to zero some variables
|
||||||
# the ESP-IDF project.mk makefile exports first, to not let them interfere.
|
# the ESP-IDF project.mk makefile exports first, to not let them interfere.
|
||||||
#
|
#
|
||||||
ifeq ("$(IS_BOOTLOADER_BUILD)","")
|
ifndef IS_BOOTLOADER_BUILD
|
||||||
|
|
||||||
BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH)
|
BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||||
BOOTLOADER_BUILD_DIR=$(BUILD_DIR_BASE)/bootloader
|
BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader)
|
||||||
BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin
|
BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin
|
||||||
|
|
||||||
|
# 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) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR)
|
||||||
|
|
||||||
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
|
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
|
||||||
|
|
||||||
$(BOOTLOADER_BIN): $(COMPONENT_PATH)/src/sdkconfig
|
$(BOOTLOADER_BIN): $(SDKCONFIG_MAKEFILE)
|
||||||
$(Q) PROJECT_PATH= \
|
$(BOOTLOADER_MAKE) $@
|
||||||
BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) \
|
|
||||||
$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src MAKEFLAGS= V=$(V) TARGET_BIN_LAYOUT="$(BOOTLOADER_TARGET_BIN_LAYOUT)" $(BOOTLOADER_BIN)
|
|
||||||
|
|
||||||
bootloader-clean:
|
|
||||||
$(Q) PROJECT_PATH= \
|
|
||||||
BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) \
|
|
||||||
$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src app-clean MAKEFLAGS= V=$(V)
|
|
||||||
|
|
||||||
clean: bootloader-clean
|
clean: bootloader-clean
|
||||||
|
|
||||||
bootloader: $(BOOTLOADER_BIN)
|
ifdef CONFIG_SECURE_BOOTLOADER_DISABLED
|
||||||
@echo "Bootloader built. Default flash command is:"
|
# If secure boot disabled, bootloader flashing is integrated
|
||||||
@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
|
# 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)
|
ESPTOOL_ALL_FLASH_ARGS += 0x1000 $(BOOTLOADER_BIN)
|
||||||
|
|
||||||
# synchronise the project level config to the component's
|
|
||||||
# config
|
|
||||||
$(COMPONENT_PATH)/src/sdkconfig: $(PROJECT_PATH)/sdkconfig
|
|
||||||
$(Q) cp $< $@
|
|
||||||
|
|
||||||
# bootloader-flash calls flash in the bootloader dummy project
|
|
||||||
bootloader-flash: $(BOOTLOADER_BIN)
|
bootloader-flash: $(BOOTLOADER_BIN)
|
||||||
$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src flash MAKEFLAGS= V=$(V)
|
$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^
|
||||||
|
|
||||||
|
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):
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
else
|
else
|
||||||
CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include
|
CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include
|
||||||
|
@ -4,14 +4,18 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
PROJECT_NAME := bootloader
|
PROJECT_NAME := bootloader
|
||||||
COMPONENTS := esptool_py bootloader log
|
|
||||||
|
#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.
|
# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
|
||||||
#
|
#
|
||||||
# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op
|
# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op
|
||||||
IS_BOOTLOADER_BUILD := 1
|
IS_BOOTLOADER_BUILD := 1
|
||||||
|
export IS_BOOTLOADER_BUILD
|
||||||
|
|
||||||
#We cannot include the esp32 component directly but we need its includes.
|
# include the top-level "project" include directory, for sdkconfig.h
|
||||||
#This is fixed by adding CFLAGS from Makefile.projbuild
|
CFLAGS += -I$(BUILD_DIR_BASE)/../include
|
||||||
|
|
||||||
include $(IDF_PATH)/make/project.mk
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
@ -20,12 +20,11 @@
|
|||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "esp_flash_data_types.h"
|
||||||
|
|
||||||
#define BOOT_VERSION "V0.1"
|
#define BOOT_VERSION "V0.1"
|
||||||
#define SPI_SEC_SIZE 0x1000
|
#define SPI_SEC_SIZE 0x1000
|
||||||
#define MEM_CACHE(offset) (uint8_t *)(0x3f400000 + (offset))
|
|
||||||
#define CACHE_READ_32(offset) ((uint32_t *)(0x3f400000 + (offset)))
|
|
||||||
#define PARTITION_ADD 0x4000
|
|
||||||
#define PARTITION_MAGIC 0x50AA
|
|
||||||
#define IROM_LOW 0x400D0000
|
#define IROM_LOW 0x400D0000
|
||||||
#define IROM_HIGH 0x40400000
|
#define IROM_HIGH 0x40400000
|
||||||
#define DROM_LOW 0x3F400000
|
#define DROM_LOW 0x3F400000
|
||||||
@ -35,74 +34,6 @@ extern "C"
|
|||||||
#define RTC_DATA_LOW 0x50000000
|
#define RTC_DATA_LOW 0x50000000
|
||||||
#define RTC_DATA_HIGH 0x50002000
|
#define RTC_DATA_HIGH 0x50002000
|
||||||
|
|
||||||
/*spi mode,saved in third byte in flash */
|
|
||||||
enum {
|
|
||||||
SPI_MODE_QIO,
|
|
||||||
SPI_MODE_QOUT,
|
|
||||||
SPI_MODE_DIO,
|
|
||||||
SPI_MODE_DOUT,
|
|
||||||
SPI_MODE_FAST_READ,
|
|
||||||
SPI_MODE_SLOW_READ
|
|
||||||
};
|
|
||||||
/* spi speed*/
|
|
||||||
enum {
|
|
||||||
SPI_SPEED_40M,
|
|
||||||
SPI_SPEED_26M,
|
|
||||||
SPI_SPEED_20M,
|
|
||||||
SPI_SPEED_80M = 0xF
|
|
||||||
};
|
|
||||||
/*suppport flash size in esp32 */
|
|
||||||
enum {
|
|
||||||
SPI_SIZE_1MB = 0,
|
|
||||||
SPI_SIZE_2MB,
|
|
||||||
SPI_SIZE_4MB,
|
|
||||||
SPI_SIZE_8MB,
|
|
||||||
SPI_SIZE_16MB,
|
|
||||||
SPI_SIZE_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct flash_hdr {
|
|
||||||
char magic;
|
|
||||||
char blocks;
|
|
||||||
char spi_mode; /* flag of flash read mode in unpackage and usage in future */
|
|
||||||
char spi_speed: 4; /* low bit */
|
|
||||||
char spi_size: 4;
|
|
||||||
unsigned int entry_addr;
|
|
||||||
uint8_t encrypt_flag; /* encrypt flag */
|
|
||||||
uint8_t secury_boot_flag; /* secury boot flag */
|
|
||||||
char extra_header[14]; /* ESP32 additional header, unused by second bootloader */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* each header of flash bin block */
|
|
||||||
struct block_hdr {
|
|
||||||
unsigned int load_addr;
|
|
||||||
unsigned int data_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* OTA selection structure (two copies in the OTA data partition.)
|
|
||||||
|
|
||||||
Size of 32 bytes is friendly to flash encryption */
|
|
||||||
typedef struct {
|
|
||||||
uint32_t ota_seq;
|
|
||||||
uint8_t seq_label[24];
|
|
||||||
uint32_t crc; /* CRC32 of ota_seq field only */
|
|
||||||
} ota_select;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t offset;
|
|
||||||
uint32_t size;
|
|
||||||
} partition_pos_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t magic;
|
|
||||||
uint8_t type; /* partition Type */
|
|
||||||
uint8_t subtype; /* part_subtype */
|
|
||||||
partition_pos_t pos;
|
|
||||||
uint8_t label[16]; /* label for the partition */
|
|
||||||
uint8_t reserved[4]; /* reserved */
|
|
||||||
} partition_info_t;
|
|
||||||
|
|
||||||
#define PART_TYPE_APP 0x00
|
#define PART_TYPE_APP 0x00
|
||||||
#define PART_SUBTYPE_FACTORY 0x00
|
#define PART_SUBTYPE_FACTORY 0x00
|
||||||
#define PART_SUBTYPE_OTA_FLAG 0x10
|
#define PART_SUBTYPE_OTA_FLAG 0x10
|
||||||
@ -120,20 +51,15 @@ typedef struct {
|
|||||||
#define SPI_ERROR_LOG "spi flash error"
|
#define SPI_ERROR_LOG "spi flash error"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
partition_pos_t ota_info;
|
esp_partition_pos_t ota_info;
|
||||||
partition_pos_t factory;
|
esp_partition_pos_t factory;
|
||||||
partition_pos_t test;
|
esp_partition_pos_t test;
|
||||||
partition_pos_t ota[16];
|
esp_partition_pos_t ota[16];
|
||||||
uint32_t app_count;
|
uint32_t app_count;
|
||||||
uint32_t selected_subtype;
|
uint32_t selected_subtype;
|
||||||
} bootloader_state_t;
|
} 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 flash_encrypt(bootloader_state_t *bs);
|
||||||
bool secure_boot(void);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
@ -33,6 +33,9 @@
|
|||||||
#include "soc/timer_group_reg.h"
|
#include "soc/timer_group_reg.h"
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_image_format.h"
|
||||||
|
#include "esp_secure_boot.h"
|
||||||
|
#include "bootloader_flash.h"
|
||||||
|
|
||||||
#include "bootloader_config.h"
|
#include "bootloader_config.h"
|
||||||
|
|
||||||
@ -49,15 +52,16 @@ 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);
|
extern void Cache_Flush(int);
|
||||||
|
|
||||||
void bootloader_main();
|
void bootloader_main();
|
||||||
void unpack_load_app(const partition_pos_t *app_node);
|
static void unpack_load_app(const esp_partition_pos_t *app_node);
|
||||||
void print_flash_info(struct flash_hdr* pfhdr);
|
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_load_addr,
|
||||||
uint32_t drom_size,
|
uint32_t drom_size,
|
||||||
uint32_t irom_addr,
|
uint32_t irom_addr,
|
||||||
uint32_t irom_load_addr,
|
uint32_t irom_load_addr,
|
||||||
uint32_t irom_size,
|
uint32_t irom_size,
|
||||||
uint32_t entry_addr);
|
uint32_t entry_addr);
|
||||||
|
static void update_flash_config(const esp_image_header_t* pfhdr);
|
||||||
|
|
||||||
|
|
||||||
void IRAM_ATTR call_start_cpu0()
|
void IRAM_ATTR call_start_cpu0()
|
||||||
@ -93,53 +97,6 @@ void IRAM_ATTR call_start_cpu0()
|
|||||||
bootloader_main();
|
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
|
* @function : load_partition_table
|
||||||
@ -147,95 +104,113 @@ void boot_cache_redirect( uint32_t pos, size_t size )
|
|||||||
* OTA info sector, factory app sector, and test app sector.
|
* OTA info sector, factory app sector, and test app sector.
|
||||||
*
|
*
|
||||||
* @inputs: bs bootloader state structure used to save the data
|
* @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)
|
* @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)
|
||||||
{
|
{
|
||||||
partition_info_t partition;
|
const esp_partition_info_t *partitions;
|
||||||
uint32_t end = addr + 0x1000;
|
const int ESP_PARTITION_TABLE_DATA_LEN = 0xC00; /* length of actual data (signature is appended to this) */
|
||||||
int index = 0;
|
const int MAX_PARTITIONS = ESP_PARTITION_TABLE_DATA_LEN / sizeof(esp_partition_info_t);
|
||||||
char *partition_usage;
|
char *partition_usage;
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Partition Table:");
|
ESP_LOGI(TAG, "Partition Table:");
|
||||||
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
|
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
|
||||||
|
|
||||||
while (addr < end) {
|
#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||||
ESP_LOGD(TAG, "load partition table entry from %x(%08x)", addr, MEM_CACHE(addr));
|
if(esp_secure_boot_enabled()) {
|
||||||
memcpy(&partition, MEM_CACHE(addr), sizeof(partition));
|
ESP_LOGI(TAG, "Verifying partition table signature...");
|
||||||
ESP_LOGD(TAG, "type=%x subtype=%x", partition.type, partition.subtype);
|
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";
|
partition_usage = "unknown";
|
||||||
|
|
||||||
if (partition.magic == PARTITION_MAGIC) { /* valid partition definition */
|
if (partition->magic != ESP_PARTITION_MAGIC) {
|
||||||
switch(partition.type) {
|
/* invalid partition definition indicates end-of-table */
|
||||||
case PART_TYPE_APP: /* app partition */
|
break;
|
||||||
switch(partition.subtype) {
|
}
|
||||||
case PART_SUBTYPE_FACTORY: /* factory binary */
|
|
||||||
bs->factory = partition.pos;
|
/* valid partition table */
|
||||||
partition_usage = "factory app";
|
switch(partition->type) {
|
||||||
break;
|
case PART_TYPE_APP: /* app partition */
|
||||||
case PART_SUBTYPE_TEST: /* test binary */
|
switch(partition->subtype) {
|
||||||
bs->test = partition.pos;
|
case PART_SUBTYPE_FACTORY: /* factory binary */
|
||||||
partition_usage = "test app";
|
bs->factory = partition->pos;
|
||||||
break;
|
partition_usage = "factory app";
|
||||||
default:
|
break;
|
||||||
/* OTA binary */
|
case PART_SUBTYPE_TEST: /* test binary */
|
||||||
if ((partition.subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
|
bs->test = partition->pos;
|
||||||
bs->ota[partition.subtype & PART_SUBTYPE_OTA_MASK] = partition.pos;
|
partition_usage = "test app";
|
||||||
++bs->app_count;
|
break;
|
||||||
partition_usage = "OTA app";
|
default:
|
||||||
}
|
/* OTA binary */
|
||||||
else {
|
if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
|
||||||
partition_usage = "Unknown app";
|
bs->ota[partition->subtype & PART_SUBTYPE_OTA_MASK] = partition->pos;
|
||||||
}
|
++bs->app_count;
|
||||||
break;
|
partition_usage = "OTA app";
|
||||||
}
|
}
|
||||||
break; /* PART_TYPE_APP */
|
else {
|
||||||
case PART_TYPE_DATA: /* data partition */
|
partition_usage = "Unknown app";
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
break; /* PART_TYPE_APP */
|
||||||
/* invalid partition magic number */
|
case PART_TYPE_DATA: /* data partition */
|
||||||
else {
|
switch(partition->subtype) {
|
||||||
break; /* todo: validate md5 */
|
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 */
|
/* print partition type info */
|
||||||
ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", index, partition.label, partition_usage,
|
ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", i, partition->label, partition_usage,
|
||||||
partition.type, partition.subtype,
|
partition->type, partition->subtype,
|
||||||
partition.pos.offset, partition.pos.size);
|
partition->pos.offset, partition->pos.size);
|
||||||
index++;
|
|
||||||
addr += sizeof(partition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bootloader_munmap(partitions);
|
||||||
|
|
||||||
ESP_LOGI(TAG,"End of partition table");
|
ESP_LOGI(TAG,"End of partition table");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t ota_select_crc(const ota_select *s)
|
static uint32_t ota_select_crc(const esp_ota_select_entry_t *s)
|
||||||
{
|
{
|
||||||
return crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
|
return crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ota_select_valid(const ota_select *s)
|
static bool ota_select_valid(const esp_ota_select_entry_t *s)
|
||||||
{
|
{
|
||||||
return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
|
return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
|
||||||
}
|
}
|
||||||
@ -251,36 +226,51 @@ void bootloader_main()
|
|||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Espressif ESP32 2nd stage bootloader v. %s", BOOT_VERSION);
|
ESP_LOGI(TAG, "Espressif ESP32 2nd stage bootloader v. %s", BOOT_VERSION);
|
||||||
|
|
||||||
struct flash_hdr fhdr;
|
esp_image_header_t fhdr;
|
||||||
bootloader_state_t bs;
|
bootloader_state_t bs;
|
||||||
SpiFlashOpResult spiRet1,spiRet2;
|
SpiFlashOpResult spiRet1,spiRet2;
|
||||||
ota_select sa,sb;
|
esp_ota_select_entry_t sa,sb;
|
||||||
|
const esp_ota_select_entry_t *ota_select_map;
|
||||||
|
|
||||||
memset(&bs, 0, sizeof(bs));
|
memset(&bs, 0, sizeof(bs));
|
||||||
|
|
||||||
ESP_LOGI(TAG, "compile time " __TIME__ );
|
ESP_LOGI(TAG, "compile time " __TIME__ );
|
||||||
/* close watch dog here */
|
/* disable watch dog here */
|
||||||
REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
|
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 );
|
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
|
||||||
SPIUnlock();
|
SPIUnlock();
|
||||||
/*register first sector in drom0 page 0 */
|
|
||||||
boot_cache_redirect( 0, 0x5000 );
|
|
||||||
|
|
||||||
memcpy((unsigned int *) &fhdr, MEM_CACHE(0x1000), sizeof(struct flash_hdr) );
|
if(esp_image_load_header(0x1000, &fhdr) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "failed to load bootloader header!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
print_flash_info(&fhdr);
|
print_flash_info(&fhdr);
|
||||||
|
|
||||||
if (!load_partition_table(&bs, PARTITION_ADD)) {
|
update_flash_config(&fhdr);
|
||||||
|
|
||||||
|
if (!load_partition_table(&bs)) {
|
||||||
ESP_LOGE(TAG, "load partition table error!");
|
ESP_LOGE(TAG, "load partition table error!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
partition_pos_t load_part_pos;
|
esp_partition_pos_t load_part_pos;
|
||||||
|
|
||||||
if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
|
if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
|
||||||
//ESP_LOGE("OTA info sector handling is not implemented");
|
//ESP_LOGE("OTA info sector handling is not implemented");
|
||||||
boot_cache_redirect(bs.ota_info.offset, bs.ota_info.size );
|
if (bs.ota_info.size < 2 * sizeof(esp_ota_select_entry_t)) {
|
||||||
memcpy(&sa,MEM_CACHE(bs.ota_info.offset & 0x0000ffff),sizeof(sa));
|
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));
|
||||||
memcpy(&sb,MEM_CACHE((bs.ota_info.offset + 0x1000)&0x0000ffff) ,sizeof(sb));
|
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) {
|
if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
|
||||||
// init status flash
|
// init status flash
|
||||||
load_part_pos = bs.ota[0];
|
load_part_pos = bs.ota[0];
|
||||||
@ -296,8 +286,8 @@ void bootloader_main()
|
|||||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
spiRet1 = SPIWrite(bs.ota_info.offset,(uint32_t *)&sa,sizeof(ota_select));
|
spiRet1 = SPIWrite(bs.ota_info.offset,(uint32_t *)&sa,sizeof(esp_ota_select_entry_t));
|
||||||
spiRet2 = SPIWrite(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(ota_select));
|
spiRet2 = SPIWrite(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(esp_ota_select_entry_t));
|
||||||
if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) {
|
if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) {
|
||||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||||
return;
|
return;
|
||||||
@ -326,13 +316,18 @@ void bootloader_main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
|
ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
|
||||||
if(fhdr.secury_boot_flag == 0x01) {
|
|
||||||
/* protect the 2nd_boot */
|
#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||||
if(false == secure_boot()){
|
/* Generate secure digest from this bootloader to protect future
|
||||||
ESP_LOGE(TAG, "secure boot failed");
|
modifications */
|
||||||
return;
|
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) {
|
if(fhdr.encrypt_flag == 0x01) {
|
||||||
/* encrypt flash */
|
/* encrypt flash */
|
||||||
@ -342,19 +337,40 @@ void bootloader_main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
unpack_load_app(&load_part_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void unpack_load_app(const partition_pos_t* partition)
|
static void unpack_load_app(const esp_partition_pos_t* partition)
|
||||||
{
|
{
|
||||||
boot_cache_redirect(partition->offset, partition->size);
|
esp_err_t err;
|
||||||
|
esp_image_header_t image_header;
|
||||||
|
uint32_t image_length;
|
||||||
|
|
||||||
uint32_t pos = 0;
|
/* TODO: verify the app image as part of OTA boot decision, so can have fallbacks */
|
||||||
struct flash_hdr image_header;
|
err = esp_image_basic_verify(partition->offset, &image_length);
|
||||||
memcpy(&image_header, MEM_CACHE(pos), sizeof(image_header));
|
if (err != ESP_OK) {
|
||||||
pos += sizeof(image_header);
|
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_addr = 0;
|
||||||
uint32_t drom_load_addr = 0;
|
uint32_t drom_load_addr = 0;
|
||||||
@ -363,24 +379,27 @@ void unpack_load_app(const partition_pos_t* partition)
|
|||||||
uint32_t irom_load_addr = 0;
|
uint32_t irom_load_addr = 0;
|
||||||
uint32_t irom_size = 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 occuring */
|
is occurring */
|
||||||
bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
|
bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
|
||||||
|
|
||||||
ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
|
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_mode,
|
||||||
image_header.spi_size,
|
image_header.spi_size,
|
||||||
(unsigned)image_header.entry_addr);
|
(unsigned)image_header.entry_addr);
|
||||||
|
|
||||||
for (uint32_t section_index = 0;
|
for (int segment = 0; segment < image_header.segment_count; segment++) {
|
||||||
section_index < image_header.blocks;
|
esp_image_segment_header_t segment_header;
|
||||||
++section_index) {
|
uint32_t data_offs;
|
||||||
struct block_hdr section_header = {0};
|
if(esp_image_load_segment_header(segment, partition->offset,
|
||||||
memcpy(§ion_header, MEM_CACHE(pos), sizeof(section_header));
|
&image_header, &segment_header,
|
||||||
pos += sizeof(section_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 load = true;
|
||||||
bool map = false;
|
bool map = false;
|
||||||
if (address == 0x00000000) { // padding, ignore block
|
if (address == 0x00000000) { // padding, ignore block
|
||||||
@ -392,45 +411,48 @@ void unpack_load_app(const partition_pos_t* partition)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (address >= DROM_LOW && address < DROM_HIGH) {
|
if (address >= DROM_LOW && address < DROM_HIGH) {
|
||||||
ESP_LOGD(TAG, "found drom section, map from %08x to %08x", pos,
|
ESP_LOGD(TAG, "found drom segment, map from %08x to %08x", data_offs,
|
||||||
section_header.load_addr);
|
segment_header.load_addr);
|
||||||
drom_addr = partition->offset + pos - sizeof(section_header);
|
drom_addr = data_offs;
|
||||||
drom_load_addr = section_header.load_addr;
|
drom_load_addr = segment_header.load_addr;
|
||||||
drom_size = section_header.data_len + sizeof(section_header);
|
drom_size = segment_header.data_len + sizeof(segment_header);
|
||||||
load = false;
|
load = false;
|
||||||
map = true;
|
map = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address >= IROM_LOW && address < IROM_HIGH) {
|
if (address >= IROM_LOW && address < IROM_HIGH) {
|
||||||
ESP_LOGD(TAG, "found irom section, map from %08x to %08x", pos,
|
ESP_LOGD(TAG, "found irom segment, map from %08x to %08x", data_offs,
|
||||||
section_header.load_addr);
|
segment_header.load_addr);
|
||||||
irom_addr = partition->offset + pos - sizeof(section_header);
|
irom_addr = data_offs;
|
||||||
irom_load_addr = section_header.load_addr;
|
irom_load_addr = segment_header.load_addr;
|
||||||
irom_size = section_header.data_len + sizeof(section_header);
|
irom_size = segment_header.data_len + sizeof(segment_header);
|
||||||
load = false;
|
load = false;
|
||||||
map = true;
|
map = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) {
|
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;
|
load = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) {
|
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;
|
load = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos,
|
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),
|
||||||
section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":"");
|
segment_header.load_addr, segment_header.data_len, segment_header.data_len, (load)?"load":(map)?"map":"");
|
||||||
|
|
||||||
if (!load) {
|
if (load) {
|
||||||
pos += section_header.data_len;
|
const void *data = bootloader_mmap(data_offs, segment_header.data_len);
|
||||||
continue;
|
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,
|
set_cache_and_start_app(drom_addr,
|
||||||
@ -442,7 +464,7 @@ void unpack_load_app(const partition_pos_t* partition)
|
|||||||
image_header.entry_addr);
|
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_addr,
|
||||||
uint32_t drom_load_addr,
|
uint32_t drom_load_addr,
|
||||||
uint32_t drom_size,
|
uint32_t drom_size,
|
||||||
@ -453,9 +475,7 @@ void IRAM_ATTR set_cache_and_start_app(
|
|||||||
{
|
{
|
||||||
ESP_LOGD(TAG, "configure drom and irom and start");
|
ESP_LOGD(TAG, "configure drom and irom and start");
|
||||||
Cache_Read_Disable( 0 );
|
Cache_Read_Disable( 0 );
|
||||||
Cache_Read_Disable( 1 );
|
|
||||||
Cache_Flush( 0 );
|
Cache_Flush( 0 );
|
||||||
Cache_Flush( 1 );
|
|
||||||
uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
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 );
|
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 );
|
int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||||
@ -471,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_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 );
|
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( 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);
|
ESP_LOGD(TAG, "start: 0x%08x", entry_addr);
|
||||||
typedef void (*entry_t)(void);
|
typedef void (*entry_t)(void);
|
||||||
@ -482,67 +503,84 @@ void IRAM_ATTR set_cache_and_start_app(
|
|||||||
(*entry)();
|
(*entry)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_flash_config(const esp_image_header_t* pfhdr)
|
||||||
|
{
|
||||||
|
uint32_t size;
|
||||||
|
switch(pfhdr->spi_size) {
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_1MB:
|
||||||
|
size = 1;
|
||||||
|
break;
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_2MB:
|
||||||
|
size = 2;
|
||||||
|
break;
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_4MB:
|
||||||
|
size = 4;
|
||||||
|
break;
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_8MB:
|
||||||
|
size = 8;
|
||||||
|
break;
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_16MB:
|
||||||
|
size = 16;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
size = 2;
|
||||||
|
}
|
||||||
|
Cache_Read_Disable( 0 );
|
||||||
|
// Set flash chip size
|
||||||
|
SPIParamCfg(g_rom_flashchip.deviceId, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
|
||||||
|
// TODO: set mode
|
||||||
|
// TODO: set frequency
|
||||||
|
Cache_Flush(0);
|
||||||
|
Cache_Read_Enable( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
void print_flash_info(struct flash_hdr* pfhdr)
|
void print_flash_info(const esp_image_header_t* phdr)
|
||||||
{
|
{
|
||||||
#if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
|
#if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
|
||||||
|
|
||||||
struct flash_hdr fhdr = *pfhdr;
|
ESP_LOGD(TAG, "magic %02x", phdr->magic );
|
||||||
|
ESP_LOGD(TAG, "segments %02x", phdr->segment_count );
|
||||||
ESP_LOGD(TAG, "magic %02x", fhdr.magic );
|
ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode );
|
||||||
ESP_LOGD(TAG, "blocks %02x", fhdr.blocks );
|
ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed );
|
||||||
ESP_LOGD(TAG, "spi_mode %02x", fhdr.spi_mode );
|
ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size );
|
||||||
ESP_LOGD(TAG, "spi_speed %02x", fhdr.spi_speed );
|
|
||||||
ESP_LOGD(TAG, "spi_size %02x", fhdr.spi_size );
|
|
||||||
|
|
||||||
const char* str;
|
const char* str;
|
||||||
switch ( fhdr.spi_speed ) {
|
switch ( phdr->spi_speed ) {
|
||||||
case SPI_SPEED_40M:
|
case ESP_IMAGE_SPI_SPEED_40M:
|
||||||
str = "40MHz";
|
str = "40MHz";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_SPI_SPEED_26M:
|
||||||
case SPI_SPEED_26M:
|
|
||||||
str = "26.7MHz";
|
str = "26.7MHz";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_SPI_SPEED_20M:
|
||||||
case SPI_SPEED_20M:
|
|
||||||
str = "20MHz";
|
str = "20MHz";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_SPI_SPEED_80M:
|
||||||
case SPI_SPEED_80M:
|
|
||||||
str = "80MHz";
|
str = "80MHz";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
str = "20MHz";
|
str = "20MHz";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "SPI Speed : %s", str );
|
ESP_LOGI(TAG, "SPI Speed : %s", str );
|
||||||
|
|
||||||
|
switch ( phdr->spi_mode ) {
|
||||||
|
case ESP_IMAGE_SPI_MODE_QIO:
|
||||||
switch ( fhdr.spi_mode ) {
|
|
||||||
case SPI_MODE_QIO:
|
|
||||||
str = "QIO";
|
str = "QIO";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_SPI_MODE_QOUT:
|
||||||
case SPI_MODE_QOUT:
|
|
||||||
str = "QOUT";
|
str = "QOUT";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_SPI_MODE_DIO:
|
||||||
case SPI_MODE_DIO:
|
|
||||||
str = "DIO";
|
str = "DIO";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_SPI_MODE_DOUT:
|
||||||
case SPI_MODE_DOUT:
|
|
||||||
str = "DOUT";
|
str = "DOUT";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_SPI_MODE_FAST_READ:
|
||||||
case SPI_MODE_FAST_READ:
|
|
||||||
str = "FAST READ";
|
str = "FAST READ";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_SPI_MODE_SLOW_READ:
|
||||||
case SPI_MODE_SLOW_READ:
|
|
||||||
str = "SLOW READ";
|
str = "SLOW READ";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -551,31 +589,24 @@ void print_flash_info(struct flash_hdr* pfhdr)
|
|||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "SPI Mode : %s", str );
|
ESP_LOGI(TAG, "SPI Mode : %s", str );
|
||||||
|
|
||||||
|
switch ( phdr->spi_size ) {
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_1MB:
|
||||||
switch ( fhdr.spi_size ) {
|
|
||||||
case SPI_SIZE_1MB:
|
|
||||||
str = "1MB";
|
str = "1MB";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_2MB:
|
||||||
case SPI_SIZE_2MB:
|
|
||||||
str = "2MB";
|
str = "2MB";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_4MB:
|
||||||
case SPI_SIZE_4MB:
|
|
||||||
str = "4MB";
|
str = "4MB";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_8MB:
|
||||||
case SPI_SIZE_8MB:
|
|
||||||
str = "8MB";
|
str = "8MB";
|
||||||
break;
|
break;
|
||||||
|
case ESP_IMAGE_FLASH_SIZE_16MB:
|
||||||
case SPI_SIZE_16MB:
|
|
||||||
str = "16MB";
|
str = "16MB";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
str = "1MB";
|
str = "2MB";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "SPI Flash Size : %s", str );
|
ESP_LOGI(TAG, "SPI Flash Size : %s", str );
|
||||||
|
@ -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 is basically the same as a component makefile, but in the case of the bootloader
|
||||||
# this will take the sources in the src/ directory, compile them and link them into
|
# we pull in bootloader-specific linker arguments.
|
||||||
# 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.
|
|
||||||
#
|
#
|
||||||
|
|
||||||
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
|
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. */
|
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||||
dport0_seg (RW) : org = 0x3FF00000, len = 0x10 /* IO */
|
dport0_seg (RW) : org = 0x3FF00000, len = 0x10 /* IO */
|
||||||
iram_seg (RWX) : org = 0x40098000, 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 */
|
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.*/
|
dram_seg (RW) : org = 0x3FFC0000, len = 0x20000 /* Shared RAM, minus rom bss/data/stack.*/
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "esp_types.h"
|
#include "esp_types.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
|
||||||
#include "rom/cache.h"
|
#include "rom/cache.h"
|
||||||
#include "rom/ets_sys.h"
|
#include "rom/ets_sys.h"
|
||||||
@ -30,6 +31,7 @@
|
|||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#include "bootloader_config.h"
|
#include "bootloader_config.h"
|
||||||
|
#include "esp_image_format.h"
|
||||||
|
|
||||||
static const char* TAG = "flash_encrypt";
|
static const char* TAG = "flash_encrypt";
|
||||||
|
|
||||||
@ -90,6 +92,8 @@ bool flash_encrypt_write(uint32_t pos, uint32_t len)
|
|||||||
Cache_Read_Enable(0);
|
Cache_Read_Enable(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function : flash_encrypt
|
* @function : flash_encrypt
|
||||||
* @description: encrypt 2nd boot ,partition table ,factory bin <EFBFBD><EFBFBD>test bin (if use)<EFBFBD><EFBFBD>ota bin
|
* @description: encrypt 2nd boot ,partition table ,factory bin <EFBFBD><EFBFBD>test bin (if use)<EFBFBD><EFBFBD>ota bin
|
||||||
@ -102,91 +106,83 @@ bool flash_encrypt_write(uint32_t pos, uint32_t len)
|
|||||||
*/
|
*/
|
||||||
bool flash_encrypt(bootloader_state_t *bs)
|
bool flash_encrypt(bootloader_state_t *bs)
|
||||||
{
|
{
|
||||||
uint32_t bin_len = 0;
|
esp_err_t err;
|
||||||
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT);
|
uint32_t image_len = 0;
|
||||||
uint8_t count = bitcount(flash_crypt_cnt);
|
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT);
|
||||||
int i = 0;
|
uint8_t count = bitcount(flash_crypt_cnt);
|
||||||
ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count);
|
ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count);
|
||||||
|
|
||||||
if ((count % 2) == 0) {
|
if ((count % 2) == 0) {
|
||||||
boot_cache_redirect( 0, 64*1024);
|
/* encrypt iv and abstract */
|
||||||
/* encrypt iv and abstruct */
|
if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
|
||||||
if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
|
ESP_LOGE(TAG, "encrypt iv and abstract error");
|
||||||
ESP_LOGE(TAG, "encrypt iv and abstract error");
|
return false;
|
||||||
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 */
|
/* encrypt partition table */
|
||||||
if (false == flash_encrypt_write(PARTITION_ADD, SPI_SEC_SIZE)) {
|
if (false == flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) {
|
||||||
ESP_LOGE(TAG, "encrypt partition table error");
|
ESP_LOGE(TAG, "encrypt partition table error");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* encrypt write factory bin */
|
/* encrypt write factory bin */
|
||||||
if(bs->factory.offset != 0x00) {
|
if(bs->factory.offset != 0 && bs->factory.size != 0) {
|
||||||
ESP_LOGD(TAG, "have factory bin");
|
ESP_LOGD(TAG, "have factory bin");
|
||||||
boot_cache_redirect(bs->factory.offset, bs->factory.size);
|
if (false == flash_encrypt_write(bs->factory.offset, bs->factory.size)) {
|
||||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->factory.offset&0xffff));
|
ESP_LOGE(TAG, "encrypt factory bin error");
|
||||||
if(bin_len != 0) {
|
return false;
|
||||||
if (false == flash_encrypt_write(bs->factory.offset, bin_len)) {
|
}
|
||||||
ESP_LOGE(TAG, "encrypt factory bin error");
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* encrypt write test bin */
|
/* encrypt write test bin */
|
||||||
if(bs->test.offset != 0x00) {
|
if(bs->test.offset != 0 && bs->test.size != 0) {
|
||||||
ESP_LOGD(TAG, "have test bin");
|
ESP_LOGD(TAG, "have test bin");
|
||||||
boot_cache_redirect(bs->test.offset, bs->test.size);
|
if (false == flash_encrypt_write(bs->test.offset, bs->test.size)) {
|
||||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->test.offset&0xffff));
|
ESP_LOGE(TAG, "encrypt test bin error");
|
||||||
if(bin_len != 0) {
|
return false;
|
||||||
if (false == flash_encrypt_write(bs->test.offset, bin_len)) {
|
}
|
||||||
ESP_LOGE(TAG, "encrypt test bin error");
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* encrypt write ota bin */
|
/* encrypt write ota bin */
|
||||||
for (i = 0;i<16;i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
if(bs->ota[i].offset != 0x00) {
|
if(bs->ota[i].offset != 0 && bs->ota[i].size != 0) {
|
||||||
ESP_LOGD(TAG, "have ota[%d] bin",i);
|
ESP_LOGD(TAG, "have ota[%d] bin",i);
|
||||||
boot_cache_redirect(bs->ota[i].offset, bs->ota[i].size);
|
if (false == flash_encrypt_write(bs->ota[i].offset, bs->ota[i].size)) {
|
||||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->ota[i].offset&0xffff));
|
ESP_LOGE(TAG, "encrypt ota bin error");
|
||||||
if(bin_len != 0) {
|
return false;
|
||||||
if (false == flash_encrypt_write(bs->ota[i].offset, bin_len)) {
|
}
|
||||||
ESP_LOGE(TAG, "encrypt ota bin error");
|
}
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* encrypt write ota info bin */
|
/* encrypt write ota info bin */
|
||||||
if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
|
if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
|
||||||
ESP_LOGE(TAG, "encrypt ota info error");
|
ESP_LOGE(TAG, "encrypt ota info error");
|
||||||
return false;
|
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_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04);
|
||||||
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
|
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
|
||||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
|
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
|
||||||
ESP_LOGW(TAG, "burn flash_crypt_cnt");
|
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
|
||||||
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
|
ESP_LOGW(TAG, "burn flash_crypt_cnt");
|
||||||
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
|
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
|
||||||
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
|
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
|
||||||
return true;
|
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
|
||||||
} else {
|
return true;
|
||||||
ESP_LOGI(TAG, "flash already encrypted.");
|
} else {
|
||||||
return true;
|
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;
|
|
||||||
|
|
||||||
}
|
|
9
components/bootloader_support/README.rst
Normal file
9
components/bootloader_support/README.rst
Normal file
@ -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.)
|
35
components/bootloader_support/component.mk
Executable file
35
components/bootloader_support/component.mk
Executable file
@ -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
|
132
components/bootloader_support/include/esp_image_format.h
Normal file
132
components/bootloader_support/include/esp_image_format.h
Normal file
@ -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
|
75
components/bootloader_support/include/esp_secure_boot.h
Normal file
75
components/bootloader_support/include/esp_secure_boot.h
Normal file
@ -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
|
122
components/bootloader_support/src/bootloader_flash.c
Normal file
122
components/bootloader_support/src/bootloader_flash.c
Normal file
@ -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
|
161
components/bootloader_support/src/esp_image_format.c
Normal file
161
components/bootloader_support/src/esp_image_format.c
Normal file
@ -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>
|
||||||
|
|
||||||
|
const static 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;
|
||||||
|
}
|
222
components/bootloader_support/src/secure_boot.c
Normal file
222
components/bootloader_support/src/secure_boot.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
107
components/bootloader_support/src/secure_boot_signatures.c
Normal file
107
components/bootloader_support/src/secure_boot_signatures.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// 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, *digest_data;
|
||||||
|
uint32_t digest_len;
|
||||||
|
const signature_block_t *sigblock;
|
||||||
|
bool is_valid;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
@ -2,20 +2,16 @@
|
|||||||
# Component Makefile
|
# Component Makefile
|
||||||
#
|
#
|
||||||
|
|
||||||
#COMPONENT_ADD_INCLUDEDIRS :=
|
|
||||||
|
|
||||||
COMPONENT_ADD_INCLUDEDIRS := include
|
COMPONENT_ADD_INCLUDEDIRS := include
|
||||||
|
|
||||||
CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses
|
CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses
|
||||||
|
|
||||||
LIBS := btdm_app
|
LIBS := btdm_app
|
||||||
|
|
||||||
COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \
|
COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \
|
||||||
$(addprefix -l,$(LIBS)) \
|
$(addprefix -l,$(LIBS)) \
|
||||||
$(LINKER_SCRIPTS)
|
$(LINKER_SCRIPTS)
|
||||||
|
|
||||||
include $(IDF_PATH)/make/component_common.mk
|
|
||||||
|
|
||||||
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
||||||
$(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
|
$(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
|
||||||
|
|
||||||
|
@ -28,37 +28,36 @@ extern "C" {
|
|||||||
*
|
*
|
||||||
* This function should be called only once, before any other BT functions are called.
|
* 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
|
* 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_send_available: notify host can send packet to controller
|
||||||
* notify_host_recv: notify host that controller has packet send to host
|
* notify_host_recv: notify host that controller has packet send to host
|
||||||
*/
|
*/
|
||||||
typedef struct vhci_host_callback {
|
typedef struct vhci_host_callback {
|
||||||
|
|
||||||
void (*notify_host_send_available)(void);
|
void (*notify_host_send_available)(void);
|
||||||
int (*notify_host_recv)(uint8_t *data, uint16_t len);
|
int (*notify_host_recv)(uint8_t *data, uint16_t len);
|
||||||
} vhci_host_callback_t;
|
} 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.
|
* 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);
|
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
|
* host send packet to controller
|
||||||
* param data is the packet point, the param len is the packet length
|
* @param data the packet point
|
||||||
* return void
|
*,@param len the packet length
|
||||||
*/
|
*/
|
||||||
void API_vhci_host_send_packet(uint8_t *data, uint16_t len);
|
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
|
* register the vhci referece callback, the call back
|
||||||
* struct defined by vhci_host_callback structure.
|
* 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);
|
void API_vhci_host_register_callback(const vhci_host_callback_t *callback);
|
||||||
|
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
#
|
#
|
||||||
# Component Makefile
|
# 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_ADD_INCLUDEDIRS := include
|
||||||
|
|
||||||
COMPONENT_PRIV_INCLUDEDIRS := include/driver
|
COMPONENT_PRIV_INCLUDEDIRS := include/driver
|
||||||
|
|
||||||
include $(IDF_PATH)/make/component_common.mk
|
|
||||||
|
@ -18,34 +18,13 @@
|
|||||||
#include "freertos/xtensa_api.h"
|
#include "freertos/xtensa_api.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "soc/soc.h"
|
#include "soc/soc.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
//TODO: move debug options to menuconfig
|
static const char* GPIO_TAG = "GPIO";
|
||||||
#define GPIO_DBG_ENABLE (0)
|
#define GPIO_CHECK(a, str, ret_val) if (!(a)) { \
|
||||||
#define GPIO_WARNING_ENABLE (0)
|
ESP_LOGE(GPIO_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||||
#define GPIO_ERROR_ENABLE (0)
|
return (ret_val); \
|
||||||
#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
|
|
||||||
|
|
||||||
const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
|
const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
|
||||||
GPIO_PIN_REG_0,
|
GPIO_PIN_REG_0,
|
||||||
@ -90,33 +69,85 @@ const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
|
|||||||
GPIO_PIN_REG_39
|
GPIO_PIN_REG_39
|
||||||
};
|
};
|
||||||
|
|
||||||
static int is_valid_gpio(int gpio_num)
|
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},
|
||||||
if(gpio_num >= GPIO_PIN_COUNT || GPIO_PIN_MUX_REG[gpio_num] == 0) {
|
{PERIPHS_IO_MUX_U0TXD_U, FUN_PU, FUN_PD},
|
||||||
GPIO_ERROR("GPIO io_num=%d does not exist\n",gpio_num);
|
{RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M},
|
||||||
return 0;
|
{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},
|
||||||
return 1;
|
{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)
|
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||||
{
|
{
|
||||||
if(!is_valid_gpio(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
GPIO_CHECK(intr_type < GPIO_INTR_MAX, "GPIO interrupt type error", 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.pin[gpio_num].int_type = intr_type;
|
GPIO.pin[gpio_num].int_type = intr_type;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
|
esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
|
||||||
{
|
{
|
||||||
if(!is_valid_gpio(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if(xPortGetCoreID() == 0) {
|
if(xPortGetCoreID() == 0) {
|
||||||
GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr
|
GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr
|
||||||
} else {
|
} 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)
|
esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
|
||||||
{
|
{
|
||||||
if(!is_valid_gpio(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
GPIO.pin[gpio_num].int_ena = 0; //disable GPIO intr
|
GPIO.pin[gpio_num].int_ena = 0; //disable GPIO intr
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
|
static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
|
||||||
{
|
{
|
||||||
if(!is_valid_gpio(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if(gpio_num < 32) {
|
if(gpio_num < 32) {
|
||||||
GPIO.enable_w1tc = (0x1 << gpio_num);
|
GPIO.enable_w1tc = (0x1 << gpio_num);
|
||||||
} else {
|
} 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)
|
static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
|
||||||
{
|
{
|
||||||
if(gpio_num >= 34) {
|
GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG);
|
||||||
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;
|
|
||||||
}
|
|
||||||
if(gpio_num < 32) {
|
if(gpio_num < 32) {
|
||||||
GPIO.enable_w1ts = (0x1 << gpio_num);
|
GPIO.enable_w1ts = (0x1 << gpio_num);
|
||||||
} else {
|
} 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)
|
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
|
||||||
{
|
{
|
||||||
if(!GPIO_IS_VALID_GPIO(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if(level) {
|
if(level) {
|
||||||
if(gpio_num < 32) {
|
if(gpio_num < 32) {
|
||||||
GPIO.out_w1ts = (1 << gpio_num);
|
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)
|
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
|
||||||
{
|
{
|
||||||
if(!is_valid_gpio(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
GPIO_CHECK(pull <= GPIO_FLOATING, "GPIO pull mode error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
switch(pull) {
|
switch(pull) {
|
||||||
case GPIO_PULLUP_ONLY:
|
case GPIO_PULLUP_ONLY:
|
||||||
PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]);
|
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||||
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].pd);
|
||||||
break;
|
break;
|
||||||
case GPIO_PULLDOWN_ONLY:
|
case GPIO_PULLDOWN_ONLY:
|
||||||
PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]);
|
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||||
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].pd);
|
||||||
break;
|
break;
|
||||||
case GPIO_PULLUP_PULLDOWN:
|
case GPIO_PULLUP_PULLDOWN:
|
||||||
PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]);
|
REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||||
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].pd);
|
||||||
break;
|
break;
|
||||||
case GPIO_FLOATING:
|
case GPIO_FLOATING:
|
||||||
PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]);
|
REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
|
||||||
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].pd);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
ret = ESP_ERR_INVALID_ARG;
|
||||||
break;
|
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)
|
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
|
||||||
{
|
{
|
||||||
if(!is_valid_gpio(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if(gpio_num >= 34 && (mode & (GPIO_MODE_DEF_OUTPUT))) {
|
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;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
esp_err_t ret = ESP_OK;
|
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);
|
uint64_t gpio_pin_mask = (pGPIOConfig->pin_bit_mask);
|
||||||
uint32_t io_reg = 0;
|
uint32_t io_reg = 0;
|
||||||
uint32_t io_num = 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)) {
|
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;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if((pGPIOConfig->mode) & (GPIO_MODE_DEF_OUTPUT)) {
|
if((pGPIOConfig->mode) & (GPIO_MODE_DEF_OUTPUT)) {
|
||||||
//GPIO 34/35/36/37/38/39 can only be used as input mode;
|
//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))) {
|
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;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
io_reg = GPIO_PIN_MUX_REG[io_num];
|
io_reg = GPIO_PIN_MUX_REG[io_num];
|
||||||
if(((gpio_pin_mask >> io_num) & BIT(0)) && io_reg) {
|
if(((gpio_pin_mask >> io_num) & BIT(0)) && io_reg) {
|
||||||
GPIO_INFO("Gpio%02d |Mode:",io_num);
|
|
||||||
if((pGPIOConfig->mode) & GPIO_MODE_DEF_INPUT) {
|
if((pGPIOConfig->mode) & GPIO_MODE_DEF_INPUT) {
|
||||||
GPIO_INFO("INPUT ");
|
input_en = 1;
|
||||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_num]);
|
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_num]);
|
||||||
} else {
|
} else {
|
||||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[io_num]);
|
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[io_num]);
|
||||||
}
|
}
|
||||||
if((pGPIOConfig->mode) & GPIO_MODE_DEF_OD) {
|
if((pGPIOConfig->mode) & GPIO_MODE_DEF_OD) {
|
||||||
GPIO_INFO("OD ");
|
od_en = 1;
|
||||||
GPIO.pin[io_num].pad_driver = 1; /*0x01 Open-drain */
|
GPIO.pin[io_num].pad_driver = 1; /*0x01 Open-drain */
|
||||||
} else {
|
} else {
|
||||||
GPIO.pin[io_num].pad_driver = 0; /*0x00 Normal gpio output */
|
GPIO.pin[io_num].pad_driver = 0; /*0x00 Normal gpio output */
|
||||||
}
|
}
|
||||||
if((pGPIOConfig->mode) & GPIO_MODE_DEF_OUTPUT) {
|
if((pGPIOConfig->mode) & GPIO_MODE_DEF_OUTPUT) {
|
||||||
GPIO_INFO("OUTPUT ");
|
output_en = 1;
|
||||||
gpio_output_enable(io_num);
|
gpio_output_enable(io_num);
|
||||||
} else {
|
} else {
|
||||||
gpio_output_disable(io_num);
|
gpio_output_disable(io_num);
|
||||||
}
|
}
|
||||||
GPIO_INFO("|");
|
|
||||||
if(pGPIOConfig->pull_up_en) {
|
if(pGPIOConfig->pull_up_en) {
|
||||||
GPIO_INFO("PU ");
|
pu_en = 1;
|
||||||
PIN_PULLUP_EN(io_reg);
|
REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
|
||||||
} else {
|
} else {
|
||||||
PIN_PULLUP_DIS(io_reg);
|
REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
|
||||||
}
|
}
|
||||||
if(pGPIOConfig->pull_down_en) {
|
if(pGPIOConfig->pull_down_en) {
|
||||||
GPIO_INFO("PD ");
|
pd_en = 1;
|
||||||
PIN_PULLDWN_EN(io_reg);
|
REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
|
||||||
} else {
|
} 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);
|
gpio_set_intr_type(io_num, pGPIOConfig->intr_type);
|
||||||
if(pGPIOConfig->intr_type) {
|
if(pGPIOConfig->intr_type) {
|
||||||
gpio_intr_enable(io_num);
|
gpio_intr_enable(io_num);
|
||||||
@ -321,8 +339,6 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
|
|||||||
gpio_intr_disable(io_num);
|
gpio_intr_disable(io_num);
|
||||||
}
|
}
|
||||||
PIN_FUNC_SELECT(io_reg, PIN_FUNC_GPIO); /*function number 2 is GPIO_FUNC for each pin */
|
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++;
|
io_num++;
|
||||||
} while(io_num < GPIO_PIN_COUNT);
|
} 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)
|
esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg)
|
||||||
{
|
{
|
||||||
if(fn == NULL) {
|
GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
ESP_INTR_DISABLE(gpio_intr_num);
|
ESP_INTR_DISABLE(gpio_intr_num);
|
||||||
intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num);
|
intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num);
|
||||||
xt_set_interrupt_handler(gpio_intr_num, fn, arg);
|
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*/
|
/*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)
|
esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||||
{
|
{
|
||||||
if(!is_valid_gpio(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) {
|
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].int_type = intr_type;
|
||||||
GPIO.pin[gpio_num].wakeup_enable = 0x1;
|
GPIO.pin[gpio_num].wakeup_enable = 0x1;
|
||||||
} else {
|
} 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;
|
ret = ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
return ret;
|
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)
|
esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num)
|
||||||
{
|
{
|
||||||
if(!is_valid_gpio(gpio_num)) {
|
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
GPIO.pin[gpio_num].wakeup_enable = 0;
|
GPIO.pin[gpio_num].wakeup_enable = 0;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "soc/gpio_struct.h"
|
#include "soc/gpio_struct.h"
|
||||||
#include "soc/rtc_io_reg.h"
|
#include "soc/rtc_io_reg.h"
|
||||||
#include "soc/io_mux_reg.h"
|
#include "soc/io_mux_reg.h"
|
||||||
|
#include "soc/gpio_sig_map.h"
|
||||||
#include "rom/gpio.h"
|
#include "rom/gpio.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
|
|
||||||
@ -27,43 +28,43 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GPIO_SEL_0 (BIT(0)) /* Pin 0 selected */
|
#define GPIO_SEL_0 (BIT(0)) /*!< Pin 0 selected */
|
||||||
#define GPIO_SEL_1 (BIT(1)) /* Pin 1 selected */
|
#define GPIO_SEL_1 (BIT(1)) /*!< Pin 1 selected */
|
||||||
#define GPIO_SEL_2 (BIT(2)) /* Pin 2 selected */
|
#define GPIO_SEL_2 (BIT(2)) /*!< Pin 2 selected */
|
||||||
#define GPIO_SEL_3 (BIT(3)) /* Pin 3 selected */
|
#define GPIO_SEL_3 (BIT(3)) /*!< Pin 3 selected */
|
||||||
#define GPIO_SEL_4 (BIT(4)) /* Pin 4 selected */
|
#define GPIO_SEL_4 (BIT(4)) /*!< Pin 4 selected */
|
||||||
#define GPIO_SEL_5 (BIT(5)) /* Pin 5 selected */
|
#define GPIO_SEL_5 (BIT(5)) /*!< Pin 5 selected */
|
||||||
#define GPIO_SEL_6 (BIT(6)) /* Pin 6 selected */
|
#define GPIO_SEL_6 (BIT(6)) /*!< Pin 6 selected */
|
||||||
#define GPIO_SEL_7 (BIT(7)) /* Pin 7 selected */
|
#define GPIO_SEL_7 (BIT(7)) /*!< Pin 7 selected */
|
||||||
#define GPIO_SEL_8 (BIT(8)) /* Pin 8 selected */
|
#define GPIO_SEL_8 (BIT(8)) /*!< Pin 8 selected */
|
||||||
#define GPIO_SEL_9 (BIT(9)) /* Pin 9 selected */
|
#define GPIO_SEL_9 (BIT(9)) /*!< Pin 9 selected */
|
||||||
#define GPIO_SEL_10 (BIT(10)) /* Pin 10 selected */
|
#define GPIO_SEL_10 (BIT(10)) /*!< Pin 10 selected */
|
||||||
#define GPIO_SEL_11 (BIT(11)) /* Pin 11 selected */
|
#define GPIO_SEL_11 (BIT(11)) /*!< Pin 11 selected */
|
||||||
#define GPIO_SEL_12 (BIT(12)) /* Pin 12 selected */
|
#define GPIO_SEL_12 (BIT(12)) /*!< Pin 12 selected */
|
||||||
#define GPIO_SEL_13 (BIT(13)) /* Pin 13 selected */
|
#define GPIO_SEL_13 (BIT(13)) /*!< Pin 13 selected */
|
||||||
#define GPIO_SEL_14 (BIT(14)) /* Pin 14 selected */
|
#define GPIO_SEL_14 (BIT(14)) /*!< Pin 14 selected */
|
||||||
#define GPIO_SEL_15 (BIT(15)) /* Pin 15 selected */
|
#define GPIO_SEL_15 (BIT(15)) /*!< Pin 15 selected */
|
||||||
#define GPIO_SEL_16 (BIT(16)) /* Pin 16 selected */
|
#define GPIO_SEL_16 (BIT(16)) /*!< Pin 16 selected */
|
||||||
#define GPIO_SEL_17 (BIT(17)) /* Pin 17 selected */
|
#define GPIO_SEL_17 (BIT(17)) /*!< Pin 17 selected */
|
||||||
#define GPIO_SEL_18 (BIT(18)) /* Pin 18 selected */
|
#define GPIO_SEL_18 (BIT(18)) /*!< Pin 18 selected */
|
||||||
#define GPIO_SEL_19 (BIT(19)) /* Pin 19 selected */
|
#define GPIO_SEL_19 (BIT(19)) /*!< Pin 19 selected */
|
||||||
|
|
||||||
#define GPIO_SEL_21 (BIT(21)) /* Pin 21 selected */
|
#define GPIO_SEL_21 (BIT(21)) /*!< Pin 21 selected */
|
||||||
#define GPIO_SEL_22 (BIT(22)) /* Pin 22 selected */
|
#define GPIO_SEL_22 (BIT(22)) /*!< Pin 22 selected */
|
||||||
#define GPIO_SEL_23 (BIT(23)) /* Pin 23 selected */
|
#define GPIO_SEL_23 (BIT(23)) /*!< Pin 23 selected */
|
||||||
|
|
||||||
#define GPIO_SEL_25 (BIT(25)) /* Pin 25 selected */
|
#define GPIO_SEL_25 (BIT(25)) /*!< Pin 25 selected */
|
||||||
#define GPIO_SEL_26 (BIT(26)) /* Pin 26 selected */
|
#define GPIO_SEL_26 (BIT(26)) /*!< Pin 26 selected */
|
||||||
#define GPIO_SEL_27 (BIT(27)) /* Pin 27 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_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_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_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_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_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_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_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_39 ((uint64_t)(((uint64_t)1)<<39)) /*!< Pin 39 selected */
|
||||||
|
|
||||||
#define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U
|
#define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U
|
||||||
#define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U
|
#define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U
|
||||||
@ -116,223 +117,217 @@ 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_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
|
#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
|
||||||
|
|
||||||
|
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 {
|
typedef enum {
|
||||||
GPIO_NUM_0 = 0,
|
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
|
||||||
GPIO_NUM_1 = 1,
|
GPIO_NUM_1 = 1, /*!< GPIO1, input and output */
|
||||||
GPIO_NUM_2 = 2,
|
GPIO_NUM_2 = 2, /*!< GPIO2, input and output */
|
||||||
GPIO_NUM_3 = 3,
|
GPIO_NUM_3 = 3, /*!< GPIO3, input and output */
|
||||||
GPIO_NUM_4 = 4,
|
GPIO_NUM_4 = 4, /*!< GPIO4, input and output */
|
||||||
GPIO_NUM_5 = 5,
|
GPIO_NUM_5 = 5, /*!< GPIO5, input and output */
|
||||||
GPIO_NUM_6 = 6,
|
GPIO_NUM_6 = 6, /*!< GPIO6, input and output */
|
||||||
GPIO_NUM_7 = 7,
|
GPIO_NUM_7 = 7, /*!< GPIO7, input and output */
|
||||||
GPIO_NUM_8 = 8,
|
GPIO_NUM_8 = 8, /*!< GPIO8, input and output */
|
||||||
GPIO_NUM_9 = 9,
|
GPIO_NUM_9 = 9, /*!< GPIO9, input and output */
|
||||||
GPIO_NUM_10 = 10,
|
GPIO_NUM_10 = 10, /*!< GPIO10, input and output */
|
||||||
GPIO_NUM_11 = 11,
|
GPIO_NUM_11 = 11, /*!< GPIO11, input and output */
|
||||||
GPIO_NUM_12 = 12,
|
GPIO_NUM_12 = 12, /*!< GPIO12, input and output */
|
||||||
GPIO_NUM_13 = 13,
|
GPIO_NUM_13 = 13, /*!< GPIO13, input and output */
|
||||||
GPIO_NUM_14 = 14,
|
GPIO_NUM_14 = 14, /*!< GPIO14, input and output */
|
||||||
GPIO_NUM_15 = 15,
|
GPIO_NUM_15 = 15, /*!< GPIO15, input and output */
|
||||||
GPIO_NUM_16 = 16,
|
GPIO_NUM_16 = 16, /*!< GPIO16, input and output */
|
||||||
GPIO_NUM_17 = 17,
|
GPIO_NUM_17 = 17, /*!< GPIO17, input and output */
|
||||||
GPIO_NUM_18 = 18,
|
GPIO_NUM_18 = 18, /*!< GPIO18, input and output */
|
||||||
GPIO_NUM_19 = 19,
|
GPIO_NUM_19 = 19, /*!< GPIO19, input and output */
|
||||||
|
|
||||||
GPIO_NUM_21 = 21,
|
GPIO_NUM_21 = 21, /*!< GPIO21, input and output */
|
||||||
GPIO_NUM_22 = 22,
|
GPIO_NUM_22 = 22, /*!< GPIO22, input and output */
|
||||||
GPIO_NUM_23 = 23,
|
GPIO_NUM_23 = 23, /*!< GPIO23, input and output */
|
||||||
|
|
||||||
GPIO_NUM_25 = 25,
|
GPIO_NUM_25 = 25, /*!< GPIO25, input and output */
|
||||||
GPIO_NUM_26 = 26,
|
GPIO_NUM_26 = 26, /*!< GPIO26, input and output */
|
||||||
GPIO_NUM_27 = 27,
|
GPIO_NUM_27 = 27, /*!< GPIO27, input and output */
|
||||||
|
|
||||||
GPIO_NUM_32 = 32,
|
GPIO_NUM_32 = 32, /*!< GPIO32, input and output */
|
||||||
GPIO_NUM_33 = 33,
|
GPIO_NUM_33 = 33, /*!< GPIO32, input and output */
|
||||||
GPIO_NUM_34 = 34, /*input mode only */
|
GPIO_NUM_34 = 34, /*!< GPIO34, input mode only */
|
||||||
GPIO_NUM_35 = 35, /*input mode only */
|
GPIO_NUM_35 = 35, /*!< GPIO35, input mode only */
|
||||||
GPIO_NUM_36 = 36, /*input mode only */
|
GPIO_NUM_36 = 36, /*!< GPIO36, input mode only */
|
||||||
GPIO_NUM_37 = 37, /*input mode only */
|
GPIO_NUM_37 = 37, /*!< GPIO37, input mode only */
|
||||||
GPIO_NUM_38 = 38, /*input mode only */
|
GPIO_NUM_38 = 38, /*!< GPIO38, input mode only */
|
||||||
GPIO_NUM_39 = 39, /*input mode only */
|
GPIO_NUM_39 = 39, /*!< GPIO39, input mode only */
|
||||||
} gpio_num_t;
|
} gpio_num_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_INTR_DISABLE = 0, /* disable GPIO interrupt */
|
GPIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */
|
||||||
GPIO_INTR_POSEDGE = 1, /* GPIO interrupt type : rising edge */
|
GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */
|
||||||
GPIO_INTR_NEGEDGE = 2, /* GPIO interrupt type : falling edge */
|
GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */
|
||||||
GPIO_INTR_ANYEDGE = 3, /* GPIO interrupt type : both rising and 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_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */
|
||||||
GPIO_INTR_HIGH_LEVEL = 5, /* GPIO interrupt type : input high level trigger */
|
GPIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */
|
||||||
GPIO_INTR_MAX,
|
GPIO_INTR_MAX,
|
||||||
} gpio_int_type_t;
|
} gpio_int_type_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /* GPIO mode : input only */
|
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 = 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_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_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_OUTPUT = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)), /*!< GPIO mode : output and input mode */
|
||||||
} gpio_mode_t;
|
} gpio_mode_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_PULLUP_DISABLE = 0x0, /* disable GPIO pull-up resistor */
|
GPIO_PULLUP_DISABLE = 0x0, /*!< Disable GPIO pull-up resistor */
|
||||||
GPIO_PULLUP_ENABLE = 0x1, /* enable GPIO pull-up resistor */
|
GPIO_PULLUP_ENABLE = 0x1, /*!< Enable GPIO pull-up resistor */
|
||||||
} gpio_pullup_t;
|
} gpio_pullup_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_PULLDOWN_DISABLE = 0x0, /* disable GPIO pull-down resistor */
|
GPIO_PULLDOWN_DISABLE = 0x0, /*!< Disable GPIO pull-down resistor */
|
||||||
GPIO_PULLDOWN_ENABLE = 0x1, /* enable GPIO pull-down resistor */
|
GPIO_PULLDOWN_ENABLE = 0x1, /*!< Enable GPIO pull-down resistor */
|
||||||
} gpio_pulldown_t;
|
} gpio_pulldown_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t pin_bit_mask; /* GPIO pin: set with bit mask, each bit maps to a GPIO */
|
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_mode_t mode; /*!< GPIO mode: set input/output mode */
|
||||||
gpio_pullup_t pull_up_en; /* GPIO pull-up */
|
gpio_pullup_t pull_up_en; /*!< GPIO pull-up */
|
||||||
gpio_pulldown_t pull_down_en; /* GPIO pull-down */
|
gpio_pulldown_t pull_down_en; /*!< GPIO pull-down */
|
||||||
gpio_int_type_t intr_type; /* GPIO interrupt type */
|
gpio_int_type_t intr_type; /*!< GPIO interrupt type */
|
||||||
} gpio_config_t;
|
} gpio_config_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_LOW_LEVEL = 0,
|
GPIO_PULLUP_ONLY, /*!< Pad pull up */
|
||||||
GPIO_HIGH_LEVEL = 1,
|
GPIO_PULLDOWN_ONLY, /*!< Pad pull down */
|
||||||
GPIO_LEVEL_ERR,
|
GPIO_PULLUP_PULLDOWN, /*!< Pad pull up + pull down*/
|
||||||
} gpio_level_t;
|
GPIO_FLOATING, /*!< Pad floating */
|
||||||
|
|
||||||
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_pull_mode_t;
|
} gpio_pull_mode_t;
|
||||||
|
|
||||||
typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num);
|
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
|
* @param pGPIOConfig Pointer to GPIO configure struct
|
||||||
* 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;
|
* @return
|
||||||
* pGPIOConfig.mode : Configure GPIO mode,such as output ,input...
|
* - ESP_OK success
|
||||||
* pGPIOConfig.pull_up_en : Enable or Disable pull-up
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
* 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
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_config(gpio_config_t *pGPIOConfig);
|
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.
|
* @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);
|
||||||
* If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
* @param intr_type Interrupt type, select from gpio_int_type_t
|
||||||
* @parameter[in] intr_type: interrupt type, select from gpio_int_type_t
|
|
||||||
*
|
*
|
||||||
* @return ESP_OK : success
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - 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);
|
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.
|
* @param gpio_num GPIO number. If you want to enable an interrupt on e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||||
* If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
|
||||||
*
|
*
|
||||||
* @return ESP_OK : success
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - ESP_OK Success
|
||||||
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_intr_enable(gpio_num_t gpio_num);
|
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.
|
* @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||||
* If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
|
||||||
*
|
*
|
||||||
* @return ESP_OK : success
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - ESP_OK success
|
||||||
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_intr_disable(gpio_num_t gpio_num);
|
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.
|
* @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);
|
||||||
* If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
* @param level Output level. 0: low ; 1: high
|
||||||
* @parameter[in] level : Output level. 0: low ; 1: high
|
|
||||||
*
|
*
|
||||||
* @return ESP_OK : success
|
* @return
|
||||||
* ESP_FAIL : GPIO error
|
* - ESP_OK Success
|
||||||
|
* - GPIO_IS_VALID_GPIO GPIO number error
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);
|
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.
|
* @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);
|
||||||
* If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
|
||||||
*
|
*
|
||||||
* @return 0 : the GPIO input level is 0
|
* @return
|
||||||
* 1 : the GPIO input level is 1
|
* - 0 the GPIO input level is 0
|
||||||
|
* - 1 the GPIO input level is 1
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int gpio_get_level(gpio_num_t gpio_num);
|
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
|
* 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.
|
* @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);
|
||||||
* If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
* @param mode GPIO direction
|
||||||
* @parameter[in] mode : Configure GPIO direction,such as output_only,input_only,...
|
|
||||||
*
|
*
|
||||||
* @return ESP_OK : success
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG : fail
|
* - ESP_OK Success
|
||||||
* ESP_FAIL : GPIO error
|
* - ESP_ERR_INVALID_ARG GPIO error
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
|
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
|
* 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.
|
* @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);
|
||||||
* If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16);
|
* @param pull GPIO pull up/down mode.
|
||||||
* @parameter[in] pull : Configure GPIO pull up/down mode,such as pullup_only,pulldown_only,pullup_and_pulldown,...
|
|
||||||
*
|
*
|
||||||
* @return ESP_OK : success
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG : fail
|
* - ESP_OK Success
|
||||||
* ESP_FAIL : GPIO error
|
* - ESP_ERR_INVALID_ARG : Parameter error
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
|
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
|
||||||
@ -340,121 +335,187 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
|
|||||||
/**
|
/**
|
||||||
* @brief enable GPIO wake-up function.
|
* @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\GPIO_INTR_HIGH_LEVEL can be used.
|
||||||
*
|
*
|
||||||
* @return ESP_OK: success
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - 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);
|
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
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - ESP_OK Success
|
||||||
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
|
esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief register GPIO interrupt handler, the handler is an ISR.
|
* @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.
|
* 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.
|
* 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.
|
* 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 ;
|
* @param gpio_intr_num GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details
|
||||||
* ESP_FAIL: gpio error
|
* @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);
|
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 ********************/
|
* *************** ATTENTION ********************/
|
||||||
/**
|
/**
|
||||||
*
|
*@attention
|
||||||
* Each GPIO has its own separate configuration register, so we do not use
|
* 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
|
* 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
|
* 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.
|
* pin simultaneously. It is up to the application developer to guarantee this.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
/*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ */
|
*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ *
|
||||||
/* gpio_config_t io_conf;
|
* @code{c}
|
||||||
|
* gpio_config_t io_conf;
|
||||||
* io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
|
* io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
|
||||||
* io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode
|
* 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.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_down_en = 0; //disable pull-down mode
|
||||||
* io_conf.pull_up_en = 0; //disable pull-up mode
|
* io_conf.pull_up_en = 0; //disable pull-up mode
|
||||||
* gpio_config(&io_conf); //configure GPIO with the given settings
|
* 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.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.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_down_en = 0; //disable pull-down mode
|
||||||
* io_conf.pull_up_en = 1; //enable pull-up mode
|
* io_conf.pull_up_en = 1; //enable pull-up mode
|
||||||
* gpio_config(&io_conf); //configure GPIO with the given settings
|
* gpio_config(&io_conf); //configure GPIO with the given settings
|
||||||
*----------EXAMPLE TO SET ISR HANDLER ----------------------*/
|
* @endcode
|
||||||
/* 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.
|
*----------EXAMPLE TO SET ISR HANDLER ----------------------
|
||||||
* //NOTE2:do not pick the INUM that already occupied by the system.
|
* @code{c}
|
||||||
* //NOTE3:refer to soc.h to check which INUMs that can be used.
|
* //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
|
||||||
*-------------EXAMPLE OF HANDLER FUNCTION-------------------*/
|
* gpio_isr_register(18,gpio_intr_test,NULL); //hook the isr handler for GPIO interrupt
|
||||||
/*#include "esp_attr.h"
|
* @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)
|
* void IRAM_ATTR gpio_intr_test(void* arg)
|
||||||
*{
|
* {
|
||||||
* //GPIO intr process
|
* //GPIO intr process
|
||||||
* ets_printf("in gpio_intr\n");
|
* ets_printf("in gpio_intr\n");
|
||||||
* uint32_t gpio_num = 0;
|
* 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 = 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
|
* 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_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
|
* SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39
|
||||||
* do {
|
* do {
|
||||||
* if(gpio_num < 32) {
|
* if(gpio_num < 32) {
|
||||||
* if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
|
* if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
|
||||||
* ets_printf("Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num));
|
* 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.
|
* //This is an isr handler, you should post an event to process it in RTOS queue.
|
||||||
* }
|
* }
|
||||||
* } else {
|
* } else {
|
||||||
* if(gpio_intr_status_h & BIT(gpio_num - 32)) {
|
* if(gpio_intr_status_h & BIT(gpio_num - 32)) {
|
||||||
* ets_printf("Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num));
|
* 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.
|
* //This is an isr handler, you should post an event to process it in RTOS queue.
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* } while(++gpio_num < GPIO_PIN_COUNT);
|
* } while(++gpio_num < GPIO_PIN_COUNT);
|
||||||
*}
|
* }
|
||||||
*----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---*/
|
* @endcode
|
||||||
/* 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
|
*----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---*
|
||||||
* io_conf.pull_down_en = 0; //disable pull-down mode
|
* @code{c}
|
||||||
* io_conf.pull_up_en = 1; //enable pull-up mode
|
* gpio_config_t io_conf;
|
||||||
* gpio_config(&io_conf); //configure GPIO with the given settings
|
* io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
|
||||||
* gpio_matrix_out(21, EXT_I2C_SCL_O_IDX, 0, 0); //set output signal for io_matrix
|
* io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD; //set as output mode
|
||||||
* gpio_matrix_out(22, EXT_I2C_SDA_O_IDX, 0, 0); //set output signal for io_matrix
|
* 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
|
||||||
* gpio_matrix_in( 22, EXT_I2C_SDA_I_IDX, 0); //set input signal for io_matrix
|
* 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,68 +30,68 @@ extern "C" {
|
|||||||
#define LEDC_REF_CLK_HZ (1*1000000)
|
#define LEDC_REF_CLK_HZ (1*1000000)
|
||||||
|
|
||||||
typedef enum {
|
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
|
//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_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */
|
||||||
LEDC_SPEED_MODE_MAX,
|
LEDC_SPEED_MODE_MAX, /*!< LEDC speed limit */
|
||||||
} ledc_mode_t;
|
} ledc_mode_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LEDC_INTR_DISABLE = 0, /*Disable LEDC interrupt */
|
LEDC_INTR_DISABLE = 0, /*!< Disable LEDC interrupt */
|
||||||
LEDC_INTR_FADE_END, /*Enable LEDC interrupt */
|
LEDC_INTR_FADE_END, /*!< Enable LEDC interrupt */
|
||||||
} ledc_intr_type_t;
|
} ledc_intr_type_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LEDC_DUTY_DIR_DECREASE = 0, /*LEDC duty decrease direction */
|
LEDC_DUTY_DIR_DECREASE = 0, /*!< LEDC duty decrease direction */
|
||||||
LEDC_DUTY_DIR_INCREASE = 1, /*LEDC duty increase direction */
|
LEDC_DUTY_DIR_INCREASE = 1, /*!< LEDC duty increase direction */
|
||||||
} ledc_duty_direction_t;
|
} ledc_duty_direction_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LEDC_REF_TICK = 0, /*LEDC timer clock divided from reference tick(1Mhz) */
|
LEDC_REF_TICK = 0, /*!< LEDC timer clock divided from reference tick(1Mhz) */
|
||||||
LEDC_APB_CLK, /*LEDC timer clock divided from APB clock(80Mhz)*/
|
LEDC_APB_CLK, /*!< LEDC timer clock divided from APB clock(80Mhz)*/
|
||||||
} ledc_clk_src_t;
|
} ledc_clk_src_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LEDC_TIMER_0 = 0, /*LEDC source timer TIMER0 */
|
LEDC_TIMER_0 = 0, /*!< LEDC source timer TIMER0 */
|
||||||
LEDC_TIMER_1, /*LEDC source timer TIMER1 */
|
LEDC_TIMER_1, /*!< LEDC source timer TIMER1 */
|
||||||
LEDC_TIMER_2, /*LEDC source timer TIMER2 */
|
LEDC_TIMER_2, /*!< LEDC source timer TIMER2 */
|
||||||
LEDC_TIMER_3, /*LEDC source timer TIMER3 */
|
LEDC_TIMER_3, /*!< LEDC source timer TIMER3 */
|
||||||
} ledc_timer_t;
|
} ledc_timer_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LEDC_CHANNEL_0 = 0, /*LEDC channel 0 */
|
LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */
|
||||||
LEDC_CHANNEL_1, /*LEDC channel 1 */
|
LEDC_CHANNEL_1, /*!< LEDC channel 1 */
|
||||||
LEDC_CHANNEL_2, /*LEDC channel 2 */
|
LEDC_CHANNEL_2, /*!< LEDC channel 2 */
|
||||||
LEDC_CHANNEL_3, /*LEDC channel 3 */
|
LEDC_CHANNEL_3, /*!< LEDC channel 3 */
|
||||||
LEDC_CHANNEL_4, /*LEDC channel 4 */
|
LEDC_CHANNEL_4, /*!< LEDC channel 4 */
|
||||||
LEDC_CHANNEL_5, /*LEDC channel 5 */
|
LEDC_CHANNEL_5, /*!< LEDC channel 5 */
|
||||||
LEDC_CHANNEL_6, /*LEDC channel 6 */
|
LEDC_CHANNEL_6, /*!< LEDC channel 6 */
|
||||||
LEDC_CHANNEL_7, /*LEDC channel 7 */
|
LEDC_CHANNEL_7, /*!< LEDC channel 7 */
|
||||||
} ledc_channel_t;
|
} ledc_channel_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LEDC_TIMER_10_BIT = 10, /*LEDC PWM depth 10Bit */
|
LEDC_TIMER_10_BIT = 10, /*!< LEDC PWM depth 10Bit */
|
||||||
LEDC_TIMER_11_BIT = 11, /*LEDC PWM depth 11Bit */
|
LEDC_TIMER_11_BIT = 11, /*!< LEDC PWM depth 11Bit */
|
||||||
LEDC_TIMER_12_BIT = 12, /*LEDC PWM depth 12Bit */
|
LEDC_TIMER_12_BIT = 12, /*!< LEDC PWM depth 12Bit */
|
||||||
LEDC_TIMER_13_BIT = 13, /*LEDC PWM depth 13Bit */
|
LEDC_TIMER_13_BIT = 13, /*!< LEDC PWM depth 13Bit */
|
||||||
LEDC_TIMER_14_BIT = 14, /*LEDC PWM depth 14Bit */
|
LEDC_TIMER_14_BIT = 14, /*!< LEDC PWM depth 14Bit */
|
||||||
LEDC_TIMER_15_BIT = 15, /*LEDC PWM depth 15Bit */
|
LEDC_TIMER_15_BIT = 15, /*!< LEDC PWM depth 15Bit */
|
||||||
} ledc_timer_bit_t;
|
} ledc_timer_bit_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int gpio_num; /*the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/
|
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_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/
|
||||||
ledc_channel_t channel; /*LEDC channel(0 - 7)*/
|
ledc_channel_t channel; /*!< LEDC channel(0 - 7)*/
|
||||||
ledc_intr_type_t intr_type; /*configure interrupt, Fade interrupt enable or Fade interrupt disable*/
|
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)*/
|
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], */
|
uint32_t duty; /*!< LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */
|
||||||
} ledc_channel_config_t;
|
} ledc_channel_config_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ledc_mode_t speed_mode; /*LEDC speed speed_mode, high-speed mode or low-speed mode*/
|
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_bit_t bit_num; /*!< LEDC channel duty depth*/
|
||||||
ledc_timer_t timer_num; /*The timer source of channel (0 - 3)*/
|
ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3)*/
|
||||||
uint32_t freq_hz; /*LEDC timer frequency(Hz)*/
|
uint32_t freq_hz; /*!< LEDC timer frequency(Hz)*/
|
||||||
} ledc_timer_config_t;
|
} ledc_timer_config_t;
|
||||||
|
|
||||||
|
|
||||||
@ -100,15 +100,10 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* User this Function, configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC depth
|
* 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
|
* @param ledc_conf Pointer of LEDC channel configure struct
|
||||||
* ledc_channel_config_t.speed_mode : LEDC speed speed_mode
|
* @return
|
||||||
* ledc_channel_config_t.gpio_num : LEDC output gpio_num, if you want to use gpio16, ledc_channel_config_t.gpio_num = 16
|
* - ESP_OK Success
|
||||||
* ledc_channel_config_t.channel : LEDC channel(0 - 7)
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
* 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
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf);
|
esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf);
|
||||||
@ -118,14 +113,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
|
* User this Function, configure LEDC timer with the given source timer/frequency(Hz)/bit_num
|
||||||
*
|
*
|
||||||
* @param[in] ledc_timer_config_t
|
* @param timer_conf Pointer of LEDC timer configure struct
|
||||||
* 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),
|
* @return
|
||||||
* ledc_timer_config_t.bit_num : LEDC channel duty depth
|
* - ESP_OK Success
|
||||||
* @return ESP_OK: success
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
* 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_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);
|
esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf);
|
||||||
@ -136,12 +130,13 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf);
|
|||||||
* Call this function to activate the LEDC updated parameters.
|
* 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.
|
* 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
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - ESP_OK Success
|
||||||
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||||
@ -151,12 +146,13 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
|||||||
*
|
*
|
||||||
* Disable LEDC output, and set idle level
|
* 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
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - 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);
|
esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level);
|
||||||
|
|
||||||
@ -165,27 +161,29 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl
|
|||||||
*
|
*
|
||||||
* Set LEDC frequency(Hz)
|
* 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
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - ESP_OK Success
|
||||||
* ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num.
|
* - 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);
|
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)
|
* @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
|
* @return
|
||||||
* others : current LEDC frequency
|
* - 0 error
|
||||||
|
* - Others Current LEDC frequency
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
|
uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
|
||||||
@ -195,27 +193,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.
|
* 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
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG: parameter error
|
* - 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);
|
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief LEDC get 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
|
* @return
|
||||||
* other value: current LEDC duty
|
* - (-1) parameter error
|
||||||
|
* - Others Current LEDC duty
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||||
@ -225,22 +225,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.
|
* 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
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG : parameter error
|
* - 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,
|
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);
|
uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale);
|
||||||
@ -248,34 +249,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.
|
* @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.
|
* 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.
|
* @note
|
||||||
* We can find the information of INUM and interrupt level in soc.h.
|
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||||
* TODO: to move INUM options to menu_config
|
* We can find the information of INUM and interrupt level in soc.h.
|
||||||
* @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 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.
|
* @param fn Interrupt handler function.
|
||||||
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
* @note
|
||||||
* @param[in] void * arg : parameter for handler function
|
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||||
|
* @param arg Parameter for handler function
|
||||||
*
|
*
|
||||||
* @return ESP_OK : success ;
|
* @return
|
||||||
* ESP_ERR_INVALID_ARG : function ptr error.
|
* - 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);
|
esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief configure LEDC settings
|
* @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
|
* @return
|
||||||
* other value: current LEDC duty
|
* - (-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);
|
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 +287,14 @@ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_
|
|||||||
/**
|
/**
|
||||||
* @brief reset LEDC timer
|
* @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
|
* @return
|
||||||
* ESP_OK: success
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
|
* - ESP_OK Success
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
|
esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
|
||||||
@ -297,13 +302,14 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
|
|||||||
/**
|
/**
|
||||||
* @brief pause LEDC timer counter
|
* @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
|
* @return
|
||||||
* ESP_OK: success
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
|
* - ESP_OK Success
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
|
esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
|
||||||
@ -311,13 +317,14 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
|
|||||||
/**
|
/**
|
||||||
* @brief pause LEDC timer resume
|
* @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
|
* @return
|
||||||
* ESP_OK: success
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
|
* - ESP_OK Success
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
|
esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
|
||||||
@ -325,15 +332,16 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
|
|||||||
/**
|
/**
|
||||||
* @brief bind LEDC channel with the selected timer
|
* @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
|
* @return
|
||||||
* ESP_OK: success
|
* - 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);
|
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx);
|
||||||
@ -342,44 +350,56 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* ----------------EXAMPLE OF LEDC SETTING ---------------------
|
* ----------------EXAMPLE OF LEDC SETTING ---------------------
|
||||||
* //1. enable LEDC
|
* @code{c}
|
||||||
* periph_module_enable(PERIPH_LEDC_MODULE); //enable LEDC module, or you can not set any register of it.
|
* //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
|
* @code{c}
|
||||||
* ledc_timer_config_t timer_conf = {
|
* //2. set LEDC timer
|
||||||
* .bit_num = LEDC_TIMER_12_BIT, //set timer counter bit number
|
* ledc_timer_config_t timer_conf = {
|
||||||
* .freq_hz = 1000, //set frequency of pwm, here, 1000Hz
|
* .bit_num = LEDC_TIMER_12_BIT, //set timer counter bit number
|
||||||
* .speed_mode = LEDC_HIGH_SPEED_MODE //timer mode,
|
* .freq_hz = 1000, //set frequency of pwm, here, 1000Hz
|
||||||
* .timer_num = LEDC_TIMER_0, //timer number
|
* .speed_mode = LEDC_HIGH_SPEED_MODE, //timer mode,
|
||||||
* };
|
* .timer_num = LEDC_TIMER_0, //timer number
|
||||||
* ledc_timer_config(&timer_conf); //setup timer.
|
* };
|
||||||
|
* ledc_timer_config(&timer_conf); //setup timer.
|
||||||
|
* @endcode
|
||||||
*
|
*
|
||||||
* //3. set LEDC channel
|
* @code{c}
|
||||||
* ledc_channel_config_t ledc_conf = {
|
* //3. set LEDC channel
|
||||||
* .channel = LEDC_CHANNEL_0; //set LEDC channel 0
|
* ledc_channel_config_t ledc_conf = {
|
||||||
* .duty = 1000; //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
|
* .channel = LEDC_CHANNEL_0; //set LEDC channel 0
|
||||||
* .gpio_num = 16; //GPIO number
|
* .duty = 1000; //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
|
||||||
* .intr_type = LEDC_INTR_FADE_END; //GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
|
* .gpio_num = 16; //GPIO number
|
||||||
* .speed_mode = LEDC_HIGH_SPEED_MODE; //set LEDC mode, from ledc_mode_t
|
* .intr_type = LEDC_INTR_FADE_END; //GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
|
||||||
* .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
|
* .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
|
* }
|
||||||
|
* ledc_channel_config(&ledc_conf); //setup the configuration
|
||||||
*
|
*
|
||||||
* ----------------EXAMPLE OF SETTING DUTY --- -----------------
|
* ----------------EXAMPLE OF SETTING DUTY --- -----------------
|
||||||
* uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73)
|
* @code{c}
|
||||||
* uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1)
|
* uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73)
|
||||||
* LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty.
|
* uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1)
|
||||||
* ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel); //after set duty, we need to call ledc_update_duty to update the settings.
|
* 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 ------------------
|
* ----------------EXAMPLE OF LEDC INTERRUPT ------------------
|
||||||
* //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here.
|
* @code{c}
|
||||||
* ledc_isr_register(18, ledc_isr_handler, NULL); //hook the isr handler for LEDC interrupt
|
* //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here.
|
||||||
* //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
|
* ledc_isr_register(18, ledc_isr_handler, NULL); //hook the isr handler for LEDC interrupt
|
||||||
* //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
|
* @endcode
|
||||||
* //NOTE2:do not pick the INUM that already occupied by the system.
|
* @note
|
||||||
* //NOTE3:refer to soc.h to check which INUMs that can be used.
|
* 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 ---------------
|
* ----------------EXAMPLE OF INTERRUPT HANDLER ---------------
|
||||||
|
* @code{c}
|
||||||
* #include "esp_attr.h"
|
* #include "esp_attr.h"
|
||||||
* void IRAM_ATTR ledc_isr_handler(void* arg) //we should add 'IRAM_ATTR' attribution when we declare the isr function
|
* void IRAM_ATTR ledc_isr_handler(void* arg) //we should add 'IRAM_ATTR' attribution when we declare the isr function
|
||||||
* {
|
* {
|
||||||
@ -391,7 +411,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.
|
* LEDC.int_clr.val = intr_st; //clear LEDC interrupt status.
|
||||||
* }
|
* }
|
||||||
*
|
* @endcode
|
||||||
*
|
*
|
||||||
*--------------------------END OF EXAMPLE --------------------------
|
*--------------------------END OF EXAMPLE --------------------------
|
||||||
*/
|
*/
|
||||||
|
763
components/driver/include/driver/uart.h
Normal file
763
components/driver/include/driver/uart.h
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
// 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
|
||||||
|
#define UART_LINE_INV_MASK (0x3f << 19)
|
||||||
|
#define UART_BITRATE_MAX 5000000
|
||||||
|
#define UART_PIN_NO_CHANGE (-1)
|
||||||
|
|
||||||
|
#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*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/
|
||||||
|
UART_PARITY_EVEN = 0x10, /*!< Enable UART even parity*/
|
||||||
|
UART_PARITY_ODD = 0x11 /*!< Enable UART odd parity*/
|
||||||
|
} uart_parity_t;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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_no 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_no UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||||
|
*
|
||||||
|
* @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_no 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_no, uart_stop_bits_t bit_num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set UART stop bits.
|
||||||
|
*
|
||||||
|
* @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||||
|
*
|
||||||
|
* @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_no 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_no, uart_parity_t parity_mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get UART parity mode.
|
||||||
|
*
|
||||||
|
* @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||||
|
*
|
||||||
|
* @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_no 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_no, uint32_t baud_rate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get UART bit-rate.
|
||||||
|
*
|
||||||
|
* @param uart_no: UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||||
|
*
|
||||||
|
* @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_no 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_no, uint32_t inverse_mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set hardware flow control.
|
||||||
|
*
|
||||||
|
* @param uart_no 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_no, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get hardware flow control mode
|
||||||
|
*
|
||||||
|
* @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||||
|
*
|
||||||
|
* @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_no 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_no 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_no 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_no 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_no 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_no 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_no 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.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param uart_no 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.
|
||||||
|
* @attention
|
||||||
|
* The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now.
|
||||||
|
* @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_no 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_no 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_no 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_no 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_no 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_no 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_no 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_no 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_no 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_no, 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_no 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_no 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: one bit's time@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_no 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_no 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;
|
||||||
|
* uint8_t dtmp[1000];
|
||||||
|
* 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, sizeof(dtmp));
|
||||||
|
* //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;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* 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, 15, 13);
|
||||||
|
* //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, RINGBUF_TYPE_BYTEBUF);
|
||||||
|
* //Create a task to handler UART event from ISR
|
||||||
|
* xTaskCreate(uart_task, "uTask", 2048*8, (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 "freertos/xtensa_api.h"
|
||||||
#include "soc/gpio_sig_map.h"
|
#include "soc/gpio_sig_map.h"
|
||||||
#include "driver/ledc.h"
|
#include "driver/ledc.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
//TODO: to use APIs in esp_log.h.
|
static const char* LEDC_TAG = "LEDC";
|
||||||
#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 portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
#define LEDC_CHECK(a, str, ret_val) if (!(a)) { \
|
||||||
static bool ledc_is_valid_channel(uint32_t channel)
|
ESP_LOGE(LEDC_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||||
{
|
return (ret_val); \
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
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)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
if(!ledc_is_valid_timer(timer_sel)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
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.div_num = div_num;
|
||||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src;
|
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)
|
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)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
LEDC_CHECK(timer_idx <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
if(!ledc_is_valid_timer(timer_idx)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
portENTER_CRITICAL(&ledc_spinlock);
|
||||||
LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx;
|
LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx;
|
||||||
portEXIT_CRITICAL(&ledc_spinlock);
|
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)
|
esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||||
{
|
{
|
||||||
if(!ledc_is_valid_mode(speed_mode)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
if(!ledc_is_valid_timer(timer_sel)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
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 = 1;
|
||||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
|
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)
|
esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||||
{
|
{
|
||||||
if(!ledc_is_valid_mode(speed_mode)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
if(!ledc_is_valid_timer(timer_sel)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
portENTER_CRITICAL(&ledc_spinlock);
|
||||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
|
LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
|
||||||
portEXIT_CRITICAL(&ledc_spinlock);
|
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)
|
esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||||
{
|
{
|
||||||
if(!ledc_is_valid_mode(speed_mode)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
if(!ledc_is_valid_timer(timer_sel)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
portENTER_CRITICAL(&ledc_spinlock);
|
||||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
|
LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
|
||||||
portEXIT_CRITICAL(&ledc_spinlock);
|
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)
|
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)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t intr_type = type;
|
uint32_t intr_type = type;
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
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)
|
esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg)
|
||||||
{
|
{
|
||||||
if(fn == NULL) {
|
LEDC_CHECK(fn, "ledc isr null", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
portENTER_CRITICAL(&ledc_spinlock);
|
||||||
ESP_INTR_DISABLE(ledc_intr_num);
|
ESP_INTR_DISABLE(ledc_intr_num);
|
||||||
intr_matrix_set(xPortGetCoreID(), ETS_LEDC_INTR_SOURCE, 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 bit_num = timer_conf->bit_num;
|
||||||
int timer_num = timer_conf->timer_num;
|
int timer_num = timer_conf->timer_num;
|
||||||
int speed_mode = timer_conf->speed_mode;
|
int speed_mode = timer_conf->speed_mode;
|
||||||
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
if(!ledc_is_valid_mode(speed_mode)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if(freq_hz == 0 || bit_num == 0 || bit_num > LEDC_TIMER_15_BIT) {
|
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;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if(timer_num > LEDC_TIMER_3) {
|
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;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
esp_err_t ret = ESP_OK;
|
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*/
|
/*Selet the reference tick*/
|
||||||
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||||
if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) {
|
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;
|
ret = ESP_FAIL;
|
||||||
}
|
}
|
||||||
timer_clk_src = LEDC_REF_TICK;
|
timer_clk_src = LEDC_REF_TICK;
|
||||||
@ -254,6 +164,21 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
|
|||||||
return ret;
|
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)
|
esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
||||||
{
|
{
|
||||||
uint32_t speed_mode = ledc_conf->speed_mode;
|
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 timer_select = ledc_conf->timer_sel;
|
||||||
uint32_t intr_type = ledc_conf->intr_type;
|
uint32_t intr_type = ledc_conf->intr_type;
|
||||||
uint32_t duty = ledc_conf->duty;
|
uint32_t duty = ledc_conf->duty;
|
||||||
|
LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||||
if(!ledc_is_valid_channel(ledc_channel)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return 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);
|
||||||
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;
|
|
||||||
}
|
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
/*set channel parameters*/
|
/*set channel parameters*/
|
||||||
/* channel parameters decide how the waveform looks like in one period*/
|
/* 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);
|
ledc_bind_channel_timer(speed_mode, ledc_channel, timer_select);
|
||||||
/*set interrupt type*/
|
/*set interrupt type*/
|
||||||
ledc_enable_intr_type(speed_mode, ledc_channel, intr_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
|
ledc_channel, gpio_num, duty, timer_select
|
||||||
);
|
);
|
||||||
/*set LEDC signal in gpio matrix*/
|
/*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)
|
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||||
{
|
{
|
||||||
if(!ledc_is_valid_mode(speed_mode)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
if(!ledc_is_valid_channel(channel)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
portENTER_CRITICAL(&ledc_spinlock);
|
||||||
LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
|
LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
|
||||||
LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 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)
|
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)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
if(!ledc_is_valid_channel(channel)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
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.idle_lv = idle_level & 0x1;
|
||||||
LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 0;
|
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,
|
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)
|
uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale)
|
||||||
{
|
{
|
||||||
if(!ledc_is_valid_mode(speed_mode)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return 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(!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;
|
|
||||||
}
|
|
||||||
if(step_num > LEDC_DUTY_NUM_HSCH0_V || duty_cyle_num > LEDC_DUTY_CYCLE_HSCH0_V || duty_scale > LEDC_DUTY_SCALE_HSCH0_V) {
|
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;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
ledc_duty_config(speed_mode,
|
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)
|
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)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||||
}
|
|
||||||
if(!ledc_is_valid_channel(channel)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
ledc_duty_config(speed_mode,
|
ledc_duty_config(speed_mode,
|
||||||
channel, //uint32_t chan_num,
|
channel, //uint32_t chan_num,
|
||||||
0, //uint32_t hpoint_val,
|
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)
|
int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||||
{
|
{
|
||||||
if(!ledc_is_valid_mode(speed_mode)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (-1));
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4);
|
uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4);
|
||||||
return duty;
|
return duty;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz)
|
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)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
portENTER_CRITICAL(&ledc_spinlock);
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
uint32_t div_num = 0;
|
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;
|
div_num = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||||
}
|
}
|
||||||
if(div_num <= 256 || div_num > LEDC_DIV_NUM_HSTIMER0) {
|
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;
|
ret = ESP_FAIL;
|
||||||
}
|
}
|
||||||
LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num = div_num;
|
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)
|
uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)
|
||||||
{
|
{
|
||||||
if(!ledc_is_valid_mode(speed_mode)) {
|
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (0));
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
portENTER_CRITICAL(&ledc_spinlock);
|
portENTER_CRITICAL(&ledc_spinlock);
|
||||||
uint32_t freq = 0;
|
uint32_t freq = 0;
|
||||||
uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;
|
uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;
|
||||||
|
1008
components/driver/uart.c
Normal file
1008
components/driver/uart.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -63,14 +63,28 @@ config MEMMAP_TRACEMEM
|
|||||||
of memory that can't be used for general purposes anymore. Disable this if you do not know
|
of memory that can't be used for general purposes anymore. Disable this if you do not know
|
||||||
what this is.
|
what this is.
|
||||||
|
|
||||||
|
config MEMMAP_TRACEMEM_TWOBANKS
|
||||||
|
bool "Reserve memory for tracing both pro as well as app cpu execution"
|
||||||
|
default "n"
|
||||||
|
depends on MEMMAP_TRACEMEM && MEMMAP_SMP
|
||||||
|
help
|
||||||
|
The ESP32 contains a feature which allows you to trace the execution path the processor
|
||||||
|
has taken through the program. This is stored in a chunk of 32K (16K for single-processor)
|
||||||
|
of memory that can't be used for general purposes anymore. Disable this if you do not know
|
||||||
|
what this is.
|
||||||
|
|
||||||
|
|
||||||
# Memory to reverse for trace, used in linker script
|
# Memory to reverse for trace, used in linker script
|
||||||
config TRACEMEM_RESERVE_DRAM
|
config TRACEMEM_RESERVE_DRAM
|
||||||
hex
|
hex
|
||||||
default 0x8000 if MEMMAP_TRACEMEM
|
default 0x8000 if MEMMAP_TRACEMEM && MEMMAP_TRACEMEM_TWOBANKS
|
||||||
|
default 0x4000 if MEMMAP_TRACEMEM && !MEMMAP_TRACEMEM_TWOBANKS
|
||||||
default 0x0
|
default 0x0
|
||||||
|
|
||||||
|
# Not implemented and/or needs new silicon rev to work
|
||||||
config MEMMAP_SPISRAM
|
config MEMMAP_SPISRAM
|
||||||
bool "Use external SPI SRAM chip as main memory"
|
bool "Use external SPI SRAM chip as main memory"
|
||||||
|
depends on ESP32_NEEDS_NEW_SILICON_REV
|
||||||
default "n"
|
default "n"
|
||||||
help
|
help
|
||||||
The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the
|
The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the
|
||||||
@ -140,4 +154,214 @@ config ULP_COPROC_RESERVE_MEM
|
|||||||
default 0
|
default 0
|
||||||
depends on !ULP_COPROC_ENABLED
|
depends on !ULP_COPROC_ENABLED
|
||||||
|
|
||||||
|
|
||||||
|
choice ESP32_PANIC
|
||||||
|
prompt "Panic handler behaviour"
|
||||||
|
default ESP32_PANIC_PRINT_REBOOT
|
||||||
|
help
|
||||||
|
If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is
|
||||||
|
invoked. Configure the panic handlers action here.
|
||||||
|
|
||||||
|
config ESP32_PANIC_PRINT_HALT
|
||||||
|
bool "Print registers and halt"
|
||||||
|
help
|
||||||
|
Outputs the relevant registers over the serial port and halt the
|
||||||
|
processor. Needs a manual reset to restart.
|
||||||
|
|
||||||
|
config ESP32_PANIC_PRINT_REBOOT
|
||||||
|
bool "Print registers and reboot"
|
||||||
|
help
|
||||||
|
Outputs the relevant registers over the serial port and immediately
|
||||||
|
reset the processor.
|
||||||
|
|
||||||
|
config ESP32_PANIC_SILENT_REBOOT
|
||||||
|
bool "Silent reboot"
|
||||||
|
help
|
||||||
|
Just resets the processor without outputting anything
|
||||||
|
|
||||||
|
config ESP32_PANIC_GDBSTUB
|
||||||
|
bool "Invoke GDBStub"
|
||||||
|
help
|
||||||
|
Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
|
||||||
|
of the crash.
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config ESP32_DEBUG_OCDAWARE
|
||||||
|
bool "Make exception and panic handlers JTAG/OCD aware"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
|
||||||
|
instead of panicking, have the debugger stop on the offending instruction.
|
||||||
|
|
||||||
|
|
||||||
|
config INT_WDT
|
||||||
|
bool "Interrupt watchdog"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This watchdog timer can detect if the FreeRTOS tick interrupt has not been called for a certain time,
|
||||||
|
either because a task turned off interrupts and did not turn them on for a long time, or because an
|
||||||
|
interrupt handler did not return. It will try to invoke the panic handler first and failing that
|
||||||
|
reset the SoC.
|
||||||
|
|
||||||
|
config INT_WDT_TIMEOUT_MS
|
||||||
|
int "Interrupt watchdog timeout (ms)"
|
||||||
|
depends on INT_WDT
|
||||||
|
default 300
|
||||||
|
range 10 10000
|
||||||
|
help
|
||||||
|
The timeout of the watchdog, in miliseconds. Make this higher than the FreeRTOS tick rate.
|
||||||
|
|
||||||
|
config INT_WDT_CHECK_CPU1
|
||||||
|
bool "Also watch CPU1 tick interrupt"
|
||||||
|
depends on INT_WDT && !FREERTOS_UNICORE
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Also detect if interrupts on CPU 1 are disabled for too long.
|
||||||
|
|
||||||
|
config TASK_WDT
|
||||||
|
bool "Task watchdog"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This watchdog timer can be used to make sure individual tasks are still running.
|
||||||
|
|
||||||
|
config TASK_WDT_PANIC
|
||||||
|
bool "Invoke panic handler when Task Watchdog is triggered"
|
||||||
|
depends on TASK_WDT
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Normally, the Task Watchdog will only print out a warning if it detects it has not
|
||||||
|
been fed. If this is enabled, it will invoke the panic handler instead, which
|
||||||
|
can then halt or reboot the chip.
|
||||||
|
|
||||||
|
config TASK_WDT_TIMEOUT_S
|
||||||
|
int "Task watchdog timeout (seconds)"
|
||||||
|
depends on TASK_WDT
|
||||||
|
range 1 60
|
||||||
|
default 5
|
||||||
|
help
|
||||||
|
Timeout for the task WDT, in seconds.
|
||||||
|
|
||||||
|
config TASK_WDT_CHECK_IDLE_TASK
|
||||||
|
bool "Task watchdog watches CPU0 idle task"
|
||||||
|
depends on TASK_WDT
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
With this turned on, the task WDT can detect if the idle task is not called within the task
|
||||||
|
watchdog timeout period. The idle task not being called usually is a symptom of another
|
||||||
|
task hoarding the CPU. It is also a bad thing because FreeRTOS household tasks depend on the
|
||||||
|
idle task getting some runtime every now and then. Take Care: With this disabled, this
|
||||||
|
watchdog will trigger if no tasks register themselves within the timeout value.
|
||||||
|
|
||||||
|
config TASK_WDT_CHECK_IDLE_TASK_CPU1
|
||||||
|
bool "Task watchdog also watches CPU1 idle task"
|
||||||
|
depends on TASK_WDT_CHECK_IDLE_TASK && !FREERTOS_UNICORE
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Also check the idle task that runs on CPU1.
|
||||||
|
|
||||||
|
#The brownout detector code is disabled (by making it depend on a nonexisting symbol) because the current revision of ESP32
|
||||||
|
#silicon has a bug in the brown-out detector, rendering it unusable for resetting the CPU.
|
||||||
|
config BROWNOUT_DET
|
||||||
|
bool "Hardware brownout detect & reset"
|
||||||
|
default y
|
||||||
|
depends on NEEDS_ESP32_NEW_SILICON_REV
|
||||||
|
help
|
||||||
|
The ESP32 has a built-in brownout detector which can detect if the voltage is lower than
|
||||||
|
a specific value. If this happens, it will reset the chip in order to prevent unintended
|
||||||
|
behaviour.
|
||||||
|
|
||||||
|
choice BROWNOUT_DET_LVL_SEL
|
||||||
|
prompt "Brownout voltage level"
|
||||||
|
depends on BROWNOUT_DET
|
||||||
|
default BROWNOUT_DET_LVL_SEL_25
|
||||||
|
help
|
||||||
|
The brownout detector will reset the chip when the supply voltage is below this level.
|
||||||
|
|
||||||
|
#The voltage levels here are estimates, more work needs to be done to figure out the exact voltages
|
||||||
|
#of the brownout threshold levels.
|
||||||
|
config BROWNOUT_DET_LVL_SEL_0
|
||||||
|
bool "2.1V"
|
||||||
|
config BROWNOUT_DET_LVL_SEL_1
|
||||||
|
bool "2.2V"
|
||||||
|
config BROWNOUT_DET_LVL_SEL_2
|
||||||
|
bool "2.3V"
|
||||||
|
config BROWNOUT_DET_LVL_SEL_3
|
||||||
|
bool "2.4V"
|
||||||
|
config BROWNOUT_DET_LVL_SEL_4
|
||||||
|
bool "2.5V"
|
||||||
|
config BROWNOUT_DET_LVL_SEL_5
|
||||||
|
bool "2.6V"
|
||||||
|
config BROWNOUT_DET_LVL_SEL_6
|
||||||
|
bool "2.7V"
|
||||||
|
config BROWNOUT_DET_LVL_SEL_7
|
||||||
|
bool "2.8V"
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config BROWNOUT_DET_LVL
|
||||||
|
int
|
||||||
|
default 0 if BROWNOUT_DET_LVL_SEL_0
|
||||||
|
default 1 if BROWNOUT_DET_LVL_SEL_1
|
||||||
|
default 2 if BROWNOUT_DET_LVL_SEL_2
|
||||||
|
default 3 if BROWNOUT_DET_LVL_SEL_3
|
||||||
|
default 4 if BROWNOUT_DET_LVL_SEL_4
|
||||||
|
default 5 if BROWNOUT_DET_LVL_SEL_5
|
||||||
|
default 6 if BROWNOUT_DET_LVL_SEL_6
|
||||||
|
default 7 if BROWNOUT_DET_LVL_SEL_7
|
||||||
|
|
||||||
|
|
||||||
|
config BROWNOUT_DET_RESETDELAY
|
||||||
|
int "Brownout reset delay (in uS)"
|
||||||
|
depends on BROWNOUT_DET
|
||||||
|
range 0 6820
|
||||||
|
default 1000
|
||||||
|
help
|
||||||
|
The brownout detector can reset the chip after a certain delay, in order to make sure e.g. a voltage dip has entirely passed
|
||||||
|
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
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
39
components/esp32/brownout.c
Normal file
39
components/esp32/brownout.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "soc/soc.h"
|
||||||
|
#include "soc/rtc_cntl_reg.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if CONFIG_BROWNOUT_DET
|
||||||
|
/*
|
||||||
|
This file is included in esp-idf, but the menuconfig option for this is disabled because a silicon bug
|
||||||
|
prohibits the brownout detector from functioning correctly on the ESP32.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void esp_brownout_init() {
|
||||||
|
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG,
|
||||||
|
RTC_CNTL_BROWN_OUT_ENA | (CONFIG_BROWNOUT_DET_LVL << RTC_CNTL_DBROWN_OUT_THRES_S) |
|
||||||
|
RTC_CNTL_BROWN_OUT_RST_ENA | (((CONFIG_BROWNOUT_DET_RESETDELAY*150)/1000) << RTC_CNTL_BROWN_OUT_RST_WAIT_S) |
|
||||||
|
RTC_CNTL_BROWN_OUT_PD_RF_ENA|RTC_CNTL_BROWN_OUT_CLOSE_FLASH_ENA);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,28 +1,20 @@
|
|||||||
#
|
#
|
||||||
# Component Makefile
|
# 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 $(PROJECT_PATH)/build/include/config/auto.conf
|
|
||||||
|
|
||||||
COMPONENT_SRCDIRS := . hwcrypto
|
COMPONENT_SRCDIRS := . hwcrypto
|
||||||
|
|
||||||
LIBS := crypto core net80211 phy rtc pp wpa smartconfig
|
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
|
LINKER_SCRIPTS += -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld
|
||||||
|
|
||||||
COMPONENT_ADD_LDFLAGS := -lesp32 \
|
COMPONENT_ADD_LDFLAGS := -lesp32 \
|
||||||
$(abspath libhal.a) \
|
$(COMPONENT_PATH)/libhal.a \
|
||||||
-L$(abspath lib) \
|
-L$(COMPONENT_PATH)/lib \
|
||||||
$(addprefix -l,$(LIBS)) \
|
$(addprefix -l,$(LIBS)) \
|
||||||
-L $(abspath ld) \
|
-L $(COMPONENT_PATH)/ld \
|
||||||
$(LINKER_SCRIPTS)
|
$(LINKER_SCRIPTS)
|
||||||
|
|
||||||
include $(IDF_PATH)/make/component_common.mk
|
|
||||||
|
|
||||||
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
||||||
|
|
||||||
# automatically trigger a git submodule update
|
# automatically trigger a git submodule update
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "rom/ets_sys.h"
|
#include "rom/ets_sys.h"
|
||||||
#include "rom/uart.h"
|
#include "rom/uart.h"
|
||||||
|
#include "rom/rtc.h"
|
||||||
|
#include "rom/cache.h"
|
||||||
|
|
||||||
#include "soc/cpu.h"
|
#include "soc/cpu.h"
|
||||||
#include "soc/dport_reg.h"
|
#include "soc/dport_reg.h"
|
||||||
@ -41,7 +43,14 @@
|
|||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_spi_flash.h"
|
#include "esp_spi_flash.h"
|
||||||
#include "esp_ipc.h"
|
#include "esp_ipc.h"
|
||||||
|
#include "esp_crosscore_int.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_vfs_dev.h"
|
||||||
|
#include "esp_newlib.h"
|
||||||
|
#include "esp_brownout.h"
|
||||||
|
#include "esp_int_wdt.h"
|
||||||
|
#include "esp_task_wdt.h"
|
||||||
|
#include "trax.h"
|
||||||
|
|
||||||
void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
|
void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
|
||||||
void start_cpu0_default(void) IRAM_ATTR;
|
void start_cpu0_default(void) IRAM_ATTR;
|
||||||
@ -54,11 +63,12 @@ static bool app_cpu_started = false;
|
|||||||
|
|
||||||
static void do_global_ctors(void);
|
static void do_global_ctors(void);
|
||||||
static void main_task(void* args);
|
static void main_task(void* args);
|
||||||
extern void ets_setup_syscalls(void);
|
|
||||||
extern void app_main(void);
|
extern void app_main(void);
|
||||||
|
|
||||||
extern int _bss_start;
|
extern int _bss_start;
|
||||||
extern int _bss_end;
|
extern int _bss_end;
|
||||||
|
extern int _rtc_bss_start;
|
||||||
|
extern int _rtc_bss_end;
|
||||||
extern int _init_start;
|
extern int _init_start;
|
||||||
extern void (*__init_array_start)(void);
|
extern void (*__init_array_start)(void);
|
||||||
extern void (*__init_array_end)(void);
|
extern void (*__init_array_end)(void);
|
||||||
@ -89,6 +99,11 @@ void IRAM_ATTR call_start_cpu0()
|
|||||||
|
|
||||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
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
|
// Initialize heap allocator
|
||||||
heap_alloc_caps_init();
|
heap_alloc_caps_init();
|
||||||
|
|
||||||
@ -96,7 +111,13 @@ void IRAM_ATTR call_start_cpu0()
|
|||||||
|
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
|
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);
|
||||||
|
//Enable clock gating and reset the app cpu.
|
||||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
||||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
|
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
|
||||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
|
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
|
||||||
@ -131,12 +152,41 @@ void IRAM_ATTR call_start_cpu1()
|
|||||||
|
|
||||||
void start_cpu0_default(void)
|
void start_cpu0_default(void)
|
||||||
{
|
{
|
||||||
|
//Enable trace memory and immediately start trace.
|
||||||
|
#if CONFIG_MEMMAP_TRACEMEM
|
||||||
|
#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS
|
||||||
|
trax_enable(TRAX_ENA_PRO_APP);
|
||||||
|
#else
|
||||||
|
trax_enable(TRAX_ENA_PRO);
|
||||||
|
#endif
|
||||||
|
trax_start_trace(TRAX_DOWNCOUNT_WORDS);
|
||||||
|
#endif
|
||||||
esp_set_cpu_freq(); // set CPU frequency configured in menuconfig
|
esp_set_cpu_freq(); // set CPU frequency configured in menuconfig
|
||||||
uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
|
uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
|
||||||
ets_setup_syscalls();
|
#if CONFIG_BROWNOUT_DET
|
||||||
|
esp_brownout_init();
|
||||||
|
#endif
|
||||||
|
#if CONFIG_INT_WDT
|
||||||
|
esp_int_wdt_init();
|
||||||
|
#endif
|
||||||
|
#if CONFIG_TASK_WDT
|
||||||
|
esp_task_wdt_init();
|
||||||
|
#endif
|
||||||
|
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");
|
||||||
do_global_ctors();
|
do_global_ctors();
|
||||||
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
|
esp_crosscore_int_init();
|
||||||
|
#endif
|
||||||
esp_ipc_init();
|
esp_ipc_init();
|
||||||
spi_flash_init();
|
spi_flash_init();
|
||||||
|
|
||||||
xTaskCreatePinnedToCore(&main_task, "main",
|
xTaskCreatePinnedToCore(&main_task, "main",
|
||||||
ESP_TASK_MAIN_STACK, NULL,
|
ESP_TASK_MAIN_STACK, NULL,
|
||||||
ESP_TASK_MAIN_PRIO, NULL, 0);
|
ESP_TASK_MAIN_PRIO, NULL, 0);
|
||||||
@ -147,10 +197,14 @@ void start_cpu0_default(void)
|
|||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
void start_cpu1_default(void)
|
void start_cpu1_default(void)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS
|
||||||
|
trax_start_trace(TRAX_DOWNCOUNT_WORDS);
|
||||||
|
#endif
|
||||||
// Wait for FreeRTOS initialization to finish on PRO CPU
|
// Wait for FreeRTOS initialization to finish on PRO CPU
|
||||||
while (port_xSchedulerRunning[0] == 0) {
|
while (port_xSchedulerRunning[0] == 0) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
esp_crosscore_int_init();
|
||||||
ESP_LOGI(TAG, "Starting scheduler on APP CPU.");
|
ESP_LOGI(TAG, "Starting scheduler on APP CPU.");
|
||||||
xPortStartScheduler();
|
xPortStartScheduler();
|
||||||
}
|
}
|
||||||
|
98
components/esp32/crosscore_int.c
Normal file
98
components/esp32/crosscore_int.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// 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 <string.h>
|
||||||
|
|
||||||
|
#include "esp_attr.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_intr.h"
|
||||||
|
|
||||||
|
#include "rom/ets_sys.h"
|
||||||
|
#include "rom/uart.h"
|
||||||
|
|
||||||
|
#include "soc/cpu.h"
|
||||||
|
#include "soc/dport_reg.h"
|
||||||
|
#include "soc/io_mux_reg.h"
|
||||||
|
#include "soc/rtc_cntl_reg.h"
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "freertos/portmacro.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define REASON_YIELD (1<<0)
|
||||||
|
|
||||||
|
static portMUX_TYPE reasonSpinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
static volatile uint32_t reason[ portNUM_PROCESSORS ];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
ToDo: There is a small chance the CPU already has yielded when this ISR is serviced. In that case, it's running the intended task but
|
||||||
|
the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably just schedule the task again, but have to check that.
|
||||||
|
*/
|
||||||
|
static void esp_crosscore_isr(void *arg) {
|
||||||
|
uint32_t myReasonVal;
|
||||||
|
//A pointer to the correct reason array item is passed to this ISR.
|
||||||
|
volatile uint32_t *myReason=arg;
|
||||||
|
|
||||||
|
//Clear the interrupt first.
|
||||||
|
if (xPortGetCoreID()==0) {
|
||||||
|
WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0);
|
||||||
|
} else {
|
||||||
|
WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, 0);
|
||||||
|
}
|
||||||
|
//Grab the reason and clear it.
|
||||||
|
portENTER_CRITICAL(&reasonSpinlock);
|
||||||
|
myReasonVal=*myReason;
|
||||||
|
*myReason=0;
|
||||||
|
portEXIT_CRITICAL(&reasonSpinlock);
|
||||||
|
|
||||||
|
//Check what we need to do.
|
||||||
|
if (myReasonVal&REASON_YIELD) {
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Initialize the crosscore interrupt on this core. Call this once
|
||||||
|
//on each active core.
|
||||||
|
void esp_crosscore_int_init() {
|
||||||
|
portENTER_CRITICAL(&reasonSpinlock);
|
||||||
|
reason[xPortGetCoreID()]=0;
|
||||||
|
portEXIT_CRITICAL(&reasonSpinlock);
|
||||||
|
ESP_INTR_DISABLE(ETS_FROM_CPU_INUM);
|
||||||
|
if (xPortGetCoreID()==0) {
|
||||||
|
intr_matrix_set(xPortGetCoreID(), ETS_FROM_CPU_INTR0_SOURCE, ETS_FROM_CPU_INUM);
|
||||||
|
} else {
|
||||||
|
intr_matrix_set(xPortGetCoreID(), ETS_FROM_CPU_INTR1_SOURCE, ETS_FROM_CPU_INUM);
|
||||||
|
}
|
||||||
|
xt_set_interrupt_handler(ETS_FROM_CPU_INUM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()]);
|
||||||
|
ESP_INTR_ENABLE(ETS_FROM_CPU_INUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void esp_crosscore_int_send_yield(int coreId) {
|
||||||
|
assert(coreId<portNUM_PROCESSORS);
|
||||||
|
//Mark the reason we interrupt the other CPU
|
||||||
|
portENTER_CRITICAL(&reasonSpinlock);
|
||||||
|
reason[coreId]|=REASON_YIELD;
|
||||||
|
portEXIT_CRITICAL(&reasonSpinlock);
|
||||||
|
//Poke the other CPU.
|
||||||
|
if (coreId==0) {
|
||||||
|
WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0);
|
||||||
|
} else {
|
||||||
|
WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, DPORT_CPU_INTR_FROM_CPU_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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) {
|
void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) {
|
||||||
//
|
/* Clear MMU for CPU 0 */
|
||||||
//mmu_init(0);
|
|
||||||
REG_SET_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR);
|
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);
|
REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR);
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
|
#include "esp_wifi_internal.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_event_loop.h"
|
#include "esp_event_loop.h"
|
||||||
#include "esp_task.h"
|
#include "esp_task.h"
|
||||||
|
#include "rom/ets_sys.h"
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.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_DISCONNECTED, system_event_sta_disconnected_handle_default},
|
||||||
{SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
|
{SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
|
||||||
{SYSTEM_EVENT_STA_GOT_IP, system_event_sta_got_ip_default},
|
{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_START, system_event_ap_start_handle_default},
|
||||||
{SYSTEM_EVENT_AP_STOP, system_event_ap_stop_handle_default},
|
{SYSTEM_EVENT_AP_STOP, system_event_ap_stop_handle_default},
|
||||||
{SYSTEM_EVENT_AP_STACONNECTED, NULL},
|
{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)
|
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_internal_set_sta_ip", esp_wifi_internal_set_sta_ip(), ESP_OK);
|
||||||
WIFI_API_CALL_CHECK("esp_wifi_set_sta_ip", esp_wifi_set_sta_ip(), ESP_OK);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR,
|
ESP_LOGI(TAG, "ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR,
|
||||||
IP2STR(&event->event_info.got_ip.ip_info.ip),
|
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;
|
tcpip_adapter_ip_info_t ap_ip;
|
||||||
uint8_t ap_mac[6];
|
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);
|
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);
|
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)
|
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);
|
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;
|
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);
|
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)
|
esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event)
|
||||||
{
|
{
|
||||||
tcpip_adapter_down(TCPIP_ADAPTER_IF_STA);
|
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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,16 +201,14 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
|
|||||||
}
|
}
|
||||||
case SYSTEM_EVENT_STA_CONNECTED: {
|
case SYSTEM_EVENT_STA_CONNECTED: {
|
||||||
system_event_sta_connected_t *connected = &event->event_info.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", \
|
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_CONNECTED, ssid:%s, ssid_len:%d, bssid:" MACSTR ", channel:%d, authmode:%d", \
|
||||||
connected->ssid, connected->ssid_len, connected->bssid[0], connected->bssid[0], connected->bssid[1], \
|
connected->ssid, connected->ssid_len, MAC2STR(connected->bssid), connected->channel, connected->authmode);
|
||||||
connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel, connected->authmode);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SYSTEM_EVENT_STA_DISCONNECTED: {
|
case SYSTEM_EVENT_STA_DISCONNECTED: {
|
||||||
system_event_sta_disconnected_t *disconnected = &event->event_info.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", \
|
ESP_LOGD(TAG, "SYSTEM_EVENT_STA_DISCONNECTED, ssid:%s, ssid_len:%d, bssid:" MACSTR ", reason:%d", \
|
||||||
disconnected->ssid, disconnected->ssid_len, disconnected->bssid[0], disconnected->bssid[0], disconnected->bssid[1], \
|
disconnected->ssid, disconnected->ssid_len, MAC2STR(disconnected->bssid), disconnected->reason);
|
||||||
disconnected->bssid[3], disconnected->bssid[4], disconnected->bssid[5], disconnected->reason);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: {
|
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));
|
IP2STR(&got_ip->ip_info.gw));
|
||||||
break;
|
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: {
|
case SYSTEM_EVENT_AP_START: {
|
||||||
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START");
|
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START");
|
||||||
break;
|
break;
|
||||||
@ -231,23 +250,21 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
|
|||||||
}
|
}
|
||||||
case SYSTEM_EVENT_AP_STACONNECTED: {
|
case SYSTEM_EVENT_AP_STACONNECTED: {
|
||||||
system_event_ap_staconnected_t *staconnected = &event->event_info.sta_connected;
|
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", \
|
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STACONNECTED, mac:" MACSTR ", aid:%d", \
|
||||||
staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \
|
MAC2STR(staconnected->mac), staconnected->aid);
|
||||||
staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SYSTEM_EVENT_AP_STADISCONNECTED: {
|
case SYSTEM_EVENT_AP_STADISCONNECTED: {
|
||||||
system_event_ap_stadisconnected_t *stadisconnected = &event->event_info.sta_disconnected;
|
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", \
|
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED, mac:" MACSTR ", aid:%d", \
|
||||||
stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \
|
MAC2STR(stadisconnected->mac), stadisconnected->aid);
|
||||||
stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SYSTEM_EVENT_AP_PROBEREQRECVED: {
|
case SYSTEM_EVENT_AP_PROBEREQRECVED: {
|
||||||
system_event_ap_probe_req_rx_t *ap_probereqrecved = &event->event_info.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", \
|
ESP_LOGD(TAG, "SYSTEM_EVENT_AP_PROBEREQRECVED, rssi:%d, mac:" MACSTR, \
|
||||||
ap_probereqrecved->rssi, ap_probereqrecved->mac[0], ap_probereqrecved->mac[0], ap_probereqrecved->mac[1], \
|
ap_probereqrecved->rssi, \
|
||||||
ap_probereqrecved->mac[3], ap_probereqrecved->mac[4], ap_probereqrecved->mac[5]);
|
MAC2STR(ap_probereqrecved->mac));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
96
components/esp32/freertos_hooks.c
Normal file
96
components/esp32/freertos_hooks.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,7 +24,8 @@
|
|||||||
#include "soc/uart_reg.h"
|
#include "soc/uart_reg.h"
|
||||||
#include "soc/io_mux_reg.h"
|
#include "soc/io_mux_reg.h"
|
||||||
|
|
||||||
#include "gdbstub.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
|
//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.
|
//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);
|
dumpHwToRegfile(frame);
|
||||||
//Make sure txd/rxd are enabled
|
//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_U0RXD_U, FUNC_U0RXD_U0RXD);
|
||||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
|
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
|
||||||
|
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include <freertos/heap_regions.h>
|
#include <freertos/heap_regions.h>
|
||||||
|
|
||||||
#include "heap_alloc_caps.h"
|
#include "esp_heap_alloc_caps.h"
|
||||||
#include "spiram.h"
|
#include "spiram.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
|
||||||
@ -40,23 +40,23 @@ Tag descriptors. These describe the capabilities of a bit of memory that's tagge
|
|||||||
Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request.
|
Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request.
|
||||||
*/
|
*/
|
||||||
static const uint32_t tagDesc[][NO_PRIOS]={
|
static const uint32_t tagDesc[][NO_PRIOS]={
|
||||||
{ MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, //Tag 0: Plain ole D-port RAM
|
{ MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, //Tag 0: Plain ole D-port RAM
|
||||||
{ 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, //Tag 1: Plain ole D-port RAM which has an alias on the I-port
|
{ 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, //Tag 1: Plain ole D-port RAM which has an alias on the I-port
|
||||||
{ MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }, //Tag 2: IRAM
|
{ MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }, //Tag 2: IRAM
|
||||||
{ MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //Tag 3-8: PID 2-7 IRAM
|
{ MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //Tag 3-8: PID 2-7 IRAM
|
||||||
{ MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //Tag 9-14: PID 2-7 DRAM
|
{ MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //Tag 9-14: PID 2-7 DRAM
|
||||||
{ MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
{ MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //
|
||||||
{ MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, //Tag 15: SPI SRAM data
|
{ MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, //Tag 15: SPI SRAM data
|
||||||
{ MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID } //End
|
{ MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID } //End
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -79,81 +79,81 @@ be sorted from low to high start address.
|
|||||||
This array is *NOT* const because it gets modified depending on what pools are/aren't available.
|
This array is *NOT* const because it gets modified depending on what pools are/aren't available.
|
||||||
*/
|
*/
|
||||||
static HeapRegionTagged_t regions[]={
|
static HeapRegionTagged_t regions[]={
|
||||||
{ (uint8_t *)0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available
|
{ (uint8_t *)0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available
|
||||||
{ (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code
|
{ (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code
|
||||||
{ (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- can be used for BT
|
{ (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- can be used for BT
|
||||||
{ (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- can be used for BT
|
{ (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- can be used for BT
|
||||||
{ (uint8_t *)0x3FFC0000, 0x2000, 0, 0}, //pool 10-13, mmu page 0
|
{ (uint8_t *)0x3FFC0000, 0x2000, 0, 0}, //pool 10-13, mmu page 0
|
||||||
{ (uint8_t *)0x3FFC2000, 0x2000, 0, 0}, //pool 10-13, mmu page 1
|
{ (uint8_t *)0x3FFC2000, 0x2000, 0, 0}, //pool 10-13, mmu page 1
|
||||||
{ (uint8_t *)0x3FFC4000, 0x2000, 0, 0}, //pool 10-13, mmu page 2
|
{ (uint8_t *)0x3FFC4000, 0x2000, 0, 0}, //pool 10-13, mmu page 2
|
||||||
{ (uint8_t *)0x3FFC6000, 0x2000, 0, 0}, //pool 10-13, mmu page 3
|
{ (uint8_t *)0x3FFC6000, 0x2000, 0, 0}, //pool 10-13, mmu page 3
|
||||||
{ (uint8_t *)0x3FFC8000, 0x2000, 0, 0}, //pool 10-13, mmu page 4
|
{ (uint8_t *)0x3FFC8000, 0x2000, 0, 0}, //pool 10-13, mmu page 4
|
||||||
{ (uint8_t *)0x3FFCA000, 0x2000, 0, 0}, //pool 10-13, mmu page 5
|
{ (uint8_t *)0x3FFCA000, 0x2000, 0, 0}, //pool 10-13, mmu page 5
|
||||||
{ (uint8_t *)0x3FFCC000, 0x2000, 0, 0}, //pool 10-13, mmu page 6
|
{ (uint8_t *)0x3FFCC000, 0x2000, 0, 0}, //pool 10-13, mmu page 6
|
||||||
{ (uint8_t *)0x3FFCE000, 0x2000, 0, 0}, //pool 10-13, mmu page 7
|
{ (uint8_t *)0x3FFCE000, 0x2000, 0, 0}, //pool 10-13, mmu page 7
|
||||||
{ (uint8_t *)0x3FFD0000, 0x2000, 0, 0}, //pool 10-13, mmu page 8
|
{ (uint8_t *)0x3FFD0000, 0x2000, 0, 0}, //pool 10-13, mmu page 8
|
||||||
{ (uint8_t *)0x3FFD2000, 0x2000, 0, 0}, //pool 10-13, mmu page 9
|
{ (uint8_t *)0x3FFD2000, 0x2000, 0, 0}, //pool 10-13, mmu page 9
|
||||||
{ (uint8_t *)0x3FFD4000, 0x2000, 0, 0}, //pool 10-13, mmu page 10
|
{ (uint8_t *)0x3FFD4000, 0x2000, 0, 0}, //pool 10-13, mmu page 10
|
||||||
{ (uint8_t *)0x3FFD6000, 0x2000, 0, 0}, //pool 10-13, mmu page 11
|
{ (uint8_t *)0x3FFD6000, 0x2000, 0, 0}, //pool 10-13, mmu page 11
|
||||||
{ (uint8_t *)0x3FFD8000, 0x2000, 0, 0}, //pool 10-13, mmu page 12
|
{ (uint8_t *)0x3FFD8000, 0x2000, 0, 0}, //pool 10-13, mmu page 12
|
||||||
{ (uint8_t *)0x3FFDA000, 0x2000, 0, 0}, //pool 10-13, mmu page 13
|
{ (uint8_t *)0x3FFDA000, 0x2000, 0, 0}, //pool 10-13, mmu page 13
|
||||||
{ (uint8_t *)0x3FFDC000, 0x2000, 0, 0}, //pool 10-13, mmu page 14
|
{ (uint8_t *)0x3FFDC000, 0x2000, 0, 0}, //pool 10-13, mmu page 14
|
||||||
{ (uint8_t *)0x3FFDE000, 0x2000, 0, 0}, //pool 10-13, mmu page 15
|
{ (uint8_t *)0x3FFDE000, 0x2000, 0, 0}, //pool 10-13, mmu page 15
|
||||||
{ (uint8_t *)0x3FFE0000, 0x4000, 1, 0x400BC000}, //pool 9 blk 1
|
{ (uint8_t *)0x3FFE0000, 0x4000, 1, 0x400BC000}, //pool 9 blk 1
|
||||||
{ (uint8_t *)0x3FFE4000, 0x4000, 1, 0x400B8000}, //pool 9 blk 0
|
{ (uint8_t *)0x3FFE4000, 0x4000, 1, 0x400B8000}, //pool 9 blk 0
|
||||||
{ (uint8_t *)0x3FFE8000, 0x8000, 1, 0x400B0000}, //pool 8 <- can be remapped to ROM, used for MAC dump
|
{ (uint8_t *)0x3FFE8000, 0x8000, 1, 0x400B0000}, //pool 8 <- can be remapped to ROM, used for MAC dump
|
||||||
{ (uint8_t *)0x3FFF0000, 0x8000, 1, 0x400A8000}, //pool 7 <- can be used for MAC dump
|
{ (uint8_t *)0x3FFF0000, 0x8000, 1, 0x400A8000}, //pool 7 <- can be used for MAC dump
|
||||||
{ (uint8_t *)0x3FFF8000, 0x4000, 1, 0x400A4000}, //pool 6 blk 1 <- can be used as trace memory
|
{ (uint8_t *)0x3FFF8000, 0x4000, 1, 0x400A4000}, //pool 6 blk 1 <- can be used as trace memory
|
||||||
{ (uint8_t *)0x3FFFC000, 0x4000, 1, 0x400A0000}, //pool 6 blk 0 <- can be used as trace memory
|
{ (uint8_t *)0x3FFFC000, 0x4000, 1, 0x400A0000}, //pool 6 blk 0 <- can be used as trace memory
|
||||||
{ (uint8_t *)0x40070000, 0x8000, 2, 0}, //pool 0
|
{ (uint8_t *)0x40070000, 0x8000, 2, 0}, //pool 0
|
||||||
{ (uint8_t *)0x40078000, 0x8000, 2, 0}, //pool 1
|
{ (uint8_t *)0x40078000, 0x8000, 2, 0}, //pool 1
|
||||||
{ (uint8_t *)0x40080000, 0x2000, 2, 0}, //pool 2-5, mmu page 0
|
{ (uint8_t *)0x40080000, 0x2000, 2, 0}, //pool 2-5, mmu page 0
|
||||||
{ (uint8_t *)0x40082000, 0x2000, 2, 0}, //pool 2-5, mmu page 1
|
{ (uint8_t *)0x40082000, 0x2000, 2, 0}, //pool 2-5, mmu page 1
|
||||||
{ (uint8_t *)0x40084000, 0x2000, 2, 0}, //pool 2-5, mmu page 2
|
{ (uint8_t *)0x40084000, 0x2000, 2, 0}, //pool 2-5, mmu page 2
|
||||||
{ (uint8_t *)0x40086000, 0x2000, 2, 0}, //pool 2-5, mmu page 3
|
{ (uint8_t *)0x40086000, 0x2000, 2, 0}, //pool 2-5, mmu page 3
|
||||||
{ (uint8_t *)0x40088000, 0x2000, 2, 0}, //pool 2-5, mmu page 4
|
{ (uint8_t *)0x40088000, 0x2000, 2, 0}, //pool 2-5, mmu page 4
|
||||||
{ (uint8_t *)0x4008A000, 0x2000, 2, 0}, //pool 2-5, mmu page 5
|
{ (uint8_t *)0x4008A000, 0x2000, 2, 0}, //pool 2-5, mmu page 5
|
||||||
{ (uint8_t *)0x4008C000, 0x2000, 2, 0}, //pool 2-5, mmu page 6
|
{ (uint8_t *)0x4008C000, 0x2000, 2, 0}, //pool 2-5, mmu page 6
|
||||||
{ (uint8_t *)0x4008E000, 0x2000, 2, 0}, //pool 2-5, mmu page 7
|
{ (uint8_t *)0x4008E000, 0x2000, 2, 0}, //pool 2-5, mmu page 7
|
||||||
{ (uint8_t *)0x40090000, 0x2000, 2, 0}, //pool 2-5, mmu page 8
|
{ (uint8_t *)0x40090000, 0x2000, 2, 0}, //pool 2-5, mmu page 8
|
||||||
{ (uint8_t *)0x40092000, 0x2000, 2, 0}, //pool 2-5, mmu page 9
|
{ (uint8_t *)0x40092000, 0x2000, 2, 0}, //pool 2-5, mmu page 9
|
||||||
{ (uint8_t *)0x40094000, 0x2000, 2, 0}, //pool 2-5, mmu page 10
|
{ (uint8_t *)0x40094000, 0x2000, 2, 0}, //pool 2-5, mmu page 10
|
||||||
{ (uint8_t *)0x40096000, 0x2000, 2, 0}, //pool 2-5, mmu page 11
|
{ (uint8_t *)0x40096000, 0x2000, 2, 0}, //pool 2-5, mmu page 11
|
||||||
{ (uint8_t *)0x40098000, 0x2000, 2, 0}, //pool 2-5, mmu page 12
|
{ (uint8_t *)0x40098000, 0x2000, 2, 0}, //pool 2-5, mmu page 12
|
||||||
{ (uint8_t *)0x4009A000, 0x2000, 2, 0}, //pool 2-5, mmu page 13
|
{ (uint8_t *)0x4009A000, 0x2000, 2, 0}, //pool 2-5, mmu page 13
|
||||||
{ (uint8_t *)0x4009C000, 0x2000, 2, 0}, //pool 2-5, mmu page 14
|
{ (uint8_t *)0x4009C000, 0x2000, 2, 0}, //pool 2-5, mmu page 14
|
||||||
{ (uint8_t *)0x4009E000, 0x2000, 2, 0}, //pool 2-5, mmu page 15
|
{ (uint8_t *)0x4009E000, 0x2000, 2, 0}, //pool 2-5, mmu page 15
|
||||||
{ NULL, 0, 0, 0} //end
|
{ NULL, 0, 0, 0} //end
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//Modify regions array to disable the given range of memory.
|
//Modify regions array to disable the given range of memory.
|
||||||
static void disable_mem_region(void *from, void *to) {
|
static void disable_mem_region(void *from, void *to) {
|
||||||
int i;
|
int i;
|
||||||
//Align from and to on word boundaries
|
//Align from and to on word boundaries
|
||||||
from=(void*)((uint32_t)from&~3);
|
from=(void*)((uint32_t)from&~3);
|
||||||
to=(void*)(((uint32_t)to+3)&~3);
|
to=(void*)(((uint32_t)to+3)&~3);
|
||||||
for (i=0; regions[i].xSizeInBytes!=0; i++) {
|
for (i=0; regions[i].xSizeInBytes!=0; i++) {
|
||||||
void *regStart=regions[i].pucStartAddress;
|
void *regStart=regions[i].pucStartAddress;
|
||||||
void *regEnd=regions[i].pucStartAddress+regions[i].xSizeInBytes;
|
void *regEnd=regions[i].pucStartAddress+regions[i].xSizeInBytes;
|
||||||
if (regStart>=from && regEnd<=to) {
|
if (regStart>=from && regEnd<=to) {
|
||||||
//Entire region falls in the range. Disable entirely.
|
//Entire region falls in the range. Disable entirely.
|
||||||
regions[i].xTag=-1;
|
regions[i].xTag=-1;
|
||||||
} else if (regStart>=from && regEnd>to && regStart<to) {
|
} else if (regStart>=from && regEnd>to && regStart<to) {
|
||||||
//Start of the region falls in the range. Modify address/len.
|
//Start of the region falls in the range. Modify address/len.
|
||||||
int overlap=(uint8_t *)to-(uint8_t *)regStart;
|
int overlap=(uint8_t *)to-(uint8_t *)regStart;
|
||||||
regions[i].pucStartAddress+=overlap;
|
regions[i].pucStartAddress+=overlap;
|
||||||
regions[i].xSizeInBytes-=overlap;
|
regions[i].xSizeInBytes-=overlap;
|
||||||
if (regions[i].xExecAddr) regions[i].xExecAddr+=overlap;
|
if (regions[i].xExecAddr) regions[i].xExecAddr+=overlap;
|
||||||
} else if (regStart<from && regEnd>from && regEnd<=to) {
|
} else if (regStart<from && regEnd>from && regEnd<=to) {
|
||||||
//End of the region falls in the range. Modify length.
|
//End of the region falls in the range. Modify length.
|
||||||
regions[i].xSizeInBytes-=(uint8_t *)regEnd-(uint8_t *)from;
|
regions[i].xSizeInBytes-=(uint8_t *)regEnd-(uint8_t *)from;
|
||||||
} else if (regStart<from && regEnd>to) {
|
} else if (regStart<from && regEnd>to) {
|
||||||
//Range punches a hole in the region! We do not support this.
|
//Range punches a hole in the region! We do not support this.
|
||||||
ESP_EARLY_LOGE(TAG, "region %d: hole punching is not supported!", i);
|
ESP_EARLY_LOGE(TAG, "region %d: hole punching is not supported!", i);
|
||||||
regions[i].xTag=-1; //Just disable memory region. That'll teach them!
|
regions[i].xTag=-1; //Just disable memory region. That'll teach them!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -170,52 +170,56 @@ ToDo: The regions are different when stuff like trace memory, BT, ... is used. M
|
|||||||
Same with loading of apps. Same with using SPI RAM.
|
Same with loading of apps. Same with using SPI RAM.
|
||||||
*/
|
*/
|
||||||
void heap_alloc_caps_init() {
|
void heap_alloc_caps_init() {
|
||||||
int i;
|
int i;
|
||||||
//Disable the bits of memory where this code is loaded.
|
//Disable the bits of memory where this code is loaded.
|
||||||
disable_mem_region(&_bss_start, &_heap_start);
|
disable_mem_region(&_bss_start, &_heap_start);
|
||||||
disable_mem_region((void*)0x3ffae000, (void*)0x3ffb0000); //knock out ROM data region
|
disable_mem_region((void*)0x3ffae000, (void*)0x3ffb0000); //knock out ROM data region
|
||||||
disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region
|
disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region
|
||||||
disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region
|
disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region
|
||||||
disable_mem_region((void*)0x40080000, (void*)0x400a0000); //pool 2-5
|
disable_mem_region((void*)0x40080000, (void*)0x400a0000); //pool 2-5
|
||||||
|
|
||||||
// TODO: this region should be checked, since we don't need to knock out all region finally
|
// TODO: this region should be checked, since we don't need to knock out all region finally
|
||||||
disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region
|
disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region
|
||||||
|
|
||||||
#if CONFIG_MEMMAP_BT
|
#if CONFIG_MEMMAP_BT
|
||||||
disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT data region
|
disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //knock out BT data region
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_MEMMAP_TRACEMEM
|
#if CONFIG_MEMMAP_TRACEMEM
|
||||||
disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region
|
#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS
|
||||||
|
disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //knock out trace mem region
|
||||||
|
#else
|
||||||
|
disable_mem_region((void*)0x3fff8000, (void*)0x3fffc000); //knock out trace mem region
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
enable_spi_sram();
|
enable_spi_sram();
|
||||||
#else
|
#else
|
||||||
disable_mem_region((void*)0x3f800000, (void*)0x3f820000); //SPI SRAM not installed
|
disable_mem_region((void*)0x3f800000, (void*)0x3f820000); //SPI SRAM not installed
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//The heap allocator will treat every region given to it as separate. In order to get bigger ranges of contiguous memory,
|
//The heap allocator will treat every region given to it as separate. In order to get bigger ranges of contiguous memory,
|
||||||
//it's useful to coalesce adjacent regions that have the same tag.
|
//it's useful to coalesce adjacent regions that have the same tag.
|
||||||
|
|
||||||
for (i=1; regions[i].xSizeInBytes!=0; i++) {
|
for (i=1; regions[i].xSizeInBytes!=0; i++) {
|
||||||
if (regions[i].pucStartAddress == (regions[i-1].pucStartAddress + regions[i-1].xSizeInBytes) &&
|
if (regions[i].pucStartAddress == (regions[i-1].pucStartAddress + regions[i-1].xSizeInBytes) &&
|
||||||
regions[i].xTag == regions[i-1].xTag ) {
|
regions[i].xTag == regions[i-1].xTag ) {
|
||||||
regions[i-1].xTag=-1;
|
regions[i-1].xTag=-1;
|
||||||
regions[i].pucStartAddress=regions[i-1].pucStartAddress;
|
regions[i].pucStartAddress=regions[i-1].pucStartAddress;
|
||||||
regions[i].xSizeInBytes+=regions[i-1].xSizeInBytes;
|
regions[i].xSizeInBytes+=regions[i-1].xSizeInBytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_EARLY_LOGI(TAG, "Initializing heap allocator:");
|
ESP_EARLY_LOGI(TAG, "Initializing heap allocator:");
|
||||||
for (i=0; regions[i].xSizeInBytes!=0; i++) {
|
for (i=0; regions[i].xSizeInBytes!=0; i++) {
|
||||||
if (regions[i].xTag != -1) {
|
if (regions[i].xTag != -1) {
|
||||||
ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %d", i,
|
ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %d", i,
|
||||||
(int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag);
|
(int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Initialize the malloc implementation.
|
//Initialize the malloc implementation.
|
||||||
vPortDefineHeapRegionsTagged( regions );
|
vPortDefineHeapRegionsTagged( regions );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -223,7 +227,7 @@ Standard malloc() implementation. Will return ho-hum byte-accessible data memory
|
|||||||
*/
|
*/
|
||||||
void *pvPortMalloc( size_t xWantedSize )
|
void *pvPortMalloc( size_t xWantedSize )
|
||||||
{
|
{
|
||||||
return pvPortMallocCaps( xWantedSize, MALLOC_CAP_8BIT );
|
return pvPortMallocCaps( xWantedSize, MALLOC_CAP_8BIT );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -231,30 +235,30 @@ Routine to allocate a bit of memory with certain capabilities. caps is a bitfiel
|
|||||||
*/
|
*/
|
||||||
void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps )
|
void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps )
|
||||||
{
|
{
|
||||||
int prio;
|
int prio;
|
||||||
int tag, j;
|
int tag, j;
|
||||||
void *ret=NULL;
|
void *ret=NULL;
|
||||||
uint32_t remCaps;
|
uint32_t remCaps;
|
||||||
for (prio=0; prio<NO_PRIOS; prio++) {
|
for (prio=0; prio<NO_PRIOS; prio++) {
|
||||||
//Iterate over tag descriptors for this priority
|
//Iterate over tag descriptors for this priority
|
||||||
for (tag=0; tagDesc[tag][prio]!=MALLOC_CAP_INVALID; tag++) {
|
for (tag=0; tagDesc[tag][prio]!=MALLOC_CAP_INVALID; tag++) {
|
||||||
if ((tagDesc[tag][prio]&caps)!=0) {
|
if ((tagDesc[tag][prio]&caps)!=0) {
|
||||||
//Tag has at least one of the caps requested. If caps has other bits set that this prio
|
//Tag has at least one of the caps requested. If caps has other bits set that this prio
|
||||||
//doesn't cover, see if they're available in other prios.
|
//doesn't cover, see if they're available in other prios.
|
||||||
remCaps=caps&(~tagDesc[tag][prio]); //Remaining caps to be fulfilled
|
remCaps=caps&(~tagDesc[tag][prio]); //Remaining caps to be fulfilled
|
||||||
j=prio+1;
|
j=prio+1;
|
||||||
while (remCaps!=0 && j<NO_PRIOS) {
|
while (remCaps!=0 && j<NO_PRIOS) {
|
||||||
remCaps=remCaps&(~tagDesc[tag][j]);
|
remCaps=remCaps&(~tagDesc[tag][j]);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
if (remCaps==0) {
|
if (remCaps==0) {
|
||||||
//This tag can satisfy all the requested capabilities. See if we can grab some memory using it.
|
//This tag can satisfy all the requested capabilities. See if we can grab some memory using it.
|
||||||
ret=pvPortMallocTagged(xWantedSize, tag);
|
ret=pvPortMallocTagged(xWantedSize, tag);
|
||||||
if (ret!=NULL) return ret;
|
if (ret!=NULL) return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Nothing usable found.
|
//Nothing usable found.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -20,22 +20,21 @@
|
|||||||
//and all variables in shared RAM. These macros can be used to redirect
|
//and all variables in shared RAM. These macros can be used to redirect
|
||||||
//particular functions/variables to other memory regions.
|
//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")))
|
#define IRAM_ATTR __attribute__((section(".iram1")))
|
||||||
|
|
||||||
// Forces data into DRAM instead of flash
|
// Forces data into DRAM instead of flash
|
||||||
#define DRAM_ATTR __attribute__((section(".dram1")))
|
#define DRAM_ATTR __attribute__((section(".dram1")))
|
||||||
|
|
||||||
// Forces code into RTC fast memory
|
// Forces code into RTC fast memory. See "docs/deep-sleep-stub.rst"
|
||||||
#define RTC_IRAM_ATTR __attribute__((section(".rtc.text")))
|
#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
|
// Any variable marked with this attribute will keep its value
|
||||||
// during a deep sleep / wake cycle.
|
// during a deep sleep / wake cycle.
|
||||||
#define RTC_DATA_ATTR __attribute__((section(".rtc.data")))
|
#define RTC_DATA_ATTR __attribute__((section(".rtc.data")))
|
||||||
|
|
||||||
// Forces read-only data into RTC slow memory
|
// Forces read-only data into RTC slow memory. See "docs/deep-sleep-stub.rst"
|
||||||
// Makes constant data available to RTC wake stubs (see esp_deepsleep.h)
|
|
||||||
#define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata")))
|
#define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata")))
|
||||||
|
|
||||||
#endif /* __ESP_ATTR_H__ */
|
#endif /* __ESP_ATTR_H__ */
|
||||||
|
21
components/esp32/include/esp_brownout.h
Normal file
21
components/esp32/include/esp_brownout.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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_BROWNOUT_H
|
||||||
|
#define __ESP_BROWNOUT_H
|
||||||
|
|
||||||
|
void esp_brownout_init();
|
||||||
|
|
||||||
|
#endif
|
42
components/esp32/include/esp_crosscore_int.h
Normal file
42
components/esp32/include/esp_crosscore_int.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// 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_CROSSCORE_INT_H
|
||||||
|
#define __ESP_CROSSCORE_INT_H
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the crosscore interrupt system for this CPU.
|
||||||
|
* This needs to be called once on every CPU that is used
|
||||||
|
* by FreeRTOS.
|
||||||
|
*
|
||||||
|
* If multicore FreeRTOS support is enabled, this will be
|
||||||
|
* called automatically by the startup code and should not
|
||||||
|
* be called manually.
|
||||||
|
*/
|
||||||
|
void esp_crosscore_int_init();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an interrupt to a CPU indicating it should yield its
|
||||||
|
* currently running task in favour of a higher-priority task
|
||||||
|
* that presumably just woke up.
|
||||||
|
*
|
||||||
|
* This is used internally by FreeRTOS in multicore mode
|
||||||
|
* and should not be called by the user.
|
||||||
|
*
|
||||||
|
* @param coreID Core that should do the yielding
|
||||||
|
*/
|
||||||
|
void esp_crosscore_int_send_yield(int coreId);
|
||||||
|
|
||||||
|
#endif
|
@ -54,37 +54,7 @@ void system_deep_sleep(uint64_t time_in_us);
|
|||||||
* to run code immediately when the chip wakes from
|
* to run code immediately when the chip wakes from
|
||||||
* sleep.
|
* sleep.
|
||||||
*
|
*
|
||||||
* For example:
|
* See docs/deep-sleep-stub.rst for details.
|
||||||
* @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().
|
|
||||||
*/
|
*/
|
||||||
void esp_wake_deep_sleep(void);
|
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.
|
/* The default esp-idf-provided esp_wake_deep_sleep() stub.
|
||||||
|
|
||||||
If you replace esp_wake_deep_sleep() in your program, or use
|
See docs/deep-sleep-stub.rst for details.
|
||||||
esp_set_deep_sleep_wake_stub(), then it is recommended you call
|
|
||||||
esp_default_wake_deep_sleep() as the first function in your stub.
|
|
||||||
*/
|
*/
|
||||||
void esp_default_wake_deep_sleep(void);
|
void esp_default_wake_deep_sleep(void);
|
||||||
|
|
||||||
|
@ -31,6 +31,13 @@ typedef int32_t esp_err_t;
|
|||||||
#define ESP_ERR_NO_MEM 0x101
|
#define ESP_ERR_NO_MEM 0x101
|
||||||
#define ESP_ERR_INVALID_ARG 0x102
|
#define ESP_ERR_INVALID_ARG 0x102
|
||||||
#define ESP_ERR_INVALID_STATE 0x103
|
#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,
|
* Macro which can be used to check the error code,
|
||||||
|
@ -35,6 +35,10 @@ typedef enum {
|
|||||||
SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
|
SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
|
||||||
SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
|
SYSTEM_EVENT_STA_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_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_START, /**< ESP32 soft-AP start */
|
||||||
SYSTEM_EVENT_AP_STOP, /**< ESP32 soft-AP stop */
|
SYSTEM_EVENT_AP_STOP, /**< ESP32 soft-AP stop */
|
||||||
SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
|
SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
|
||||||
@ -73,6 +77,10 @@ typedef struct {
|
|||||||
tcpip_adapter_ip_info_t ip_info;
|
tcpip_adapter_ip_info_t ip_info;
|
||||||
} system_event_sta_got_ip_t;
|
} 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 {
|
typedef struct {
|
||||||
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */
|
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 */
|
uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */
|
||||||
@ -94,6 +102,7 @@ typedef union {
|
|||||||
system_event_sta_scan_done_t scan_done; /**< ESP32 station scan (APs) done */
|
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_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_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_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_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_probe_req_rx_t ap_probereqrecved; /**< ESP32 soft-AP receive probe request packet */
|
||||||
|
58
components/esp32/include/esp_flash_data_types.h
Normal file
58
components/esp32/include/esp_flash_data_types.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// 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_BIN_TYPES_H__
|
||||||
|
#define __ESP_BIN_TYPES_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ESP_PARTITION_TABLE_ADDR 0x8000
|
||||||
|
#define ESP_PARTITION_MAGIC 0x50AA
|
||||||
|
|
||||||
|
/* OTA selection structure (two copies in the OTA data partition.)
|
||||||
|
Size of 32 bytes is friendly to flash encryption */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t ota_seq;
|
||||||
|
uint8_t seq_label[24];
|
||||||
|
uint32_t crc; /* CRC32 of ota_seq field only */
|
||||||
|
} esp_ota_select_entry_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t size;
|
||||||
|
} esp_partition_pos_t;
|
||||||
|
|
||||||
|
/* Structure which describes the layout of partition table entry.
|
||||||
|
* See docs/partition_tables.rst for more information about individual fields.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t magic;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t subtype;
|
||||||
|
esp_partition_pos_t pos;
|
||||||
|
uint8_t label[16];
|
||||||
|
uint8_t reserved[4];
|
||||||
|
} esp_partition_info_t;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //__ESP_BIN_TYPES_H__
|
83
components/esp32/include/esp_freertos_hooks.h
Normal file
83
components/esp32/include/esp_freertos_hooks.h
Normal file
@ -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
|
@ -17,6 +17,6 @@
|
|||||||
#include <xtensa/config/core.h>
|
#include <xtensa/config/core.h>
|
||||||
#include "freertos/xtensa_api.h"
|
#include "freertos/xtensa_api.h"
|
||||||
|
|
||||||
void gdbstubPanicHandler(XtExcFrame *frame);
|
void esp_gdbstub_panic_handler(XtExcFrame *frame);
|
||||||
|
|
||||||
#endif
|
#endif
|
60
components/esp32/include/esp_int_wdt.h
Normal file
60
components/esp32/include/esp_int_wdt.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// 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_INT_WDT_H
|
||||||
|
#define __ESP_INT_WDT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @addtogroup Watchdog_APIs
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This routine enables a watchdog to catch instances of processes disabling
|
||||||
|
interrupts for too long, or code within interrupt handlers taking too long.
|
||||||
|
It does this by setting up a watchdog which gets fed from the FreeRTOS
|
||||||
|
task switch interrupt. When this watchdog times out, initially it will call
|
||||||
|
a high-level interrupt routine that will panic FreeRTOS in order to allow
|
||||||
|
for forensic examination of the state of the CPU. When this interrupt
|
||||||
|
handler is not called and the watchdog times out a second time, it will
|
||||||
|
reset the SoC.
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
21
components/esp32/include/esp_panic.h
Normal file
21
components/esp32/include/esp_panic.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef PANIC_H
|
||||||
|
#define PANIC_H
|
||||||
|
|
||||||
|
|
||||||
|
#define PANIC_RSN_NONE 0
|
||||||
|
#define PANIC_RSN_DEBUGEXCEPTION 1
|
||||||
|
#define PANIC_RSN_DOUBLEEXCEPTION 2
|
||||||
|
#define PANIC_RSN_KERNELEXCEPTION 3
|
||||||
|
#define PANIC_RSN_COPROCEXCEPTION 4
|
||||||
|
#define PANIC_RSN_INTWDT_CPU0 5
|
||||||
|
#define PANIC_RSN_INTWDT_CPU1 6
|
||||||
|
#define PANIC_RSN_MAX 6
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
void esp_set_breakpoint_if_jtag(void *fn);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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.
|
* @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]);
|
esp_err_t system_efuse_read_mac(uint8_t mac[6]);
|
||||||
|
|
||||||
|
|
||||||
void system_init(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
83
components/esp32/include/esp_task_wdt.h
Normal file
83
components/esp32/include/esp_task_wdt.h
Normal file
@ -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_TASK_WDT_H
|
||||||
|
#define __ESP_TASK_WDT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** \defgroup Watchdog_APIs Watchdog APIs
|
||||||
|
* @brief Watchdog APIs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup Watchdog_APIs
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This routine enables a more general-purpose task watchdog: tasks can individually
|
||||||
|
feed the watchdog and the watchdog will bark if one or more tasks haven't fed the
|
||||||
|
watchdog within the specified time. Optionally, the idle tasks can also configured
|
||||||
|
to feed the watchdog in a similar fashion, to detect CPU starvation.
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete the watchdog for the current task.
|
||||||
|
*
|
||||||
|
* @param null
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
void esp_task_wdt_delete();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -70,6 +70,24 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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 */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
system_event_handler_t event_handler; /**< WiFi event handler */
|
system_event_handler_t event_handler; /**< WiFi event handler */
|
||||||
} wifi_init_config_t;
|
} wifi_init_config_t;
|
||||||
@ -92,8 +110,10 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* @param wifi_init_config_t *config : provide WiFi init configuration
|
* @param wifi_init_config_t *config : provide WiFi init configuration
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_init(wifi_init_config_t *config);
|
||||||
|
|
||||||
@ -104,7 +124,6 @@ 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
|
* @attention 1. This API should be called if you want to remove WiFi driver from the system
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return ESP_OK : succeed
|
||||||
* @return others : fail
|
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_deinit(void);
|
esp_err_t esp_wifi_deinit(void);
|
||||||
|
|
||||||
@ -116,8 +135,11 @@ esp_err_t esp_wifi_deinit(void);
|
|||||||
*
|
*
|
||||||
* @param wifi_mode_t mode : WiFi operating modes:
|
* @param wifi_mode_t mode : WiFi operating modes:
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_set_mode(wifi_mode_t mode);
|
||||||
|
|
||||||
@ -126,8 +148,10 @@ esp_err_t esp_wifi_set_mode(wifi_mode_t mode);
|
|||||||
*
|
*
|
||||||
* @param wifi_mode_t *mode : store current WiFi mode
|
* @param wifi_mode_t *mode : store current WiFi mode
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_get_mode(wifi_mode_t *mode);
|
||||||
|
|
||||||
@ -139,8 +163,13 @@ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode);
|
|||||||
*
|
*
|
||||||
* @param null
|
* @param null
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_start(void);
|
||||||
|
|
||||||
@ -152,8 +181,9 @@ esp_err_t esp_wifi_start(void);
|
|||||||
*
|
*
|
||||||
* @param null
|
* @param null
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - ESP_OK : succeed
|
||||||
|
* - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_stop(void);
|
esp_err_t esp_wifi_stop(void);
|
||||||
|
|
||||||
@ -165,8 +195,12 @@ esp_err_t esp_wifi_stop(void);
|
|||||||
*
|
*
|
||||||
* @param null
|
* @param null
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_connect(void);
|
||||||
|
|
||||||
@ -175,8 +209,11 @@ esp_err_t esp_wifi_connect(void);
|
|||||||
*
|
*
|
||||||
* @param null
|
* @param null
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_disconnect(void);
|
||||||
|
|
||||||
@ -185,20 +222,25 @@ esp_err_t esp_wifi_disconnect(void);
|
|||||||
*
|
*
|
||||||
* @param null
|
* @param null
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - ESP_OK : succeed
|
||||||
|
* - others : fail
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_clear_fast_connect(void);
|
esp_err_t esp_wifi_clear_fast_connect(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Kick the all station or associated id equals to aid
|
* @brief deauthenticate all stations or associated id equals to aid
|
||||||
*
|
*
|
||||||
* @param uint16_t aid : when aid is 0, kick all stations, otherwise kick station whose associated id is aid
|
* @param uint16_t aid : when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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_kick_station(uint16_t aid);
|
esp_err_t esp_wifi_deauth_sta(uint16_t aid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Scan all available APs.
|
* @brief Scan all available APs.
|
||||||
@ -211,8 +253,12 @@ esp_err_t esp_wifi_kick_station(uint16_t aid);
|
|||||||
* @param bool block : if block is true, this API will block the caller until the scan is done, otherwise
|
* @param bool block : if block is true, this API will block the caller until the scan is done, otherwise
|
||||||
* it will return immediately
|
* it will return immediately
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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 *conf, bool block);
|
||||||
|
|
||||||
@ -220,8 +266,10 @@ esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf, bool block);
|
|||||||
* @brief Stop the scan in process
|
* @brief Stop the scan in process
|
||||||
*
|
*
|
||||||
* @param null
|
* @param null
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_scan_stop(void);
|
||||||
|
|
||||||
@ -232,30 +280,48 @@ esp_err_t esp_wifi_scan_stop(void);
|
|||||||
*
|
*
|
||||||
* @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
|
||||||
* @return others : fail
|
* - 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_get_ap_num(uint16_t *number);
|
esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get AP list found in last scan
|
* @brief Get AP list found in last scan
|
||||||
*
|
*
|
||||||
* @param uint16_t *number : as input param, it stores max AP number ap_list can hold, as output param, it store
|
* @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
|
the actual AP number this API returns
|
||||||
* @param wifi_ap_list_t *ap_list : a list to hold the found APs
|
* @param wifi_ap_record_t *ap_records: wifi_ap_record_t array to hold the found APs
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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_get_ap_list(uint16_t *number, wifi_ap_list_t *ap_list);
|
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
|
||||||
|
*
|
||||||
|
* @param wifi_ap_record_t *ap_info: the wifi_ap_record_t to hold station assocated AP
|
||||||
|
*
|
||||||
|
* @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
|
* @brief Set current power save type
|
||||||
*
|
*
|
||||||
* @param wifi_ps_type_t type : power save type
|
* @param wifi_ps_type_t type : power save type
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return ESP_ERR_WIFI_NOT_SUPPORT : not support yet
|
||||||
* @return others : fail
|
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_set_ps(wifi_ps_type_t type);
|
esp_err_t esp_wifi_set_ps(wifi_ps_type_t type);
|
||||||
|
|
||||||
@ -264,8 +330,7 @@ esp_err_t esp_wifi_set_ps(wifi_ps_type_t type);
|
|||||||
*
|
*
|
||||||
* @param wifi_ps_type_t *type : store current power save type
|
* @param wifi_ps_type_t *type : store current power save type
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return ESP_ERR_WIFI_NOT_SUPPORT : not support yet
|
||||||
* @return others : fail
|
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
|
esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
|
||||||
|
|
||||||
@ -278,8 +343,11 @@ esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
|
|||||||
* @param wifi_interface_t ifx : interfaces
|
* @param wifi_interface_t ifx : interfaces
|
||||||
* @param uint8_t protocol : WiFi protocol bitmap
|
* @param uint8_t protocol : WiFi protocol bitmap
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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 erro code in esp_err.h
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap);
|
esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap);
|
||||||
|
|
||||||
@ -289,8 +357,12 @@ esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap);
|
|||||||
* @param wifi_interface_t ifx : interfaces
|
* @param wifi_interface_t ifx : interfaces
|
||||||
* @param uint8_t protocol : store current WiFi protocol bitmap of interface ifx
|
* @param uint8_t protocol : store current WiFi protocol bitmap of interface ifx
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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 code in esp_err.h
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
|
esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
|
||||||
|
|
||||||
@ -303,8 +375,12 @@ esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
|
|||||||
* @param wifi_interface_t ifx : interface to be configured
|
* @param wifi_interface_t ifx : interface to be configured
|
||||||
* @param wifi_bandwidth_t bw : bandwidth
|
* @param wifi_bandwidth_t bw : bandwidth
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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 code in esp_err.h
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
|
esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
|
||||||
|
|
||||||
@ -316,8 +392,11 @@ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
|
|||||||
* @param wifi_interface_t ifx : interface to be configured
|
* @param wifi_interface_t ifx : interface to be configured
|
||||||
* @param wifi_bandwidth_t *bw : store bandwidth of interface ifx
|
* @param wifi_bandwidth_t *bw : store bandwidth of interface ifx
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw);
|
||||||
|
|
||||||
@ -329,8 +408,11 @@ esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw);
|
|||||||
* @param uint8_t primary : for HT20, primary is the channel number, for HT40, primary is the primary channel
|
* @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 wifi_second_chan_t second : for HT20, second is ignored, for HT40, second is the second channel
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second);
|
||||||
|
|
||||||
@ -342,8 +424,10 @@ esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second);
|
|||||||
* @param uint8_t *primary : store current primary channel
|
* @param uint8_t *primary : store current primary channel
|
||||||
* @param wifi_second_chan_t *second : store current second channel
|
* @param wifi_second_chan_t *second : store current second channel
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second);
|
||||||
|
|
||||||
@ -353,8 +437,11 @@ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second);
|
|||||||
*
|
*
|
||||||
* @param wifi_country_t country : country type
|
* @param wifi_country_t country : country type
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_set_country(wifi_country_t country);
|
||||||
|
|
||||||
@ -363,8 +450,10 @@ esp_err_t esp_wifi_set_country(wifi_country_t country);
|
|||||||
*
|
*
|
||||||
* @param wifi_country_t country : store current country
|
* @param wifi_country_t country : store current country
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_get_country(wifi_country_t *country);
|
||||||
|
|
||||||
@ -379,8 +468,14 @@ esp_err_t esp_wifi_get_country(wifi_country_t *country);
|
|||||||
* @param wifi_interface_t ifx : interface
|
* @param wifi_interface_t ifx : interface
|
||||||
* @param uint8 mac[6]: the MAC address.
|
* @param uint8 mac[6]: the MAC address.
|
||||||
*
|
*
|
||||||
* @return true : succeed
|
* @return
|
||||||
* @return false : fail
|
* - 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 code in esp_err.h
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6]);
|
esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6]);
|
||||||
|
|
||||||
@ -389,8 +484,11 @@ esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6]);
|
|||||||
*
|
*
|
||||||
* @param uint8_t mac[6] : store mac of this interface ifx
|
* @param uint8_t mac[6] : store mac of this interface ifx
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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]);
|
esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);
|
||||||
|
|
||||||
@ -402,8 +500,7 @@ esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);
|
|||||||
* @param void *buf : the data received
|
* @param void *buf : the data received
|
||||||
* @param uint16_t len : data length
|
* @param uint16_t len : data length
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return none
|
||||||
* @return others : fail
|
|
||||||
*/
|
*/
|
||||||
typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len);
|
typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len);
|
||||||
|
|
||||||
@ -414,8 +511,9 @@ typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len);
|
|||||||
*
|
*
|
||||||
* @param wifi_promiscuous_cb_t cb : callback
|
* @param wifi_promiscuous_cb_t cb : callback
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
|
||||||
|
|
||||||
@ -424,8 +522,9 @@ esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
|
|||||||
*
|
*
|
||||||
* @param bool promiscuous : false - disable / true - enable
|
* @param bool promiscuous : false - disable / true - enable
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_set_promiscuous(bool en);
|
||||||
|
|
||||||
@ -434,8 +533,10 @@ esp_err_t esp_wifi_set_promiscuous(bool en);
|
|||||||
*
|
*
|
||||||
* @param bool *enable : store the current status of promiscuous mode
|
* @param bool *enable : store the current status of promiscuous mode
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_get_promiscuous(bool *en);
|
||||||
|
|
||||||
@ -450,8 +551,15 @@ esp_err_t esp_wifi_get_promiscuous(bool *en);
|
|||||||
* @param wifi_interface_t ifx : interface
|
* @param wifi_interface_t ifx : interface
|
||||||
* @param wifi_config_t *conf : station or soft-AP configuration
|
* @param wifi_config_t *conf : station or soft-AP configuration
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf);
|
||||||
|
|
||||||
@ -461,8 +569,11 @@ esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf);
|
|||||||
* @param wifi_interface_t ifx : interface
|
* @param wifi_interface_t ifx : interface
|
||||||
* @param wifi_config_t *conf : station or soft-AP configuration
|
* @param wifi_config_t *conf : station or soft-AP configuration
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
|
||||||
|
|
||||||
@ -471,14 +582,17 @@ esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
|
|||||||
*
|
*
|
||||||
* @attention SSC only API
|
* @attention SSC only API
|
||||||
*
|
*
|
||||||
* @param struct station_info **station : station list
|
* @param wifi_sta_list_t *sta: station list
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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_get_station_list(struct station_info **station);
|
esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta);
|
||||||
|
|
||||||
esp_err_t esp_wifi_free_station_list(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the WiFi API configuration storage type
|
* @brief Set the WiFi API configuration storage type
|
||||||
@ -487,42 +601,24 @@ esp_err_t esp_wifi_free_station_list(void);
|
|||||||
*
|
*
|
||||||
* @param wifi_storage_t storage : storage type
|
* @param wifi_storage_t storage : storage type
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
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
|
* @brief Set auto connect
|
||||||
* The default value is true
|
* The default value is true
|
||||||
*
|
*
|
||||||
* @attention 1.
|
|
||||||
*
|
|
||||||
* @param bool 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
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_set_auto_connect(bool en);
|
||||||
|
|
||||||
@ -531,8 +627,10 @@ esp_err_t esp_wifi_set_auto_connect(bool en);
|
|||||||
*
|
*
|
||||||
* @param bool *en : store current auto connect configuration
|
* @param bool *en : store current auto connect configuration
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_get_auto_connect(bool *en);
|
||||||
|
|
||||||
@ -549,8 +647,11 @@ esp_err_t esp_wifi_get_auto_connect(bool *en);
|
|||||||
1 - WIFI_VND_IE_ID_1
|
1 - WIFI_VND_IE_ID_1
|
||||||
* @param uint8_t *vnd_ie : pointer to a vendor specific element
|
* @param uint8_t *vnd_ie : pointer to a vendor specific element
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
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);
|
||||||
|
|
||||||
@ -574,8 +675,9 @@ typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const
|
|||||||
* @param esp_vendor_ie_cb_t cb : callback function
|
* @param esp_vendor_ie_cb_t cb : callback function
|
||||||
* @param void *ctx : reserved
|
* @param void *ctx : reserved
|
||||||
*
|
*
|
||||||
* @return ESP_OK : succeed
|
* @return
|
||||||
* @return others : fail
|
* - 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);
|
esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx);
|
||||||
|
|
||||||
|
112
components/esp32/include/esp_wifi_internal.h
Normal file
112
components/esp32/include/esp_wifi_internal.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All the APIs declared here are internal only APIs, it can only be used by
|
||||||
|
* espressif internal modules, such as SSC, LWIP, TCPIP adapter etc, espressif
|
||||||
|
* customers are not recommended to use them.
|
||||||
|
*
|
||||||
|
* If someone really want to use specified APIs declared in here, please contact
|
||||||
|
* espressif AE/developer to make sure you know the limitations or risk of
|
||||||
|
* the API, otherwise you may get unexpected behavior!!!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __ESP_WIFI_INTERNAL_H__
|
||||||
|
#define __ESP_WIFI_INTERNAL_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "rom/queue.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_wifi_types.h"
|
||||||
|
#include "esp_event.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get whether the wifi driver is allowed to transmit data or not
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
*
|
||||||
|
* @return true : upper layer should stop to transmit data to wifi driver
|
||||||
|
* @return false : upper layer can transmit data to wifi driver
|
||||||
|
*/
|
||||||
|
bool esp_wifi_internal_tx_is_stop(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief free the rx buffer which allocated by wifi driver
|
||||||
|
*
|
||||||
|
* @param void* buffer: rx buffer pointer
|
||||||
|
*
|
||||||
|
* @return nonoe
|
||||||
|
*/
|
||||||
|
void esp_wifi_internal_free_rx_buffer(void* buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief transmit the buffer via wifi driver
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* - ERR_OK : Successfully transmit the buffer to wifi driver
|
||||||
|
* - ERR_MEM : Out of memory
|
||||||
|
* - ERR_IF : WiFi driver error
|
||||||
|
* - ERR_ARG : Invalid argument
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __ESP_WIFI_H__ */
|
@ -109,7 +109,7 @@ typedef struct {
|
|||||||
wifi_second_chan_t second; /**< second channel of AP */
|
wifi_second_chan_t second; /**< second channel of AP */
|
||||||
int8_t rssi; /**< signal strength of AP */
|
int8_t rssi; /**< signal strength of AP */
|
||||||
wifi_auth_mode_t authmode; /**< authmode of AP */
|
wifi_auth_mode_t authmode; /**< authmode of AP */
|
||||||
} wifi_ap_list_t;
|
} wifi_ap_record_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WIFI_PS_NONE, /**< No power save */
|
WIFI_PS_NONE, /**< No power save */
|
||||||
@ -150,10 +150,15 @@ typedef union {
|
|||||||
wifi_sta_config_t sta; /**< configuration of STA */
|
wifi_sta_config_t sta; /**< configuration of STA */
|
||||||
} wifi_config_t;
|
} wifi_config_t;
|
||||||
|
|
||||||
struct station_info {
|
typedef struct {
|
||||||
STAILQ_ENTRY(station_info) next;
|
uint8_t mac[6]; /**< mac address of sta that associated with ESP32 soft-AP */
|
||||||
uint8_t bssid[6];
|
}wifi_sta_info_t;
|
||||||
};
|
|
||||||
|
#define ESP_WIFI_MAX_CONN_NUM (10) /**< max number of stations which can connect to ESP32 soft-AP */
|
||||||
|
typedef struct {
|
||||||
|
wifi_sta_info_t sta[ESP_WIFI_MAX_CONN_NUM]; /**< station list */
|
||||||
|
int num; /**< number of station that associated with ESP32 soft-AP */
|
||||||
|
}wifi_sta_list_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WIFI_STORAGE_FLASH, /**< all configuration will strore in both memory and flash */
|
WIFI_STORAGE_FLASH, /**< all configuration will strore in both memory and flash */
|
||||||
|
111
components/esp32/include/esp_wps.h
Normal file
111
components/esp32/include/esp_wps.h
Normal file
@ -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__ */
|
34
components/esp32/include/heap_alloc_caps.h
Normal file
34
components/esp32/include/heap_alloc_caps.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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 HEAP_ALLOC_CAPS_H
|
||||||
|
#define HEAP_ALLOC_CAPS_H
|
||||||
|
|
||||||
|
#define MALLOC_CAP_EXEC (1<<0) //Memory must be able to run executable code
|
||||||
|
#define MALLOC_CAP_32BIT (1<<1) //Memory must allow for aligned 32-bit data accesses
|
||||||
|
#define MALLOC_CAP_8BIT (1<<2) //Memory must allow for 8/16/...-bit data accesses
|
||||||
|
#define MALLOC_CAP_DMA (1<<3) //Memory must be able to accessed by DMA
|
||||||
|
#define MALLOC_CAP_PID2 (1<<4) //Memory must be mapped to PID2 memory space
|
||||||
|
#define MALLOC_CAP_PID3 (1<<5) //Memory must be mapped to PID3 memory space
|
||||||
|
#define MALLOC_CAP_PID4 (1<<6) //Memory must be mapped to PID4 memory space
|
||||||
|
#define MALLOC_CAP_PID5 (1<<7) //Memory must be mapped to PID5 memory space
|
||||||
|
#define MALLOC_CAP_PID6 (1<<8) //Memory must be mapped to PID6 memory space
|
||||||
|
#define MALLOC_CAP_PID7 (1<<9) //Memory must be mapped to PID7 memory space
|
||||||
|
#define MALLOC_CAP_SPISRAM (1<<10) //Memory must be in SPI SRAM
|
||||||
|
#define MALLOC_CAP_INVALID (1<<31) //Memory can't be used / list end marker
|
||||||
|
|
||||||
|
|
||||||
|
void heap_alloc_caps_init();
|
||||||
|
void *pvPortMallocCaps(size_t xWantedSize, uint32_t caps);
|
||||||
|
|
||||||
|
#endif
|
@ -25,7 +25,7 @@ void ets_secure_boot_start(void);
|
|||||||
|
|
||||||
void ets_secure_boot_finish(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);
|
void ets_secure_boot_obtain(void);
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ void SelectSpiFunction(uint32_t ishspi);
|
|||||||
void spi_flash_attach(uint32_t ishspi, bool legacy);
|
void spi_flash_attach(uint32_t ishspi, bool legacy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SPI Read Flash status register. We use CMD 0x05.
|
* @brief SPI Read Flash status register. We use CMD 0x05 (RDSR).
|
||||||
* Please do not call this function in SDK.
|
* Please do not call this function in SDK.
|
||||||
*
|
*
|
||||||
* @param SpiFlashChip *spi : The information for Flash, which is exported from ld file.
|
* @param SpiFlashChip *spi : The information for Flash, which is exported from ld file.
|
||||||
@ -232,7 +232,7 @@ void spi_flash_attach(uint32_t ishspi, bool legacy);
|
|||||||
SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status);
|
SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SPI Read Flash status register high 16 bit. We use CMD 0x35.
|
* @brief SPI Read Flash status register bits 8-15. We use CMD 0x35 (RDSR2).
|
||||||
* Please do not call this function in SDK.
|
* Please do not call this function in SDK.
|
||||||
*
|
*
|
||||||
* @param SpiFlashChip *spi : The information for Flash, which is exported from ld file.
|
* @param SpiFlashChip *spi : The information for Flash, which is exported from ld file.
|
||||||
@ -243,7 +243,7 @@ SpiFlashOpResult SPI_read_status(SpiFlashChip *spi, uint32_t *status);
|
|||||||
* SPI_FLASH_RESULT_ERR : read error.
|
* SPI_FLASH_RESULT_ERR : read error.
|
||||||
* SPI_FLASH_RESULT_TIMEOUT : read timeout.
|
* SPI_FLASH_RESULT_TIMEOUT : read timeout.
|
||||||
*/
|
*/
|
||||||
SpiFlashOpResult SPI_read_status_high(SpiFlashChip *spi, uint32_t *status);
|
SpiFlashOpResult SPI_read_status_high(uint32_t *status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write status to Falsh status register.
|
* @brief Write status to Falsh status register.
|
||||||
@ -503,6 +503,12 @@ void SPI_Write_Encrypt_Disable(void);
|
|||||||
*/
|
*/
|
||||||
SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len);
|
SpiFlashOpResult SPI_Encrypt_Write(uint32_t flash_addr, uint32_t *data, uint32_t len);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Global SpiFlashChip structure used by ROM functions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
extern SpiFlashChip g_rom_flashchip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
#ifndef _SOC_CPU_H
|
#ifndef _SOC_CPU_H
|
||||||
#define _SOC_CPU_H
|
#define _SOC_CPU_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include "xtensa/corebits.h"
|
#include "xtensa/corebits.h"
|
||||||
|
|
||||||
/* C macros for xtensa special register read/write/exchange */
|
/* C macros for xtensa special register read/write/exchange */
|
||||||
|
@ -3830,6 +3830,11 @@
|
|||||||
#define DPORT_DATE_S 0
|
#define DPORT_DATE_S 0
|
||||||
#define DPORT_DPORT_DATE_VERSION 0x1605190
|
#define DPORT_DPORT_DATE_VERSION 0x1605190
|
||||||
|
|
||||||
|
/* Flash MMU table for PRO CPU */
|
||||||
|
#define DPORT_PRO_FLASH_MMU_TABLE ((volatile uint32_t*) 0x3FF10000)
|
||||||
|
|
||||||
|
/* Flash MMU table for APP CPU */
|
||||||
|
#define DPORT_APP_FLASH_MMU_TABLE ((volatile uint32_t*) 0x3FF12000)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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_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_V 0xF
|
||||||
#define EFUSE_RD_EFUSE_RD_DIS_S 16
|
#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 ; */
|
/* EFUSE_RD_EFUSE_WR_DIS : RO ;bitpos:[15:0] ;default: 16'b0 ; */
|
||||||
/*description: read for efuse_wr_disable*/
|
/*description: read for efuse_wr_disable*/
|
||||||
#define EFUSE_RD_EFUSE_WR_DIS 0x0000FFFF
|
#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_V 0xFFFF
|
||||||
#define EFUSE_RD_EFUSE_WR_DIS_S 0
|
#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)
|
#define EFUSE_BLK0_RDATA1_REG (DR_REG_EFUSE_BASE + 0x004)
|
||||||
/* EFUSE_RD_WIFI_MAC_CRC_LOW : RO ;bitpos:[31:0] ;default: 32'b0 ; */
|
/* EFUSE_RD_WIFI_MAC_CRC_LOW : RO ;bitpos:[31:0] ;default: 32'b0 ; */
|
||||||
/*description: read for low 32bit WIFI_MAC_Address*/
|
/*description: read for low 32bit WIFI_MAC_Address*/
|
||||||
|
49
components/esp32/include/soc/frc_timer_reg.h
Normal file
49
components/esp32/include/soc/frc_timer_reg.h
Normal file
@ -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_
|
@ -34,10 +34,41 @@
|
|||||||
#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE)
|
#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_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_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)
|
* @attention
|
||||||
#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD)
|
* 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_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC)
|
||||||
|
|
||||||
#define PIN_FUNC_GPIO 2
|
#define PIN_FUNC_GPIO 2
|
||||||
|
@ -231,11 +231,10 @@ typedef volatile struct {
|
|||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t level1: 1;
|
|
||||||
uint32_t duration1: 15;
|
|
||||||
uint32_t level0: 1;
|
|
||||||
uint32_t duration0: 15;
|
uint32_t duration0: 15;
|
||||||
|
uint32_t level0: 1;
|
||||||
|
uint32_t duration1: 15;
|
||||||
|
uint32_t level1: 1;
|
||||||
};
|
};
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
} data[64];
|
} data[64];
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
#ifndef _SOC_RTC_CNTL_REG_H_
|
#ifndef _SOC_RTC_CNTL_REG_H_
|
||||||
#define _SOC_RTC_CNTL_REG_H_
|
#define _SOC_RTC_CNTL_REG_H_
|
||||||
|
|
||||||
|
/* The value that needs to be written to RTC_CNTL_WDT_WKEY to write-enable the wdt registers */
|
||||||
|
#define RTC_CNTL_WDT_WKEY_VALUE 0x50D83AA1
|
||||||
|
|
||||||
|
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
#define RTC_CNTL_OPTIONS0_REG (DR_REG_RTCCNTL_BASE + 0x0)
|
#define RTC_CNTL_OPTIONS0_REG (DR_REG_RTCCNTL_BASE + 0x0)
|
||||||
@ -236,6 +239,9 @@
|
|||||||
#define RTC_CNTL_TIME_VALID_V 0x1
|
#define RTC_CNTL_TIME_VALID_V 0x1
|
||||||
#define RTC_CNTL_TIME_VALID_S 30
|
#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)
|
#define RTC_CNTL_TIME0_REG (DR_REG_RTCCNTL_BASE + 0x10)
|
||||||
/* RTC_CNTL_TIME_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */
|
/* RTC_CNTL_TIME_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */
|
||||||
/*description: RTC timer low 32 bits*/
|
/*description: RTC timer low 32 bits*/
|
||||||
|
@ -149,6 +149,7 @@
|
|||||||
#define DR_REG_GPIO_SD_BASE 0x3ff44f00
|
#define DR_REG_GPIO_SD_BASE 0x3ff44f00
|
||||||
#define DR_REG_FE2_BASE 0x3ff45000
|
#define DR_REG_FE2_BASE 0x3ff45000
|
||||||
#define DR_REG_FE_BASE 0x3ff46000
|
#define DR_REG_FE_BASE 0x3ff46000
|
||||||
|
#define DR_REG_FRC_TIMER_BASE 0x3ff47000
|
||||||
#define DR_REG_RTCCNTL_BASE 0x3ff48000
|
#define DR_REG_RTCCNTL_BASE 0x3ff48000
|
||||||
#define DR_REG_RTCIO_BASE 0x3ff48400
|
#define DR_REG_RTCIO_BASE 0x3ff48400
|
||||||
#define DR_REG_SARADC_BASE 0x3ff48800
|
#define DR_REG_SARADC_BASE 0x3ff48800
|
||||||
@ -282,9 +283,9 @@
|
|||||||
* 19 2 extern level
|
* 19 2 extern level
|
||||||
* 20 2 extern level
|
* 20 2 extern level
|
||||||
* 21 2 extern level
|
* 21 2 extern level
|
||||||
* 22 3 extern edge
|
* 22 3 extern edge FRC1 timer
|
||||||
* 23 3 extern level
|
* 23 3 extern level
|
||||||
* 24 4 extern level
|
* 24 4 extern level TG1_WDT
|
||||||
* 25 4 extern level Reserved Reserved
|
* 25 4 extern level Reserved Reserved
|
||||||
* 26 5 extern level Reserved Reserved
|
* 26 5 extern level Reserved Reserved
|
||||||
* 27 3 extern level Reserved Reserved
|
* 27 3 extern level Reserved Reserved
|
||||||
@ -302,8 +303,10 @@
|
|||||||
#define ETS_T0_WDT_INUM 3
|
#define ETS_T0_WDT_INUM 3
|
||||||
#define ETS_WBB_INUM 4
|
#define ETS_WBB_INUM 4
|
||||||
#define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/
|
#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_SLC_INUM 1
|
||||||
#define ETS_UART0_INUM 5
|
#define ETS_UART0_INUM 5
|
||||||
#define ETS_UART1_INUM 5
|
#define ETS_UART1_INUM 5
|
||||||
|
@ -15,6 +15,16 @@
|
|||||||
#define __TIMG_REG_H__
|
#define __TIMG_REG_H__
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
|
|
||||||
|
/* The value that needs to be written to TIMG_WDT_WKEY to write-enable the wdt registers */
|
||||||
|
#define TIMG_WDT_WKEY_VALUE 0x50D83AA1
|
||||||
|
|
||||||
|
/* Possible values for TIMG_WDT_STGx */
|
||||||
|
#define TIMG_WDT_STG_SEL_OFF 0
|
||||||
|
#define TIMG_WDT_STG_SEL_INT 1
|
||||||
|
#define TIMG_WDT_STG_SEL_RESET_CPU 2
|
||||||
|
#define TIMG_WDT_STG_SEL_RESET_SYSTEM 3
|
||||||
|
|
||||||
|
|
||||||
#define REG_TIMG_BASE(i) (DR_REG_TIMERGROUP0_BASE + i*0x1000)
|
#define REG_TIMG_BASE(i) (DR_REG_TIMERGROUP0_BASE + i*0x1000)
|
||||||
#define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000)
|
#define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000)
|
||||||
/* TIMG_T0_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */
|
/* TIMG_T0_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */
|
||||||
|
@ -18,8 +18,10 @@
|
|||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
|
|
||||||
#define REG_UART_BASE( i ) (DR_REG_UART_BASE + (i) * 0x10000 + ( i > 1 ? 0xe000 : 0 ) )
|
#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)
|
#define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0)
|
||||||
|
|
||||||
/* UART_RXFIFO_RD_BYTE : RO ;bitpos:[7:0] ;default: 8'b0 ; */
|
/* UART_RXFIFO_RD_BYTE : RO ;bitpos:[7:0] ;default: 8'b0 ; */
|
||||||
/*description: This register stores one byte data read by rx fifo.*/
|
/*description: This register stores one byte data read by rx fifo.*/
|
||||||
#define UART_RXFIFO_RD_BYTE 0x000000FF
|
#define UART_RXFIFO_RD_BYTE 0x000000FF
|
||||||
|
100
components/esp32/int_wdt.c
Normal file
100
components/esp32/int_wdt.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// 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 <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.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_int_wdt.h"
|
||||||
|
|
||||||
|
#if CONFIG_INT_WDT
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
|
TIMERG1.wdt_config0.cpu_reset_length=7; //3.2uS
|
||||||
|
TIMERG1.wdt_config0.level_int_en=1;
|
||||||
|
TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt
|
||||||
|
TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
|
||||||
|
TIMERG1.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
|
||||||
|
//The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
|
||||||
|
//it to their actual value.
|
||||||
|
TIMERG1.wdt_config2=10000;
|
||||||
|
TIMERG1.wdt_config3=10000;
|
||||||
|
TIMERG1.wdt_config0.en=1;
|
||||||
|
TIMERG1.wdt_feed=1;
|
||||||
|
TIMERG1.wdt_wprotect=0;
|
||||||
|
TIMERG1.int_clr_timers.wdt=1;
|
||||||
|
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
|
||||||
|
//is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for
|
||||||
|
//this interrupt.
|
||||||
|
ESP_INTR_ENABLE(WDT_INT_NUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -3,6 +3,36 @@ ENTRY(call_start_cpu0);
|
|||||||
|
|
||||||
SECTIONS
|
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 */
|
/* Send .iram0 code to iram */
|
||||||
.iram0.vectors :
|
.iram0.vectors :
|
||||||
{
|
{
|
||||||
@ -47,6 +77,7 @@ SECTIONS
|
|||||||
_iram_text_start = ABSOLUTE(.);
|
_iram_text_start = ABSOLUTE(.);
|
||||||
*(.iram1 .iram1.*)
|
*(.iram1 .iram1.*)
|
||||||
*libfreertos.a:(.literal .text .literal.* .text.*)
|
*libfreertos.a:(.literal .text .literal.* .text.*)
|
||||||
|
*libesp32.a:panic.o(.literal .text .literal.* .text.*)
|
||||||
*libphy.a:(.literal .text .literal.* .text.*)
|
*libphy.a:(.literal .text .literal.* .text.*)
|
||||||
*librtc.a:(.literal .text .literal.* .text.*)
|
*librtc.a:(.literal .text .literal.* .text.*)
|
||||||
*libpp.a:(.literal .text .literal.* .text.*)
|
*libpp.a:(.literal .text .literal.* .text.*)
|
||||||
@ -92,6 +123,7 @@ SECTIONS
|
|||||||
KEEP(*(.gnu.linkonce.s2.*))
|
KEEP(*(.gnu.linkonce.s2.*))
|
||||||
KEEP(*(.jcr))
|
KEEP(*(.jcr))
|
||||||
*(.dram1 .dram1.*)
|
*(.dram1 .dram1.*)
|
||||||
|
*libesp32.a:panic.o(.rodata .rodata.*)
|
||||||
_data_end = ABSOLUTE(.);
|
_data_end = ABSOLUTE(.);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_heap_start = ABSOLUTE(.);
|
_heap_start = ABSOLUTE(.);
|
||||||
@ -153,16 +185,4 @@ SECTIONS
|
|||||||
_text_end = ABSOLUTE(.);
|
_text_end = ABSOLUTE(.);
|
||||||
_etext = .;
|
_etext = .;
|
||||||
} >iram0_2_seg
|
} >iram0_2_seg
|
||||||
|
|
||||||
.rtc.text :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
*(.rtc.literal .rtc.text)
|
|
||||||
} >rtc_iram_seg
|
|
||||||
|
|
||||||
.rtc.data :
|
|
||||||
{
|
|
||||||
*(.rtc.data)
|
|
||||||
*(.rtc.rodata)
|
|
||||||
} > rtc_slow_seg
|
|
||||||
}
|
}
|
||||||
|
@ -286,6 +286,7 @@ PROVIDE ( _global_impure_ptr = 0x3ffae0b0 );
|
|||||||
PROVIDE ( gmtime = 0x40059848 );
|
PROVIDE ( gmtime = 0x40059848 );
|
||||||
PROVIDE ( gmtime_r = 0x40059868 );
|
PROVIDE ( gmtime_r = 0x40059868 );
|
||||||
PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 );
|
PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 );
|
||||||
|
PROVIDE ( g_rom_flashchip = 0x3ffae270 );
|
||||||
PROVIDE ( gpio_init = 0x40009c20 );
|
PROVIDE ( gpio_init = 0x40009c20 );
|
||||||
PROVIDE ( gpio_input_get = 0x40009b88 );
|
PROVIDE ( gpio_input_get = 0x40009b88 );
|
||||||
PROVIDE ( gpio_input_get_high = 0x40009b9c );
|
PROVIDE ( gpio_input_get_high = 0x40009b9c );
|
||||||
@ -1584,6 +1585,8 @@ PROVIDE ( SPIEraseBlock = 0x40062c4c );
|
|||||||
PROVIDE ( SPIEraseChip = 0x40062c14 );
|
PROVIDE ( SPIEraseChip = 0x40062c14 );
|
||||||
PROVIDE ( SPIEraseSector = 0x40062ccc );
|
PROVIDE ( SPIEraseSector = 0x40062ccc );
|
||||||
PROVIDE ( spi_flash_attach = 0x40062a6c );
|
PROVIDE ( spi_flash_attach = 0x40062a6c );
|
||||||
|
/* NB: SPIUnlock @ 0x400628b0 has been replaced with an updated
|
||||||
|
version in the "spi_flash" component */
|
||||||
PROVIDE ( SPILock = 0x400628f0 );
|
PROVIDE ( SPILock = 0x400628f0 );
|
||||||
PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 );
|
PROVIDE ( SPIMasterReadModeCnfig = 0x40062b64 );
|
||||||
PROVIDE ( spi_modes = 0x3ff99270 );
|
PROVIDE ( spi_modes = 0x3ff99270 );
|
||||||
@ -1595,9 +1598,8 @@ PROVIDE ( SPIReadModeCnfig = 0x40062944 );
|
|||||||
PROVIDE ( SPI_read_status = 0x4006226c );
|
PROVIDE ( SPI_read_status = 0x4006226c );
|
||||||
/* This is static function, but can be used, not generated by script*/
|
/* This is static function, but can be used, not generated by script*/
|
||||||
PROVIDE ( SPI_read_status_high = 0x40062448 );
|
PROVIDE ( SPI_read_status_high = 0x40062448 );
|
||||||
PROVIDE ( SPIUnlock = 0x400628b0 );
|
|
||||||
PROVIDE ( SPI_user_command_read = 0x400621b0 );
|
PROVIDE ( SPI_user_command_read = 0x400621b0 );
|
||||||
PROVIDE ( spi_w25q16 = 0x3ffae270 );
|
PROVIDE ( SPI_flashchip_data = 0x3ffae270 );
|
||||||
PROVIDE ( SPIWrite = 0x40062d50 );
|
PROVIDE ( SPIWrite = 0x40062d50 );
|
||||||
/* This is static function, but can be used, not generated by script*/
|
/* This is static function, but can be used, not generated by script*/
|
||||||
PROVIDE ( SPI_write_enable = 0x40062320 );
|
PROVIDE ( SPI_write_enable = 0x40062320 );
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit a1e5f8b953c7934677ba7a6ed0a6dd2da0e6bd0f
|
Subproject commit 01f5c068e1ac3968add98439ee2f1748b9e391fa
|
@ -25,8 +25,12 @@
|
|||||||
#include "soc/io_mux_reg.h"
|
#include "soc/io_mux_reg.h"
|
||||||
#include "soc/dport_reg.h"
|
#include "soc/dport_reg.h"
|
||||||
#include "soc/rtc_cntl_reg.h"
|
#include "soc/rtc_cntl_reg.h"
|
||||||
|
#include "soc/timer_group_struct.h"
|
||||||
|
#include "soc/timer_group_reg.h"
|
||||||
|
|
||||||
#include "gdbstub.h"
|
#include "esp_gdbstub.h"
|
||||||
|
#include "esp_panic.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Panic handlers; these get called when an unhandled exception occurs or the assembly-level
|
Panic handlers; these get called when an unhandled exception occurs or the assembly-level
|
||||||
@ -34,7 +38,11 @@ task switching / interrupt code runs into an unrecoverable error. The default ta
|
|||||||
overflow handler also is in here.
|
overflow handler also is in here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !CONFIG_FREERTOS_PANIC_SILENT_REBOOT
|
/*
|
||||||
|
Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||||
//printf may be broken, so we fix our own printing fns...
|
//printf may be broken, so we fix our own printing fns...
|
||||||
inline static void panicPutchar(char c) {
|
inline static void panicPutchar(char c) {
|
||||||
while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
|
while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
|
||||||
@ -76,7 +84,6 @@ inline static void panicPutHex(int a) { }
|
|||||||
inline static void panicPutDec(int a) { }
|
inline static void panicPutDec(int a) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int xPortGetCoreID();
|
|
||||||
|
|
||||||
void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {
|
void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {
|
||||||
panicPutStr("***ERROR*** A stack overflow in task ");
|
panicPutStr("***ERROR*** A stack overflow in task ");
|
||||||
@ -105,22 +112,22 @@ void commonErrorHandler(XtExcFrame *frame);
|
|||||||
static void haltOtherCore() {
|
static void haltOtherCore() {
|
||||||
if (xPortGetCoreID()==0) {
|
if (xPortGetCoreID()==0) {
|
||||||
//Kill app cpu
|
//Kill app cpu
|
||||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C1<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
|
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M);
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 0x21<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
|
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
|
||||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C0<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
|
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M);
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 2<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
|
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
|
||||||
} else {
|
} else {
|
||||||
//Kill pro cpu
|
//Kill pro cpu
|
||||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C1<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
|
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_PROCPU_C1_M);
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 0x21<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
|
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
|
||||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_PROCPU_C0<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
|
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C0_M);
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 2<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
|
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Returns true when a debugger is attached using JTAG.
|
//Returns true when a debugger is attached using JTAG.
|
||||||
static int inOCDMode() {
|
static int inOCDMode() {
|
||||||
#if CONFIG_FREERTOS_DEBUG_OCDAWARE
|
#if CONFIG_ESP32_DEBUG_OCDAWARE
|
||||||
int dcr;
|
int dcr;
|
||||||
int reg=0x10200C; //DSRSET register
|
int reg=0x10200C; //DSRSET register
|
||||||
asm("rer %0,%1":"=r"(dcr):"r"(reg));
|
asm("rer %0,%1":"=r"(dcr):"r"(reg));
|
||||||
@ -131,10 +138,26 @@ static int inOCDMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void panicHandler(XtExcFrame *frame) {
|
void panicHandler(XtExcFrame *frame) {
|
||||||
|
int *regs=(int*)frame;
|
||||||
|
//Please keep in sync with PANIC_RSN_* defines
|
||||||
|
const char *reasons[]={
|
||||||
|
"Unknown reason",
|
||||||
|
"Unhandled debug exception",
|
||||||
|
"Double exception",
|
||||||
|
"Unhandled kernel exception",
|
||||||
|
"Coprocessor exception",
|
||||||
|
"Interrupt wdt timeout on CPU0",
|
||||||
|
"Interrupt wdt timeout on CPU1",
|
||||||
|
};
|
||||||
|
const char *reason=reasons[0];
|
||||||
|
//The panic reason is stored in the EXCCAUSE register.
|
||||||
|
if (regs[20]<=PANIC_RSN_MAX) reason=reasons[regs[20]];
|
||||||
haltOtherCore();
|
haltOtherCore();
|
||||||
panicPutStr("Guru Meditation Error: Core ");
|
panicPutStr("Guru Meditation Error: Core ");
|
||||||
panicPutDec(xPortGetCoreID());
|
panicPutDec(xPortGetCoreID());
|
||||||
panicPutStr(" panic'ed.\r\n");
|
panicPutStr(" panic'ed (");
|
||||||
|
panicPutStr(reason);
|
||||||
|
panicPutStr(")\r\n");
|
||||||
|
|
||||||
if (inOCDMode()) {
|
if (inOCDMode()) {
|
||||||
asm("break.n 1");
|
asm("break.n 1");
|
||||||
@ -176,6 +199,44 @@ void xt_unhandled_exception(XtExcFrame *frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
|
||||||
|
an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
|
||||||
|
the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
|
||||||
|
all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
|
||||||
|
one second.
|
||||||
|
*/
|
||||||
|
static void reconfigureAllWdts() {
|
||||||
|
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||||
|
TIMERG0.wdt_feed=1;
|
||||||
|
TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
|
||||||
|
TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS
|
||||||
|
TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system
|
||||||
|
TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
|
||||||
|
TIMERG0.wdt_config2=2000; //1 second before reset
|
||||||
|
TIMERG0.wdt_config0.en=1;
|
||||||
|
TIMERG0.wdt_wprotect=0;
|
||||||
|
//Disable wdt 1
|
||||||
|
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||||
|
TIMERG1.wdt_config0.en=0;
|
||||||
|
TIMERG1.wdt_wprotect=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_ESP32_PANIC_GDBSTUB || CONFIG_ESP32_PANIC_PRINT_HALT
|
||||||
|
/*
|
||||||
|
This disables all the watchdogs for when we call the gdbstub.
|
||||||
|
*/
|
||||||
|
static void disableAllWdts() {
|
||||||
|
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||||
|
TIMERG0.wdt_config0.en=0;
|
||||||
|
TIMERG0.wdt_wprotect=0;
|
||||||
|
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||||
|
TIMERG1.wdt_config0.en=0;
|
||||||
|
TIMERG0.wdt_wprotect=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
|
We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
|
||||||
serial port and either jump to the gdb stub, halt the CPU or reboot.
|
serial port and either jump to the gdb stub, halt the CPU or reboot.
|
||||||
@ -188,6 +249,9 @@ void commonErrorHandler(XtExcFrame *frame) {
|
|||||||
"A6 ","A7 ","A8 ","A9 ","A10 ","A11 ","A12 ","A13 ",
|
"A6 ","A7 ","A8 ","A9 ","A10 ","A11 ","A12 ","A13 ",
|
||||||
"A14 ","A15 ","SAR ","EXCCAUSE","EXCVADDR","LBEG ","LEND ","LCOUNT "};
|
"A14 ","A15 ","SAR ","EXCCAUSE","EXCVADDR","LBEG ","LEND ","LCOUNT "};
|
||||||
|
|
||||||
|
//Feed the watchdogs, so they will give us time to print out debug info
|
||||||
|
reconfigureAllWdts();
|
||||||
|
|
||||||
panicPutStr("Register dump:\r\n");
|
panicPutStr("Register dump:\r\n");
|
||||||
|
|
||||||
for (x=0; x<24; x+=4) {
|
for (x=0; x<24; x+=4) {
|
||||||
@ -201,21 +265,23 @@ void commonErrorHandler(XtExcFrame *frame) {
|
|||||||
}
|
}
|
||||||
panicPutStr("\r\n");
|
panicPutStr("\r\n");
|
||||||
}
|
}
|
||||||
#if CONFIG_FREERTOS_PANIC_GDBSTUB
|
#if CONFIG_ESP32_PANIC_GDBSTUB
|
||||||
|
disableAllWdts();
|
||||||
panicPutStr("Entering gdb stub now.\r\n");
|
panicPutStr("Entering gdb stub now.\r\n");
|
||||||
gdbstubPanicHandler(frame);
|
esp_gdbstub_panic_handler(frame);
|
||||||
#elif CONFIG_FREERTOS_PANIC_PRINT_REBOOT || CONFIG_FREERTOS_PANIC_SILENT_REBOOT
|
#elif CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||||
panicPutStr("Rebooting...\r\n");
|
panicPutStr("Rebooting...\r\n");
|
||||||
for (x=0; x<100; x++) ets_delay_us(1000);
|
for (x=0; x<100; x++) ets_delay_us(1000);
|
||||||
software_reset();
|
software_reset();
|
||||||
#else
|
#else
|
||||||
|
disableAllWdts();
|
||||||
panicPutStr("CPU halted.\r\n");
|
panicPutStr("CPU halted.\r\n");
|
||||||
while(1);
|
while(1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setBreakpointIfJtag(void *fn) {
|
void esp_set_breakpoint_if_jtag(void *fn) {
|
||||||
if (!inOCDMode()) return;
|
if (!inOCDMode()) return;
|
||||||
setFirstBreakpoint((uint32_t)fn);
|
setFirstBreakpoint((uint32_t)fn);
|
||||||
}
|
}
|
181
components/esp32/task_wdt.c
Normal file
181
components/esp32/task_wdt.c
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.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"
|
||||||
|
|
||||||
|
#include "esp_task_wdt.h"
|
||||||
|
|
||||||
|
#if CONFIG_TASK_WDT
|
||||||
|
|
||||||
|
static const char* TAG = "task_wdt";
|
||||||
|
|
||||||
|
typedef struct wdt_task_t wdt_task_t;
|
||||||
|
struct wdt_task_t {
|
||||||
|
TaskHandle_t task_handle;
|
||||||
|
bool fed_watchdog;
|
||||||
|
wdt_task_t *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static wdt_task_t *wdt_task_list=NULL;
|
||||||
|
|
||||||
|
static void IRAM_ATTR task_wdt_isr(void *arg) {
|
||||||
|
wdt_task_t *wdttask;
|
||||||
|
const char *cpu;
|
||||||
|
//Feed the watchdog so we do not reset
|
||||||
|
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||||
|
TIMERG0.wdt_feed=1;
|
||||||
|
TIMERG0.wdt_wprotect=0;
|
||||||
|
//Ack interrupt
|
||||||
|
TIMERG0.int_clr_timers.wdt=1;
|
||||||
|
//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");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ets_printf("Tasks currently running:\n");
|
||||||
|
for (int x=0; x<portNUM_PROCESSORS; x++) {
|
||||||
|
ets_printf("CPU %d: %s\n", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_TASK_WDT_PANIC
|
||||||
|
ets_printf("Aborting.\n");
|
||||||
|
abort();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void esp_task_wdt_feed() {
|
||||||
|
wdt_task_t *wdttask=wdt_task_list;
|
||||||
|
bool found_task=false, do_feed_wdt=true;
|
||||||
|
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
|
||||||
|
//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) {
|
||||||
|
//See if we are at the current task.
|
||||||
|
if (wdttask->task_handle == handle) {
|
||||||
|
wdttask->fed_watchdog=true;
|
||||||
|
found_task=true;
|
||||||
|
}
|
||||||
|
//If even one task in the list doesn't have the do_feed_wdt var set, we do not feed the watchdog.
|
||||||
|
if (!wdttask->fed_watchdog) do_feed_wdt=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_task) {
|
||||||
|
//This is the first time the task calls the task_wdt_feed function. Create a new entry for it in
|
||||||
|
//the linked list.
|
||||||
|
wdt_task_t *newtask=malloc(sizeof(wdt_task_t));
|
||||||
|
memset(newtask, 0, sizeof(wdt_task_t));
|
||||||
|
newtask->task_handle=handle;
|
||||||
|
newtask->fed_watchdog=true;
|
||||||
|
if (wdt_task_list == NULL) {
|
||||||
|
wdt_task_list=newtask;
|
||||||
|
} else {
|
||||||
|
for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) ;
|
||||||
|
wdttask->next=newtask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (do_feed_wdt) {
|
||||||
|
//All tasks have checked in; time to feed the hw watchdog.
|
||||||
|
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||||
|
TIMERG0.wdt_feed=1;
|
||||||
|
TIMERG0.wdt_wprotect=0;
|
||||||
|
//Reset fed_watchdog status
|
||||||
|
for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) wdttask->fed_watchdog=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void esp_task_wdt_delete() {
|
||||||
|
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
|
||||||
|
wdt_task_t *wdttask=wdt_task_list;
|
||||||
|
//Wdt task list can't be empty
|
||||||
|
if (!wdt_task_list) {
|
||||||
|
ESP_LOGE(TAG, "task_wdt_delete: No tasks in list?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (handle==wdt_task_list) {
|
||||||
|
//Current task is first on list.
|
||||||
|
wdt_task_list=wdt_task_list->next;
|
||||||
|
free(wdttask);
|
||||||
|
} else {
|
||||||
|
//Find current task in list
|
||||||
|
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!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wdt_task_t *freeme=wdttask->next;
|
||||||
|
wdttask->next=wdttask->next->next;
|
||||||
|
free(freeme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
|
TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS
|
||||||
|
TIMERG0.wdt_config0.level_int_en=1;
|
||||||
|
TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt
|
||||||
|
TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
|
||||||
|
TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
|
||||||
|
TIMERG0.wdt_config2=CONFIG_TASK_WDT_TIMEOUT_S*2000; //Set timeout before interrupt
|
||||||
|
TIMERG0.wdt_config3=CONFIG_TASK_WDT_TIMEOUT_S*4000; //Set timeout before reset
|
||||||
|
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);
|
||||||
|
TIMERG0.int_clr_timers.wdt=1;
|
||||||
|
TIMERG0.int_ena.wdt=1;
|
||||||
|
ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -94,4 +94,31 @@ config ESPTOOLPY_FLASHFREQ
|
|||||||
default "26m" if ESPTOOLPY_FLASHFREQ_26M
|
default "26m" if ESPTOOLPY_FLASHFREQ_26M
|
||||||
default "20m" if ESPTOOLPY_FLASHFREQ_20M
|
default "20m" if ESPTOOLPY_FLASHFREQ_20M
|
||||||
|
|
||||||
|
|
||||||
|
choice ESPTOOLPY_FLASHSIZE
|
||||||
|
prompt "Flash size"
|
||||||
|
default ESPTOOLPY_FLASHSIZE_2MB
|
||||||
|
help
|
||||||
|
SPI flash size, in megabytes
|
||||||
|
|
||||||
|
config ESPTOOLPY_FLASHSIZE_1MB
|
||||||
|
bool "1 MB"
|
||||||
|
config ESPTOOLPY_FLASHSIZE_2MB
|
||||||
|
bool "2 MB"
|
||||||
|
config ESPTOOLPY_FLASHSIZE_4MB
|
||||||
|
bool "4 MB"
|
||||||
|
config ESPTOOLPY_FLASHSIZE_8MB
|
||||||
|
bool "8 MB"
|
||||||
|
config ESPTOOLPY_FLASHSIZE_16MB
|
||||||
|
bool "16 MB"
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config ESPTOOLPY_FLASHSIZE
|
||||||
|
string
|
||||||
|
default "1MB" if ESPTOOLPY_FLASHSIZE_1MB
|
||||||
|
default "2MB" if ESPTOOLPY_FLASHSIZE_2MB
|
||||||
|
default "4MB" if ESPTOOLPY_FLASHSIZE_4MB
|
||||||
|
default "8MB" if ESPTOOLPY_FLASHSIZE_8MB
|
||||||
|
default "16MB" if ESPTOOLPY_FLASHSIZE_16MB
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -4,31 +4,54 @@ ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT)
|
|||||||
ESPBAUD ?= $(CONFIG_ESPTOOLPY_BAUD)
|
ESPBAUD ?= $(CONFIG_ESPTOOLPY_BAUD)
|
||||||
ESPFLASHMODE ?= $(CONFIG_ESPTOOLPY_FLASHMODE)
|
ESPFLASHMODE ?= $(CONFIG_ESPTOOLPY_FLASHMODE)
|
||||||
ESPFLASHFREQ ?= $(CONFIG_ESPTOOLPY_FLASHFREQ)
|
ESPFLASHFREQ ?= $(CONFIG_ESPTOOLPY_FLASHFREQ)
|
||||||
|
ESPFLASHSIZE ?= $(CONFIG_ESPTOOLPY_FLASHSIZE)
|
||||||
|
|
||||||
PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
|
PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
|
||||||
|
|
||||||
# two commands that can be used from other components
|
# two commands that can be used from other components
|
||||||
# to invoke esptool.py (with or without serial port args)
|
# 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_SRC := $(COMPONENT_PATH)/esptool/esptool.py
|
||||||
ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
|
ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
|
||||||
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
|
ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
|
||||||
|
|
||||||
# the no-stub argument is temporary until esptool.py fully supports compressed uploads
|
# Supporting esptool command line tools
|
||||||
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ)
|
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)
|
||||||
|
|
||||||
|
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)
|
ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
|
||||||
|
|
||||||
$(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC)
|
ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
|
||||||
$(Q) $(ESPTOOLPY) elf2image --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) -o $@ $<
|
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)
|
flash: all_binaries $(ESPTOOLPY_SRC)
|
||||||
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..."
|
@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)
|
app-flash: $(APP_BIN) $(ESPTOOLPY_SRC)
|
||||||
@echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..."
|
@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))
|
$(eval $(call SubmoduleCheck,$(ESPTOOLPY_SRC),$(COMPONENT_PATH)/esptool))
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 197ba605fe0c05e16bf4c5ec07b726adc8d86abc
|
Subproject commit b1e00025fa6cbc63062b205259ee70d91bfe4989
|
@ -1,15 +1,9 @@
|
|||||||
#
|
#
|
||||||
# Component Makefile
|
# 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_ADD_INCLUDEDIRS := port/include include/expat
|
||||||
|
|
||||||
COMPONENT_SRCDIRS := library port
|
COMPONENT_SRCDIRS := library port
|
||||||
|
|
||||||
CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H
|
CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H
|
||||||
|
|
||||||
include $(IDF_PATH)/make/component_common.mk
|
|
||||||
|
@ -18,6 +18,6 @@
|
|||||||
#define USED
|
#define USED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_DEBUG_OCDAWARE
|
#ifdef CONFIG_ESP32_DEBUG_OCDAWARE
|
||||||
const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1;
|
const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1;
|
||||||
#endif
|
#endif
|
@ -93,45 +93,6 @@ config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
|
|||||||
|
|
||||||
If using the WiFi stack, this value must be at least 1.
|
If using the WiFi stack, this value must be at least 1.
|
||||||
|
|
||||||
#This still needs to be implemented.
|
|
||||||
choice FREERTOS_PANIC
|
|
||||||
prompt "Panic handler behaviour"
|
|
||||||
default FREERTOS_PANIC_PRINT_REBOOT
|
|
||||||
help
|
|
||||||
If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is
|
|
||||||
invoked. Configure the panic handlers action here.
|
|
||||||
|
|
||||||
config FREERTOS_PANIC_PRINT_HALT
|
|
||||||
bool "Print registers and halt"
|
|
||||||
help
|
|
||||||
Outputs the relevant registers over the serial port and halt the
|
|
||||||
processor. Needs a manual reset to restart.
|
|
||||||
|
|
||||||
config FREERTOS_PANIC_PRINT_REBOOT
|
|
||||||
bool "Print registers and reboot"
|
|
||||||
help
|
|
||||||
Outputs the relevant registers over the serial port and immediately
|
|
||||||
reset the processor.
|
|
||||||
|
|
||||||
config FREERTOS_PANIC_SILENT_REBOOT
|
|
||||||
bool "Silent reboot"
|
|
||||||
help
|
|
||||||
Just resets the processor without outputting anything
|
|
||||||
|
|
||||||
config FREERTOS_PANIC_GDBSTUB
|
|
||||||
bool "Invoke GDBStub"
|
|
||||||
help
|
|
||||||
Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
|
|
||||||
of the crash.
|
|
||||||
endchoice
|
|
||||||
|
|
||||||
config FREERTOS_DEBUG_OCDAWARE
|
|
||||||
bool "Make exception and panic handlers JTAG/OCD aware"
|
|
||||||
default y
|
|
||||||
help
|
|
||||||
The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
|
|
||||||
instead of panicking, have the debugger stop on the offending instruction.
|
|
||||||
|
|
||||||
choice FREERTOS_ASSERT
|
choice FREERTOS_ASSERT
|
||||||
prompt "FreeRTOS assertions"
|
prompt "FreeRTOS assertions"
|
||||||
default FREERTOS_ASSERT_FAIL_ABORT
|
default FREERTOS_ASSERT_FAIL_ABORT
|
||||||
@ -160,7 +121,7 @@ endchoice
|
|||||||
|
|
||||||
config FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
config FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
||||||
bool "Stop program on scheduler start when JTAG/OCD is detected"
|
bool "Stop program on scheduler start when JTAG/OCD is detected"
|
||||||
depends on FREERTOS_DEBUG_OCDAWARE
|
depends on ESP32_DEBUG_OCDAWARE
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
If JTAG/OCD is connected, stop execution when the scheduler is started and the first
|
If JTAG/OCD is connected, stop execution when the scheduler is started and the first
|
||||||
@ -172,6 +133,43 @@ menuconfig ENABLE_MEMORY_DEBUG
|
|||||||
help
|
help
|
||||||
Enable this option to show malloc heap block and memory crash detect
|
Enable this option to show malloc heap block and memory crash detect
|
||||||
|
|
||||||
|
config FREERTOS_ISR_STACKSIZE
|
||||||
|
int "ISR stack size"
|
||||||
|
range 1536 32768
|
||||||
|
default 1536
|
||||||
|
help
|
||||||
|
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
|
menuconfig FREERTOS_DEBUG_INTERNALS
|
||||||
bool "Debug FreeRTOS internals"
|
bool "Debug FreeRTOS internals"
|
||||||
default n
|
default n
|
||||||
@ -197,6 +195,8 @@ config FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
|||||||
If enabled, additional debug information will be printed for recursive
|
If enabled, additional debug information will be printed for recursive
|
||||||
portMUX usage.
|
portMUX usage.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
endif # FREERTOS_DEBUG_INTERNALS
|
endif # FREERTOS_DEBUG_INTERNALS
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -6,4 +6,3 @@ COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) -Wl,--undefined=uxTopUsedPriority
|
|||||||
COMPONENT_ADD_INCLUDEDIRS := include
|
COMPONENT_ADD_INCLUDEDIRS := include
|
||||||
COMPONENT_PRIV_INCLUDEDIRS := include/freertos
|
COMPONENT_PRIV_INCLUDEDIRS := include/freertos
|
||||||
|
|
||||||
include $(IDF_PATH)/make/component_common.mk
|
|
||||||
|
@ -74,6 +74,7 @@
|
|||||||
* Include the generic headers required for the FreeRTOS port being used.
|
* Include the generic headers required for the FreeRTOS port being used.
|
||||||
*/
|
*/
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include "sys/reent.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If stdint.h cannot be located then:
|
* If stdint.h cannot be located then:
|
||||||
@ -739,6 +740,20 @@ extern "C" {
|
|||||||
#define portTICK_TYPE_IS_ATOMIC 0
|
#define portTICK_TYPE_IS_ATOMIC 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configSUPPORT_STATIC_ALLOCATION
|
||||||
|
/* Defaults to 0 for backward compatibility. */
|
||||||
|
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef configSUPPORT_DYNAMIC_ALLOCATION
|
||||||
|
/* Defaults to 1 for backward compatibility. */
|
||||||
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if( ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) )
|
||||||
|
#error configSUPPORT_STATIC_ALLOCATION and configSUPPORT_DYNAMIC_ALLOCATION cannot both be 0, but can both be 1.
|
||||||
|
#endif
|
||||||
|
|
||||||
#if( portTICK_TYPE_IS_ATOMIC == 0 )
|
#if( portTICK_TYPE_IS_ATOMIC == 0 )
|
||||||
/* Either variables of tick type cannot be read atomically, or
|
/* Either variables of tick type cannot be read atomically, or
|
||||||
portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when
|
portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when
|
||||||
@ -791,6 +806,153 @@ V8 if desired. */
|
|||||||
#define configESP32_PER_TASK_DATA 1
|
#define configESP32_PER_TASK_DATA 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In line with software engineering best practice, FreeRTOS implements a strict
|
||||||
|
* data hiding policy, so the real structures used by FreeRTOS to maintain the
|
||||||
|
* state of tasks, queues, semaphores, etc. are not accessible to the application
|
||||||
|
* code. However, if the application writer wants to statically allocate such
|
||||||
|
* an object then the size of the object needs to be know. Dummy structures
|
||||||
|
* that are guaranteed to have the same size and alignment requirements of the
|
||||||
|
* real objects are used for this purpose. The dummy list and list item
|
||||||
|
* structures below are used for inclusion in such a dummy structure.
|
||||||
|
*/
|
||||||
|
struct xSTATIC_LIST_ITEM
|
||||||
|
{
|
||||||
|
TickType_t xDummy1;
|
||||||
|
void *pvDummy2[ 4 ];
|
||||||
|
};
|
||||||
|
typedef struct xSTATIC_LIST_ITEM StaticListItem_t;
|
||||||
|
|
||||||
|
/* See the comments above the struct xSTATIC_LIST_ITEM definition. */
|
||||||
|
struct xSTATIC_MINI_LIST_ITEM
|
||||||
|
{
|
||||||
|
TickType_t xDummy1;
|
||||||
|
void *pvDummy2[ 2 ];
|
||||||
|
};
|
||||||
|
typedef struct xSTATIC_MINI_LIST_ITEM StaticMiniListItem_t;
|
||||||
|
|
||||||
|
/* See the comments above the struct xSTATIC_LIST_ITEM definition. */
|
||||||
|
typedef struct xSTATIC_LIST
|
||||||
|
{
|
||||||
|
UBaseType_t uxDummy1;
|
||||||
|
void *pvDummy2;
|
||||||
|
StaticMiniListItem_t xDummy3;
|
||||||
|
} StaticList_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In line with software engineering best practice, especially when supplying a
|
||||||
|
* library that is likely to change in future versions, FreeRTOS implements a
|
||||||
|
* strict data hiding policy. This means the Task structure used internally by
|
||||||
|
* FreeRTOS is not accessible to application code. However, if the application
|
||||||
|
* writer wants to statically allocate the memory required to create a task then
|
||||||
|
* the size of the task object needs to be know. The StaticTask_t structure
|
||||||
|
* below is provided for this purpose. Its sizes and alignment requirements are
|
||||||
|
* guaranteed to match those of the genuine structure, no matter which
|
||||||
|
* architecture is being used, and no matter how the values in FreeRTOSConfig.h
|
||||||
|
* are set. Its contents are somewhat obfuscated in the hope users will
|
||||||
|
* recognise that it would be unwise to make direct use of the structure members.
|
||||||
|
*/
|
||||||
|
typedef struct xSTATIC_TCB
|
||||||
|
{
|
||||||
|
void *pxDummy1;
|
||||||
|
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||||
|
xMPU_SETTINGS xDummy2;
|
||||||
|
#endif
|
||||||
|
StaticListItem_t xDummy3[ 2 ];
|
||||||
|
UBaseType_t uxDummy5;
|
||||||
|
void *pxDummy6;
|
||||||
|
uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
|
||||||
|
UBaseType_t uxDummyCoreId;
|
||||||
|
#if ( portSTACK_GROWTH > 0 )
|
||||||
|
void *pxDummy8;
|
||||||
|
#endif
|
||||||
|
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||||
|
UBaseType_t uxDummy9;
|
||||||
|
uint32_t OldInterruptState;
|
||||||
|
#endif
|
||||||
|
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||||
|
UBaseType_t uxDummy10[ 2 ];
|
||||||
|
#endif
|
||||||
|
#if ( configUSE_MUTEXES == 1 )
|
||||||
|
UBaseType_t uxDummy12[ 2 ];
|
||||||
|
#endif
|
||||||
|
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||||
|
void *pxDummy14;
|
||||||
|
#endif
|
||||||
|
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
|
||||||
|
void *pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
|
||||||
|
#if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
||||||
|
void *pvDummyLocalStorageCallBack[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||||
|
uint32_t ulDummy16;
|
||||||
|
#endif
|
||||||
|
#if ( configUSE_NEWLIB_REENTRANT == 1 )
|
||||||
|
struct _reent xDummy17;
|
||||||
|
#endif
|
||||||
|
#if ( configUSE_TASK_NOTIFICATIONS == 1 )
|
||||||
|
uint32_t ulDummy18;
|
||||||
|
uint32_t ucDummy19;
|
||||||
|
#endif
|
||||||
|
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||||
|
uint8_t uxDummy20;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} StaticTask_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In line with software engineering best practice, especially when supplying a
|
||||||
|
* library that is likely to change in future versions, FreeRTOS implements a
|
||||||
|
* strict data hiding policy. This means the Queue structure used internally by
|
||||||
|
* FreeRTOS is not accessible to application code. However, if the application
|
||||||
|
* writer wants to statically allocate the memory required to create a queue
|
||||||
|
* then the size of the queue object needs to be know. The StaticQueue_t
|
||||||
|
* structure below is provided for this purpose. Its sizes and alignment
|
||||||
|
* requirements are guaranteed to match those of the genuine structure, no
|
||||||
|
* matter which architecture is being used, and no matter how the values in
|
||||||
|
* FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in the hope
|
||||||
|
* users will recognise that it would be unwise to make direct use of the
|
||||||
|
* structure members.
|
||||||
|
*/
|
||||||
|
typedef struct xSTATIC_QUEUE
|
||||||
|
{
|
||||||
|
void *pvDummy1[ 3 ];
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
void *pvDummy2;
|
||||||
|
UBaseType_t uxDummy2;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
StaticList_t xDummy3[ 2 ];
|
||||||
|
UBaseType_t uxDummy4[ 3 ];
|
||||||
|
BaseType_t ucDummy5[ 2 ];
|
||||||
|
|
||||||
|
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||||
|
uint8_t ucDummy6;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configUSE_QUEUE_SETS == 1 )
|
||||||
|
void *pvDummy7;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||||
|
UBaseType_t uxDummy8;
|
||||||
|
uint8_t ucDummy9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct {
|
||||||
|
volatile uint32_t mux;
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
|
const char *lastLockedFn;
|
||||||
|
int lastLockedLine;
|
||||||
|
#endif
|
||||||
|
} mux;
|
||||||
|
|
||||||
|
} StaticQueue_t;
|
||||||
|
typedef StaticQueue_t StaticSemaphore_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -152,9 +152,9 @@
|
|||||||
*----------------------------------------------------------*/
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
#define configUSE_PREEMPTION 1
|
#define configUSE_PREEMPTION 1
|
||||||
#define configUSE_IDLE_HOOK 0
|
#define configUSE_IDLE_HOOK ( CONFIG_FREERTOS_LEGACY_IDLE_HOOK )
|
||||||
|
|
||||||
#define configUSE_TICK_HOOK 0
|
#define configUSE_TICK_HOOK ( CONFIG_FREERTOS_LEGACY_TICK_HOOK )
|
||||||
|
|
||||||
#define configTICK_RATE_HZ ( CONFIG_FREERTOS_HZ )
|
#define configTICK_RATE_HZ ( CONFIG_FREERTOS_HZ )
|
||||||
|
|
||||||
@ -180,7 +180,7 @@
|
|||||||
/* The Xtensa port uses a separate interrupt stack. Adjust the stack size */
|
/* The Xtensa port uses a separate interrupt stack. Adjust the stack size */
|
||||||
/* to suit the needs of your specific application. */
|
/* to suit the needs of your specific application. */
|
||||||
#ifndef configISR_STACK_SIZE
|
#ifndef configISR_STACK_SIZE
|
||||||
#define configISR_STACK_SIZE 1024//2048
|
#define configISR_STACK_SIZE CONFIG_FREERTOS_ISR_STACKSIZE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Minimal heap size to make sure examples can run on memory limited
|
/* Minimal heap size to make sure examples can run on memory limited
|
||||||
@ -231,6 +231,7 @@
|
|||||||
#define INCLUDE_vTaskDelayUntil 1
|
#define INCLUDE_vTaskDelayUntil 1
|
||||||
#define INCLUDE_vTaskDelay 1
|
#define INCLUDE_vTaskDelay 1
|
||||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||||
|
#define INCLUDE_pcTaskGetTaskName 1
|
||||||
|
|
||||||
#if CONFIG_ENABLE_MEMORY_DEBUG
|
#if CONFIG_ENABLE_MEMORY_DEBUG
|
||||||
#define configENABLE_MEMORY_DEBUG 1
|
#define configENABLE_MEMORY_DEBUG 1
|
||||||
@ -251,6 +252,8 @@
|
|||||||
|
|
||||||
#define configUSE_NEWLIB_REENTRANT 1
|
#define configUSE_NEWLIB_REENTRANT 1
|
||||||
|
|
||||||
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
|
|
||||||
/* Test FreeRTOS timers (with timer task) and more. */
|
/* Test FreeRTOS timers (with timer task) and more. */
|
||||||
/* Some files don't compile if this flag is disabled */
|
/* Some files don't compile if this flag is disabled */
|
||||||
#define configUSE_TIMERS 1
|
#define configUSE_TIMERS 1
|
||||||
@ -262,12 +265,6 @@
|
|||||||
#define INCLUDE_eTaskGetState 1
|
#define INCLUDE_eTaskGetState 1
|
||||||
#define configUSE_QUEUE_SETS 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_BOARD 1 /* Board mode */
|
||||||
#define configXT_SIMULATOR 0
|
#define configXT_SIMULATOR 0
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef PANIC_H
|
|
||||||
#define PANIC_H
|
|
||||||
|
|
||||||
void setBreakpointIfJtag(void *fn);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -179,6 +179,14 @@ BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION;
|
|||||||
*/
|
*/
|
||||||
void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
|
void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send an interrupt to another core in order to make the task running
|
||||||
|
* on it yield for a higher-priority task.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void vPortYieldOtherCore( BaseType_t coreid) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The structures and methods of manipulating the MPU are contained within the
|
* The structures and methods of manipulating the MPU are contained within the
|
||||||
* port layer.
|
* port layer.
|
||||||
@ -192,8 +200,14 @@ void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Multi-core: get current core ID */
|
/* Multi-core: get current core ID */
|
||||||
int xPortGetCoreID( void );
|
static inline uint32_t xPortGetCoreID() {
|
||||||
|
int id;
|
||||||
|
asm volatile(
|
||||||
|
"rsr.prid %0\n"
|
||||||
|
" extui %0,%0,13,1"
|
||||||
|
:"=r"(id));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -225,6 +225,26 @@ static inline unsigned portENTER_CRITICAL_NESTED() { unsigned state = XTOS_SET_I
|
|||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(state) portEXIT_CRITICAL_NESTED(state)
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(state) portEXIT_CRITICAL_NESTED(state)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare
|
||||||
|
* *mux to compare, and if it's the same, will set *mux to set. It will return the old value
|
||||||
|
* of *addr in *set.
|
||||||
|
*
|
||||||
|
* Warning: From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the
|
||||||
|
* *bitwise inverse* of the old mem if the mem wasn't written. This doesn't seem to happen on the
|
||||||
|
* ESP32, though. (Would show up directly if it did because the magic wouldn't match.)
|
||||||
|
*/
|
||||||
|
static inline void uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set) {
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"WSR %2,SCOMPARE1 \n"
|
||||||
|
"ISYNC \n"
|
||||||
|
"S32C1I %0, %1, 0 \n"
|
||||||
|
:"=r"(*set)
|
||||||
|
:"r"(addr), "r"(compare), "0"(*set)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* Architecture specifics. */
|
/* Architecture specifics. */
|
||||||
|
@ -170,7 +170,95 @@ typedef void * QueueSetMemberHandle_t;
|
|||||||
* \defgroup xQueueCreate xQueueCreate
|
* \defgroup xQueueCreate xQueueCreate
|
||||||
* \ingroup QueueManagement
|
* \ingroup QueueManagement
|
||||||
*/
|
*/
|
||||||
#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( uxQueueLength, uxItemSize, queueQUEUE_TYPE_BASE )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* queue. h
|
||||||
|
* <pre>
|
||||||
|
QueueHandle_t xQueueCreateStatic(
|
||||||
|
UBaseType_t uxQueueLength,
|
||||||
|
UBaseType_t uxItemSize,
|
||||||
|
uint8_t *pucQueueStorageBuffer,
|
||||||
|
StaticQueue_t *pxQueueBuffer
|
||||||
|
);
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Creates a new queue instance, and returns a handle by which the new queue
|
||||||
|
* can be referenced.
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, queues use two blocks of
|
||||||
|
* memory. The first block is used to hold the queue's data structures. The
|
||||||
|
* second block is used to hold items placed into the queue. If a queue is
|
||||||
|
* created using xQueueCreate() then both blocks of memory are automatically
|
||||||
|
* dynamically allocated inside the xQueueCreate() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a queue is created using
|
||||||
|
* xQueueCreateStatic() then the application writer must provide the memory that
|
||||||
|
* will get used by the queue. xQueueCreateStatic() therefore allows a queue to
|
||||||
|
* be created without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org/Embedded-RTOS-Queues.html
|
||||||
|
*
|
||||||
|
* @param uxQueueLength The maximum number of items that the queue can contain.
|
||||||
|
*
|
||||||
|
* @param uxItemSize The number of bytes each item in the queue will require.
|
||||||
|
* Items are queued by copy, not by reference, so this is the number of bytes
|
||||||
|
* that will be copied for each posted item. Each item on the queue must be
|
||||||
|
* the same size.
|
||||||
|
*
|
||||||
|
* @param pucQueueStorageBuffer If uxItemSize is not zero then
|
||||||
|
* pucQueueStorageBuffer must point to a uint8_t array that is at least large
|
||||||
|
* enough to hold the maximum number of items that can be in the queue at any
|
||||||
|
* one time - which is ( uxQueueLength * uxItemsSize ) bytes. If uxItemSize is
|
||||||
|
* zero then pucQueueStorageBuffer can be NULL.
|
||||||
|
*
|
||||||
|
* @param pxQueueBuffer Must point to a variable of type StaticQueue_t, which
|
||||||
|
* will be used to hold the queue's data structure.
|
||||||
|
*
|
||||||
|
* @return If the queue is created then a handle to the created queue is
|
||||||
|
* returned. If pxQueueBuffer is NULL then NULL is returned.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
struct AMessage
|
||||||
|
{
|
||||||
|
char ucMessageID;
|
||||||
|
char ucData[ 20 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define QUEUE_LENGTH 10
|
||||||
|
#define ITEM_SIZE sizeof( uint32_t )
|
||||||
|
|
||||||
|
// xQueueBuffer will hold the queue structure.
|
||||||
|
StaticQueue_t xQueueBuffer;
|
||||||
|
|
||||||
|
// ucQueueStorage will hold the items posted to the queue. Must be at least
|
||||||
|
// [(queue length) * ( queue item size)] bytes long.
|
||||||
|
uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ];
|
||||||
|
|
||||||
|
void vATask( void *pvParameters )
|
||||||
|
{
|
||||||
|
QueueHandle_t xQueue1;
|
||||||
|
|
||||||
|
// Create a queue capable of containing 10 uint32_t values.
|
||||||
|
xQueue1 = xQueueCreate( QUEUE_LENGTH, // The number of items the queue can hold.
|
||||||
|
ITEM_SIZE // The size of each item in the queue
|
||||||
|
&( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue.
|
||||||
|
&xQueueBuffer ); // The buffer that will hold the queue structure.
|
||||||
|
|
||||||
|
// The queue is guaranteed to be created successfully as no dynamic memory
|
||||||
|
// allocation is used. Therefore xQueue1 is now a handle to a valid queue.
|
||||||
|
|
||||||
|
// ... Rest of task code.
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xQueueCreateStatic xQueueCreateStatic
|
||||||
|
* \ingroup QueueManagement
|
||||||
|
*/
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
#define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer ) xQueueGenericCreateStatic( ( uxQueueLength ), ( uxItemSize ), ( pucQueueStorage ), ( pxQueueBuffer ), ( queueQUEUE_TYPE_BASE ) )
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* queue. h
|
* queue. h
|
||||||
@ -1479,7 +1567,9 @@ BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTi
|
|||||||
* these functions directly.
|
* these functions directly.
|
||||||
*/
|
*/
|
||||||
QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION;
|
QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION;
|
||||||
|
QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION;
|
||||||
QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION;
|
QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION;
|
||||||
|
QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION;
|
||||||
void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
|
void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1538,10 +1628,22 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic version of the queue creation function, which is in turn called by
|
* Generic version of the function used to creaet a queue using dynamic memory
|
||||||
* any queue, semaphore or mutex creation function or macro.
|
* allocation. This is called by other functions and macros that create other
|
||||||
|
* RTOS objects that use the queue structure as their base.
|
||||||
*/
|
*/
|
||||||
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION;
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic version of the function used to creaet a queue using dynamic memory
|
||||||
|
* allocation. This is called by other functions and macros that create other
|
||||||
|
* RTOS objects that use the queue structure as their base.
|
||||||
|
*/
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Queue sets provide a mechanism to allow a task to block (pend) on a read
|
* Queue sets provide a mechanism to allow a task to block (pend) on a read
|
||||||
|
@ -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 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
|
the next item would involve a wraparound from the end to the beginning of the ringbuffer. This can
|
||||||
be solved in two ways:
|
be solved (or not) in a few ways:
|
||||||
- allow_split_items = pdTRUE: The insertion code will split the item in two items; one which fits
|
- 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 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.
|
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
|
unused and instead will put the entire item at the start of the ringbuffer, as soon as there is
|
||||||
enough free space.
|
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
|
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
|
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.
|
//An opaque handle for a ringbuff object.
|
||||||
typedef void * RingbufHandle_t;
|
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
|
* @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.
|
* @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);
|
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
|
* @brief Return a previously-retrieved item to the ringbuffer
|
||||||
*
|
*
|
||||||
|
@ -128,19 +128,37 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||||||
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
|
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
|
||||||
* \ingroup Semaphores
|
* \ingroup Semaphores
|
||||||
*/
|
*/
|
||||||
#define vSemaphoreCreateBinary( xSemaphore ) \
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
{ \
|
#define vSemaphoreCreateBinary( xSemaphore ) \
|
||||||
( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \
|
{ \
|
||||||
if( ( xSemaphore ) != NULL ) \
|
( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \
|
||||||
{ \
|
if( ( xSemaphore ) != NULL ) \
|
||||||
( void ) xSemaphoreGive( ( xSemaphore ) ); \
|
{ \
|
||||||
} \
|
( void ) xSemaphoreGive( ( xSemaphore ) ); \
|
||||||
}
|
} \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* semphr. h
|
* semphr. h
|
||||||
* <pre>SemaphoreHandle_t xSemaphoreCreateBinary( void )</pre>
|
* <pre>SemaphoreHandle_t xSemaphoreCreateBinary( void )</pre>
|
||||||
*
|
*
|
||||||
|
* Creates a new binary semaphore instance, and returns a handle by which the
|
||||||
|
* new semaphore can be referenced.
|
||||||
|
*
|
||||||
|
* In many usage scenarios it is faster and more memory efficient to use a
|
||||||
|
* direct to task notification in place of a binary semaphore!
|
||||||
|
* http://www.freertos.org/RTOS-task-notifications.html
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, binary semaphores use a block
|
||||||
|
* of memory, in which the semaphore structure is stored. If a binary semaphore
|
||||||
|
* is created using xSemaphoreCreateBinary() then the required memory is
|
||||||
|
* automatically dynamically allocated inside the xSemaphoreCreateBinary()
|
||||||
|
* function. (see http://www.freertos.org/a00111.html). If a binary semaphore
|
||||||
|
* is created using xSemaphoreCreateBinaryStatic() then the application writer
|
||||||
|
* must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a
|
||||||
|
* binary semaphore to be created without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
* The old vSemaphoreCreateBinary() macro is now deprecated in favour of this
|
* The old vSemaphoreCreateBinary() macro is now deprecated in favour of this
|
||||||
* xSemaphoreCreateBinary() function. Note that binary semaphores created using
|
* xSemaphoreCreateBinary() function. Note that binary semaphores created using
|
||||||
* the vSemaphoreCreateBinary() macro are created in a state such that the
|
* the vSemaphoreCreateBinary() macro are created in a state such that the
|
||||||
@ -182,7 +200,68 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||||||
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
|
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
|
||||||
* \ingroup Semaphores
|
* \ingroup Semaphores
|
||||||
*/
|
*/
|
||||||
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* semphr. h
|
||||||
|
* <pre>SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )</pre>
|
||||||
|
*
|
||||||
|
* Creates a new binary semaphore instance, and returns a handle by which the
|
||||||
|
* new semaphore can be referenced.
|
||||||
|
*
|
||||||
|
* NOTE: In many usage scenarios it is faster and more memory efficient to use a
|
||||||
|
* direct to task notification in place of a binary semaphore!
|
||||||
|
* http://www.freertos.org/RTOS-task-notifications.html
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, binary semaphores use a block
|
||||||
|
* of memory, in which the semaphore structure is stored. If a binary semaphore
|
||||||
|
* is created using xSemaphoreCreateBinary() then the required memory is
|
||||||
|
* automatically dynamically allocated inside the xSemaphoreCreateBinary()
|
||||||
|
* function. (see http://www.freertos.org/a00111.html). If a binary semaphore
|
||||||
|
* is created using xSemaphoreCreateBinaryStatic() then the application writer
|
||||||
|
* must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a
|
||||||
|
* binary semaphore to be created without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* This type of semaphore can be used for pure synchronisation between tasks or
|
||||||
|
* between an interrupt and a task. The semaphore need not be given back once
|
||||||
|
* obtained, so one task/interrupt can continuously 'give' the semaphore while
|
||||||
|
* another continuously 'takes' the semaphore. For this reason this type of
|
||||||
|
* semaphore does not use a priority inheritance mechanism. For an alternative
|
||||||
|
* that does use priority inheritance see xSemaphoreCreateMutex().
|
||||||
|
*
|
||||||
|
* @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t,
|
||||||
|
* which will then be used to hold the semaphore's data structure, removing the
|
||||||
|
* need for the memory to be allocated dynamically.
|
||||||
|
*
|
||||||
|
* @return If the semaphore is created then a handle to the created semaphore is
|
||||||
|
* returned. If pxSemaphoreBuffer is NULL then NULL is returned.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
SemaphoreHandle_t xSemaphore = NULL;
|
||||||
|
StaticSemaphore_t xSemaphoreBuffer;
|
||||||
|
|
||||||
|
void vATask( void * pvParameters )
|
||||||
|
{
|
||||||
|
// Semaphore cannot be used before a call to xSemaphoreCreateBinary().
|
||||||
|
// The semaphore's data structures will be placed in the xSemaphoreBuffer
|
||||||
|
// variable, the address of which is passed into the function. The
|
||||||
|
// function's parameter is not NULL, so the function will not attempt any
|
||||||
|
// dynamic memory allocation, and therefore the function will not return
|
||||||
|
// return NULL.
|
||||||
|
xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer );
|
||||||
|
|
||||||
|
// Rest of task code goes here.
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xSemaphoreCreateBinaryStatic xSemaphoreCreateBinaryStatic
|
||||||
|
* \ingroup Semaphores
|
||||||
|
*/
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
#define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE )
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* semphr. h
|
* semphr. h
|
||||||
@ -652,9 +731,18 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||||||
* <i>Macro</i> that implements a mutex semaphore by using the existing queue
|
* <i>Macro</i> that implements a mutex semaphore by using the existing queue
|
||||||
* mechanism.
|
* mechanism.
|
||||||
*
|
*
|
||||||
* Mutexes created using this macro can be accessed using the xSemaphoreTake()
|
* Internally, within the FreeRTOS implementation, mutex semaphores use a block
|
||||||
|
* of memory, in which the mutex structure is stored. If a mutex is created
|
||||||
|
* using xSemaphoreCreateMutex() then the required memory is automatically
|
||||||
|
* dynamically allocated inside the xSemaphoreCreateMutex() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a mutex is created using
|
||||||
|
* xSemaphoreCreateMutexStatic() then the application writer must provided the
|
||||||
|
* memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created
|
||||||
|
* without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* Mutexes created using this function can be accessed using the xSemaphoreTake()
|
||||||
* and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and
|
* and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and
|
||||||
* xSemaphoreGiveRecursive() macros should not be used.
|
* xSemaphoreGiveRecursive() macros must not be used.
|
||||||
*
|
*
|
||||||
* This type of semaphore uses a priority inheritance mechanism so a task
|
* This type of semaphore uses a priority inheritance mechanism so a task
|
||||||
* 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
|
* 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
|
||||||
@ -667,8 +755,9 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||||||
* semaphore and another always 'takes' the semaphore) and from within interrupt
|
* semaphore and another always 'takes' the semaphore) and from within interrupt
|
||||||
* service routines.
|
* service routines.
|
||||||
*
|
*
|
||||||
* @return xSemaphore Handle to the created mutex semaphore. Should be of type
|
* @return If the mutex was successfully created then a handle to the created
|
||||||
* SemaphoreHandle_t.
|
* semaphore is returned. If there was not enough heap to allocate the mutex
|
||||||
|
* data structures then NULL is returned.
|
||||||
*
|
*
|
||||||
* Example usage:
|
* Example usage:
|
||||||
<pre>
|
<pre>
|
||||||
@ -690,19 +779,93 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||||||
* \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
|
* \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
|
||||||
* \ingroup Semaphores
|
* \ingroup Semaphores
|
||||||
*/
|
*/
|
||||||
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* semphr. h
|
||||||
|
* <pre>SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )</pre>
|
||||||
|
*
|
||||||
|
* Creates a new mutex type semaphore instance, and returns a handle by which
|
||||||
|
* the new mutex can be referenced.
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, mutex semaphores use a block
|
||||||
|
* of memory, in which the mutex structure is stored. If a mutex is created
|
||||||
|
* using xSemaphoreCreateMutex() then the required memory is automatically
|
||||||
|
* dynamically allocated inside the xSemaphoreCreateMutex() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a mutex is created using
|
||||||
|
* xSemaphoreCreateMutexStatic() then the application writer must provided the
|
||||||
|
* memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created
|
||||||
|
* without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* Mutexes created using this function can be accessed using the xSemaphoreTake()
|
||||||
|
* and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and
|
||||||
|
* xSemaphoreGiveRecursive() macros must not be used.
|
||||||
|
*
|
||||||
|
* This type of semaphore uses a priority inheritance mechanism so a task
|
||||||
|
* 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
|
||||||
|
* semaphore it is no longer required.
|
||||||
|
*
|
||||||
|
* Mutex type semaphores cannot be used from within interrupt service routines.
|
||||||
|
*
|
||||||
|
* See xSemaphoreCreateBinary() for an alternative implementation that can be
|
||||||
|
* used for pure synchronisation (where one task or interrupt always 'gives' the
|
||||||
|
* semaphore and another always 'takes' the semaphore) and from within interrupt
|
||||||
|
* service routines.
|
||||||
|
*
|
||||||
|
* @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t,
|
||||||
|
* which will be used to hold the mutex's data structure, removing the need for
|
||||||
|
* the memory to be allocated dynamically.
|
||||||
|
*
|
||||||
|
* @return If the mutex was successfully created then a handle to the created
|
||||||
|
* mutex is returned. If pxMutexBuffer was NULL then NULL is returned.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
SemaphoreHandle_t xSemaphore;
|
||||||
|
StaticSemaphore_t xMutexBuffer;
|
||||||
|
|
||||||
|
void vATask( void * pvParameters )
|
||||||
|
{
|
||||||
|
// A mutex cannot be used before it has been created. xMutexBuffer is
|
||||||
|
// into xSemaphoreCreateMutexStatic() so no dynamic memory allocation is
|
||||||
|
// attempted.
|
||||||
|
xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
|
||||||
|
|
||||||
|
// As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
|
||||||
|
// so there is no need to check it.
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xSemaphoreCreateMutexStatic xSemaphoreCreateMutexStatic
|
||||||
|
* \ingroup Semaphores
|
||||||
|
*/
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
#define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) )
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* semphr. h
|
* semphr. h
|
||||||
* <pre>SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )</pre>
|
* <pre>SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )</pre>
|
||||||
*
|
*
|
||||||
* <i>Macro</i> that implements a recursive mutex by using the existing queue
|
* Creates a new recursive mutex type semaphore instance, and returns a handle
|
||||||
* mechanism.
|
* by which the new recursive mutex can be referenced.
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, recursive mutexs use a block
|
||||||
|
* of memory, in which the mutex structure is stored. If a recursive mutex is
|
||||||
|
* created using xSemaphoreCreateRecursiveMutex() then the required memory is
|
||||||
|
* automatically dynamically allocated inside the
|
||||||
|
* xSemaphoreCreateRecursiveMutex() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a recursive mutex is created using
|
||||||
|
* xSemaphoreCreateRecursiveMutexStatic() then the application writer must
|
||||||
|
* provide the memory that will get used by the mutex.
|
||||||
|
* xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to
|
||||||
|
* be created without using any dynamic memory allocation.
|
||||||
*
|
*
|
||||||
* Mutexes created using this macro can be accessed using the
|
* Mutexes created using this macro can be accessed using the
|
||||||
* xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The
|
* xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The
|
||||||
* xSemaphoreTake() and xSemaphoreGive() macros should not be used.
|
* xSemaphoreTake() and xSemaphoreGive() macros must not be used.
|
||||||
*
|
*
|
||||||
* A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
|
* A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
|
||||||
* doesn't become available again until the owner has called
|
* doesn't become available again until the owner has called
|
||||||
@ -745,14 +908,104 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||||||
* \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
|
* \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex
|
||||||
* \ingroup Semaphores
|
* \ingroup Semaphores
|
||||||
*/
|
*/
|
||||||
#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
|
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
|
||||||
|
#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* semphr. h
|
||||||
|
* <pre>SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )</pre>
|
||||||
|
*
|
||||||
|
* Creates a new recursive mutex type semaphore instance, and returns a handle
|
||||||
|
* by which the new recursive mutex can be referenced.
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, recursive mutexs use a block
|
||||||
|
* of memory, in which the mutex structure is stored. If a recursive mutex is
|
||||||
|
* created using xSemaphoreCreateRecursiveMutex() then the required memory is
|
||||||
|
* automatically dynamically allocated inside the
|
||||||
|
* xSemaphoreCreateRecursiveMutex() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a recursive mutex is created using
|
||||||
|
* xSemaphoreCreateRecursiveMutexStatic() then the application writer must
|
||||||
|
* provide the memory that will get used by the mutex.
|
||||||
|
* xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to
|
||||||
|
* be created without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* Mutexes created using this macro can be accessed using the
|
||||||
|
* xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The
|
||||||
|
* xSemaphoreTake() and xSemaphoreGive() macros must not be used.
|
||||||
|
*
|
||||||
|
* A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
|
||||||
|
* doesn't become available again until the owner has called
|
||||||
|
* xSemaphoreGiveRecursive() for each successful 'take' request. For example,
|
||||||
|
* if a task successfully 'takes' the same mutex 5 times then the mutex will
|
||||||
|
* not be available to any other task until it has also 'given' the mutex back
|
||||||
|
* exactly five times.
|
||||||
|
*
|
||||||
|
* This type of semaphore uses a priority inheritance mechanism so a task
|
||||||
|
* 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
|
||||||
|
* semaphore it is no longer required.
|
||||||
|
*
|
||||||
|
* Mutex type semaphores cannot be used from within interrupt service routines.
|
||||||
|
*
|
||||||
|
* See xSemaphoreCreateBinary() for an alternative implementation that can be
|
||||||
|
* used for pure synchronisation (where one task or interrupt always 'gives' the
|
||||||
|
* semaphore and another always 'takes' the semaphore) and from within interrupt
|
||||||
|
* service routines.
|
||||||
|
*
|
||||||
|
* @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t,
|
||||||
|
* which will then be used to hold the recursive mutex's data structure,
|
||||||
|
* removing the need for the memory to be allocated dynamically.
|
||||||
|
*
|
||||||
|
* @return If the recursive mutex was successfully created then a handle to the
|
||||||
|
* created recursive mutex is returned. If pxMutexBuffer was NULL then NULL is
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
SemaphoreHandle_t xSemaphore;
|
||||||
|
StaticSemaphore_t xMutexBuffer;
|
||||||
|
|
||||||
|
void vATask( void * pvParameters )
|
||||||
|
{
|
||||||
|
// A recursive semaphore cannot be used before it is created. Here a
|
||||||
|
// recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic().
|
||||||
|
// The address of xMutexBuffer is passed into the function, and will hold
|
||||||
|
// the mutexes data structures - so no dynamic memory allocation will be
|
||||||
|
// attempted.
|
||||||
|
xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );
|
||||||
|
|
||||||
|
// As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
|
||||||
|
// so there is no need to check it.
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xSemaphoreCreateRecursiveMutexStatic xSemaphoreCreateRecursiveMutexStatic
|
||||||
|
* \ingroup Semaphores
|
||||||
|
*/
|
||||||
|
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
|
||||||
|
#define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore )
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* semphr. h
|
* semphr. h
|
||||||
* <pre>SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )</pre>
|
* <pre>SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )</pre>
|
||||||
*
|
*
|
||||||
* <i>Macro</i> that creates a counting semaphore by using the existing
|
* Creates a new counting semaphore instance, and returns a handle by which the
|
||||||
* queue mechanism.
|
* new counting semaphore can be referenced.
|
||||||
|
*
|
||||||
|
* In many usage scenarios it is faster and more memory efficient to use a
|
||||||
|
* direct to task notification in place of a counting semaphore!
|
||||||
|
* http://www.freertos.org/RTOS-task-notifications.html
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, counting semaphores use a
|
||||||
|
* block of memory, in which the counting semaphore structure is stored. If a
|
||||||
|
* counting semaphore is created using xSemaphoreCreateCounting() then the
|
||||||
|
* required memory is automatically dynamically allocated inside the
|
||||||
|
* xSemaphoreCreateCounting() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a counting semaphore is created
|
||||||
|
* using xSemaphoreCreateCountingStatic() then the application writer can
|
||||||
|
* instead optionally provide the memory that will get used by the counting
|
||||||
|
* semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting
|
||||||
|
* semaphore to be created without using any dynamic memory allocation.
|
||||||
*
|
*
|
||||||
* Counting semaphores are typically used for two things:
|
* Counting semaphores are typically used for two things:
|
||||||
*
|
*
|
||||||
@ -808,7 +1061,94 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||||||
* \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting
|
* \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting
|
||||||
* \ingroup Semaphores
|
* \ingroup Semaphores
|
||||||
*/
|
*/
|
||||||
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* semphr. h
|
||||||
|
* <pre>SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )</pre>
|
||||||
|
*
|
||||||
|
* Creates a new counting semaphore instance, and returns a handle by which the
|
||||||
|
* new counting semaphore can be referenced.
|
||||||
|
*
|
||||||
|
* In many usage scenarios it is faster and more memory efficient to use a
|
||||||
|
* direct to task notification in place of a counting semaphore!
|
||||||
|
* http://www.freertos.org/RTOS-task-notifications.html
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, counting semaphores use a
|
||||||
|
* block of memory, in which the counting semaphore structure is stored. If a
|
||||||
|
* counting semaphore is created using xSemaphoreCreateCounting() then the
|
||||||
|
* required memory is automatically dynamically allocated inside the
|
||||||
|
* xSemaphoreCreateCounting() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a counting semaphore is created
|
||||||
|
* using xSemaphoreCreateCountingStatic() then the application writer must
|
||||||
|
* provide the memory. xSemaphoreCreateCountingStatic() therefore allows a
|
||||||
|
* counting semaphore to be created without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* Counting semaphores are typically used for two things:
|
||||||
|
*
|
||||||
|
* 1) Counting events.
|
||||||
|
*
|
||||||
|
* In this usage scenario an event handler will 'give' a semaphore each time
|
||||||
|
* an event occurs (incrementing the semaphore count value), and a handler
|
||||||
|
* task will 'take' a semaphore each time it processes an event
|
||||||
|
* (decrementing the semaphore count value). The count value is therefore
|
||||||
|
* the difference between the number of events that have occurred and the
|
||||||
|
* number that have been processed. In this case it is desirable for the
|
||||||
|
* initial count value to be zero.
|
||||||
|
*
|
||||||
|
* 2) Resource management.
|
||||||
|
*
|
||||||
|
* In this usage scenario the count value indicates the number of resources
|
||||||
|
* available. To obtain control of a resource a task must first obtain a
|
||||||
|
* semaphore - decrementing the semaphore count value. When the count value
|
||||||
|
* reaches zero there are no free resources. When a task finishes with the
|
||||||
|
* resource it 'gives' the semaphore back - incrementing the semaphore count
|
||||||
|
* value. In this case it is desirable for the initial count value to be
|
||||||
|
* equal to the maximum count value, indicating that all resources are free.
|
||||||
|
*
|
||||||
|
* @param uxMaxCount The maximum count value that can be reached. When the
|
||||||
|
* semaphore reaches this value it can no longer be 'given'.
|
||||||
|
*
|
||||||
|
* @param uxInitialCount The count value assigned to the semaphore when it is
|
||||||
|
* created.
|
||||||
|
*
|
||||||
|
* @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t,
|
||||||
|
* which will then be used to hold the semaphore's data structure, removing the
|
||||||
|
* need for the memory to be allocated dynamically.
|
||||||
|
*
|
||||||
|
* @return If the counting semaphore was successfully created then a handle to
|
||||||
|
* the created counting semaphore is returned. If pxSemaphoreBuffer was NULL
|
||||||
|
* then NULL is returned.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
SemaphoreHandle_t xSemaphore;
|
||||||
|
StaticSemaphore_t xSemaphoreBuffer;
|
||||||
|
|
||||||
|
void vATask( void * pvParameters )
|
||||||
|
{
|
||||||
|
SemaphoreHandle_t xSemaphore = NULL;
|
||||||
|
|
||||||
|
// Counting semaphore cannot be used before they have been created. Create
|
||||||
|
// a counting semaphore using xSemaphoreCreateCountingStatic(). The max
|
||||||
|
// value to which the semaphore can count is 10, and the initial value
|
||||||
|
// assigned to the count will be 0. The address of xSemaphoreBuffer is
|
||||||
|
// passed in and will be used to hold the semaphore structure, so no dynamic
|
||||||
|
// memory allocation will be used.
|
||||||
|
xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer );
|
||||||
|
|
||||||
|
// No memory allocation was attempted so xSemaphore cannot be NULL, so there
|
||||||
|
// is no need to check its value.
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xSemaphoreCreateCountingStatic xSemaphoreCreateCountingStatic
|
||||||
|
* \ingroup Semaphores
|
||||||
|
*/
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
#define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) )
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* semphr. h
|
* semphr. h
|
||||||
|
@ -177,6 +177,7 @@ typedef struct xTASK_STATUS
|
|||||||
UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */
|
UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */
|
||||||
UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */
|
UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */
|
||||||
uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */
|
uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */
|
||||||
|
StackType_t *pxStackBase; /* Points to the lowest address of the task's stack area. */
|
||||||
uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */
|
uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */
|
||||||
} TaskStatus_t;
|
} TaskStatus_t;
|
||||||
|
|
||||||
@ -281,8 +282,19 @@ is used in assert() statements. */
|
|||||||
);</pre>
|
);</pre>
|
||||||
*
|
*
|
||||||
* Create a new task and add it to the list of tasks that are ready to run.
|
* Create a new task and add it to the list of tasks that are ready to run.
|
||||||
* On multicore environments, this will give no specific affinity to the task.
|
*
|
||||||
* Use xTaskCreatePinnedToCore to give affinity.
|
* Internally, within the FreeRTOS implementation, tasks use two blocks of
|
||||||
|
* memory. The first block is used to hold the task's data structures. The
|
||||||
|
* second block is used by the task as its stack. If a task is created using
|
||||||
|
* xTaskCreate() then both blocks of memory are automatically dynamically
|
||||||
|
* allocated inside the xTaskCreate() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a task is created using
|
||||||
|
* xTaskCreateStatic() then the application writer must provide the required
|
||||||
|
* memory. xTaskCreateStatic() therefore allows a task to be created without
|
||||||
|
* using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* See xTaskCreateStatic() for a version that does not use any dynamic memory
|
||||||
|
* allocation.
|
||||||
*
|
*
|
||||||
* xTaskCreate() can only be used to create a task that has unrestricted
|
* xTaskCreate() can only be used to create a task that has unrestricted
|
||||||
* access to the entire microcontroller memory map. Systems that include MPU
|
* access to the entire microcontroller memory map. Systems that include MPU
|
||||||
@ -350,8 +362,139 @@ is used in assert() statements. */
|
|||||||
* \defgroup xTaskCreate xTaskCreate
|
* \defgroup xTaskCreate xTaskCreate
|
||||||
* \ingroup Tasks
|
* \ingroup Tasks
|
||||||
*/
|
*/
|
||||||
#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ), tskNO_AFFINITY )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
#define xTaskCreatePinnedToCore( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ), xCoreID )
|
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode,
|
||||||
|
const char * const pcName,
|
||||||
|
const uint16_t usStackDepth,
|
||||||
|
void * const pvParameters,
|
||||||
|
UBaseType_t uxPriority,
|
||||||
|
TaskHandle_t * const pxCreatedTask,
|
||||||
|
const BaseType_t xCoreID);
|
||||||
|
|
||||||
|
#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskCreatePinnedToCore( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), tskNO_AFFINITY )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* task. h
|
||||||
|
*<pre>
|
||||||
|
TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode,
|
||||||
|
const char * const pcName,
|
||||||
|
uint32_t ulStackDepth,
|
||||||
|
void *pvParameters,
|
||||||
|
UBaseType_t uxPriority,
|
||||||
|
StackType_t *pxStackBuffer,
|
||||||
|
StaticTask_t *pxTaskBuffer,
|
||||||
|
const BaseType_t xCoreID );</pre>
|
||||||
|
|
||||||
|
*
|
||||||
|
* Create a new task and add it to the list of tasks that are ready to run.
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, tasks use two blocks of
|
||||||
|
* memory. The first block is used to hold the task's data structures. The
|
||||||
|
* second block is used by the task as its stack. If a task is created using
|
||||||
|
* xTaskCreate() then both blocks of memory are automatically dynamically
|
||||||
|
* allocated inside the xTaskCreate() function. (see
|
||||||
|
* http://www.freertos.org/a00111.html). If a task is created using
|
||||||
|
* xTaskCreateStatic() then the application writer must provide the required
|
||||||
|
* memory. xTaskCreateStatic() therefore allows a task to be created without
|
||||||
|
* using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* @param pvTaskCode Pointer to the task entry function. Tasks
|
||||||
|
* must be implemented to never return (i.e. continuous loop).
|
||||||
|
*
|
||||||
|
* @param pcName A descriptive name for the task. This is mainly used to
|
||||||
|
* facilitate debugging. The maximum length of the string is defined by
|
||||||
|
* configMAX_TASK_NAME_LEN in FreeRTOSConfig.h.
|
||||||
|
*
|
||||||
|
* @param ulStackDepth The size of the task stack specified as the number of
|
||||||
|
* variables the stack can hold - not the number of bytes. For example, if
|
||||||
|
* the stack is 32-bits wide and ulStackDepth is defined as 100 then 400 bytes
|
||||||
|
* will be allocated for stack storage.
|
||||||
|
*
|
||||||
|
* @param pvParameters Pointer that will be used as the parameter for the task
|
||||||
|
* being created.
|
||||||
|
*
|
||||||
|
* @param uxPriority The priority at which the task will run.
|
||||||
|
*
|
||||||
|
* @param pxStackBuffer Must point to a StackType_t array that has at least
|
||||||
|
* ulStackDepth indexes - the array will then be used as the task's stack,
|
||||||
|
* removing the need for the stack to be allocated dynamically.
|
||||||
|
*
|
||||||
|
* @param pxTaskBuffer Must point to a variable of type StaticTask_t, which will
|
||||||
|
* then be used to hold the task's data structures, removing the need for the
|
||||||
|
* memory to be allocated dynamically.
|
||||||
|
*
|
||||||
|
* @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will
|
||||||
|
* be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer
|
||||||
|
* are NULL then the task will not be created and
|
||||||
|
* errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
// Dimensions the buffer that the task being created will use as its stack.
|
||||||
|
// NOTE: This is the number of words the stack will hold, not the number of
|
||||||
|
// bytes. For example, if each stack item is 32-bits, and this is set to 100,
|
||||||
|
// then 400 bytes (100 * 32-bits) will be allocated.
|
||||||
|
#define STACK_SIZE 200
|
||||||
|
|
||||||
|
// Structure that will hold the TCB of the task being created.
|
||||||
|
StaticTask_t xTaskBuffer;
|
||||||
|
|
||||||
|
// Buffer that the task being created will use as its stack. Note this is
|
||||||
|
// an array of StackType_t variables. The size of StackType_t is dependent on
|
||||||
|
// the RTOS port.
|
||||||
|
StackType_t xStack[ STACK_SIZE ];
|
||||||
|
|
||||||
|
// Function that implements the task being created.
|
||||||
|
void vTaskCode( void * pvParameters )
|
||||||
|
{
|
||||||
|
// The parameter value is expected to be 1 as 1 is passed in the
|
||||||
|
// pvParameters value in the call to xTaskCreateStatic().
|
||||||
|
configASSERT( ( uint32_t ) pvParameters == 1UL );
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
// Task code goes here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that creates a task.
|
||||||
|
void vOtherFunction( void )
|
||||||
|
{
|
||||||
|
TaskHandle_t xHandle = NULL;
|
||||||
|
|
||||||
|
// Create the task without using any dynamic memory allocation.
|
||||||
|
xHandle = xTaskCreateStatic(
|
||||||
|
vTaskCode, // Function that implements the task.
|
||||||
|
"NAME", // Text name for the task.
|
||||||
|
STACK_SIZE, // Stack size in words, not bytes.
|
||||||
|
( void * ) 1, // Parameter passed into the task.
|
||||||
|
tskIDLE_PRIORITY,// Priority at which the task is created.
|
||||||
|
xStack, // Array to use as the task's stack.
|
||||||
|
&xTaskBuffer ); // Variable to hold the task's data structure.
|
||||||
|
|
||||||
|
// puxStackBuffer and pxTaskBuffer were not NULL, so the task will have
|
||||||
|
// been created, and xHandle will be the task's handle. Use the handle
|
||||||
|
// to suspend the task.
|
||||||
|
vTaskSuspend( xHandle );
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xTaskCreateStatic xTaskCreateStatic
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode,
|
||||||
|
const char * const pcName,
|
||||||
|
const uint32_t ulStackDepth,
|
||||||
|
void * const pvParameters,
|
||||||
|
UBaseType_t uxPriority,
|
||||||
|
StackType_t * const puxStackBuffer,
|
||||||
|
StaticTask_t * const pxTaskBuffer,
|
||||||
|
const BaseType_t xCoreID );
|
||||||
|
|
||||||
|
#define xTaskCreateStatic( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxStackBuffer, pxTaskBuffer ) xTaskCreateStaticPinnedToCore( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxStackBuffer ), ( pxTaskBuffer ), tskNO_AFFINITY )
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* task. h
|
* task. h
|
||||||
@ -420,7 +563,9 @@ TaskHandle_t xHandle;
|
|||||||
* \defgroup xTaskCreateRestricted xTaskCreateRestricted
|
* \defgroup xTaskCreateRestricted xTaskCreateRestricted
|
||||||
* \ingroup Tasks
|
* \ingroup Tasks
|
||||||
*/
|
*/
|
||||||
#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) )
|
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||||
|
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* task. h
|
* task. h
|
||||||
@ -1933,6 +2078,17 @@ TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION;
|
|||||||
*/
|
*/
|
||||||
TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
|
TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the handle of the task running on a certain CPU. Because of
|
||||||
|
* the nature of SMP processing, there is no guarantee that this
|
||||||
|
* value will still be valid on return and should only be used for
|
||||||
|
* debugging purposes.
|
||||||
|
*/
|
||||||
|
TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t cpuid );
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Capture the current time status for future reference.
|
* Capture the current time status for future reference.
|
||||||
*/
|
*/
|
||||||
@ -1968,12 +2124,6 @@ void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTIO
|
|||||||
*/
|
*/
|
||||||
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
|
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
|
||||||
* Generic version of the task creation function which is in turn called by the
|
|
||||||
* xTaskCreate() and xTaskCreateRestricted() macros.
|
|
||||||
*/
|
|
||||||
BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions, const BaseType_t xCoreID) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
|
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
|
||||||
*/
|
*/
|
||||||
|
@ -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)
|
n - Exception number (type)
|
||||||
f - Handler function address, NULL to uninstall handler.
|
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.
|
n - Interrupt number.
|
||||||
f - Handler function address, NULL to uninstall handler.
|
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.
|
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.
|
mask - Bit mask of interrupts to be disabled.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
@ -322,12 +322,7 @@ STRUCT_END(XtSolFrame)
|
|||||||
#ifdef __ASSEMBLER__
|
#ifdef __ASSEMBLER__
|
||||||
.macro getcoreid reg
|
.macro getcoreid reg
|
||||||
rsr.prid \reg
|
rsr.prid \reg
|
||||||
bbci \reg,1,1f
|
extui \reg,\reg,13,1
|
||||||
movi \reg,1
|
|
||||||
j 2f
|
|
||||||
1:
|
|
||||||
movi \reg,0
|
|
||||||
2:
|
|
||||||
.endm
|
.endm
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -101,7 +101,9 @@
|
|||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
|
||||||
#include "panic.h"
|
#include "esp_panic.h"
|
||||||
|
|
||||||
|
#include "esp_crosscore_int.h"
|
||||||
|
|
||||||
/* Defined in portasm.h */
|
/* Defined in portasm.h */
|
||||||
extern void _frxt_tick_timer_init(void);
|
extern void _frxt_tick_timer_init(void);
|
||||||
@ -228,6 +230,12 @@ BaseType_t xPortSysTickHandler( void )
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void vPortYieldOtherCore( BaseType_t coreid ) {
|
||||||
|
esp_crosscore_int_send_yield( coreid );
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -253,28 +261,6 @@ void vPortAssertIfInISR()
|
|||||||
configASSERT(port_interruptNesting[xPortGetCoreID()]==0)
|
configASSERT(port_interruptNesting[xPortGetCoreID()]==0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare
|
|
||||||
* *mux to compare, and if it's the same, will set *mux to set. It will return the old value
|
|
||||||
* of *addr.
|
|
||||||
*
|
|
||||||
* Warning: From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the
|
|
||||||
* *bitwise inverse* of the old mem if the mem wasn't written. This doesn't seem to happen on the
|
|
||||||
* ESP32, though. (Would show up directly if it did because the magic wouldn't match.)
|
|
||||||
*/
|
|
||||||
uint32_t uxPortCompareSet(volatile uint32_t *mux, uint32_t compare, uint32_t set)
|
|
||||||
{
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"WSR %2,SCOMPARE1 \n" //initialize SCOMPARE1
|
|
||||||
"ISYNC \n" //wait sync
|
|
||||||
"S32C1I %0, %1, 0 \n" //store id into the lock, if the lock is the same as comparel. Otherwise, no write-access
|
|
||||||
:"=r"(set) \
|
|
||||||
:"r"(mux), "r"(compare), "0"(set) \
|
|
||||||
);
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For kernel use: Initialize a per-CPU mux. Mux will be initialized unlocked.
|
* For kernel use: Initialize a per-CPU mux. Mux will be initialized unlocked.
|
||||||
*/
|
*/
|
||||||
@ -310,7 +296,8 @@ void vPortCPUAcquireMutex(portMUX_TYPE *mux) {
|
|||||||
irqStatus=portENTER_CRITICAL_NESTED();
|
irqStatus=portENTER_CRITICAL_NESTED();
|
||||||
do {
|
do {
|
||||||
//Lock mux if it's currently unlocked
|
//Lock mux if it's currently unlocked
|
||||||
res=uxPortCompareSet(&mux->mux, portMUX_FREE_VAL, (xPortGetCoreID()<<portMUX_VAL_SHIFT)|portMUX_MAGIC_VAL);
|
res=(xPortGetCoreID()<<portMUX_VAL_SHIFT)|portMUX_MAGIC_VAL;
|
||||||
|
uxPortCompareSet(&mux->mux, portMUX_FREE_VAL, &res);
|
||||||
//If it wasn't free and we're the owner of the lock, we are locking recursively.
|
//If it wasn't free and we're the owner of the lock, we are locking recursively.
|
||||||
if ( (res != portMUX_FREE_VAL) && (((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT) == xPortGetCoreID()) ) {
|
if ( (res != portMUX_FREE_VAL) && (((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT) == xPortGetCoreID()) ) {
|
||||||
//Mux was already locked by us. Just bump the recurse count by one.
|
//Mux was already locked by us. Just bump the recurse count by one.
|
||||||
@ -362,29 +349,33 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
|||||||
if ( (mux->mux & portMUX_MAGIC_MASK) != portMUX_MAGIC_VAL ) ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is uninitialized (0x%X)!\n", mux, mux->mux);
|
if ( (mux->mux & portMUX_MAGIC_MASK) != portMUX_MAGIC_VAL ) ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is uninitialized (0x%X)!\n", mux, mux->mux);
|
||||||
#endif
|
#endif
|
||||||
//Unlock mux if it's currently locked with a recurse count of 0
|
//Unlock mux if it's currently locked with a recurse count of 0
|
||||||
res=uxPortCompareSet(&mux->mux, (xPortGetCoreID()<<portMUX_VAL_SHIFT)|portMUX_MAGIC_VAL, portMUX_FREE_VAL);
|
res=portMUX_FREE_VAL;
|
||||||
|
uxPortCompareSet(&mux->mux, (xPortGetCoreID()<<portMUX_VAL_SHIFT)|portMUX_MAGIC_VAL, &res);
|
||||||
|
|
||||||
if ( res == portMUX_FREE_VAL ) {
|
if ( ((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT) == xPortGetCoreID() ) {
|
||||||
|
//Lock is valid, we can return safely. Just need to check if it's a recursive lock; if so we need to decrease the refcount.
|
||||||
|
if ( ((res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT)!=0) {
|
||||||
|
//We locked this, but the reccount isn't zero. Decrease refcount and continue.
|
||||||
|
recCnt=(res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT;
|
||||||
|
recCnt--;
|
||||||
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
||||||
|
ets_printf("Recursive unlock: recCnt=%d last locked %s line %d, curr %s line %d\n", recCnt, lastLockedFn, lastLockedLine, fnName, line);
|
||||||
|
#endif
|
||||||
|
mux->mux=portMUX_MAGIC_VAL|(recCnt<<portMUX_CNT_SHIFT)|(xPortGetCoreID()<<portMUX_VAL_SHIFT);
|
||||||
|
}
|
||||||
|
} else if ( res == portMUX_FREE_VAL ) {
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux);
|
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux);
|
||||||
ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line);
|
ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line);
|
||||||
#endif
|
#endif
|
||||||
ret=pdFALSE;
|
ret=pdFALSE;
|
||||||
} else if ( ((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT) != xPortGetCoreID() ) {
|
} else {
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p wasn't locked by this core (%d) but by core %d (ret=%x, mux=%x).\n", mux, xPortGetCoreID(), ((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT), res, mux->mux);
|
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p wasn't locked by this core (%d) but by core %d (ret=%x, mux=%x).\n", mux, xPortGetCoreID(), ((res&portMUX_VAL_MASK)>>portMUX_VAL_SHIFT), res, mux->mux);
|
||||||
ets_printf("Last non-recursive lock %s line %d\n", lastLockedFn, lastLockedLine);
|
ets_printf("Last non-recursive lock %s line %d\n", lastLockedFn, lastLockedLine);
|
||||||
ets_printf("Called by %s line %d\n", fnName, line);
|
ets_printf("Called by %s line %d\n", fnName, line);
|
||||||
#endif
|
#endif
|
||||||
ret=pdFALSE;
|
ret=pdFALSE;
|
||||||
} else if ( ((res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT)!=0) {
|
|
||||||
//We locked this, but the reccount isn't zero. Decrease refcount and continue.
|
|
||||||
recCnt=(res&portMUX_CNT_MASK)>>portMUX_CNT_SHIFT;
|
|
||||||
recCnt--;
|
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
|
|
||||||
ets_printf("Recursive unlock: recCnt=%d last locked %s line %d, curr %s line %d\n", recCnt, lastLockedFn, lastLockedLine, fnName, line);
|
|
||||||
#endif
|
|
||||||
mux->mux=portMUX_MAGIC_VAL|(recCnt<<portMUX_CNT_SHIFT)|(xPortGetCoreID()<<portMUX_VAL_SHIFT);
|
|
||||||
}
|
}
|
||||||
portEXIT_CRITICAL_NESTED(irqStatus);
|
portEXIT_CRITICAL_NESTED(irqStatus);
|
||||||
return ret;
|
return ret;
|
||||||
@ -392,7 +383,7 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
|||||||
|
|
||||||
#if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
#if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
||||||
void vPortFirstTaskHook(TaskFunction_t function) {
|
void vPortFirstTaskHook(TaskFunction_t function) {
|
||||||
setBreakpointIfJtag(function);
|
esp_set_breakpoint_if_jtag(function);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -51,18 +51,6 @@ port_switch_flag:
|
|||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* C function to get proc ID.*/
|
|
||||||
.global xPortGetCoreID
|
|
||||||
.type xPortGetCoreID,@function
|
|
||||||
.align 4
|
|
||||||
xPortGetCoreID:
|
|
||||||
ENTRY(16)
|
|
||||||
getcoreid a2
|
|
||||||
RET(16)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* _frxt_setup_switch
|
* _frxt_setup_switch
|
||||||
@ -81,9 +69,8 @@ _frxt_setup_switch:
|
|||||||
ENTRY(16)
|
ENTRY(16)
|
||||||
|
|
||||||
getcoreid a3
|
getcoreid a3
|
||||||
slli a3, a3, 2
|
|
||||||
movi a2, port_switch_flag
|
movi a2, port_switch_flag
|
||||||
add a2, a2, a3
|
addx4 a2, a3, a2
|
||||||
|
|
||||||
movi a3, 1
|
movi a3, 1
|
||||||
s32i a3, a2, 0
|
s32i a3, a2, 0
|
||||||
@ -128,12 +115,11 @@ _frxt_int_enter:
|
|||||||
Manage nesting directly rather than call the generic IntEnter()
|
Manage nesting directly rather than call the generic IntEnter()
|
||||||
(in windowed ABI we can't call a C function here anyway because PS.EXCM is still set).
|
(in windowed ABI we can't call a C function here anyway because PS.EXCM is still set).
|
||||||
*/
|
*/
|
||||||
getcoreid a3
|
getcoreid a4
|
||||||
slli a4, a3, 2 /* a4 = cpuid * 4 */
|
|
||||||
movi a2, port_xSchedulerRunning
|
movi a2, port_xSchedulerRunning
|
||||||
add a2, a2, a4
|
addx4 a2, a4, a2
|
||||||
movi a3, port_interruptNesting
|
movi a3, port_interruptNesting
|
||||||
add a3, a3, a4
|
addx4 a3, a4, a3
|
||||||
l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */
|
l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */
|
||||||
beqz a2, 1f /* scheduler not running, no tasks */
|
beqz a2, 1f /* scheduler not running, no tasks */
|
||||||
l32i a2, a3, 0 /* a2 = port_interruptNesting */
|
l32i a2, a3, 0 /* a2 = port_interruptNesting */
|
||||||
@ -142,14 +128,13 @@ _frxt_int_enter:
|
|||||||
bnei a2, 1, .Lnested /* !=0 before incr, so nested */
|
bnei a2, 1, .Lnested /* !=0 before incr, so nested */
|
||||||
|
|
||||||
movi a2, pxCurrentTCB
|
movi a2, pxCurrentTCB
|
||||||
add a2, a2, a4
|
addx4 a2, a4, a2
|
||||||
l32i a2, a2, 0 /* a2 = current TCB */
|
l32i a2, a2, 0 /* a2 = current TCB */
|
||||||
beqz a2, 1f
|
beqz a2, 1f
|
||||||
s32i a1, a2, TOPOFSTACK_OFFS /* pxCurrentTCB->pxTopOfStack = SP */
|
s32i a1, a2, TOPOFSTACK_OFFS /* pxCurrentTCB->pxTopOfStack = SP */
|
||||||
movi a1, port_IntStackTop /* a1 = top of intr stack */
|
movi a1, port_IntStackTop /* a1 = top of intr stack */
|
||||||
movi a2, configISR_STACK_SIZE
|
movi a2, configISR_STACK_SIZE
|
||||||
getcoreid a3
|
mull a2, a4, a2
|
||||||
mull a2, a3, a2
|
|
||||||
add a1, a1, a2 /* for current proc */
|
add a1, a1, a2 /* for current proc */
|
||||||
|
|
||||||
.Lnested:
|
.Lnested:
|
||||||
@ -177,12 +162,11 @@ _frxt_int_enter:
|
|||||||
.align 4
|
.align 4
|
||||||
_frxt_int_exit:
|
_frxt_int_exit:
|
||||||
|
|
||||||
getcoreid a3
|
getcoreid a4
|
||||||
slli a4, a3, 2 /* a4 is core * 4 */
|
|
||||||
movi a2, port_xSchedulerRunning
|
movi a2, port_xSchedulerRunning
|
||||||
add a2, a2, a4
|
addx4 a2, a4, a2
|
||||||
movi a3, port_interruptNesting
|
movi a3, port_interruptNesting
|
||||||
add a3, a3, a4
|
addx4 a3, a4, a3
|
||||||
rsil a0, XCHAL_EXCM_LEVEL /* lock out interrupts */
|
rsil a0, XCHAL_EXCM_LEVEL /* lock out interrupts */
|
||||||
l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */
|
l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */
|
||||||
beqz a2, .Lnoswitch /* scheduler not running, no tasks */
|
beqz a2, .Lnoswitch /* scheduler not running, no tasks */
|
||||||
@ -192,13 +176,13 @@ _frxt_int_exit:
|
|||||||
bnez a2, .Lnesting /* !=0 after decr so still nested */
|
bnez a2, .Lnesting /* !=0 after decr so still nested */
|
||||||
|
|
||||||
movi a2, pxCurrentTCB
|
movi a2, pxCurrentTCB
|
||||||
add a2, a2, a4
|
addx4 a2, a4, a2
|
||||||
l32i a2, a2, 0 /* a2 = current TCB */
|
l32i a2, a2, 0 /* a2 = current TCB */
|
||||||
beqz a2, 1f /* no task ? go to dispatcher */
|
beqz a2, 1f /* no task ? go to dispatcher */
|
||||||
l32i a1, a2, TOPOFSTACK_OFFS /* SP = pxCurrentTCB->pxTopOfStack */
|
l32i a1, a2, TOPOFSTACK_OFFS /* SP = pxCurrentTCB->pxTopOfStack */
|
||||||
|
|
||||||
movi a2, port_switch_flag /* address of switch flag */
|
movi a2, port_switch_flag /* address of switch flag */
|
||||||
add a2, a2, a4 /* point to flag for this cpu */
|
addx4 a2, a4, a2 /* point to flag for this cpu */
|
||||||
l32i a3, a2, 0 /* a3 = port_switch_flag */
|
l32i a3, a2, 0 /* a3 = port_switch_flag */
|
||||||
beqz a3, .Lnoswitch /* flag = 0 means no switch reqd */
|
beqz a3, .Lnoswitch /* flag = 0 means no switch reqd */
|
||||||
movi a3, 0
|
movi a3, 0
|
||||||
@ -404,14 +388,12 @@ _frxt_dispatch:
|
|||||||
call0 vTaskSwitchContext // Get next TCB to resume
|
call0 vTaskSwitchContext // Get next TCB to resume
|
||||||
movi a2, pxCurrentTCB
|
movi a2, pxCurrentTCB
|
||||||
getcoreid a3
|
getcoreid a3
|
||||||
slli a3, a3, 2
|
addx4 a2, a3, a2
|
||||||
add a2, a2, a3
|
|
||||||
#else
|
#else
|
||||||
call4 vTaskSwitchContext // Get next TCB to resume
|
call4 vTaskSwitchContext // Get next TCB to resume
|
||||||
movi a2, pxCurrentTCB
|
movi a2, pxCurrentTCB
|
||||||
getcoreid a3
|
getcoreid a3
|
||||||
slli a3, a3, 2
|
addx4 a2, a3, a2
|
||||||
add a2, a2, a3
|
|
||||||
#endif
|
#endif
|
||||||
l32i a3, a2, 0
|
l32i a3, a2, 0
|
||||||
l32i sp, a3, TOPOFSTACK_OFFS /* SP = next_TCB->pxTopOfStack; */
|
l32i sp, a3, TOPOFSTACK_OFFS /* SP = next_TCB->pxTopOfStack; */
|
||||||
@ -451,8 +433,7 @@ _frxt_dispatch:
|
|||||||
/* Restore CPENABLE from task's co-processor save area. */
|
/* Restore CPENABLE from task's co-processor save area. */
|
||||||
movi a3, pxCurrentTCB /* cp_state = */
|
movi a3, pxCurrentTCB /* cp_state = */
|
||||||
getcoreid a2
|
getcoreid a2
|
||||||
slli a2, a2, 2
|
addx4 a3, a2, a3
|
||||||
add a3, a2, a3
|
|
||||||
l32i a3, a3, 0
|
l32i a3, a3, 0
|
||||||
l32i a2, a3, CP_TOPOFSTACK_OFFS /* StackType_t *pxStack; */
|
l32i a2, a3, CP_TOPOFSTACK_OFFS /* StackType_t *pxStack; */
|
||||||
l16ui a3, a2, XT_CPENABLE /* CPENABLE = cp_state->cpenable; */
|
l16ui a3, a2, XT_CPENABLE /* CPENABLE = cp_state->cpenable; */
|
||||||
@ -541,8 +522,7 @@ vPortYield:
|
|||||||
|
|
||||||
movi a2, pxCurrentTCB
|
movi a2, pxCurrentTCB
|
||||||
getcoreid a3
|
getcoreid a3
|
||||||
slli a3, a3, 2
|
addx4 a2, a3, a2
|
||||||
add a2, a2, a3
|
|
||||||
l32i a2, a2, 0 /* a2 = pxCurrentTCB */
|
l32i a2, a2, 0 /* a2 = pxCurrentTCB */
|
||||||
movi a3, 0
|
movi a3, 0
|
||||||
s32i a3, sp, XT_SOL_EXIT /* 0 to flag as solicited frame */
|
s32i a3, sp, XT_SOL_EXIT /* 0 to flag as solicited frame */
|
||||||
@ -593,8 +573,7 @@ vPortYieldFromInt:
|
|||||||
/* Save CPENABLE in task's co-processor save area, and clear CPENABLE. */
|
/* Save CPENABLE in task's co-processor save area, and clear CPENABLE. */
|
||||||
movi a3, pxCurrentTCB /* cp_state = */
|
movi a3, pxCurrentTCB /* cp_state = */
|
||||||
getcoreid a2
|
getcoreid a2
|
||||||
slli a2, a2, 2
|
addx4 a3, a2, a3
|
||||||
add a3, a2, a3
|
|
||||||
l32i a3, a3, 0
|
l32i a3, a3, 0
|
||||||
|
|
||||||
l32i a2, a3, CP_TOPOFSTACK_OFFS
|
l32i a2, a3, CP_TOPOFSTACK_OFFS
|
||||||
@ -637,18 +616,17 @@ _frxt_task_coproc_state:
|
|||||||
|
|
||||||
/* We can use a3 as a scratchpad, the instances of code calling XT_RTOS_CP_STATE don't seem to need it saved. */
|
/* We can use a3 as a scratchpad, the instances of code calling XT_RTOS_CP_STATE don't seem to need it saved. */
|
||||||
getcoreid a3
|
getcoreid a3
|
||||||
slli a3, a3, 2 /* a3=coreid*4 */
|
|
||||||
movi a15, port_xSchedulerRunning /* if (port_xSchedulerRunning */
|
movi a15, port_xSchedulerRunning /* if (port_xSchedulerRunning */
|
||||||
add a15, a15, a3
|
addx4 a15, a3,a15
|
||||||
l32i a15, a15, 0
|
l32i a15, a15, 0
|
||||||
beqz a15, 1f
|
beqz a15, 1f
|
||||||
movi a15, port_interruptNesting /* && port_interruptNesting == 0 */
|
movi a15, port_interruptNesting /* && port_interruptNesting == 0 */
|
||||||
add a15, a15, a3
|
addx4 a15, a3, a15
|
||||||
l32i a15, a15, 0
|
l32i a15, a15, 0
|
||||||
bnez a15, 1f
|
bnez a15, 1f
|
||||||
|
|
||||||
movi a15, pxCurrentTCB
|
movi a15, pxCurrentTCB
|
||||||
add a15, a3, a15
|
addx4 a15, a3, a15
|
||||||
l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */
|
l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */
|
||||||
|
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user