mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'master' into feature/lwip_sntp_max_servers
This commit is contained in:
commit
e54523708d
4
.flake8
4
.flake8
@ -164,3 +164,7 @@ exclude =
|
||||
components/wifi_provisioning/python/wifi_constants_pb2.py,
|
||||
components/esp_local_ctrl/python/esp_local_ctrl_pb2.py,
|
||||
examples/provisioning/legacy/custom_config/components/custom_provisioning/python/custom_config_pb2.py,
|
||||
|
||||
per-file-ignores =
|
||||
# Sphinx conf.py files use star imports to setup config variables
|
||||
docs/conf_common.py: F405
|
||||
|
@ -48,10 +48,10 @@ variables:
|
||||
|
||||
# Docker images
|
||||
BOT_DOCKER_IMAGE_TAG: ":latest"
|
||||
ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v4.4-1-v2"
|
||||
ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v4.4-1-v3"
|
||||
ESP_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-env:v4.4-1"
|
||||
AFL_FUZZER_TEST_IMAGE: "$CI_DOCKER_REGISTRY/afl-fuzzer-test:v4.4-1-1"
|
||||
CLANG_STATIC_ANALYSIS_IMAGE: "${CI_DOCKER_REGISTRY}/clang-static-analysis:v4.4-1-1"
|
||||
CLANG_STATIC_ANALYSIS_IMAGE: "${CI_DOCKER_REGISTRY}/clang-static-analysis:v4.4-1-2"
|
||||
|
||||
# target test config file, used by assign test job
|
||||
CI_TARGET_TEST_CONFIG_FILE: "$CI_PROJECT_DIR/.gitlab/ci/target-test.yml"
|
||||
@ -66,7 +66,7 @@ variables:
|
||||
export IDF_MIRROR_PREFIX_MAP=
|
||||
fi
|
||||
if [[ "$SETUP_TOOLS" == "1" || "$CI_JOB_STAGE" != "target_test" ]]; then
|
||||
tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1
|
||||
tools/idf_tools.py --non-interactive install ${SETUP_TOOLS_LIST:-} && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1
|
||||
if [[ ! -z "$OOCD_DISTRO_URL" && "$CI_JOB_STAGE" == "target_test" ]]; then
|
||||
echo "Using custom OpenOCD from ${OOCD_DISTRO_URL}"
|
||||
wget $OOCD_DISTRO_URL
|
||||
|
@ -57,6 +57,7 @@
|
||||
/export.* @esp-idf-codeowners/tools
|
||||
/install.* @esp-idf-codeowners/tools
|
||||
/sdkconfig.rename @esp-idf-codeowners/build-config
|
||||
/sonar-project.properties @esp-idf-codeowners/ci
|
||||
|
||||
# sort-order-reset
|
||||
|
||||
@ -66,6 +67,7 @@
|
||||
/components/bootloader*/ @esp-idf-codeowners/system @esp-idf-codeowners/security
|
||||
/components/bt/ @esp-idf-codeowners/bluetooth
|
||||
/components/cbor/ @esp-idf-codeowners/app-utilities
|
||||
/components/cmock/ @esp-idf-codeowners/system
|
||||
/components/coap/ @esp-idf-codeowners/app-utilities
|
||||
/components/console/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
|
||||
/components/cxx/ @esp-idf-codeowners/system
|
||||
@ -132,6 +134,7 @@
|
||||
/components/tcp_transport/ @esp-idf-codeowners/network
|
||||
/components/tcpip_adapter/ @esp-idf-codeowners/network
|
||||
/components/tinyusb/ @esp-idf-codeowners/peripherals/usb
|
||||
/components/touch_element/ @esp-idf-codeowners/peripherals
|
||||
/components/ulp/ @esp-idf-codeowners/system
|
||||
/components/unity/ @esp-idf-codeowners/ci
|
||||
/components/usb/ @esp-idf-codeowners/peripherals/usb
|
||||
@ -182,6 +185,7 @@
|
||||
/tools/kconfig*/ @esp-idf-codeowners/build-config
|
||||
/tools/ldgen/ @esp-idf-codeowners/build-config
|
||||
/tools/mass_mfg/ @esp-idf-codeowners/app-utilities
|
||||
/tools/mocks/ @esp-idf-codeowners/system
|
||||
|
||||
## Note: owners here should be the same as the owners for the same example subdir, above
|
||||
/tools/test_apps/build_system/ @esp-idf-codeowners/build-config
|
||||
|
@ -344,6 +344,7 @@ build_docker:
|
||||
- .before_script_minimal
|
||||
- .rules:build:docker
|
||||
stage: host_test
|
||||
needs: []
|
||||
image: espressif/docker-builder:1
|
||||
tags:
|
||||
- build_docker_amd64_brno
|
||||
@ -366,6 +367,7 @@ build_docker:
|
||||
- .before_script_minimal
|
||||
- .rules:build:windows
|
||||
stage: host_test
|
||||
needs: []
|
||||
image: $CI_DOCKER_REGISTRY/esp32-toolchain-win-cross
|
||||
tags:
|
||||
- build
|
||||
@ -385,28 +387,6 @@ build_idf_exe:
|
||||
variables:
|
||||
TEST_DIR: tools/windows/idf_exe
|
||||
|
||||
build_cmdlinerunner:
|
||||
extends: .test-on-windows
|
||||
stage: host_test
|
||||
artifacts:
|
||||
paths:
|
||||
- tools/windows/tool_setup/cmdlinerunner/build/cmdlinerunner.dll
|
||||
expire_in: 4 days
|
||||
variables:
|
||||
TEST_DIR: tools/windows/tool_setup/cmdlinerunner
|
||||
|
||||
build_installer:
|
||||
extends: .test-on-windows
|
||||
# using a different stage here to be able to use artifacts from build_cmdlinerunner job
|
||||
stage: test_deploy # need to be after host_test since depends on `build_cmdlinerunner`
|
||||
image: $CI_DOCKER_REGISTRY/wine-innosetup:2
|
||||
dependencies: # set dependencies to null to avoid missing artifacts issue
|
||||
needs:
|
||||
- build_cmdlinerunner
|
||||
script:
|
||||
- cd tools/windows/tool_setup/
|
||||
- ./build_installer.sh
|
||||
|
||||
# This job builds template app with permutations of targets and optimization levels
|
||||
build_template_app:
|
||||
extends:
|
||||
|
@ -72,15 +72,6 @@ build:integration_test:
|
||||
# -------------
|
||||
# Special Cases
|
||||
# -------------
|
||||
"build:example_test-esp32":
|
||||
labels:
|
||||
- build
|
||||
- weekend_test # only have esp32 jobs
|
||||
- iperf_stress_test # only have esp32 jobs
|
||||
patterns:
|
||||
- build_components
|
||||
- build_system
|
||||
|
||||
"build:example_test-esp32c3": # esp32c3 test is only run by label, but build jobs should always be triggered
|
||||
labels:
|
||||
- build
|
||||
@ -167,13 +158,27 @@ build:integration_test:
|
||||
#################################
|
||||
# Triggered Only By Labels Jobs #
|
||||
#################################
|
||||
"labels:{0}":
|
||||
matrix:
|
||||
- [weekend_test, iperf_stress_test, nvs_coverage]
|
||||
"labels:iperf_stress_test": # example_test
|
||||
labels:
|
||||
- "{0}"
|
||||
- iperf_stress_test
|
||||
included_in:
|
||||
- build:example_test-esp32
|
||||
- build:target_test
|
||||
- test:any_test
|
||||
|
||||
"labels:fuzzer_test-weekend_test":
|
||||
"labels:weekend_test": # custom test
|
||||
labels:
|
||||
- weekend_test
|
||||
included_in:
|
||||
- build:custom_test-esp32
|
||||
- build:target_test
|
||||
- test:any_test
|
||||
|
||||
"labels:nvs_coverage": # host_test
|
||||
labels:
|
||||
- nvs_coverage
|
||||
|
||||
"labels:fuzzer_test-weekend_test": # host test
|
||||
labels:
|
||||
- fuzzer_test
|
||||
- weekend_test
|
||||
|
@ -31,7 +31,6 @@ deploy_test_result:
|
||||
- ${CI_PROJECT_DIR}/test-management/*.log
|
||||
# save all test logs as artifacts, make it easier to track errors
|
||||
- ${CI_PROJECT_DIR}/TEST_LOGS
|
||||
- $CI_PROJECT_DIR/$CI_COMMIT_SHA
|
||||
expire_in: 1 mos
|
||||
variables:
|
||||
UNIT_TEST_CASE_FILE: "${CI_PROJECT_DIR}/components/idf_test/unit_test/TestCaseAll.yml"
|
||||
@ -51,7 +50,7 @@ deploy_test_result:
|
||||
- cd test-management
|
||||
- echo $BOT_JIRA_ACCOUNT > ${BOT_ACCOUNT_CONFIG_FILE}
|
||||
# update test results
|
||||
- python3 ImportTestResult.py -r "$GIT_SHA (r${REV_COUNT})" -j $JIRA_TEST_MANAGEMENT_PROJECT -s "$SUMMARY" -l CI -p ${CI_PROJECT_DIR}/TEST_LOGS ${CI_PROJECT_DIR}/${CI_COMMIT_SHA} --pipeline_url ${CI_PIPELINE_URL}
|
||||
- python3 ImportTestResult.py -r "$GIT_SHA (r${REV_COUNT})" -j $JIRA_TEST_MANAGEMENT_PROJECT -s "$SUMMARY" -l CI -p ${CI_PROJECT_DIR}/TEST_LOGS --pipeline_url ${CI_PIPELINE_URL}
|
||||
|
||||
check_submodule_sync:
|
||||
extends:
|
||||
|
@ -39,7 +39,6 @@
|
||||
check_readme_links:
|
||||
extends:
|
||||
- .pre_check_job_template
|
||||
- .doc-rules:build:docs
|
||||
tags: ["build", "amd64", "internet"]
|
||||
allow_failure: true
|
||||
script:
|
||||
@ -62,8 +61,8 @@ check_docs_lang_sync:
|
||||
dependencies: []
|
||||
script:
|
||||
- cd docs
|
||||
- python -m pip install -r requirements.txt
|
||||
- python ./build_docs.py -bs $DOC_BUILDERS -l $DOCLANG -t $DOCTGT build
|
||||
- pip install -r requirements.txt
|
||||
- build-docs -t $DOCTGT -bs $DOC_BUILDERS -l $DOCLANG build
|
||||
parallel:
|
||||
matrix:
|
||||
- DOCLANG: ["en", "zh_CN"]
|
||||
@ -78,8 +77,8 @@ check_docs_gh_links:
|
||||
- .doc-rules:build:docs
|
||||
script:
|
||||
- cd docs
|
||||
- python -m pip install -r requirements.txt
|
||||
- python ./build_docs.py gh-linkcheck
|
||||
- pip install -r requirements.txt
|
||||
- build-docs gh-linkcheck
|
||||
|
||||
# stage: build_doc
|
||||
# Add this stage to let the build_docs job run in parallel with build
|
||||
@ -168,7 +167,8 @@ build_docs_pdf:
|
||||
script:
|
||||
- add_doc_server_ssh_keys $DOCS_DEPLOY_PRIVATEKEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER
|
||||
- export GIT_VER=$(git describe --always)
|
||||
- python ${IDF_PATH}/tools/ci/deploy_docs.py
|
||||
- pip install -r docs/requirements.txt
|
||||
- deploy-docs
|
||||
|
||||
# stage: test_deploy
|
||||
deploy_docs_preview:
|
||||
@ -227,6 +227,6 @@ check_doc_links:
|
||||
allow_failure: true
|
||||
script:
|
||||
- cd docs
|
||||
- python -m pip install -r requirements.txt
|
||||
- pip install -r requirements.txt
|
||||
# At the moment this check will always fail due to multiple known limitations, ignore result
|
||||
- python ./build_docs.py -l $DOCLANG -t $DOCTGT linkcheck || { echo "THERE ARE ISSUES DUE TO KNOWN LIMITATIONS, PLEASE FIX THEM. Nowadays we're ignored them to pass pipeline."; true; }
|
||||
- build-docs -t $DOCTGT -l $DOCLANG linkcheck || { echo "THERE ARE ISSUES DUE TO KNOWN LIMITATIONS, PLEASE FIX THEM. Nowadays we're ignored them to pass pipeline."; true; }
|
||||
|
@ -196,73 +196,66 @@ test_idf_tools:
|
||||
- cd ${IDF_PATH}/tools
|
||||
- python3 ./idf_tools.py install-python-env
|
||||
|
||||
test_esp32_efuse_table_on_host:
|
||||
.test_efuse_table_on_host_template:
|
||||
extends: .host_test_template
|
||||
variables:
|
||||
IDF_TARGET: "esp32"
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- components/efuse/esp32/esp_efuse_table.c
|
||||
- components/efuse/${IDF_TARGET}/esp_efuse_table.c
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/efuse/
|
||||
- ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv
|
||||
- git diff --exit-code -- esp32/esp_efuse_table.c || { echo 'Differences found for esp32 target. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; }
|
||||
- ./efuse_table_gen.py -t "${IDF_TARGET}" ${IDF_PATH}/components/efuse/${IDF_TARGET}/esp_efuse_table.csv
|
||||
- git diff --exit-code -- ${IDF_TARGET}/esp_efuse_table.c || { echo 'Differences found for ${IDF_TARGET} target. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; }
|
||||
- cd ${IDF_PATH}/components/efuse/test_efuse_host
|
||||
- ./efuse_tests.py
|
||||
|
||||
test_esp32s2_efuse_table_on_host:
|
||||
extends: .host_test_template
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- components/efuse/esp32s2/esp_efuse_table.c
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/efuse/
|
||||
- ./efuse_table_gen.py -t "esp32s2" ${IDF_PATH}/components/efuse/esp32s2/esp_efuse_table.csv
|
||||
- git diff --exit-code -- esp32s2/esp_efuse_table.c || { echo 'Differences found for esp32s2 target. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; }
|
||||
- cd ${IDF_PATH}/components/efuse/test_efuse_host
|
||||
- ./efuse_tests.py
|
||||
test_efuse_table_on_host_esp32:
|
||||
extends: .test_efuse_table_on_host_template
|
||||
|
||||
test_esp32s3_efuse_table_on_host:
|
||||
extends: .host_test_template
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- components/efuse/esp32s3/esp_efuse_table.c
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/efuse/
|
||||
- ./efuse_table_gen.py -t "esp32s3" ${IDF_PATH}/components/efuse/esp32s3/esp_efuse_table.csv
|
||||
- git diff --exit-code -- esp32s3/esp_efuse_table.c || { echo 'Differences found for esp32s3 target. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; }
|
||||
- cd ${IDF_PATH}/components/efuse/test_efuse_host
|
||||
- ./efuse_tests.py
|
||||
test_efuse_table_on_host_esp32s2:
|
||||
extends: .test_efuse_table_on_host_template
|
||||
variables:
|
||||
IDF_TARGET: esp32s2
|
||||
|
||||
test_esp32c3_efuse_table_on_host:
|
||||
extends: .host_test_template
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- components/efuse/esp32c3/esp_efuse_table.c
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/efuse/
|
||||
- ./efuse_table_gen.py -t "esp32c3" ${IDF_PATH}/components/efuse/esp32c3/esp_efuse_table.csv
|
||||
- git diff --exit-code -- esp32c3/esp_efuse_table.c || { echo 'Differences found for esp32c3 target. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; }
|
||||
- cd ${IDF_PATH}/components/efuse/test_efuse_host
|
||||
- ./efuse_tests.py
|
||||
test_efuse_table_on_host_esp32s2:
|
||||
extends: .test_efuse_table_on_host_template
|
||||
variables:
|
||||
IDF_TARGET: esp32s2
|
||||
|
||||
test_efuse_table_on_host_esp32s3:
|
||||
extends: .test_efuse_table_on_host_template
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
|
||||
test_efuse_table_on_host_esp32c3:
|
||||
extends: .test_efuse_table_on_host_template
|
||||
variables:
|
||||
IDF_TARGET: esp32c3
|
||||
|
||||
test_efuse_table_on_host_esp32h2:
|
||||
extends: .test_efuse_table_on_host_template
|
||||
variables:
|
||||
IDF_TARGET: esp32h2
|
||||
|
||||
test_espcoredump:
|
||||
extends: .host_test_template
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- components/espcoredump/test/.coverage
|
||||
- components/espcoredump/test/output
|
||||
- components/espcoredump/test/**/.coverage
|
||||
- components/espcoredump/test/**/output
|
||||
expire_in: 1 week
|
||||
variables:
|
||||
IDF_COREDUMP_ELF_REPO: "https://gitlab-ci-token:${BOT_TOKEN}@${CI_SERVER_HOST}:${CI_SERVER_PORT}/idf/idf-coredump-elf.git"
|
||||
# install CMake version specified in tools.json
|
||||
SETUP_TOOLS_LIST: "all"
|
||||
script:
|
||||
- cd components/espcoredump/test/
|
||||
- ./test_espcoredump.sh
|
||||
- retry_failed git clone ${IDF_COREDUMP_ELF_REPO} -b master
|
||||
- cd ${IDF_PATH}/components/espcoredump/test/
|
||||
- ./test_espcoredump.sh ${CI_PROJECT_DIR}/idf-coredump-elf
|
||||
|
||||
test_logtrace_proc:
|
||||
extends: .host_test_template
|
||||
@ -302,22 +295,6 @@ test_mkuf2:
|
||||
- cd ${IDF_PATH}/tools/test_mkuf2
|
||||
- ./test_mkuf2.py
|
||||
|
||||
test_docs:
|
||||
extends: .host_test_template
|
||||
image: $ESP_IDF_DOC_ENV_IMAGE
|
||||
variables:
|
||||
PYTHON_VER: 3.6.13
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- docs/test/_build/*/*/*/html/*
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd ${IDF_PATH}/docs/test
|
||||
- python -m pip install -r ${IDF_PATH}/docs/requirements.txt
|
||||
- ./test_docs.py
|
||||
- ./test_sphinx_idf_extensions.py
|
||||
|
||||
test_autocomplete:
|
||||
extends: .host_test_template
|
||||
image: $CI_DOCKER_REGISTRY/linux-shells:1
|
||||
@ -347,7 +324,7 @@ test_nvs_page:
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/nvs_flash/host_test/nvs_page_test
|
||||
- idf.py build
|
||||
- build/host_nvs_page_test.elf
|
||||
- build/test_nvs_page_host.elf
|
||||
|
||||
test_log:
|
||||
extends: .host_test_template
|
||||
@ -356,9 +333,37 @@ test_log:
|
||||
- idf.py build
|
||||
- build/test_log_host.elf
|
||||
|
||||
test_esp_event:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/esp_event/host_test/esp_event_unit_test
|
||||
- idf.py build
|
||||
- build/test_esp_event_host.elf
|
||||
|
||||
test_esp_timer_cxx:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
- cd ${IDF_PATH}/examples/cxx/experimental/experimental_cpp_component/host_test/esp_timer
|
||||
- idf.py build
|
||||
- build/test_esp_timer_cxx_host.elf
|
||||
|
||||
test_eh_frame_parser:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/esp_system/test_eh_frame_parser
|
||||
- make
|
||||
- ./eh_frame_test
|
||||
|
||||
test_rom_on_linux_works:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/esp_rom/host_test/rom_test
|
||||
- idf.py build
|
||||
- build/test_rom_host.elf
|
||||
|
||||
test_cxx_gpio:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
- cd ${IDF_PATH}/examples/cxx/experimental/experimental_cpp_component/host_test/gpio
|
||||
- idf.py build
|
||||
- build/test_gpio_cxx_host.elf
|
||||
|
@ -3,7 +3,10 @@
|
||||
############
|
||||
.patterns-c-files: &patterns-c-files
|
||||
- ".gitlab/ci/static-code-analysis.yml"
|
||||
|
||||
- "tools/ci/static-analysis-rules.yml"
|
||||
- "tools/ci/clang_tidy_dirs.txt"
|
||||
|
||||
- "**/*.{c,C}"
|
||||
- "**/*.{h,H}"
|
||||
- "components/**/Kconfig"
|
||||
@ -13,6 +16,9 @@
|
||||
- ".gitlab/ci/static-code-analysis.yml"
|
||||
- "**/*.py"
|
||||
|
||||
.patterns-sonarqube-files: &patterns-sonarqube-files
|
||||
- "tools/ci/sonar_exclude_list.txt"
|
||||
|
||||
.patterns-example_test: &patterns-example_test
|
||||
- "tools/ci/python_packages/gitlab_api.py"
|
||||
- "tools/ci/python_packages/idf_http_server_test/**/*"
|
||||
@ -34,11 +40,13 @@
|
||||
|
||||
.patterns-build_components: &patterns-build_components
|
||||
- "components/**/*"
|
||||
- "examples/cxx/experimental/experimental_cpp_component/*"
|
||||
|
||||
.patterns-build_system: &patterns-build_system
|
||||
- "tools/cmake/**/*"
|
||||
- "tools/kconfig_new/**/*"
|
||||
- "tools/tools.json"
|
||||
- "tools/ci/test_build_system*.sh"
|
||||
|
||||
.patterns-custom_test: &patterns-custom_test
|
||||
- "components/espcoredump/**/*"
|
||||
@ -84,6 +92,9 @@
|
||||
|
||||
.patterns-host_test: &patterns-host_test
|
||||
- ".gitlab/ci/host-test.yml"
|
||||
|
||||
- "components/**/*"
|
||||
|
||||
- "tools/ci/test_autocomplete.py"
|
||||
- "tools/ci/test_build_system.sh"
|
||||
- "tools/ci/test_build_system_cmake.sh"
|
||||
@ -91,7 +102,6 @@
|
||||
- "tools/ci/test_configure_ci_environment.sh"
|
||||
|
||||
- "tools/mass_mfg/**/*"
|
||||
- "components/nvs_flash/test_nvs_host/**/*"
|
||||
|
||||
- "tools/esp_app_trace/**/*"
|
||||
- "tools/ldgen/**/*"
|
||||
@ -107,6 +117,7 @@
|
||||
- "tools/idf_size.py"
|
||||
- "tools/test_idf_size/**/*"
|
||||
|
||||
- "tools/tools.json"
|
||||
- "tools/tools_schema.json"
|
||||
- "tools/idf_tools.py"
|
||||
- "tools/test_idf_tools/**/*"
|
||||
@ -234,6 +245,8 @@
|
||||
changes: *patterns-c-files
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-python-files
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-sonarqube-files
|
||||
|
||||
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
# DO NOT place comments or maintain any code from this line
|
||||
@ -418,6 +431,7 @@
|
||||
- <<: *if-label-build
|
||||
- <<: *if-label-custom_test
|
||||
- <<: *if-label-custom_test_esp32
|
||||
- <<: *if-label-weekend_test
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-build_components
|
||||
- <<: *if-dev-push
|
||||
@ -479,7 +493,6 @@
|
||||
- <<: *if-label-example_test
|
||||
- <<: *if-label-example_test_esp32
|
||||
- <<: *if-label-iperf_stress_test
|
||||
- <<: *if-label-weekend_test
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-build-example_test
|
||||
- <<: *if-dev-push
|
||||
@ -575,11 +588,13 @@
|
||||
- <<: *if-label-example_test_esp32s2
|
||||
- <<: *if-label-example_test_esp32s3
|
||||
- <<: *if-label-integration_test
|
||||
- <<: *if-label-iperf_stress_test
|
||||
- <<: *if-label-unit_test
|
||||
- <<: *if-label-unit_test_esp32
|
||||
- <<: *if-label-unit_test_esp32c3
|
||||
- <<: *if-label-unit_test_esp32s2
|
||||
- <<: *if-label-unit_test_esp32s3
|
||||
- <<: *if-label-weekend_test
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-build-example_test
|
||||
- <<: *if-dev-push
|
||||
@ -703,11 +718,13 @@
|
||||
- <<: *if-label-example_test_esp32s3
|
||||
- <<: *if-label-host_test
|
||||
- <<: *if-label-integration_test
|
||||
- <<: *if-label-iperf_stress_test
|
||||
- <<: *if-label-unit_test
|
||||
- <<: *if-label-unit_test_esp32
|
||||
- <<: *if-label-unit_test_esp32c3
|
||||
- <<: *if-label-unit_test_esp32s2
|
||||
- <<: *if-label-unit_test_esp32s3
|
||||
- <<: *if-label-weekend_test
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-build-example_test
|
||||
- <<: *if-dev-push
|
||||
|
@ -5,17 +5,46 @@ clang_tidy_check:
|
||||
- .rules:patterns:clang_tidy
|
||||
image: ${CLANG_STATIC_ANALYSIS_IMAGE}
|
||||
artifacts:
|
||||
reports:
|
||||
junit: $IDF_PATH/output.xml
|
||||
paths:
|
||||
- $OUTPUT_DIR
|
||||
when: always
|
||||
expire_in: 1 day
|
||||
variables:
|
||||
CLANG_TIDY_RUNNER_PROJ: 2107 # idf/clang-tidy-runner
|
||||
CLANG_TIDY_DIRS_TXT: ${CI_PROJECT_DIR}/tools/ci/clang_tidy_dirs.txt
|
||||
RULES_FILE: ${CI_PROJECT_DIR}/tools/ci/static-analysis-rules.yml
|
||||
OUTPUT_DIR: ${CI_PROJECT_DIR}/clang_tidy_reports
|
||||
script:
|
||||
- python -m pip install -U pip
|
||||
- internal_pip_install $CLANG_TIDY_RUNNER_PROJ pyclang
|
||||
- export PATH=$PATH:$(python -c "import sys; print(sys.executable.rsplit('/', 1)[0])")
|
||||
- dirs=$(cat ${CLANG_TIDY_DIRS_TXT} | while read line; do echo ${CI_PROJECT_DIR}/${line}; done | xargs)
|
||||
- run_cmd idf_clang ${dirs}
|
||||
--output-path ${OUTPUT_DIR}
|
||||
--limit-file ${RULES_FILE}
|
||||
--xtensa-include-dir
|
||||
--run-clang-tidy-py ${RUN_CLANG_TIDY_PY}
|
||||
|
||||
check_pylint:
|
||||
extends:
|
||||
- .pre_check_base_template
|
||||
- .rules:patterns:python-files
|
||||
- .before_script_minimal
|
||||
image: $CI_DOCKER_REGISTRY/sonarqube-scanner:2
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- $IDF_PATH/examples/get-started/hello_world/tidybuild/report/*
|
||||
expire_in: 1 day
|
||||
- pylint-report.txt
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- retry_failed git clone $IDF_ANALYSIS_UTILS static_analysis_utils && cd static_analysis_utils
|
||||
# Setup parameters of triggered/regular job
|
||||
- export TARGET_BRANCH=${BOT_CUSTOMIZED_REVISION-}
|
||||
- ./analyze.sh $IDF_PATH/examples/get-started/hello_world/ $IDF_PATH/tools/ci/static-analysis-rules.yml $IDF_PATH/output.xml
|
||||
- export PYTHONPATH="$IDF_PATH/tools:$IDF_PATH/tools/ci/python_packages:$PYTHONPATH"
|
||||
- |
|
||||
if [ -n "$CI_MERGE_REQUEST_IID" ]; then
|
||||
export files=$(python ${CI_PROJECT_DIR}/tools/ci/ci_get_mr_info.py files ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} | grep ".py");
|
||||
else
|
||||
export files=$(find . -iname "*.py" -print);
|
||||
fi
|
||||
- pylint --rcfile=.pylintrc $files -r n --output-format=parseable > pylint-report.txt || exit 0
|
||||
|
||||
# build stage
|
||||
# Sonarqube related jobs put here for this reason:
|
||||
@ -38,21 +67,18 @@ clang_tidy_check:
|
||||
- source tools/ci/utils.sh
|
||||
- export PYTHONPATH="$CI_PROJECT_DIR/tools:$CI_PROJECT_DIR/tools/ci/python_packages:$PYTHONPATH"
|
||||
- fetch_submodules
|
||||
# Exclude the submodules, all paths ends with /**
|
||||
- export SUBMODULES=$(get_all_submodules)
|
||||
# get all exclude paths specified in tools/ci/sonar_exclude_list.txt | ignore lines start with # | xargs | replace all <space> to <comma>
|
||||
- export CUSTOM_EXCLUDES=$(cat $CI_PROJECT_DIR/tools/ci/sonar_exclude_list.txt | grep -v '^#' | xargs | sed -e 's/ /,/g')
|
||||
# Exclude the report dir
|
||||
- export EXCLUSIONS="$SUBMODULES,$REPORT_DIR/**,docs/_static/**,**/*.png,**/*.jpg"
|
||||
- python $NORMALIZE_CLANGTIDY_PY $CI_PROJECT_DIR/$REPORT_DIR/warnings.txt $CI_PROJECT_DIR/$REPORT_DIR/clang_tidy_report.txt $CI_PROJECT_DIR
|
||||
variables:
|
||||
GIT_DEPTH: 0
|
||||
NORMALIZE_CLANGTIDY_PY: $CI_PROJECT_DIR/tools/ci/normalize_clangtidy_path.py
|
||||
REPORT_DIR: examples/get-started/hello_world/tidybuild/report
|
||||
REPORT_PATTERN: clang_tidy_reports/*.txt
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- $REPORT_PATTERN
|
||||
tags:
|
||||
- host_test
|
||||
dependencies: # Here is not a hard dependency relationship, could be skipped when only python files changed. so we do not use "needs" here.
|
||||
- clang_tidy_check
|
||||
- check_pylint
|
||||
|
||||
code_quality_check:
|
||||
extends:
|
||||
@ -67,23 +93,14 @@ code_quality_check:
|
||||
- test -n "$CI_MERGE_REQUEST_COMMITS" || exit 0
|
||||
- sonar-scanner
|
||||
-Dsonar.analysis.mode=preview
|
||||
-Dsonar.branch.name=$CI_COMMIT_REF_NAME
|
||||
-Dsonar.cxx.clangtidy.reportPath=$REPORT_DIR/clang_tidy_report.txt
|
||||
-Dsonar.cxx.includeDirectories=components,/usr/include
|
||||
-Dsonar.exclusions=$EXCLUSIONS
|
||||
-Dsonar.branch.name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
|
||||
-Dsonar.cxx.clangtidy.reportPath=$REPORT_PATTERN
|
||||
-Dsonar.gitlab.ci_merge_request_iid=$CI_MERGE_REQUEST_IID
|
||||
-Dsonar.gitlab.commit_sha=$CI_MERGE_REQUEST_COMMITS
|
||||
-Dsonar.gitlab.failure_notification_mode=exit-code
|
||||
-Dsonar.gitlab.merge_request_discussion=true
|
||||
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
|
||||
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
|
||||
-Dsonar.gitlab.ref_name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
|
||||
-Dsonar.host.url=$SONAR_HOST_URL
|
||||
-Dsonar.login=$SONAR_LOGIN
|
||||
-Dsonar.projectBaseDir=$CI_PROJECT_DIR
|
||||
-Dsonar.projectKey=esp-idf
|
||||
-Dsonar.python.pylint_config=.pylintrc
|
||||
-Dsonar.sourceEncoding=UTF-8
|
||||
-Dsonar.sources=$CI_PROJECT_DIR
|
||||
-Dsonar.python.pylint.reportPath=pylint-report.txt
|
||||
|
||||
code_quality_report:
|
||||
extends:
|
||||
@ -94,41 +111,9 @@ code_quality_report:
|
||||
script:
|
||||
- sonar-scanner
|
||||
-Dsonar.branch.name=$CI_COMMIT_REF_NAME
|
||||
-Dsonar.cxx.clangtidy.reportPath=$REPORT_DIR/clang_tidy_report.txt
|
||||
-Dsonar.cxx.includeDirectories=components,/usr/include
|
||||
-Dsonar.exclusions=$EXCLUSIONS
|
||||
-Dsonar.cxx.clangtidy.reportPath=$REPORT_PATTERN
|
||||
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
|
||||
-Dsonar.gitlab.failure_notification_mode=exit-code
|
||||
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
|
||||
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
|
||||
-Dsonar.host.url=$SONAR_HOST_URL
|
||||
-Dsonar.login=$SONAR_LOGIN
|
||||
-Dsonar.projectBaseDir=$CI_PROJECT_DIR
|
||||
-Dsonar.projectKey=esp-idf
|
||||
-Dsonar.python.pylint_config=.pylintrc
|
||||
-Dsonar.sourceEncoding=UTF-8
|
||||
-Dsonar.sources=$CI_PROJECT_DIR
|
||||
|
||||
# deploy stage
|
||||
clang_tidy_deploy:
|
||||
extends:
|
||||
- .deploy_job_template
|
||||
- .rules:patterns:clang_tidy
|
||||
needs:
|
||||
- clang_tidy_check
|
||||
tags:
|
||||
- deploy
|
||||
- shiny
|
||||
script:
|
||||
- add_doc_server_ssh_keys $DOCS_DEPLOY_KEY $DOCS_SERVER $DOCS_SERVER_USER
|
||||
- export GIT_VER=$(git describe --always)
|
||||
- cd $IDF_PATH/examples/get-started/hello_world/tidybuild
|
||||
- mv report $GIT_VER
|
||||
- tar czvf $GIT_VER.tar.gz $GIT_VER
|
||||
- export STATIC_REPORT_PATH="web/static_analysis/esp-idf/"
|
||||
- ssh $DOCS_SERVER -x "mkdir -p $STATIC_REPORT_PATH/clang-tidy"
|
||||
- scp $GIT_VER.tar.gz $DOCS_SERVER:$STATIC_REPORT_PATH/clang-tidy
|
||||
- ssh $DOCS_SERVER -x "cd $STATIC_REPORT_PATH/clang-tidy && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest"
|
||||
# add link to view the report
|
||||
- echo "[static analysis][clang tidy] $CI_DOCKER_REGISTRY/static_analysis/esp-idf/clang-tidy/${GIT_VER}/index.html"
|
||||
- test ! -e ${GIT_VER}/FAILED_RULES || { echo 'Failed static analysis rules!'; cat ${GIT_VER}/FAILED_RULES; exit 1; }
|
||||
-Dsonar.python.pylint.reportPath=pylint-report.txt
|
||||
|
@ -97,7 +97,7 @@ example_test_001B_V3:
|
||||
|
||||
example_test_001C:
|
||||
extends: .example_test_esp32_template
|
||||
parallel: 3
|
||||
parallel: 4
|
||||
tags:
|
||||
- ESP32
|
||||
- Example_GENERIC
|
||||
@ -129,6 +129,12 @@ example_test_002:
|
||||
- ESP32
|
||||
- Example_ShieldBox_Basic
|
||||
|
||||
example_test_enternet:
|
||||
extends: .example_test_esp32_template
|
||||
tags:
|
||||
- ESP32
|
||||
- Example_Ethernet
|
||||
|
||||
.example_test_003:
|
||||
extends: .example_test_esp32_template
|
||||
tags:
|
||||
@ -441,7 +447,7 @@ UT_001:
|
||||
|
||||
UT_002:
|
||||
extends: .unit_test_esp32_template
|
||||
parallel: 16
|
||||
parallel: 14
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
@ -476,7 +482,7 @@ UT_006:
|
||||
|
||||
UT_007:
|
||||
extends: .unit_test_esp32_template
|
||||
parallel: 2
|
||||
parallel: 3
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
@ -502,19 +508,6 @@ UT_014:
|
||||
- UT_T2_RS485
|
||||
- psram
|
||||
|
||||
UT_015:
|
||||
extends: .unit_test_esp32_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_RMT
|
||||
|
||||
UT_016:
|
||||
extends: .unit_test_esp32_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_RMT
|
||||
- psram
|
||||
|
||||
UT_017:
|
||||
extends: .unit_test_esp32_template
|
||||
tags:
|
||||
@ -538,7 +531,6 @@ UT_020:
|
||||
|
||||
UT_021:
|
||||
extends: .unit_test_esp32_template
|
||||
parallel: 2
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- psram
|
||||
@ -573,7 +565,7 @@ UT_033:
|
||||
|
||||
UT_034:
|
||||
extends: .unit_test_esp32_template
|
||||
parallel: 3
|
||||
parallel: 2
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_ESP_FLASH
|
||||
@ -601,7 +593,7 @@ UT_036:
|
||||
|
||||
UT_038:
|
||||
extends: .unit_test_esp32s2_template
|
||||
parallel: 3
|
||||
parallel: 2
|
||||
tags:
|
||||
- ESP32S2_IDF
|
||||
- UT_T1_ESP_FLASH
|
||||
@ -646,9 +638,15 @@ UT_047:
|
||||
- ESP32S2_IDF
|
||||
- UT_T1_1
|
||||
|
||||
UT_S2_SPI_DUAL:
|
||||
extends: .unit_test_esp32s2_template
|
||||
tags:
|
||||
- ESP32S2_IDF
|
||||
- Example_SPI_Multi_device
|
||||
|
||||
UT_C3:
|
||||
extends: .unit_test_esp32c3_template
|
||||
parallel: 33
|
||||
parallel: 32
|
||||
tags:
|
||||
- ESP32C3_IDF
|
||||
- UT_T1_1
|
||||
@ -662,7 +660,6 @@ UT_C3_FLASH:
|
||||
|
||||
UT_C3_SPI_DUAL:
|
||||
extends: .unit_test_esp32c3_template
|
||||
parallel: 2
|
||||
tags:
|
||||
- ESP32C3_IDF
|
||||
- Example_SPI_Multi_device
|
||||
@ -687,11 +684,24 @@ UT_C3_FLASH_SUSPEND:
|
||||
|
||||
UT_S3:
|
||||
extends: .unit_test_esp32s3_template
|
||||
parallel: 26
|
||||
parallel: 27
|
||||
tags:
|
||||
- ESP32S3_IDF
|
||||
- UT_T1_1
|
||||
|
||||
UT_S3_SPI_DUAL:
|
||||
extends: .unit_test_esp32s3_template
|
||||
tags:
|
||||
- ESP32S3_IDF
|
||||
- Example_SPI_Multi_device
|
||||
|
||||
UT_S3_FLASH:
|
||||
extends: .unit_test_esp32s3_template
|
||||
parallel: 2
|
||||
tags:
|
||||
- ESP32S3_IDF
|
||||
- UT_T1_ESP_FLASH
|
||||
|
||||
.integration_test_template:
|
||||
extends:
|
||||
- .target_test_job_template
|
||||
@ -701,7 +711,7 @@ UT_S3:
|
||||
- build_ssc_esp32
|
||||
variables:
|
||||
LOCAL_ENV_CONFIG_PATH: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/ESP32_IDF"
|
||||
LOG_PATH: "${CI_PROJECT_DIR}/${CI_COMMIT_SHA}"
|
||||
LOG_PATH: "${CI_PROJECT_DIR}/TEST_LOGS"
|
||||
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/auto_test_script/TestCaseFiles"
|
||||
MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/components/idf_test/ModuleDefinition.yml"
|
||||
CONFIG_FILE_PATH: "${CI_PROJECT_DIR}/components/idf_test/integration_test/CIConfigs"
|
||||
|
@ -56,7 +56,6 @@ Related Documents
|
||||
style-guide
|
||||
install-pre-commit-hook
|
||||
documenting-code
|
||||
add-ons-reference
|
||||
creating-examples
|
||||
../api-reference/template
|
||||
contributor-agreement
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
* [English Version](./README.md)
|
||||
|
||||
ESP-IDF 是由乐鑫官方针对乐鑫各系列芯片产品(发布于 2016 年后<sup>[1](#fn1)</sup>)推出的开发框架,支持 Windows、Linux 和 macOS 操作系统。
|
||||
ESP-IDF 是乐鑫官方推出的开发框架,适用于 2016 年之后发布的系列芯片<sup>[1](#fn1)</sup>,支持 Windows、Linux 和 macOS 操作系统。
|
||||
|
||||
# 使用 ESP-IDF 进行开发
|
||||
|
||||
## 搭建 ESP-IDF 开发环境
|
||||
|
||||
关于不同芯片如何搭建 ESP-IDF 的开发环境,请参考 https://idf.espressif.com/。
|
||||
关于不同芯片如何搭建 ESP-IDF 的开发环境,请参考 https://idf.espressif.com/ 。
|
||||
|
||||
**注意:** 不同系列芯片和不同 ESP-IDF 版本都有其对应的文档。请参阅[版本](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/versions.html)部分,获得关于如何查找文档以及如何检出 ESP-IDF 的特定发行版的详细信息。
|
||||
|
||||
|
@ -47,7 +47,7 @@ endif()
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
PRIV_INCLUDE_DIRS "${priv_include_dirs}"
|
||||
PRIV_REQUIRES soc
|
||||
PRIV_REQUIRES soc esp_ipc
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
||||
# disable --coverage for this component, as it is used as transport
|
||||
|
@ -14,7 +14,9 @@
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/timer_periph.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "esp_private/dbg_stubs.h"
|
||||
#include "esp_ipc.h"
|
||||
#include "hal/wdt_hal.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/libc_stubs.h"
|
||||
@ -28,128 +30,113 @@
|
||||
|
||||
#include "esp_log.h"
|
||||
const static char *TAG = "esp_gcov_rtio";
|
||||
static volatile bool s_create_gcov_task = false;
|
||||
static volatile bool s_gcov_task_running = false;
|
||||
|
||||
extern void __gcov_dump(void);
|
||||
extern void __gcov_reset(void);
|
||||
|
||||
static struct syscall_stub_table s_gcov_stub_table;
|
||||
|
||||
|
||||
static int gcov_stub_lock_try_acquire_recursive(_lock_t *lock)
|
||||
void gcov_dump_task(void *pvParameter)
|
||||
{
|
||||
if (*lock && uxSemaphoreGetCount((xSemaphoreHandle)(*lock)) == 0) {
|
||||
// we can do nothing here, gcov dump is initiated with some resource locked
|
||||
// which is also used by gcov functions
|
||||
ESP_EARLY_LOGE(TAG, "Lock 0x%x is busy during GCOV dump! System state can be inconsistent after dump!", lock);
|
||||
}
|
||||
return pdTRUE;
|
||||
}
|
||||
int dump_result = 0;
|
||||
bool *running = (bool *)pvParameter;
|
||||
|
||||
static void gcov_stub_lock_acquire_recursive(_lock_t *lock)
|
||||
{
|
||||
gcov_stub_lock_try_acquire_recursive(lock);
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "%s stack use in %d", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));
|
||||
|
||||
static void gcov_stub_lock_release_recursive(_lock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static int esp_dbg_stub_gcov_dump_do(void)
|
||||
{
|
||||
int ret = ESP_OK;
|
||||
FILE* old_stderr = stderr;
|
||||
FILE* old_stdout = stdout;
|
||||
static struct syscall_stub_table *old_tables[portNUM_PROCESSORS];
|
||||
|
||||
old_tables[0] = syscall_table_ptr_pro;
|
||||
#if portNUM_PROCESSORS > 1
|
||||
old_tables[1] = syscall_table_ptr_app;
|
||||
#endif
|
||||
ESP_EARLY_LOGV(TAG, "Alloc apptrace down buf %d bytes", ESP_GCOV_DOWN_BUF_SIZE);
|
||||
void *down_buf = malloc(ESP_GCOV_DOWN_BUF_SIZE);
|
||||
if (down_buf == NULL) {
|
||||
ESP_EARLY_LOGE(TAG, "Could not allocate memory for the buffer");
|
||||
return ESP_ERR_NO_MEM;
|
||||
dump_result = ESP_ERR_NO_MEM;
|
||||
goto gcov_exit;
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "Config apptrace down buf");
|
||||
esp_apptrace_down_buffer_config(down_buf, ESP_GCOV_DOWN_BUF_SIZE);
|
||||
/* we are directing the std outputs to the fake ones in order to reduce stack usage */
|
||||
FILE *old_stderr = stderr;
|
||||
FILE *old_stdout = stdout;
|
||||
stderr = (FILE *) &__sf_fake_stderr;
|
||||
stdout = (FILE *) &__sf_fake_stdout;
|
||||
ESP_EARLY_LOGV(TAG, "Dump data...");
|
||||
// incase of dual-core chip APP and PRO CPUs share the same table, so it is safe to save only PRO's table
|
||||
memcpy(&s_gcov_stub_table, syscall_table_ptr_pro, sizeof(s_gcov_stub_table));
|
||||
s_gcov_stub_table._lock_acquire_recursive = &gcov_stub_lock_acquire_recursive;
|
||||
s_gcov_stub_table._lock_release_recursive = &gcov_stub_lock_release_recursive;
|
||||
s_gcov_stub_table._lock_try_acquire_recursive = &gcov_stub_lock_try_acquire_recursive,
|
||||
syscall_table_ptr_pro = &s_gcov_stub_table;
|
||||
#if portNUM_PROCESSORS > 1
|
||||
syscall_table_ptr_app = &s_gcov_stub_table;
|
||||
#endif
|
||||
stderr = (FILE*) &__sf_fake_stderr;
|
||||
stdout = (FILE*) &__sf_fake_stdout;
|
||||
__gcov_dump();
|
||||
// reset dump status to allow incremental data accumulation
|
||||
__gcov_reset();
|
||||
stdout = old_stdout;
|
||||
stderr = old_stderr;
|
||||
syscall_table_ptr_pro = old_tables[0];
|
||||
#if portNUM_PROCESSORS > 1
|
||||
syscall_table_ptr_app = old_tables[1];
|
||||
#endif
|
||||
ESP_EARLY_LOGV(TAG, "Free apptrace down buf");
|
||||
free(down_buf);
|
||||
stderr = old_stderr;
|
||||
stdout = old_stdout;
|
||||
ESP_EARLY_LOGV(TAG, "Finish file transfer session");
|
||||
ret = esp_apptrace_fstop(ESP_APPTRACE_DEST_TRAX);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", ret);
|
||||
dump_result = esp_apptrace_fstop(ESP_APPTRACE_DEST_TRAX);
|
||||
if (dump_result != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", dump_result);
|
||||
}
|
||||
|
||||
gcov_exit:
|
||||
ESP_EARLY_LOGV(TAG, "dump_result %d", dump_result);
|
||||
if (running) {
|
||||
*running = false;
|
||||
}
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "%s stack use out %d", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void gcov_create_task(void *arg)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
|
||||
xTaskCreatePinnedToCore(&gcov_dump_task, "gcov_dump_task", 2048, (void *)&s_gcov_task_running, configMAX_PRIORITIES - 1, NULL, 0);
|
||||
}
|
||||
|
||||
void gcov_create_task_tick_hook(void)
|
||||
{
|
||||
extern esp_err_t esp_ipc_start_gcov_from_isr(uint32_t cpu_id, esp_ipc_func_t func, void* arg);
|
||||
if (s_create_gcov_task) {
|
||||
if (esp_ipc_start_gcov_from_isr(xPortGetCoreID(), &gcov_create_task, NULL) == ESP_OK) {
|
||||
s_create_gcov_task = false;
|
||||
}
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "exit %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Triggers gcov info dump.
|
||||
* @brief Triggers gcov info dump task
|
||||
* This function is to be called by OpenOCD, not by normal user code.
|
||||
* TODO: what about interrupted flash access (when cache disabled)???
|
||||
* TODO: what about interrupted flash access (when cache disabled)
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
static int esp_dbg_stub_gcov_entry(void)
|
||||
{
|
||||
return esp_dbg_stub_gcov_dump_do();
|
||||
/* we are in isr context here */
|
||||
s_create_gcov_task = true;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int gcov_rtio_atexit(void (*function)(void) __attribute__ ((unused)))
|
||||
{
|
||||
uint32_t capabilities = 0;
|
||||
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
|
||||
esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_GCOV, (uint32_t)&esp_dbg_stub_gcov_entry);
|
||||
return 0;
|
||||
if (esp_dbg_stub_entry_get(ESP_DBG_STUB_ENTRY_CAPABILITIES, &capabilities) == ESP_OK) {
|
||||
esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_CAPABILITIES, capabilities | ESP_DBG_STUB_CAP_GCOV_TASK);
|
||||
}
|
||||
esp_register_freertos_tick_hook(gcov_create_task_tick_hook);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_gcov_dump(void)
|
||||
{
|
||||
// disable IRQs on this CPU, other CPU is halted by OpenOCD
|
||||
unsigned irq_state = portENTER_CRITICAL_NESTED();
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
int other_core = cpu_hal_get_core_id() ? 0 : 1;
|
||||
esp_cpu_stall(other_core);
|
||||
#endif
|
||||
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
|
||||
|
||||
while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) {
|
||||
wdt_hal_context_t twdt = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
|
||||
wdt_hal_context_t iwdt = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
|
||||
//Feed the Task Watchdog (TG0) to prevent it from timing out
|
||||
wdt_hal_write_protect_disable(&twdt);
|
||||
wdt_hal_feed(&twdt);
|
||||
wdt_hal_write_protect_enable(&twdt);
|
||||
//Likewise, feed the Interrupt Watchdog (TG1) to prevent a reboot
|
||||
wdt_hal_write_protect_disable(&iwdt);
|
||||
wdt_hal_feed(&iwdt);
|
||||
wdt_hal_write_protect_enable(&iwdt);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
|
||||
esp_dbg_stub_gcov_dump_do();
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
esp_cpu_unstall(other_core);
|
||||
#endif
|
||||
portEXIT_CRITICAL_NESTED(irq_state);
|
||||
/* We are not in isr context here. Waiting for the completion is safe */
|
||||
s_gcov_task_running = true;
|
||||
s_create_gcov_task = true;
|
||||
while (s_gcov_task_running) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
void *gcov_rtio_fopen(const char *path, const char *mode)
|
||||
@ -168,7 +155,7 @@ int gcov_rtio_fclose(void *stream)
|
||||
|
||||
size_t gcov_rtio_fread(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "%s read %u", __FUNCTION__, size*nmemb);
|
||||
ESP_EARLY_LOGV(TAG, "%s read %u", __FUNCTION__, size * nmemb);
|
||||
size_t sz = esp_apptrace_fread(ESP_APPTRACE_DEST_TRAX, ptr, size, nmemb, stream);
|
||||
ESP_EARLY_LOGV(TAG, "%s actually read %u", __FUNCTION__, sz);
|
||||
return sz;
|
||||
|
@ -69,7 +69,7 @@ Additional information:
|
||||
|
||||
Packets with IDs 24..31 are standard packets with extendible
|
||||
structure and contain a length field.
|
||||
<ID><Lenght><Data><TimeStampDelta>
|
||||
<ID><Length><Data><TimeStampDelta>
|
||||
|
||||
Packets with IDs >= 32 always contain a length field.
|
||||
<ID><Length><Data><TimeStampDelta>
|
||||
|
@ -117,13 +117,13 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
|
||||
#define SYSVIEW_TIMESTAMP_FREQ (esp_clk_apb_freq() / SYSVIEW_TIMER_DIV)
|
||||
|
||||
// Timer ID and group ID
|
||||
#if defined(CONFIG_APPTRACE_SV_TS_SOURCE_TIMER_00) || defined(CONFIG_APPTRACE_SV_TS_SOURCE_TIMER_01)
|
||||
#if defined(CONFIG_APPTRACE_SV_TS_SOURCE_TIMER_00) || defined(CONFIG_APPTRACE_SV_TS_SOURCE_TIMER_10)
|
||||
#define TS_TIMER_ID 0
|
||||
#else
|
||||
#define TS_TIMER_ID 1
|
||||
#endif // TIMER_00 || TIMER_01
|
||||
|
||||
#if defined(CONFIG_APPTRACE_SV_TS_SOURCE_TIMER_00) || defined(CONFIG_APPTRACE_SV_TS_SOURCE_TIMER_10)
|
||||
#if defined(CONFIG_APPTRACE_SV_TS_SOURCE_TIMER_00) || defined(CONFIG_APPTRACE_SV_TS_SOURCE_TIMER_01)
|
||||
#define TS_TIMER_GROUP 0
|
||||
#else
|
||||
#define TS_TIMER_GROUP 1
|
||||
@ -151,16 +151,17 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
|
||||
// The lowest RAM address used for IDs (pointers)
|
||||
#define SYSVIEW_RAM_BASE (SOC_DROM_LOW)
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#ifdef CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER
|
||||
#if CONFIG_FREERTOS_CORETIMER_0
|
||||
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
|
||||
#endif
|
||||
#if CONFIG_FREERTOS_CORETIMER_1
|
||||
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
|
||||
#endif
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
|
||||
#endif
|
||||
|
||||
#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
|
||||
#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE)
|
||||
#endif // CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER
|
||||
|
||||
// SystemView is single core specific: it implies that SEGGER_SYSVIEW_LOCK()
|
||||
// disables IRQs (disables rescheduling globally). So we can not use finite timeouts for locks and return error
|
||||
|
@ -371,7 +371,7 @@ static esp_err_t rewrite_ota_seq(esp_ota_select_entry_t *two_otadata, uint32_t s
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t get_ota_partition_count(void)
|
||||
uint8_t esp_ota_get_app_partition_count(void)
|
||||
{
|
||||
uint16_t ota_app_count = 0;
|
||||
while (esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_app_count, NULL) != NULL) {
|
||||
@ -389,7 +389,7 @@ static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype)
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
uint8_t ota_app_count = get_ota_partition_count();
|
||||
uint8_t ota_app_count = esp_ota_get_app_partition_count();
|
||||
if (SUB_TYPE_ID(subtype) >= ota_app_count) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@ -507,7 +507,7 @@ const esp_partition_t *esp_ota_get_boot_partition(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
int ota_app_count = esp_ota_get_app_partition_count();
|
||||
ESP_LOGD(TAG, "found ota app max = %d", ota_app_count);
|
||||
|
||||
if ((bootloader_common_ota_select_invalid(&otadata[0]) &&
|
||||
@ -652,7 +652,7 @@ bool esp_ota_check_rollback_is_possible(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
int ota_app_count = esp_ota_get_app_partition_count();
|
||||
if (ota_app_count == 0) {
|
||||
return false;
|
||||
}
|
||||
@ -710,7 +710,7 @@ static esp_err_t esp_ota_current_ota_is_workable(bool valid)
|
||||
}
|
||||
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
if (active_otadata != -1 && get_ota_partition_count() != 0) {
|
||||
if (active_otadata != -1 && esp_ota_get_app_partition_count() != 0) {
|
||||
if (valid == true && otadata[active_otadata].ota_state != ESP_OTA_IMG_VALID) {
|
||||
otadata[active_otadata].ota_state = ESP_OTA_IMG_VALID;
|
||||
ESP_LOGD(TAG, "OTA[current] partition is marked as VALID");
|
||||
@ -779,7 +779,7 @@ const esp_partition_t* esp_ota_get_last_invalid_partition(void)
|
||||
|
||||
int invalid_otadata = get_last_invalid_otadata(otadata);
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
int ota_app_count = esp_ota_get_app_partition_count();
|
||||
if (invalid_otadata != -1 && ota_app_count != 0) {
|
||||
int ota_slot = (otadata[invalid_otadata].ota_seq - 1) % ota_app_count;
|
||||
ESP_LOGD(TAG, "Find invalid ota_%d app", ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot);
|
||||
@ -807,7 +807,7 @@ esp_err_t esp_ota_get_state_partition(const esp_partition_t *partition, esp_ota_
|
||||
}
|
||||
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
int ota_app_count = esp_ota_get_app_partition_count();
|
||||
if (read_otadata(otadata) == NULL || ota_app_count == 0) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
@ -839,7 +839,7 @@ esp_err_t esp_ota_erase_last_boot_app_partition(void)
|
||||
}
|
||||
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
int ota_app_count = esp_ota_get_app_partition_count();
|
||||
if (active_otadata == -1 || ota_app_count == 0) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
@ -244,6 +244,14 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *
|
||||
*/
|
||||
esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, esp_app_desc_t *app_desc);
|
||||
|
||||
/**
|
||||
* @brief Returns number of ota partitions provided in partition table.
|
||||
*
|
||||
* @return
|
||||
* - Number of OTA partitions
|
||||
*/
|
||||
uint8_t esp_ota_get_app_partition_count(void);
|
||||
|
||||
/**
|
||||
* @brief This function is called to indicate that the running app is working well.
|
||||
*
|
||||
|
@ -386,6 +386,15 @@ menu "Bootloader config"
|
||||
in this area of memory, you can increase it. It must be a multiple of 4 bytes.
|
||||
This area (rtc_retain_mem_t) is reserved and has access from the bootloader and an application.
|
||||
|
||||
config BOOTLOADER_FLASH_XMC_SUPPORT
|
||||
bool "Enable the support for flash chips of XMC (READ HELP FIRST)"
|
||||
default y
|
||||
help
|
||||
Perform the startup flow recommended by XMC. Please consult XMC for the details of this flow.
|
||||
XMC chips will be forbidden to be used, when this option is disabled.
|
||||
|
||||
DON'T DISABLE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.
|
||||
|
||||
endmenu # Bootloader
|
||||
|
||||
|
||||
@ -415,12 +424,12 @@ menu "Security features"
|
||||
config SECURE_BOOT_SUPPORTS_RSA
|
||||
bool
|
||||
default y
|
||||
depends on ESP32_REV_MIN_3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
|
||||
depends on ESP32_REV_MIN_3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
|
||||
|
||||
config SECURE_TARGET_HAS_SECURE_ROM_DL_MODE
|
||||
bool
|
||||
default y
|
||||
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
|
||||
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
|
||||
|
||||
|
||||
config SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
@ -492,7 +501,7 @@ menu "Security features"
|
||||
config SECURE_BOOT
|
||||
bool "Enable hardware Secure Boot in bootloader (READ DOCS FIRST)"
|
||||
default n
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || ESP32C3_REV_MIN_3
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || ESP32C3_REV_MIN_3 || IDF_TARGET_ESP32S3
|
||||
help
|
||||
Build a bootloader which enables Secure Boot on first boot.
|
||||
|
||||
@ -755,9 +764,17 @@ menu "Security features"
|
||||
efuse when Secure Boot is enabled. This prevents any more efuses from being read protected.
|
||||
|
||||
If this option is set, it will remain possible to write the EFUSE_RD_DIS efuse field after Secure
|
||||
Boot is enabled. This may allow an attacker to read-protect the BLK2 efuse holding the public
|
||||
key digest, causing an immediate denial of service and possibly allowing an additional fault
|
||||
injection attack to bypass the signature protection.
|
||||
Boot is enabled. This may allow an attacker to read-protect the BLK2 efuse (for ESP32) and
|
||||
BLOCK4-BLOCK10 (i.e. BLOCK_KEY0-BLOCK_KEY5)(for other chips) holding the public key digest, causing an
|
||||
immediate denial of service and possibly allowing an additional fault injection attack to
|
||||
bypass the signature protection.
|
||||
|
||||
NOTE: Once a BLOCK is read-protected, the application will read all zeros from that block
|
||||
|
||||
NOTE: If "UART ROM download mode (Permanently disabled (recommended))" or
|
||||
"UART ROM download mode (Permanently switch to Secure mode (recommended))" is set,
|
||||
then it is __NOT__ possible to read/write efuses using espefuse.py utility.
|
||||
However, efuse can be read/written from the application
|
||||
|
||||
config SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS
|
||||
bool "Leave unused digest slots available (not revoke)"
|
||||
|
@ -10,8 +10,7 @@ LINKER_SCRIPTS := \
|
||||
$(COMPONENT_PATH)/ld/$(IDF_TARGET)/bootloader.rom.ld \
|
||||
$(IDF_PATH)/components/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.ld \
|
||||
$(IDF_PATH)/components/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.newlib-funcs.ld \
|
||||
$(IDF_PATH)/components/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.api.ld \
|
||||
$(IDF_PATH)/components/$(IDF_TARGET)/ld/$(IDF_TARGET).peripherals.ld
|
||||
$(IDF_PATH)/components/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.api.ld
|
||||
|
||||
# SPI driver patch for ROM is only needed in ESP32
|
||||
ifdef CONFIG_IDF_TARGET_ESP32
|
||||
|
@ -176,17 +176,17 @@ SECTIONS
|
||||
/**
|
||||
* Appendix: Memory Usage of ROM bootloader
|
||||
*
|
||||
* +--------+--------------+------+ 0x3FCC_B000
|
||||
* +--------+--------------+------+ 0x3FCC_AE00
|
||||
* | ^ |
|
||||
* | | |
|
||||
* | | data/bss |
|
||||
* | | |
|
||||
* | v |
|
||||
* +------------------------------+ 0x3FCD_C910
|
||||
* +------------------------------+ 0x3FCD_C710
|
||||
* | ^ |
|
||||
* | | |
|
||||
* | | stack |
|
||||
* | | |
|
||||
* | v |
|
||||
* +------------------------------+ 0x3FCD_E910
|
||||
* +------------------------------+ 0x3FCD_E710
|
||||
*/
|
||||
|
@ -34,7 +34,8 @@ else()
|
||||
"src/idf/bootloader_sha.c")
|
||||
set(include_dirs "include")
|
||||
set(priv_include_dirs "include_bootloader")
|
||||
set(priv_requires spi_flash mbedtls efuse app_update)
|
||||
# heap is required for `heap_memory_layout.h` header
|
||||
set(priv_requires spi_flash mbedtls efuse app_update heap)
|
||||
endif()
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
|
@ -10,6 +10,18 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Read flash ID by sending RDID command (0x9F)
|
||||
* @return flash raw ID
|
||||
* mfg_id = (ID >> 16) & 0xFF;
|
||||
flash_id = ID & 0xffff;
|
||||
*/
|
||||
uint32_t bootloader_read_flash_id(void);
|
||||
|
||||
#if SOC_CACHE_SUPPORT_WRAP
|
||||
/**
|
||||
* @brief Set the burst mode setting command for specified wrap mode.
|
||||
@ -19,3 +31,22 @@
|
||||
*/
|
||||
esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Unlock Flash write protect.
|
||||
* Please do not call this function in SDK.
|
||||
*
|
||||
* @note This can be overridden because it's attribute weak.
|
||||
*/
|
||||
esp_err_t bootloader_flash_unlock(void);
|
||||
|
||||
/**
|
||||
* @brief Startup flow recommended by XMC. Call at startup before any erase/write operation.
|
||||
*
|
||||
* @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write).
|
||||
*/
|
||||
esp_err_t bootloader_flash_xmc_startup(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define CMD_RDSR 0x05
|
||||
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
|
||||
#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */
|
||||
#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */
|
||||
#define CMD_WRAP 0x77 /* Set burst with wrap command */
|
||||
#define CMD_RESUME 0x7A /* Resume command to clear flash suspend bit */
|
||||
|
||||
@ -156,6 +157,15 @@ static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vad
|
||||
*/
|
||||
uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);
|
||||
|
||||
/**
|
||||
* @brief Read the SFDP of the flash
|
||||
*
|
||||
* @param sfdp_addr Address of the parameter to read
|
||||
* @param miso_byte_num Bytes to read
|
||||
* @return The read SFDP, little endian, 4 bytes at most
|
||||
*/
|
||||
uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
|
||||
|
||||
/**
|
||||
* @brief Enable the flash write protect (WEL bit).
|
||||
*/
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "soc/soc_memory_types.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
@ -141,7 +141,8 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t
|
||||
|
||||
rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)RTC_RETAIN_MEM_ADDR;
|
||||
|
||||
#if !IS_BOOTLOADER_BUILD
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#include "heap_memory_layout.h"
|
||||
/* The app needs to be told this memory is reserved, important if configured to use RTC memory as heap.
|
||||
|
||||
Note that keeping this macro here only works when other symbols in this file are referenced by the app, as
|
||||
|
@ -71,8 +71,8 @@ void bootloader_console_init(void)
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0RXD_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, PIN_FUNC_GPIO);
|
||||
// Route GPIO signals to/from pins
|
||||
const uint32_t tx_idx = uart_periph_signal[uart_num].tx_sig;
|
||||
const uint32_t rx_idx = uart_periph_signal[uart_num].rx_sig;
|
||||
const uint32_t tx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX);
|
||||
const uint32_t rx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[uart_rx_gpio]);
|
||||
esp_rom_gpio_pad_pullup_only(uart_rx_gpio);
|
||||
esp_rom_gpio_connect_out_signal(uart_tx_gpio, tx_idx, 0, 0);
|
||||
|
@ -19,5 +19,5 @@ uint8_t bootloader_common_get_chip_revision(void)
|
||||
uint32_t bootloader_common_get_chip_ver_pkg(void)
|
||||
{
|
||||
// should return the same value as esp_efuse_get_pkg_ver()
|
||||
return REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION);
|
||||
return REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_4_REG, EFUSE_PKG_VERSION);
|
||||
}
|
||||
|
@ -23,7 +23,9 @@
|
||||
# define SPIFLASH SPIMEM1
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/spi_flash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/spi_flash.h"
|
||||
@ -39,6 +41,17 @@
|
||||
#define ENCRYPTION_IS_VIRTUAL 0
|
||||
#endif
|
||||
|
||||
#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF)
|
||||
#define ISSI_ID 0x9D
|
||||
#define GD_Q_ID_HIGH 0xC8
|
||||
#define GD_Q_ID_MID 0x40
|
||||
#define GD_Q_ID_LOW 0x16
|
||||
|
||||
#define ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2)
|
||||
#define ESP_BOOTLOADER_SPIFLASH_QE_16B BIT9 // QE position when you write 16 bits at one time.
|
||||
#define ESP_BOOTLOADER_SPIFLASH_QE_8B BIT1 // QE position when you write 8 bits(for SR2) at one time.
|
||||
#define ESP_BOOTLOADER_SPIFLASH_WRITE_8B (8)
|
||||
#define ESP_BOOTLOADER_SPIFLASH_WRITE_16B (16)
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
/* Normal app version maps to esp_spi_flash.h operations...
|
||||
@ -109,7 +122,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
return spi_flash_erase_range(start_addr, size);
|
||||
}
|
||||
|
||||
#else
|
||||
#else //BOOTLOADER_BUILD
|
||||
/* Bootloader version, uses ROM functions only */
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
@ -426,7 +439,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = spi_to_esp_err(esp_rom_spiflash_unlock());
|
||||
err = bootloader_flash_unlock();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
@ -468,31 +481,132 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
return spi_to_esp_err(rc);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
|
||||
FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip)
|
||||
{
|
||||
return BYTESHIFT(chip->device_id, 2) == ISSI_ID;
|
||||
}
|
||||
|
||||
// For GD25Q32, GD25Q64, GD25Q127C, GD25Q128, which use single command to read/write different SR.
|
||||
FORCE_INLINE_ATTR bool is_gd_q_chip(const esp_rom_spiflash_chip_t* chip)
|
||||
{
|
||||
return BYTESHIFT(chip->device_id, 2) == GD_Q_ID_HIGH && BYTESHIFT(chip->device_id, 1) == GD_Q_ID_MID && BYTESHIFT(chip->device_id, 0) >= GD_Q_ID_LOW;
|
||||
}
|
||||
|
||||
esp_err_t IRAM_ATTR __attribute__((weak)) bootloader_flash_unlock(void)
|
||||
{
|
||||
uint16_t status = 0; // status for SR1 or SR1+SR2 if writing SR with 01H + 2Bytes.
|
||||
uint16_t new_status = 0;
|
||||
uint8_t status_sr2 = 0; // status_sr2 for SR2.
|
||||
uint8_t new_status_sr2 = 0;
|
||||
uint8_t write_sr_bit = 0;
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
if (is_issi_chip(&g_rom_flashchip)) {
|
||||
write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_8B;
|
||||
// ISSI chips have different QE position
|
||||
|
||||
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
|
||||
|
||||
/* Clear all bits in the mask.
|
||||
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
|
||||
*/
|
||||
new_status = status & (~ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI);
|
||||
// Skip if nothing needs to be cleared. Otherwise will waste time waiting for the flash to clear nothing.
|
||||
} else if (is_gd_q_chip(&g_rom_flashchip)) {
|
||||
/* The GD chips behaviour is to clear all bits in SR1 and clear bits in SR2 except QE bit.
|
||||
Use 01H to write SR1 and 31H to write SR2.
|
||||
*/
|
||||
write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_8B;
|
||||
|
||||
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
|
||||
new_status = 0;
|
||||
|
||||
status_sr2 = bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8);
|
||||
new_status_sr2 = status_sr2 & ESP_BOOTLOADER_SPIFLASH_QE_8B;
|
||||
} else {
|
||||
/* For common behaviour, like XMC chips, Use 01H+2Bytes to write both SR1 and SR2*/
|
||||
write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_16B;
|
||||
status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
|
||||
|
||||
/* Clear all bits except QE, if it is set.
|
||||
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
|
||||
*/
|
||||
new_status = status & ESP_BOOTLOADER_SPIFLASH_QE_16B;
|
||||
}
|
||||
|
||||
if (status != new_status) {
|
||||
/* if the status in SR not equal to the ideal status, the status need to be updated */
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
bootloader_execute_flash_command(CMD_WRSR, new_status, write_sr_bit, 0);
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
}
|
||||
|
||||
if (status_sr2 != new_status_sr2) {
|
||||
/* If the status in SR2 not equal to the ideal status, the status need to be updated.
|
||||
It doesn't need to be updated if status in SR2 is 0.
|
||||
Note: if we need to update both SR1 and SR2, the `CMD_WREN` needs to be sent again.
|
||||
*/
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
bootloader_execute_flash_command(CMD_WRSR2, new_status_sr2, write_sr_bit, 0);
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
}
|
||||
|
||||
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0);
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* dummy_len_plus values defined in ROM for SPI flash configuration */
|
||||
#ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here
|
||||
extern uint8_t g_rom_spiflash_dummy_len_plus[];
|
||||
#endif
|
||||
uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
|
||||
IRAM_ATTR static uint32_t bootloader_flash_execute_command_common(
|
||||
uint8_t command,
|
||||
uint32_t addr_len, uint32_t address,
|
||||
uint8_t dummy_len,
|
||||
uint8_t mosi_len, uint32_t mosi_data,
|
||||
uint8_t miso_len)
|
||||
{
|
||||
assert(mosi_len <= 32);
|
||||
assert(miso_len <= 32);
|
||||
uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
|
||||
uint32_t old_user_reg = SPIFLASH.user.val;
|
||||
uint32_t old_user1_reg = SPIFLASH.user1.val;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
|
||||
#else
|
||||
SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
|
||||
#endif
|
||||
SPIFLASH.user.usr_dummy = 0;
|
||||
SPIFLASH.user.usr_addr = 0;
|
||||
//command phase
|
||||
SPIFLASH.user.usr_command = 1;
|
||||
SPIFLASH.user2.usr_command_bitlen = 7;
|
||||
|
||||
SPIFLASH.user2.usr_command_value = command;
|
||||
SPIFLASH.user.usr_miso = miso_len > 0;
|
||||
//addr phase
|
||||
SPIFLASH.user.usr_addr = addr_len > 0;
|
||||
SPIFLASH.user1.usr_addr_bitlen = addr_len - 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
|
||||
SPIFLASH.addr = (addr_len > 0)? (address << (32-addr_len)) : 0;
|
||||
#else
|
||||
SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
|
||||
SPIFLASH.addr = address;
|
||||
#endif
|
||||
//dummy phase
|
||||
if (miso_len > 0) {
|
||||
uint32_t total_dummy = dummy_len + g_rom_spiflash_dummy_len_plus[1];
|
||||
SPIFLASH.user.usr_dummy = total_dummy > 0;
|
||||
SPIFLASH.user1.usr_dummy_cyclelen = total_dummy - 1;
|
||||
} else {
|
||||
SPIFLASH.user.usr_dummy = 0;
|
||||
SPIFLASH.user1.usr_dummy_cyclelen = 0;
|
||||
}
|
||||
//output data
|
||||
SPIFLASH.user.usr_mosi = mosi_len > 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
|
||||
@ -500,24 +614,52 @@ uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, u
|
||||
SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0;
|
||||
#endif
|
||||
SPIFLASH.data_buf[0] = mosi_data;
|
||||
|
||||
if (g_rom_spiflash_dummy_len_plus[1]) {
|
||||
/* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */
|
||||
if (miso_len > 0) {
|
||||
SPIFLASH.user.usr_dummy = 1;
|
||||
SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1;
|
||||
} else {
|
||||
SPIFLASH.user.usr_dummy = 0;
|
||||
SPIFLASH.user1.usr_dummy_cyclelen = 0;
|
||||
}
|
||||
}
|
||||
//input data
|
||||
SPIFLASH.user.usr_miso = miso_len > 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
|
||||
#else
|
||||
SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
|
||||
#endif
|
||||
|
||||
SPIFLASH.cmd.usr = 1;
|
||||
while (SPIFLASH.cmd.usr != 0) {
|
||||
}
|
||||
|
||||
SPIFLASH.ctrl.val = old_ctrl_reg;
|
||||
return SPIFLASH.data_buf[0];
|
||||
SPIFLASH.user.val = old_user_reg;
|
||||
SPIFLASH.user1.val = old_user1_reg;
|
||||
|
||||
uint32_t ret = SPIFLASH.data_buf[0];
|
||||
if (miso_len < 32) {
|
||||
//set unused bits to 0
|
||||
ret &= ~(UINT32_MAX << miso_len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
|
||||
{
|
||||
const uint8_t addr_len = 0;
|
||||
const uint8_t address = 0;
|
||||
const uint8_t dummy_len = 0;
|
||||
|
||||
return bootloader_flash_execute_command_common(command, addr_len, address,
|
||||
dummy_len, mosi_len, mosi_data, miso_len);
|
||||
}
|
||||
|
||||
// cmd(0x5A) + 24bit address + 8 cycles dummy
|
||||
uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
|
||||
{
|
||||
assert(miso_byte_num <= 4);
|
||||
const uint8_t command = CMD_RDSFDP;
|
||||
const uint8_t addr_len = 24;
|
||||
const uint8_t dummy_len = 8;
|
||||
const uint8_t mosi_len = 0;
|
||||
const uint32_t mosi_data = 0;
|
||||
const uint8_t miso_len = miso_byte_num * 8;
|
||||
|
||||
return bootloader_flash_execute_command_common(command, addr_len, sfdp_addr,
|
||||
dummy_len, mosi_len, mosi_data, miso_len);
|
||||
}
|
||||
|
||||
void bootloader_enable_wp(void)
|
||||
@ -525,6 +667,13 @@ void bootloader_enable_wp(void)
|
||||
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR bootloader_read_flash_id(void)
|
||||
{
|
||||
uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24);
|
||||
id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
|
||||
return id;
|
||||
}
|
||||
|
||||
#if SOC_CACHE_SUPPORT_WRAP
|
||||
esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
|
||||
{
|
||||
@ -556,3 +705,104 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif //SOC_CACHE_SUPPORT_WRAP
|
||||
|
||||
/*******************************************************************************
|
||||
* XMC startup flow
|
||||
******************************************************************************/
|
||||
|
||||
#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT
|
||||
#define XMC_VENDOR_ID 0x20
|
||||
|
||||
#if BOOTLOADER_BUILD
|
||||
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_LOG##level(TAG, ##__VA_ARGS__)
|
||||
#else
|
||||
static DRAM_ATTR char bootloader_flash_tag[] = "bootloader_flash";
|
||||
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_DRAM_LOG##level(bootloader_flash_tag, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if XMC_SUPPORT
|
||||
//strictly check the model
|
||||
static IRAM_ATTR bool is_xmc_chip_strict(uint32_t rdid)
|
||||
{
|
||||
uint32_t vendor_id = BYTESHIFT(rdid, 2);
|
||||
uint32_t mfid = BYTESHIFT(rdid, 1);
|
||||
uint32_t cpid = BYTESHIFT(rdid, 0);
|
||||
|
||||
if (vendor_id != XMC_VENDOR_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool matched = false;
|
||||
if (mfid == 0x40) {
|
||||
if (cpid >= 0x13 && cpid <= 0x20) {
|
||||
matched = true;
|
||||
}
|
||||
} else if (mfid == 0x41) {
|
||||
if (cpid >= 0x17 && cpid <= 0x20) {
|
||||
matched = true;
|
||||
}
|
||||
} else if (mfid == 0x50) {
|
||||
if (cpid >= 0x15 && cpid <= 0x16) {
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
|
||||
{
|
||||
// If the RDID value is a valid XMC one, may skip the flow
|
||||
const bool fast_check = true;
|
||||
if (fast_check && is_xmc_chip_strict(g_rom_flashchip.device_id)) {
|
||||
BOOTLOADER_FLASH_LOG(D, "XMC chip detected by RDID (%08X), skip.", g_rom_flashchip.device_id);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Check the Manufacturer ID in SFDP registers (JEDEC standard). If not XMC chip, no need to run the flow
|
||||
const int sfdp_mfid_addr = 0x10;
|
||||
uint8_t mf_id = (bootloader_flash_read_sfdp(sfdp_mfid_addr, 1) & 0xff);
|
||||
if (mf_id != XMC_VENDOR_ID) {
|
||||
BOOTLOADER_FLASH_LOG(D, "non-XMC chip detected by SFDP Read (%02X), skip.", mf_id);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
BOOTLOADER_FLASH_LOG(I, "XM25QHxxC startup flow");
|
||||
// Enter DPD
|
||||
bootloader_execute_flash_command(0xB9, 0, 0, 0);
|
||||
// Enter UDPD
|
||||
bootloader_execute_flash_command(0x79, 0, 0, 0);
|
||||
// Exit UDPD
|
||||
bootloader_execute_flash_command(0xFF, 0, 0, 0);
|
||||
// Delay tXUDPD
|
||||
esp_rom_delay_us(2000);
|
||||
// Release Power-down
|
||||
bootloader_execute_flash_command(0xAB, 0, 0, 0);
|
||||
esp_rom_delay_us(20);
|
||||
// Read flash ID and check again
|
||||
g_rom_flashchip.device_id = bootloader_read_flash_id();
|
||||
if (!is_xmc_chip_strict(g_rom_flashchip.device_id)) {
|
||||
BOOTLOADER_FLASH_LOG(E, "XMC flash startup fail");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
//only compare the vendor id
|
||||
static IRAM_ATTR bool is_xmc_chip(uint32_t rdid)
|
||||
{
|
||||
uint32_t vendor_id = (rdid >> 16) & 0xFF;
|
||||
return (vendor_id == XMC_VENDOR_ID);
|
||||
}
|
||||
|
||||
esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
|
||||
{
|
||||
if (is_xmc_chip(g_rom_flashchip.device_id)) {
|
||||
BOOTLOADER_FLASH_LOG(E, "XMC chip detected (%08X) while support disabled.", g_rom_flashchip.device_id);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif //XMC_SUPPORT
|
||||
|
@ -252,7 +252,7 @@ static esp_err_t bootloader_init_spi_flash(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_unlock();
|
||||
bootloader_flash_unlock();
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
|
||||
bootloader_enable_qio_mode();
|
||||
@ -387,6 +387,11 @@ esp_err_t bootloader_init(void)
|
||||
bootloader_print_banner();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
goto err;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
goto err;
|
||||
|
@ -203,7 +203,7 @@ static esp_err_t bootloader_init_spi_flash(void)
|
||||
#endif
|
||||
|
||||
bootloader_spi_flash_resume();
|
||||
esp_rom_spiflash_unlock();
|
||||
bootloader_flash_unlock();
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
|
||||
bootloader_enable_qio_mode();
|
||||
@ -309,6 +309,11 @@ esp_err_t bootloader_init(void)
|
||||
bootloader_print_banner();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
goto err;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
goto err;
|
||||
|
@ -40,5 +40,11 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
@ -40,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ static esp_err_t bootloader_init_spi_flash(void)
|
||||
#endif
|
||||
|
||||
bootloader_spi_flash_resume();
|
||||
esp_rom_spiflash_unlock();
|
||||
bootloader_flash_unlock();
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
|
||||
bootloader_enable_qio_mode();
|
||||
@ -301,6 +301,11 @@ esp_err_t bootloader_init(void)
|
||||
bootloader_print_banner();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
goto err;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
goto err;
|
||||
|
@ -261,7 +261,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
@ -198,7 +198,7 @@ static esp_err_t bootloader_init_spi_flash(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_unlock();
|
||||
bootloader_flash_unlock();
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
|
||||
bootloader_enable_qio_mode();
|
||||
@ -307,6 +307,11 @@ esp_err_t bootloader_init(void)
|
||||
bootloader_print_banner();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
goto err;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
goto err;
|
||||
|
@ -41,5 +41,11 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -40,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ static void print_flash_info(const esp_image_header_t *bootloader_hdr)
|
||||
str = "20MHz";
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(TAG, "SPI Speed : %s", str);
|
||||
ESP_LOGI(TAG, "Boot SPI Speed : %s", str);
|
||||
|
||||
/* SPI mode could have been set to QIO during boot already,
|
||||
so test the SPI registers not the flash header */
|
||||
@ -199,7 +199,7 @@ static esp_err_t bootloader_init_spi_flash(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_unlock();
|
||||
bootloader_flash_unlock();
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
|
||||
bootloader_enable_qio_mode();
|
||||
@ -328,6 +328,11 @@ esp_err_t bootloader_init(void)
|
||||
bootloader_print_banner();
|
||||
// update flash ID
|
||||
bootloader_flash_update_id();
|
||||
// Check and run XMC startup flow
|
||||
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
goto err;
|
||||
}
|
||||
// read bootloader header
|
||||
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
|
||||
goto err;
|
||||
|
@ -34,11 +34,18 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
|
||||
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
|
||||
// otherwise the Flash Encryption key cannot be read protected
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -27,8 +27,9 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
|
||||
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
@ -39,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
|
||||
bool rd_dis_now = true;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
|
||||
when Flash Encryption is being enabled */
|
||||
rd_dis_now = esp_flash_encryption_enabled();
|
||||
#endif
|
||||
if (rd_dis_now) {
|
||||
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "bootloader_util.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "soc/soc_memory_types.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
|
@ -82,7 +82,7 @@ esp_flash_enc_mode_t esp_get_flash_encryption_mode(void)
|
||||
bool flash_crypt_cnt_wr_dis = false;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint8_t dis_dl_enc = 0, dis_dl_dec = 0, dis_dl_cache = 0;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
uint8_t dis_dl_enc = 0;
|
||||
uint8_t dis_dl_icache = 0;
|
||||
uint8_t dis_dl_dcache = 0;
|
||||
@ -115,7 +115,7 @@ esp_flash_enc_mode_t esp_get_flash_encryption_mode(void)
|
||||
if ( dis_dl_cache && dis_dl_enc && dis_dl_dec ) {
|
||||
mode = ESP_FLASH_ENC_MODE_RELEASE;
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
dis_dl_enc = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
dis_dl_icache = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
dis_dl_dcache = esp_efuse_read_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
|
||||
@ -163,11 +163,11 @@ void esp_flash_encryption_set_release_mode(void)
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_CACHE);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_ENCRYPT);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DISABLE_DL_DECRYPT);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_DCACHE);
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DOWNLOAD_ICACHE);
|
||||
#else
|
||||
|
@ -105,14 +105,6 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn,
|
||||
The command passed here is always the on-the-wire command given to the SPI flash unit.
|
||||
*/
|
||||
|
||||
/* dummy_len_plus values defined in ROM for SPI flash configuration */
|
||||
uint32_t bootloader_read_flash_id(void)
|
||||
{
|
||||
uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24);
|
||||
id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
|
||||
return id;
|
||||
}
|
||||
|
||||
void bootloader_enable_qio_mode(void)
|
||||
{
|
||||
uint32_t raw_flash_id;
|
||||
|
@ -318,3 +318,14 @@ uint32_t osi_time_get_os_boottime_ms(void)
|
||||
{
|
||||
return (uint32_t)(esp_timer_get_time() / 1000);
|
||||
}
|
||||
|
||||
bool osi_alarm_is_active(osi_alarm_t *alarm)
|
||||
{
|
||||
assert(alarm != NULL);
|
||||
|
||||
if (alarm->alarm_hdl != NULL) {
|
||||
return esp_timer_is_active(alarm->alarm_hdl);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -77,4 +77,8 @@ period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm);
|
||||
|
||||
uint32_t osi_time_get_os_boottime_ms(void);
|
||||
|
||||
// This function returns whether the given |alarm| is active or not.
|
||||
// Return true if active, false otherwise.
|
||||
bool osi_alarm_is_active(osi_alarm_t *alarm);
|
||||
|
||||
#endif /*_ALARM_H_*/
|
||||
|
@ -1394,7 +1394,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
#if CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL
|
||||
// check whether or not EXT_CRYS is working
|
||||
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
|
||||
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
|
||||
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32kHz XTAL
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
s_btdm_allow_light_sleep = true;
|
||||
#endif
|
||||
|
@ -359,7 +359,8 @@ menu "MODEM SLEEP Options"
|
||||
bool "Internal 150kHz RC oscillator"
|
||||
depends on ESP32C3_RTC_CLK_SRC_INT_RC
|
||||
help
|
||||
Internal 150kHz RC oscillator.
|
||||
Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required
|
||||
in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.
|
||||
|
||||
|
||||
endchoice
|
||||
|
@ -992,7 +992,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
|
||||
// configure and initialize resources
|
||||
s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0;
|
||||
s_lp_cntl.no_light_sleep = 0;
|
||||
s_lp_cntl.no_light_sleep = 1;
|
||||
|
||||
if (s_lp_cntl.enable) {
|
||||
#if (CONFIG_MAC_BB_PD)
|
||||
@ -1029,31 +1029,29 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
|
||||
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
|
||||
|
||||
// // set default bluetooth sleep clock source
|
||||
// s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
|
||||
// set default bluetooth sleep clock source
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
#if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL
|
||||
// check whether or not EXT_CRYS is working
|
||||
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
|
||||
// #ifdef CONFIG_PM_ENABLE
|
||||
// s_btdm_allow_light_sleep = true;
|
||||
// #endif
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL
|
||||
s_lp_cntl.no_light_sleep = 0;
|
||||
} else {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
|
||||
"light sleep mode will not be able to apply when bluetooth is enabled");
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
}
|
||||
#elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW)
|
||||
// check whether or not EXT_CRYS is working
|
||||
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) {
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // set default value
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator
|
||||
ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is "
|
||||
"required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.");
|
||||
} else {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC oscillator not detected, fall back to main XTAL as Bluetooth sleep clock\n"
|
||||
"light sleep mode will not be able to apply when bluetooth is enabled");
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected.");
|
||||
assert(0);
|
||||
}
|
||||
#else
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
s_lp_cntl.no_light_sleep = 1;
|
||||
#endif
|
||||
|
||||
bool select_src_ret __attribute__((unused));
|
||||
|
@ -373,10 +373,11 @@ menu "MODEM SLEEP Options"
|
||||
modem sleep to be used with both DFS and light sleep.
|
||||
|
||||
config BT_CTRL_LPCLK_SEL_RTC_SLOW
|
||||
bool "Internal 90kHz RC oscillator"
|
||||
bool "Internal 150kHz RC oscillator"
|
||||
depends on ESP32S3_RTC_CLK_SRC_INT_RC
|
||||
help
|
||||
Internal 90kHz RC oscillator.
|
||||
Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required
|
||||
in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.
|
||||
|
||||
|
||||
endchoice
|
||||
|
@ -972,7 +972,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
|
||||
// configure and initialize resources
|
||||
s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0;
|
||||
s_lp_cntl.no_light_sleep = 0;
|
||||
s_lp_cntl.no_light_sleep = 1;
|
||||
|
||||
if (s_lp_cntl.enable) {
|
||||
#if (CONFIG_MAC_BB_PD)
|
||||
@ -1009,31 +1009,29 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
|
||||
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
|
||||
|
||||
// // set default bluetooth sleep clock source
|
||||
// s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
|
||||
// set default bluetooth sleep clock source
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
#if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL
|
||||
// check whether or not EXT_CRYS is working
|
||||
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
|
||||
// #ifdef CONFIG_PM_ENABLE
|
||||
// s_btdm_allow_light_sleep = true;
|
||||
// #endif
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL
|
||||
s_lp_cntl.no_light_sleep = 0;
|
||||
} else {
|
||||
ESP_LOGW(BT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
|
||||
"light sleep mode will not be able to apply when bluetooth is enabled");
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
}
|
||||
#elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW)
|
||||
// check whether or not EXT_CRYS is working
|
||||
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) {
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // set default value
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator
|
||||
ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is "
|
||||
"required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.");
|
||||
} else {
|
||||
ESP_LOGW(BT_LOG_TAG, "Internal 90kHz RC oscillator not detected, fall back to main XTAL as Bluetooth sleep clock\n"
|
||||
"light sleep mode will not be able to apply when bluetooth is enabled");
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected.");
|
||||
assert(0);
|
||||
}
|
||||
#else
|
||||
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
|
||||
s_lp_cntl.no_light_sleep = 1;
|
||||
#endif
|
||||
|
||||
bool select_src_ret __attribute__((unused));
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 735a846f927cb85bfb2e2a8cc2d9b4ced9bf739c
|
||||
Subproject commit fb49791b7c1a8a35f06e68124c90022667b4cff1
|
@ -1 +1 @@
|
||||
Subproject commit b223604efd557d0a5314afb3b751229df424d244
|
||||
Subproject commit 9ca8afd50afde57958a67fca65847edc52f7d91c
|
@ -69,6 +69,12 @@ esp_err_t esp_ble_mesh_node_prov_disable(esp_ble_mesh_prov_bearer_t bearers);
|
||||
/**
|
||||
* @brief Unprovisioned device set own oob public key & private key pair.
|
||||
*
|
||||
* @note In order to avoid suffering brute-forcing attack (CVE-2020-26559).
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* use an out-of-band mechanism to exchange the public keys.
|
||||
* So as an unprovisioned device, it should use this function to input
|
||||
* the Public Key exchanged through the out-of-band mechanism.
|
||||
*
|
||||
* @param[in] pub_key_x: Unprovisioned device's Public Key X
|
||||
* @param[in] pub_key_y: Unprovisioned device's Public Key Y
|
||||
* @param[in] private_key: Unprovisioned device's Private Key
|
||||
@ -121,6 +127,10 @@ esp_err_t esp_ble_mesh_set_unprovisioned_device_name(const char *name);
|
||||
/**
|
||||
* @brief Provisioner inputs unprovisioned device's oob public key.
|
||||
*
|
||||
* @note In order to avoid suffering brute-forcing attack (CVE-2020-26559).
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* use an out-of-band mechanism to exchange the public keys.
|
||||
*
|
||||
* @param[in] link_idx: The provisioning link index
|
||||
* @param[in] pub_key_x: Unprovisioned device's Public Key X
|
||||
* @param[in] pub_key_y: Unprovisioned device's Public Key Y
|
||||
@ -329,6 +339,14 @@ esp_err_t esp_ble_mesh_provisioner_set_prov_data_info(esp_ble_mesh_prov_data_inf
|
||||
* A large entropy helps ensure that a brute-force of the AuthValue, even a static
|
||||
* AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
|
||||
*
|
||||
* AuthValues selected using a cryptographically secure random or pseudorandom number
|
||||
* generator and having the maximum permitted entropy (128-bits) will be most difficult
|
||||
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
|
||||
* will not grant the same level of protection against this vulnerability. Selecting a
|
||||
* new AuthValue with each provisioning attempt can also make it more difficult to launch
|
||||
* a brute-force attack by requiring the attacker to restart the search with each
|
||||
* provisioning attempt (CVE-2020-26556).
|
||||
*
|
||||
* @param[in] value: Pointer to the static oob value.
|
||||
* @param[in] length: Length of the static oob value.
|
||||
*
|
||||
|
@ -573,8 +573,10 @@ typedef struct {
|
||||
esp_ble_mesh_prov_oob_info_t oob_info;
|
||||
|
||||
/* NOTE: In order to avoid suffering brute-forcing attack (CVE-2020-26559).
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh node
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* support an out-of-band mechanism to exchange the public keys.
|
||||
* So as an unprovisioned device, it should enable this flag to support
|
||||
* using an out-of-band mechanism to exchange Public Key.
|
||||
*/
|
||||
/** Flag indicates whether unprovisioned devices support OOB public key */
|
||||
bool oob_pub_key;
|
||||
@ -629,7 +631,7 @@ typedef struct {
|
||||
/** Provisioning Algorithm for the Provisioner */
|
||||
uint8_t prov_algorithm;
|
||||
|
||||
/* NOTE: In order to avoid suffering brute-forcing attack(CVE-2020-26559).
|
||||
/* NOTE: In order to avoid suffering brute-forcing attack (CVE-2020-26559).
|
||||
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* use an out-of-band mechanism to exchange the public keys.
|
||||
*/
|
||||
@ -643,6 +645,14 @@ typedef struct {
|
||||
* selected AuthValue using all of the available bits, where permitted by the
|
||||
* implementation. A large entropy helps ensure that a brute-force of the AuthValue,
|
||||
* even a static AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
|
||||
*
|
||||
* AuthValues selected using a cryptographically secure random or pseudorandom number
|
||||
* generator and having the maximum permitted entropy (128-bits) will be most difficult
|
||||
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
|
||||
* will not grant the same level of protection against this vulnerability. Selecting a
|
||||
* new AuthValue with each provisioning attempt can also make it more difficult to launch
|
||||
* a brute-force attack by requiring the attacker to restart the search with each
|
||||
* provisioning attempt (CVE-2020-26556).
|
||||
*/
|
||||
/** Provisioner static oob value */
|
||||
uint8_t *prov_static_oob_val;
|
||||
|
@ -1930,6 +1930,19 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t
|
||||
/* Provisioner ouput number/string and wait for device's Provisioning Input Complete PDU */
|
||||
link[idx].expect = PROV_INPUT_COMPLETE;
|
||||
|
||||
/* NOTE: The Bluetooth SIG recommends that mesh implementations enforce a randomly
|
||||
* selected AuthValue using all of the available bits, where permitted by the
|
||||
* implementation. A large entropy helps ensure that a brute-force of the AuthValue,
|
||||
* even a static AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
|
||||
*
|
||||
* AuthValues selected using a cryptographically secure random or pseudorandom number
|
||||
* generator and having the maximum permitted entropy (128-bits) will be most difficult
|
||||
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
|
||||
* will not grant the same level of protection against this vulnerability. Selecting a
|
||||
* new AuthValue with each provisioning attempt can also make it more difficult to launch
|
||||
* a brute-force attack by requiring the attacker to restart the search with each
|
||||
* provisioning attempt (CVE-2020-26556).
|
||||
*/
|
||||
if (input == BLE_MESH_ENTER_STRING) {
|
||||
unsigned char str[9] = {'\0'};
|
||||
uint8_t j = 0U;
|
||||
@ -2312,12 +2325,11 @@ static void prov_confirm(const uint8_t idx, const uint8_t *data)
|
||||
|
||||
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
|
||||
|
||||
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh
|
||||
* provisioners restrict the authentication procedure and not accept
|
||||
* provisioning random and provisioning confirmation numbers from a remote
|
||||
* peer that are the same as those selected by the local device (CVE-2020-26556
|
||||
* & CVE-2020-26560).
|
||||
* */
|
||||
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* restrict the authentication procedure and not accept provisioning random and
|
||||
* provisioning confirmation numbers from a remote peer that are the same as those
|
||||
* selected by the local device (CVE-2020-26560).
|
||||
*/
|
||||
if (!memcmp(data, link[idx].local_conf, 16)) {
|
||||
BT_ERR("Confirmation value is identical to ours, rejecting.");
|
||||
close_link(idx, CLOSE_REASON_FAILED);
|
||||
@ -2534,12 +2546,11 @@ static void prov_random(const uint8_t idx, const uint8_t *data)
|
||||
|
||||
BT_DBG("Remote Random: %s", bt_hex(data, 16));
|
||||
|
||||
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh
|
||||
* provisioners restrict the authentication procedure and not accept
|
||||
* provisioning random and provisioning confirmation numbers from a remote
|
||||
* peer that are the same as those selected by the local device (CVE-2020-26556
|
||||
* & CVE-2020-26560).
|
||||
* */
|
||||
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
|
||||
* restrict the authentication procedure and not accept provisioning random and
|
||||
* provisioning confirmation numbers from a remote peer that are the same as those
|
||||
* selected by the local device (CVE-2020-26560).
|
||||
*/
|
||||
if (!memcmp(data, link[idx].rand, 16)) {
|
||||
BT_ERR("Random value is identical to ours, rejecting.");
|
||||
goto fail;
|
||||
|
@ -29,6 +29,10 @@ esp_err_t esp_a2d_sink_init(void)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_init || g_a2dp_sink_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
@ -46,6 +50,10 @@ esp_err_t esp_a2d_sink_deinit(void)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
@ -63,6 +71,10 @@ esp_err_t esp_a2d_sink_register_data_callback(esp_a2d_sink_data_cb_t callback)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_sink_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_A2DP;
|
||||
@ -83,6 +95,10 @@ esp_err_t esp_a2d_sink_connect(esp_bd_addr_t remote_bda)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
bt_status_t stat;
|
||||
btc_av_args_t arg;
|
||||
btc_msg_t msg;
|
||||
@ -105,6 +121,10 @@ esp_err_t esp_a2d_sink_disconnect(esp_bd_addr_t remote_bda)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
bt_status_t stat;
|
||||
btc_av_args_t arg;
|
||||
btc_msg_t msg;
|
||||
@ -127,6 +147,10 @@ esp_err_t esp_a2d_register_callback(esp_a2d_cb_t callback)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_sink_ongoing_deinit || g_a2dp_source_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (callback == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@ -141,6 +165,10 @@ esp_err_t esp_a2d_media_ctrl(esp_a2d_media_ctrl_t ctrl)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit || g_a2dp_source_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
bt_status_t stat;
|
||||
btc_av_args_t arg;
|
||||
btc_msg_t msg;
|
||||
@ -164,6 +192,10 @@ esp_err_t esp_a2d_source_init(void)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_init || g_a2dp_source_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
@ -181,6 +213,10 @@ esp_err_t esp_a2d_source_deinit(void)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_source_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
@ -198,6 +234,10 @@ esp_err_t esp_a2d_source_connect(esp_bd_addr_t remote_bda)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_source_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
bt_status_t stat;
|
||||
btc_av_args_t arg;
|
||||
btc_msg_t msg;
|
||||
@ -220,6 +260,10 @@ esp_err_t esp_a2d_source_disconnect(esp_bd_addr_t remote_bda)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_on_deinit || g_a2dp_source_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
bt_status_t stat;
|
||||
btc_av_args_t arg;
|
||||
btc_msg_t msg;
|
||||
@ -242,6 +286,10 @@ esp_err_t esp_a2d_source_register_data_callback(esp_a2d_source_data_cb_t callbac
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (g_a2dp_source_ongoing_deinit) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_A2DP;
|
||||
|
@ -3835,7 +3835,10 @@ static void bta_dm_adjust_roles(BOOLEAN delay_role_switch)
|
||||
} else {
|
||||
bta_dm_cb.switch_delay_timer[i].p_cback =
|
||||
(TIMER_CBACK *)&bta_dm_delay_role_switch_cback;
|
||||
bta_sys_start_timer(&bta_dm_cb.switch_delay_timer[i], 0, 500);
|
||||
/* Start the timer if not active */
|
||||
if (!bta_sys_timer_is_active(&bta_dm_cb.switch_delay_timer[i])) {
|
||||
bta_sys_start_timer(&bta_dm_cb.switch_delay_timer[i], 0, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4975,9 +4978,6 @@ void bta_dm_ble_update_conn_params (tBTA_DM_MSG *p_data)
|
||||
p_data->ble_update_conn_params.latency,
|
||||
p_data->ble_update_conn_params.timeout)) {
|
||||
APPL_TRACE_ERROR("Update connection parameters failed!");
|
||||
} else {
|
||||
BTM_BleConfigConnParams(p_data->ble_update_conn_params.min_int, p_data->ble_update_conn_params.max_int,
|
||||
p_data->ble_update_conn_params.latency, p_data->ble_update_conn_params.timeout);
|
||||
}
|
||||
}
|
||||
/*******************************************************************************
|
||||
|
@ -225,6 +225,7 @@ extern void bta_sys_sendmsg(void *p_msg);
|
||||
extern void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout_ms);
|
||||
extern void bta_sys_stop_timer(TIMER_LIST_ENT *p_tle);
|
||||
extern void bta_sys_free_timer(TIMER_LIST_ENT *p_tle);
|
||||
extern BOOLEAN bta_sys_timer_is_active(TIMER_LIST_ENT *p_tle);
|
||||
extern void bta_sys_disable(tBTA_SYS_HW_MODULE module);
|
||||
extern UINT32 bta_sys_get_remaining_ticks(TIMER_LIST_ENT *p_target_tle);
|
||||
|
||||
|
@ -638,6 +638,27 @@ UINT32 bta_sys_get_remaining_ticks(TIMER_LIST_ENT *p_target_tle)
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_sys_timer_is_active
|
||||
**
|
||||
** Description Get info of timer is active or not.
|
||||
**
|
||||
** Returns true if timer is exist and active, false otherwise.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN bta_sys_timer_is_active(TIMER_LIST_ENT *p_tle)
|
||||
{
|
||||
assert(p_tle != NULL);
|
||||
|
||||
osi_alarm_t *alarm = hash_map_get(bta_alarm_hash_map, p_tle);
|
||||
if (alarm != NULL && osi_alarm_is_active(alarm)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_sys_stop_timer
|
||||
|
@ -1421,7 +1421,7 @@ static void btc_a2dp_source_handle_timer(UNUSED_ATTR void *context)
|
||||
log_tstamps_us("media task tx timer");
|
||||
|
||||
#if (BTA_AV_INCLUDED == TRUE)
|
||||
if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON){
|
||||
if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON || g_a2dp_source_ongoing_deinit){
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,11 @@ bool g_av_with_rc;
|
||||
bool g_a2dp_on_init;
|
||||
// global variable to indicate a2dp is deinitialized
|
||||
bool g_a2dp_on_deinit;
|
||||
// global variable to indicate a2dp source deinitialization is ongoing
|
||||
bool g_a2dp_source_ongoing_deinit;
|
||||
// global variable to indicate a2dp sink deinitialization is ongoing
|
||||
bool g_a2dp_sink_ongoing_deinit;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Constants & Macros
|
||||
@ -136,6 +141,7 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *data);
|
||||
static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *data);
|
||||
static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *data);
|
||||
static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *data);
|
||||
static void clean_up(int service_id);
|
||||
|
||||
#if BTC_AV_SRC_INCLUDED
|
||||
static bt_status_t btc_a2d_src_init(void);
|
||||
@ -704,6 +710,12 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
|
||||
|
||||
/* change state to idle, send acknowledgement if start is pending */
|
||||
btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
|
||||
|
||||
if (g_a2dp_source_ongoing_deinit) {
|
||||
clean_up(BTA_A2DP_SOURCE_SERVICE_ID);
|
||||
} else if (g_a2dp_sink_ongoing_deinit) {
|
||||
clean_up(BTA_A2DP_SINK_SERVICE_ID);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -892,6 +904,12 @@ static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data)
|
||||
btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda),
|
||||
close->disc_rsn);
|
||||
btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
|
||||
|
||||
if (g_a2dp_source_ongoing_deinit) {
|
||||
clean_up(BTA_A2DP_SOURCE_SERVICE_ID);
|
||||
} else if (g_a2dp_sink_ongoing_deinit) {
|
||||
clean_up(BTA_A2DP_SINK_SERVICE_ID);
|
||||
}
|
||||
break;
|
||||
|
||||
CHECK_RC_EVENT(event, p_data);
|
||||
@ -1014,6 +1032,8 @@ static bt_status_t btc_av_init(int service_id)
|
||||
#endif
|
||||
g_a2dp_on_init = false;
|
||||
g_a2dp_on_deinit = true;
|
||||
g_a2dp_source_ongoing_deinit = false;
|
||||
g_a2dp_sink_ongoing_deinit = false;
|
||||
goto av_init_fail;
|
||||
}
|
||||
|
||||
@ -1030,6 +1050,8 @@ static bt_status_t btc_av_init(int service_id)
|
||||
btc_a2dp_on_init();
|
||||
g_a2dp_on_init = true;
|
||||
g_a2dp_on_deinit = false;
|
||||
g_a2dp_source_ongoing_deinit = false;
|
||||
g_a2dp_sink_ongoing_deinit = false;
|
||||
|
||||
esp_a2d_cb_param_t param;
|
||||
memset(¶m, 0, sizeof(esp_a2d_cb_param_t));
|
||||
@ -1105,6 +1127,8 @@ static void clean_up(int service_id)
|
||||
#endif
|
||||
g_a2dp_on_init = false;
|
||||
g_a2dp_on_deinit = true;
|
||||
g_a2dp_source_ongoing_deinit = false;
|
||||
g_a2dp_sink_ongoing_deinit = false;
|
||||
|
||||
esp_a2d_cb_param_t param;
|
||||
memset(¶m, 0, sizeof(esp_a2d_cb_param_t));
|
||||
@ -1538,7 +1562,15 @@ static bt_status_t btc_a2d_sink_connect(bt_bdaddr_t *remote_bda)
|
||||
|
||||
static void btc_a2d_sink_deinit(void)
|
||||
{
|
||||
clean_up(BTA_A2DP_SINK_SERVICE_ID);
|
||||
g_a2dp_sink_ongoing_deinit = true;
|
||||
if (btc_av_is_connected()) {
|
||||
BTA_AvClose(btc_av_cb.bta_handle);
|
||||
if (btc_av_cb.peer_sep == AVDT_TSEP_SRC && g_av_with_rc == true) {
|
||||
BTA_AvCloseRc(btc_av_cb.bta_handle);
|
||||
}
|
||||
} else {
|
||||
clean_up(BTA_A2DP_SINK_SERVICE_ID);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BTC_AV_SINK_INCLUDED */
|
||||
@ -1563,7 +1595,15 @@ static bt_status_t btc_a2d_src_init(void)
|
||||
|
||||
static void btc_a2d_src_deinit(void)
|
||||
{
|
||||
clean_up(BTA_A2DP_SOURCE_SERVICE_ID);
|
||||
g_a2dp_source_ongoing_deinit = true;
|
||||
if (btc_av_is_connected()) {
|
||||
BTA_AvClose(btc_av_cb.bta_handle);
|
||||
if (btc_av_cb.peer_sep == AVDT_TSEP_SNK && g_av_with_rc == true) {
|
||||
BTA_AvCloseRc(btc_av_cb.bta_handle);
|
||||
}
|
||||
} else {
|
||||
clean_up(BTA_A2DP_SOURCE_SERVICE_ID);
|
||||
}
|
||||
}
|
||||
|
||||
static bt_status_t btc_a2d_src_connect(bt_bdaddr_t *remote_bda)
|
||||
|
@ -40,6 +40,11 @@ extern bool g_av_with_rc;
|
||||
extern bool g_a2dp_on_init;
|
||||
// global variable to indicate a2dp is deinitialized
|
||||
extern bool g_a2dp_on_deinit;
|
||||
// global variable to indicate a2dp source deinitialization is ongoing
|
||||
extern bool g_a2dp_source_ongoing_deinit;
|
||||
// global variable to indicate a2dp sink deinitialization is ongoing
|
||||
extern bool g_a2dp_sink_ongoing_deinit;
|
||||
|
||||
/*******************************************************************************
|
||||
** Type definitions for callback functions
|
||||
********************************************************************************/
|
||||
|
@ -546,6 +546,11 @@ static void btc_spp_uninit(void)
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
} while(0);
|
||||
|
||||
if (spp_local_param.tx_event_group) {
|
||||
vEventGroupDelete(spp_local_param.tx_event_group);
|
||||
spp_local_param.tx_event_group = NULL;
|
||||
}
|
||||
|
||||
if (ret != ESP_SPP_SUCCESS) {
|
||||
esp_spp_cb_param_t param;
|
||||
param.uninit.status = ret;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define BT_TARGET_H
|
||||
|
||||
#include <bt_common.h>
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifndef BUILDCFG
|
||||
#define BUILDCFG
|
||||
@ -257,6 +258,11 @@
|
||||
#define BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT UC_BT_BLE_ESTAB_LINK_CONN_TOUT
|
||||
#endif
|
||||
|
||||
#ifdef SOC_BLE_DONT_UPDATE_OWN_RPA
|
||||
#define BLE_UPDATE_BLE_ADDR_TYPE_RPA FALSE
|
||||
#else
|
||||
#define BLE_UPDATE_BLE_ADDR_TYPE_RPA TRUE
|
||||
#endif
|
||||
//------------------Added from bdroid_buildcfg.h---------------------
|
||||
#ifndef L2CAP_EXTFEA_SUPPORTED_MASK
|
||||
#define L2CAP_EXTFEA_SUPPORTED_MASK (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_FIXED_CHNLS)
|
||||
|
@ -110,8 +110,8 @@ static char *btm_ble_hci_status_to_str(tHCI_STATUS status)
|
||||
return "HCI_ERR_INVALID_LMP_PARAM";
|
||||
case HCI_ERR_UNSPECIFIED:
|
||||
return "HCI_ERR_UNSPECIFIED";
|
||||
case HCI_ERR_UNSUPPORTED_LMP_FEATURE:
|
||||
return "HCI_ERR_UNSUPPORTED_LMP_FEATURE";
|
||||
case HCI_ERR_UNSUPPORTED_LMP_PARAMETERS:
|
||||
return "HCI_ERR_UNSUPPORTED_LMP_PARAMETERS";
|
||||
case HCI_ERR_ROLE_CHANGE_NOT_ALLOWED:
|
||||
return "HCI_ERR_ROLE_CHANGE_NOT_ALLOWED";
|
||||
case HCI_ERR_LMP_RESPONSE_TIMEOUT:
|
||||
|
@ -1015,7 +1015,9 @@ uint32_t BTM_BleUpdateOwnType(uint8_t *own_bda_type, tBTM_START_ADV_CMPL_CBACK *
|
||||
}
|
||||
} else if(*own_bda_type == BLE_ADDR_PUBLIC_ID || *own_bda_type == BLE_ADDR_RANDOM_ID) {
|
||||
if((btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit & BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) == BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) {
|
||||
#if (BLE_UPDATE_BLE_ADDR_TYPE_RPA)
|
||||
*own_bda_type = BLE_ADDR_RANDOM;
|
||||
#endif
|
||||
btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = BLE_ADDR_RANDOM;
|
||||
memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.resolvale_addr, BD_ADDR_LEN);
|
||||
btsnd_hcic_ble_set_random_addr(btm_cb.ble_ctr_cb.addr_mgnt_cb.resolvale_addr);
|
||||
|
@ -240,6 +240,12 @@ BOOLEAN BTM_SecRegister(tBTM_APPL_INFO *p_cb_info)
|
||||
if (memcmp(btm_cb.devcb.id_keys.ir, &temp_value, sizeof(BT_OCTET16)) == 0) {
|
||||
btm_ble_reset_id();
|
||||
}
|
||||
#if (!BLE_UPDATE_BLE_ADDR_TYPE_RPA)
|
||||
BD_ADDR peer_addr = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
|
||||
BT_OCTET16 peer_irk = {0x0};
|
||||
/* add local irk to controller */
|
||||
btsnd_hcic_ble_add_device_resolving_list (0, peer_addr, peer_irk, btm_cb.devcb.id_keys.irk);
|
||||
#endif
|
||||
} else {
|
||||
BTM_TRACE_WARNING("%s p_cb_info->p_le_callback == NULL\n", __func__);
|
||||
}
|
||||
|
@ -844,7 +844,7 @@
|
||||
#define HCI_ERR_SCO_AIR_MODE 0x1D
|
||||
#define HCI_ERR_INVALID_LMP_PARAM 0x1E
|
||||
#define HCI_ERR_UNSPECIFIED 0x1F
|
||||
#define HCI_ERR_UNSUPPORTED_LMP_FEATURE 0x20
|
||||
#define HCI_ERR_UNSUPPORTED_LMP_PARAMETERS 0x20
|
||||
#define HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21
|
||||
#define HCI_ERR_LMP_RESPONSE_TIMEOUT 0x22
|
||||
#define HCI_ERR_LMP_ERR_TRANS_COLLISION 0x23
|
||||
|
@ -1011,7 +1011,7 @@ void l2c_link_processs_ble_num_bufs (UINT16 num_lm_ble_bufs)
|
||||
*******************************************************************************/
|
||||
void l2c_ble_link_adjust_allocation (void)
|
||||
{
|
||||
UINT16 qq, yy = 0, qq_remainder;
|
||||
UINT16 qq, qq_remainder;
|
||||
tL2C_LCB *p_lcb;
|
||||
UINT16 hi_quota, low_quota;
|
||||
UINT16 num_lowpri_links = 0;
|
||||
@ -1096,8 +1096,8 @@ void l2c_ble_link_adjust_allocation (void)
|
||||
}
|
||||
}
|
||||
|
||||
L2CAP_TRACE_EVENT("l2c_ble_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d",
|
||||
yy, p_lcb->acl_priority, p_lcb->link_xmit_quota);
|
||||
L2CAP_TRACE_EVENT("l2c_ble_link_adjust_allocation Priority: %d XmitQuota: %d",
|
||||
p_lcb->acl_priority, p_lcb->link_xmit_quota);
|
||||
|
||||
L2CAP_TRACE_EVENT(" SentNotAcked: %d RRUnacked: %d",
|
||||
p_lcb->sent_not_acked, l2cb.round_robin_unacked);
|
||||
|
@ -718,7 +718,7 @@ void l2c_info_timeout (tL2C_LCB *p_lcb)
|
||||
*******************************************************************************/
|
||||
void l2c_link_adjust_allocation (void)
|
||||
{
|
||||
UINT16 qq, yy = 0, qq_remainder;
|
||||
UINT16 qq, qq_remainder;
|
||||
tL2C_LCB *p_lcb;
|
||||
UINT16 hi_quota, low_quota;
|
||||
UINT16 num_lowpri_links = 0;
|
||||
@ -803,8 +803,8 @@ void l2c_link_adjust_allocation (void)
|
||||
}
|
||||
}
|
||||
|
||||
L2CAP_TRACE_EVENT ("l2c_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d\n",
|
||||
yy, p_lcb->acl_priority, p_lcb->link_xmit_quota);
|
||||
L2CAP_TRACE_EVENT ("l2c_link_adjust_allocation Priority: %d XmitQuota: %d\n",
|
||||
p_lcb->acl_priority, p_lcb->link_xmit_quota);
|
||||
|
||||
L2CAP_TRACE_EVENT (" SentNotAcked: %d RRUnacked: %d\n",
|
||||
p_lcb->sent_not_acked, l2cb.round_robin_unacked);
|
||||
|
@ -25,6 +25,38 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_ENABLED
|
||||
|
||||
#define SOC_MEM_BT_DATA_START 0x3ffae6e0
|
||||
#define SOC_MEM_BT_DATA_END 0x3ffaff10
|
||||
#define SOC_MEM_BT_EM_START 0x3ffb0000
|
||||
#define SOC_MEM_BT_EM_END 0x3ffb7cd8
|
||||
#define SOC_MEM_BT_EM_BTDM0_START 0x3ffb0000
|
||||
#define SOC_MEM_BT_EM_BTDM0_END 0x3ffb09a8
|
||||
#define SOC_MEM_BT_EM_BLE_START 0x3ffb09a8
|
||||
#define SOC_MEM_BT_EM_BLE_END 0x3ffb1ddc
|
||||
#define SOC_MEM_BT_EM_BTDM1_START 0x3ffb1ddc
|
||||
#define SOC_MEM_BT_EM_BTDM1_END 0x3ffb2730
|
||||
#define SOC_MEM_BT_EM_BREDR_START 0x3ffb2730
|
||||
#define SOC_MEM_BT_EM_BREDR_NO_SYNC_END 0x3ffb6388 //Not calculate with synchronize connection support
|
||||
#define SOC_MEM_BT_EM_BREDR_END 0x3ffb7cd8 //Calculate with synchronize connection support
|
||||
#define SOC_MEM_BT_EM_SYNC0_START 0x3ffb6388
|
||||
#define SOC_MEM_BT_EM_SYNC0_END 0x3ffb6bf8
|
||||
#define SOC_MEM_BT_EM_SYNC1_START 0x3ffb6bf8
|
||||
#define SOC_MEM_BT_EM_SYNC1_END 0x3ffb7468
|
||||
#define SOC_MEM_BT_EM_SYNC2_START 0x3ffb7468
|
||||
#define SOC_MEM_BT_EM_SYNC2_END 0x3ffb7cd8
|
||||
#define SOC_MEM_BT_BSS_START 0x3ffb8000
|
||||
#define SOC_MEM_BT_BSS_END 0x3ffb9a20
|
||||
#define SOC_MEM_BT_MISC_START 0x3ffbdb28
|
||||
#define SOC_MEM_BT_MISC_END 0x3ffbdb5c
|
||||
|
||||
#define SOC_MEM_BT_EM_PER_SYNC_SIZE 0x870
|
||||
|
||||
#define SOC_MEM_BT_EM_BREDR_REAL_END (SOC_MEM_BT_EM_BREDR_NO_SYNC_END + CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF * SOC_MEM_BT_EM_PER_SYNC_SIZE)
|
||||
|
||||
#endif //CONFIG_BT_ENABLED
|
||||
|
||||
#define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20200622
|
||||
|
||||
/**
|
||||
@ -351,12 +383,6 @@ esp_err_t esp_bt_controller_disable(void);
|
||||
*/
|
||||
esp_bt_controller_status_t esp_bt_controller_get_status(void);
|
||||
|
||||
/**
|
||||
* @brief Get BT MAC address.
|
||||
* @return Array pointer of length 6 storing MAC address value.
|
||||
*/
|
||||
uint8_t* esp_bt_get_mac(void);
|
||||
|
||||
/** @brief esp_vhci_host_callback
|
||||
* used for vhci call host function to notify what host need to do
|
||||
*/
|
||||
|
@ -527,12 +527,6 @@ void esp_bt_controller_wakeup_request(void);
|
||||
*/
|
||||
int esp_bt_h4tl_eif_io_event_notify(int event);
|
||||
|
||||
/**
|
||||
* @brief Get BT MAC address.
|
||||
* @return Array pointer of length 6 storing MAC address value.
|
||||
*/
|
||||
uint8_t* esp_bt_get_mac(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -526,12 +526,6 @@ void esp_bt_controller_wakeup_request(void);
|
||||
*/
|
||||
int esp_bt_h4tl_eif_io_event_notify(int event);
|
||||
|
||||
/**
|
||||
* @brief Get BT MAC address.
|
||||
* @return Array pointer of length 6 storing MAC address value.
|
||||
*/
|
||||
uint8_t* esp_bt_get_mac(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -211,7 +211,7 @@ TEST_CASE("c++ std::exception child", "[cxx] [exceptions] [leaks=" LEAKS "]")
|
||||
printf("OK?\n");
|
||||
}
|
||||
|
||||
TEST_CASE("c++ exceptions emergency pool", "[cxx] [exceptions] [ignore] [leaks=" LEAKS "]")
|
||||
TEST_CASE("c++ exceptions emergency pool", "[cxx] [exceptions] [leaks=" LEAKS "]")
|
||||
{
|
||||
void **p, **pprev = NULL;
|
||||
int thrown_value = 0;
|
||||
@ -241,7 +241,6 @@ TEST_CASE("c++ exceptions emergency pool", "[cxx] [exceptions] [ignore] [leaks="
|
||||
catch (int e)
|
||||
{
|
||||
thrown_value = e;
|
||||
printf("Got exception %d\n", thrown_value);
|
||||
}
|
||||
#if CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE > 0
|
||||
// free all memory
|
||||
|
@ -58,6 +58,7 @@ if(${target} STREQUAL "esp32s3")
|
||||
"sdmmc_host.c"
|
||||
"sdmmc_transaction.c"
|
||||
"mcpwm.c"
|
||||
"usb_serial_jtag.c"
|
||||
"spi_slave_hd.c"
|
||||
"touch_sensor_common.c")
|
||||
endif()
|
||||
|
@ -530,7 +530,7 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
|
||||
|
||||
static inline void adc2_init(void)
|
||||
{
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
/* Lock APB clock. */
|
||||
if (s_adc2_arbiter_lock == NULL) {
|
||||
@ -593,6 +593,12 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
//avoid collision with other tasks
|
||||
adc2_init(); // in critical section with whole rtc module. because the PWDET use the same registers, place it here.
|
||||
SARADC2_ENTER();
|
||||
|
||||
#if SOC_ADC_ARBITER_SUPPORTED
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
adc_hal_arbiter_config(&config);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ADC_DISABLE_DAC
|
||||
adc2_dac_disable(channel); //disable other peripherals
|
||||
#endif
|
||||
@ -603,7 +609,7 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
adc_hal_set_controller(ADC_NUM_2, ADC_CTRL_RTC);
|
||||
#endif
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (s_adc2_arbiter_lock) {
|
||||
esp_pm_lock_acquire(s_adc2_arbiter_lock);
|
||||
|
@ -538,6 +538,9 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
|
||||
SAR_ADC2_LOCK_ACQUIRE();
|
||||
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
adc_hal_arbiter_config(&config);
|
||||
|
||||
adc_atten_t atten = s_atten2_single[channel];
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_2, channel, atten);
|
||||
adc_hal_set_calibration_param(ADC_NUM_2, cal_val);
|
||||
|
@ -54,7 +54,7 @@ esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens);
|
||||
* @brief Start temperature sensor measure.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
* - ESP_ERR_INVALID_STATE if temperature sensor is started already.
|
||||
*/
|
||||
esp_err_t temp_sensor_start(void);
|
||||
|
||||
@ -62,6 +62,7 @@ esp_err_t temp_sensor_start(void);
|
||||
* @brief Stop temperature sensor measure.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_STATE if temperature sensor is stopped already.
|
||||
*/
|
||||
esp_err_t temp_sensor_stop(void);
|
||||
|
||||
|
@ -47,10 +47,22 @@ static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = {
|
||||
{TSENS_DAC_L4, 2, 10, -40, 20, 3},
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TSENS_HW_STATE_UNCONFIGURED,
|
||||
TSENS_HW_STATE_CONFIGURED,
|
||||
TSENS_HW_STATE_STARTED,
|
||||
} tsens_hw_state_t;
|
||||
|
||||
static tsens_hw_state_t tsens_hw_state = TSENS_HW_STATE_UNCONFIGURED;
|
||||
|
||||
static float s_deltaT = NAN; // unused number
|
||||
|
||||
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
{
|
||||
if (tsens_hw_state == TSENS_HW_STATE_STARTED) {
|
||||
ESP_LOGE(TAG, "Do not configure the temp sensor when it's running!");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_TSENS_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_SAR_FORCE_PD);
|
||||
SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_I2C_SAR_FORCE_PU);
|
||||
@ -62,6 +74,7 @@ esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
dac_offset[tsens.dac_offset].range_min,
|
||||
dac_offset[tsens.dac_offset].range_max,
|
||||
dac_offset[tsens.dac_offset].error_max);
|
||||
tsens_hw_state = TSENS_HW_STATE_CONFIGURED;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -83,9 +96,14 @@ esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens)
|
||||
|
||||
esp_err_t temp_sensor_start(void)
|
||||
{
|
||||
if (tsens_hw_state != TSENS_HW_STATE_CONFIGURED) {
|
||||
ESP_LOGE(TAG, "Temperature sensor is already running or not be configured");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_TSENS_CLK_EN);
|
||||
APB_SARADC.apb_tsens_ctrl2.tsens_clk_sel = 1;
|
||||
APB_SARADC.apb_tsens_ctrl.tsens_pu = 1;
|
||||
tsens_hw_state = TSENS_HW_STATE_STARTED;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -47,10 +47,22 @@ static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = {
|
||||
{TSENS_DAC_L4, 2, 10, -40, 20, 3},
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TSENS_HW_STATE_UNCONFIGURED,
|
||||
TSENS_HW_STATE_CONFIGURED,
|
||||
TSENS_HW_STATE_STARTED,
|
||||
} tsens_hw_state_t;
|
||||
|
||||
static tsens_hw_state_t tsens_hw_state = TSENS_HW_STATE_UNCONFIGURED;
|
||||
|
||||
static float s_deltaT = NAN; // unused number
|
||||
|
||||
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
{
|
||||
if (tsens_hw_state == TSENS_HW_STATE_STARTED) {
|
||||
ESP_LOGE(TAG, "Do not configure the temp sensor when it's running!");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_TSENS_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, ANA_I2C_SAR_FORCE_PD);
|
||||
SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_I2C_SAR_FORCE_PU);
|
||||
@ -62,6 +74,7 @@ esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
dac_offset[tsens.dac_offset].range_min,
|
||||
dac_offset[tsens.dac_offset].range_max,
|
||||
dac_offset[tsens.dac_offset].error_max);
|
||||
tsens_hw_state = TSENS_HW_STATE_CONFIGURED;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -83,9 +96,14 @@ esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens)
|
||||
|
||||
esp_err_t temp_sensor_start(void)
|
||||
{
|
||||
if (tsens_hw_state != TSENS_HW_STATE_CONFIGURED) {
|
||||
ESP_LOGE(TAG, "Temperature sensor is already running or not be configured");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_TSENS_CLK_EN);
|
||||
APB_SARADC.apb_tsens_ctrl2.tsens_clk_sel = 1;
|
||||
APB_SARADC.apb_tsens_ctrl.tsens_pu = 1;
|
||||
tsens_hw_state = TSENS_HW_STATE_STARTED;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -47,12 +47,25 @@ static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = {
|
||||
{TSENS_DAC_L4, 2, 10, -40, 20, 3},
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TSENS_HW_STATE_UNCONFIGURED,
|
||||
TSENS_HW_STATE_CONFIGURED,
|
||||
TSENS_HW_STATE_STARTED,
|
||||
} tsens_hw_state_t;
|
||||
|
||||
static tsens_hw_state_t tsens_hw_state = TSENS_HW_STATE_UNCONFIGURED;
|
||||
|
||||
static SemaphoreHandle_t rtc_tsens_mux = NULL;
|
||||
|
||||
static float s_deltaT = NAN; // Unused number
|
||||
|
||||
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (tsens_hw_state == TSENS_HW_STATE_STARTED) {
|
||||
ESP_LOGE(TAG, "Do not configure the temp sensor when it's running!");
|
||||
err = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PD_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PU_M);
|
||||
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_SAR_M);
|
||||
@ -68,7 +81,8 @@ esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
dac_offset[tsens.dac_offset].range_min,
|
||||
dac_offset[tsens.dac_offset].range_max,
|
||||
dac_offset[tsens.dac_offset].error_max);
|
||||
return ESP_OK;
|
||||
tsens_hw_state = TSENS_HW_STATE_CONFIGURED;
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens)
|
||||
@ -91,6 +105,11 @@ esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens)
|
||||
|
||||
esp_err_t temp_sensor_start(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (tsens_hw_state != TSENS_HW_STATE_CONFIGURED) {
|
||||
ESP_LOGE(TAG, "Temperature sensor is already running or not be configured");
|
||||
err = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (rtc_tsens_mux == NULL) {
|
||||
rtc_tsens_mux = xSemaphoreCreateMutex();
|
||||
}
|
||||
@ -98,7 +117,8 @@ esp_err_t temp_sensor_start(void)
|
||||
SENS.sar_tctrl.tsens_dump_out = 0;
|
||||
SENS.sar_tctrl2.tsens_clkgate_en = 1;
|
||||
SENS.sar_tctrl.tsens_power_up = 1;
|
||||
return ESP_OK;
|
||||
tsens_hw_state = TSENS_HW_STATE_STARTED;
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_stop(void)
|
||||
|
@ -539,6 +539,7 @@ esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode,
|
||||
ESP_RETURN_ON_FALSE(rx_trans_mode < I2C_DATA_MODE_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_TRANS_MODE_ERR_STR);
|
||||
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
i2c_hal_set_data_mode(&(i2c_context[i2c_num].hal), tx_trans_mode, rx_trans_mode);
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -690,13 +691,13 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
|
||||
i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), I2C_SLAVE_SDA_SAMPLE_DEFAULT, I2C_SLAVE_SDA_HOLD_DEFAULT);
|
||||
i2c_hal_set_tout(&(i2c_context[i2c_num].hal), I2C_SLAVE_TIMEOUT_DEFAULT);
|
||||
i2c_hal_enable_slave_rx_it(&(i2c_context[i2c_num].hal));
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
} else {
|
||||
i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num);
|
||||
//Default, we enable hardware filter
|
||||
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), I2C_FILTER_CYC_NUM_DEF);
|
||||
i2c_hal_set_bus_timing(&(i2c_context[i2c_num].hal), i2c_conf->master.clk_speed, src_clk);
|
||||
}
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -709,6 +710,7 @@ esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period)
|
||||
|
||||
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
i2c_hal_set_scl_timing(&(i2c_context[i2c_num].hal), high_period, low_period);
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -728,6 +730,7 @@ esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num)
|
||||
ESP_RETURN_ON_FALSE(p_i2c_obj[i2c_num] != NULL, ESP_FAIL, I2C_TAG, I2C_DRIVER_ERR_STR);
|
||||
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), cyc_num);
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -737,6 +740,7 @@ esp_err_t i2c_filter_disable(i2c_port_t i2c_num)
|
||||
ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR);
|
||||
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), 0);
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -749,6 +753,7 @@ esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time
|
||||
|
||||
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
i2c_hal_set_start_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time);
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -770,6 +775,7 @@ esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
|
||||
|
||||
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
i2c_hal_set_stop_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time);
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -791,6 +797,7 @@ esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time
|
||||
|
||||
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), sample_time, hold_time);
|
||||
i2c_hal_update_config(&(i2c_context[i2c_num].hal));
|
||||
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,6 @@
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
@ -28,7 +27,119 @@ extern "C" {
|
||||
|
||||
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
|
||||
|
||||
typedef intr_handle_t i2s_isr_handle_t;
|
||||
/**
|
||||
* @brief I2S port number, the max port number is (I2S_NUM_MAX -1).
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_NUM_0 = 0, /*!< I2S port 0 */
|
||||
#if SOC_I2S_NUM > 1
|
||||
I2S_NUM_1 = 1, /*!< I2S port 1 */
|
||||
#endif
|
||||
I2S_NUM_MAX, /*!< I2S port max */
|
||||
} i2s_port_t;
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PCM
|
||||
/**
|
||||
* @brief I2S PCM configuration
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
i2s_pcm_compress_t pcm_type; /*!< I2S PCM a/u-law decompress or compress type */
|
||||
} i2s_pcm_cfg_t;
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_TX
|
||||
/**
|
||||
* @brief Default I2S PDM Up-Sampling Rate configuration
|
||||
*/
|
||||
#define I2S_PDM_DEFAULT_UPSAMPLE_CONFIG(rate) { \
|
||||
.sample_rate = rate, \
|
||||
.fp = 960, \
|
||||
.fs = (rate) / 100, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S PDM up-sample rate configuration
|
||||
* @note TX PDM can only be set to the following two upsampling rate configurations:
|
||||
* 1: fp = 960, fs = sample_rate / 100, in this case, Fpdm = 128*48000
|
||||
* 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate
|
||||
* If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000.
|
||||
* Otherwise, the second configuration should be applied.
|
||||
*/
|
||||
typedef struct {
|
||||
int sample_rate; /*!< I2S PDM sample rate */
|
||||
int fp; /*!< I2S PDM TX upsampling paramater. Normally it should be set to 960 */
|
||||
int fs; /*!< I2S PDM TX upsampling paramater. When it is set to 480, the pdm clock frequency Fpdm = 128 * sample_rate, when it is set to sample_rate / 100, Fpdm will be fixed to 128*48000 */
|
||||
} i2s_pdm_tx_upsample_cfg_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2S pin number for i2s_set_pin
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
int mck_io_num; /*!< MCK in out pin*/
|
||||
int bck_io_num; /*!< BCK in out pin*/
|
||||
int ws_io_num; /*!< WS in out pin*/
|
||||
int data_out_num; /*!< DATA out pin*/
|
||||
int data_in_num; /*!< DATA in pin*/
|
||||
} i2s_pin_config_t;
|
||||
|
||||
/**
|
||||
* @brief I2S driver configuration parameters
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
i2s_mode_t mode; /*!< I2S work mode */
|
||||
uint32_t sample_rate; /*!< I2S sample rate */
|
||||
i2s_bits_per_sample_t bits_per_sample; /*!< I2S sample bits in one channel */
|
||||
i2s_channel_fmt_t channel_format; /*!< I2S channel format.*/
|
||||
i2s_comm_format_t communication_format; /*!< I2S communication format */
|
||||
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
|
||||
int dma_buf_count; /*!< I2S DMA Buffer Count */
|
||||
int dma_buf_len; /*!< I2S DMA Buffer Length */
|
||||
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
|
||||
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
|
||||
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value. If fixed_mclk set, mclk_multiple won't take effect */
|
||||
i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of I2S master clock(MCLK) to sample rate */
|
||||
i2s_bits_per_chan_t bits_per_chan; /*!< I2S total bits in one channel, only take effect when larger than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */
|
||||
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
i2s_channel_t chan_mask; /*!< I2S active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<<total_chan). */
|
||||
uint32_t total_chan; /*!< I2S Total number of channels. If it is smaller than the biggest active channel number, it will be set to this number automatically. */
|
||||
bool left_align; /*!< Set to enable left alignment */
|
||||
bool big_edin; /*!< Set to enable big edin */
|
||||
bool bit_order_msb; /*!< Set to enable msb order */
|
||||
bool skip_msk; /*!< Set to enable skip mask. If it is enabled, only the data of the enabled channels will be sent, otherwise all data stored in DMA TX buffer will be sent */
|
||||
#endif // SOC_I2S_SUPPORTS_TDM
|
||||
|
||||
} i2s_driver_config_t;
|
||||
|
||||
typedef i2s_driver_config_t i2s_config_t; // for backward compatible
|
||||
typedef intr_handle_t i2s_isr_handle_t; // for backward compatible
|
||||
|
||||
/**
|
||||
* @brief I2S event queue types
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_EVENT_DMA_ERROR,
|
||||
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
|
||||
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
|
||||
I2S_EVENT_TX_Q_OVF, /*!< I2S DMA sent queue overflow*/
|
||||
I2S_EVENT_RX_Q_OVF, /*!< I2S DMA receive queue overflow*/
|
||||
I2S_EVENT_MAX, /*!< I2S event max index*/
|
||||
} i2s_event_type_t;
|
||||
|
||||
/**
|
||||
* @brief Event structure used in I2S event queue
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
i2s_event_type_t type; /*!< I2S event type */
|
||||
size_t size; /*!< I2S data size for I2S_DATA event*/
|
||||
} i2s_event_t;
|
||||
|
||||
/**
|
||||
* @brief Set I2S pin number
|
||||
@ -37,7 +148,7 @@ typedef intr_handle_t i2s_isr_handle_t;
|
||||
* The I2S peripheral output signals can be connected to multiple GPIO pads.
|
||||
* However, the I2S peripheral input signal can only be connected to one GPIO pad.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0 or I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @param pin I2S Pin structure, or NULL to set 2-channel 8-bit internal DAC pin configuration (GPIO25 & GPIO26)
|
||||
*
|
||||
@ -54,15 +165,15 @@ typedef intr_handle_t i2s_isr_handle_t;
|
||||
*/
|
||||
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX
|
||||
/**
|
||||
* @brief Set PDM mode down-sample rate
|
||||
* In PDM RX mode, there would be 2 rounds of downsample process in hardware.
|
||||
* In the first downsample process, the sampling number can be 16 or 8.
|
||||
* In the second downsample process, the sampling number is fixed as 8.
|
||||
* So the clock frequency in PDM RX mode would be (fpcm * 64) or (fpcm * 128) accordingly.
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param dsr i2s RX down sample rate for PDM mode.
|
||||
* @param i2s_num I2S port number
|
||||
* @param downsample i2s RX down sample rate for PDM mode.
|
||||
*
|
||||
* @note After calling this function, it would call i2s_set_clk inside to update the clock frequency.
|
||||
* Please call this function after I2S driver has been initialized.
|
||||
@ -72,13 +183,31 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr);
|
||||
esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t downsample);
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_TX
|
||||
/**
|
||||
* @brief Set TX PDM mode up-sample rate
|
||||
* @note If you have set PDM mode while calling 'i2s_driver_install',
|
||||
* default PDM TX upsample parameters have already been set,
|
||||
* no need to call this function again if you don't have to change the default configuration
|
||||
*
|
||||
* @param i2s_num I2S port number
|
||||
* @param upsample_cfg Set I2S PDM up-sample rate configuration
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, const i2s_pdm_tx_upsample_cfg_t *upsample_cfg);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Install and start I2S driver.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @param i2s_config I2S configurations - see i2s_config_t struct
|
||||
*
|
||||
@ -92,24 +221,26 @@ esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr);
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
* - ESP_ERR_NOT_FOUND I2S port is not found or has been installed by others (e.g. LCD i80)
|
||||
*/
|
||||
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
|
||||
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue);
|
||||
|
||||
/**
|
||||
* @brief Uninstall I2S driver.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_INVALID_STATE I2S port has been uninstalled by others (e.g. LCD i80)
|
||||
*/
|
||||
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
|
||||
|
||||
/**
|
||||
* @brief Write data to I2S DMA transmit buffer.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @param src Source address to write from
|
||||
*
|
||||
@ -133,7 +264,7 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by
|
||||
/**
|
||||
* @brief Write data to I2S DMA transmit buffer while expanding the number of bits per sample. For example, expanding 16-bit PCM to 32-bit PCM.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @param src Source address to write from
|
||||
*
|
||||
@ -164,7 +295,7 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz
|
||||
/**
|
||||
* @brief Read data from I2S DMA receive buffer
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @param dest Destination address to read into
|
||||
*
|
||||
@ -190,7 +321,7 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re
|
||||
*
|
||||
* `bit_clock = rate * (number of channels) * bits_per_sample`
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @param rate I2S sample rate (ex: 8000, 44100...)
|
||||
*
|
||||
@ -208,7 +339,7 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
|
||||
*
|
||||
* Disables I2S TX/RX, until i2s_start() is called.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
@ -222,7 +353,7 @@ esp_err_t i2s_stop(i2s_port_t i2s_num);
|
||||
* It is not necessary to call this function after i2s_driver_install() (it is started automatically), however it is necessary to call it after i2s_stop().
|
||||
*
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
@ -235,7 +366,7 @@ esp_err_t i2s_start(i2s_port_t i2s_num);
|
||||
*
|
||||
* Pushes zero-byte samples into the TX DMA buffer, until it is full.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
@ -243,30 +374,56 @@ esp_err_t i2s_start(i2s_port_t i2s_num);
|
||||
*/
|
||||
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PCM
|
||||
/**
|
||||
* @brief Configure I2S a/u-law decompress or compress
|
||||
*
|
||||
* @note This function should be called after i2s driver installed
|
||||
* Only take effecttive when the i2s 'communication_format' is set to 'I2S_COMM_FORMAT_STAND_PCM_SHORT' or 'I2S_COMM_FORMAT_STAND_PCM_LONG'
|
||||
*
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @param pcm_cfg including mode selection and a/u-law decompress or compress configuration paramater
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_pcm_config(i2s_port_t i2s_num, const i2s_pcm_cfg_t *pcm_cfg);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set clock & bit width used for I2S RX and TX.
|
||||
*
|
||||
* Similar to i2s_set_sample_rates(), but also sets bit width.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* 1. stop i2s;
|
||||
* 2. calculate mclk, bck, bck_factor
|
||||
* 3. malloc dma buffer;
|
||||
* 4. start i2s
|
||||
*
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @param rate I2S sample rate (ex: 8000, 44100...)
|
||||
*
|
||||
* @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT)
|
||||
* @param bits_cfg I2S bits configuration
|
||||
* the low 16 bits is for data bits per sample in one channel (see 'i2s_bits_per_sample_t')
|
||||
* the high 16 bits is for total bits in one channel (see 'i2s_bits_per_chan_t')
|
||||
* high 16bits =0 means same as the bits per sample.
|
||||
*
|
||||
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
|
||||
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO or specific channel in TDM mode)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch);
|
||||
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_channel_t ch);
|
||||
|
||||
/**
|
||||
* @brief get clock set on particular port number.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S port number
|
||||
*
|
||||
* @return
|
||||
* - actual clock set by i2s driver
|
||||
|
@ -24,6 +24,38 @@ extern "C" {
|
||||
|
||||
typedef intr_handle_t ledc_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief LEDC callback event type
|
||||
*/
|
||||
typedef enum {
|
||||
LEDC_FADE_END_EVT /**< LEDC fade end event */
|
||||
} ledc_cb_event_t;
|
||||
|
||||
/**
|
||||
* @brief LEDC callback parameter
|
||||
*/
|
||||
typedef struct {
|
||||
ledc_cb_event_t event; /**< Event name */
|
||||
uint32_t speed_mode; /**< Speed mode of the LEDC channel group */
|
||||
uint32_t channel; /**< LEDC channel (0 - LEDC_CHANNEL_MAX-1) */
|
||||
uint32_t duty; /**< LEDC current duty of the channel, the range of duty is [0, (2**duty_resolution) - 1] */
|
||||
} ledc_cb_param_t;
|
||||
|
||||
/**
|
||||
* @brief Type of LEDC event callback
|
||||
* @param param LEDC callback parameter
|
||||
* @param user_arg User registered data
|
||||
*/
|
||||
typedef bool (* ledc_cb_t)(const ledc_cb_param_t *param, void *user_arg);
|
||||
|
||||
/**
|
||||
* @brief Group of supported LEDC callbacks
|
||||
* @note The callbacks are all running under ISR environment
|
||||
*/
|
||||
typedef struct {
|
||||
ledc_cb_t fade_cb; /**< LEDC fade_end callback function */
|
||||
} ledc_cbs_t;
|
||||
|
||||
/**
|
||||
* @brief LEDC channel configuration
|
||||
* Configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC duty resolution
|
||||
@ -57,7 +89,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf);
|
||||
* control one LEDC channel in different tasks at the same time.
|
||||
* A thread-safe version of API is ledc_set_duty_and_update
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
@ -72,7 +104,7 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||
*
|
||||
* @param gpio_num The LEDC output gpio
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param ledc_channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param ledc_channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
@ -85,7 +117,7 @@ esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc
|
||||
* Disable LEDC output, and set idle level
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param idle_level Set output idle level after LEDC stops.
|
||||
*
|
||||
* @return
|
||||
@ -129,8 +161,8 @@ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
|
||||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1]
|
||||
* @param hpoint Set the LEDC hpoint value(max: 0xfffff)
|
||||
*
|
||||
* @return
|
||||
@ -143,7 +175,7 @@ esp_err_t ledc_set_duty_with_hpoint(ledc_mode_t speed_mode, ledc_channel_t chann
|
||||
* @brief LEDC get hpoint value, the counter value when the output is set high level.
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @return
|
||||
* - LEDC_ERR_VAL if parameter error
|
||||
* - Others Current hpoint value of LEDC channel
|
||||
@ -160,8 +192,8 @@ int ledc_get_hpoint(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1]
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
@ -173,7 +205,7 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
|
||||
* @brief LEDC get duty
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
*
|
||||
* @return
|
||||
* - LEDC_ERR_DUTY if parameter error
|
||||
@ -187,8 +219,8 @@ uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)]
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution) - 1]
|
||||
* @param fade_direction Set the direction of the gradient
|
||||
* @param step_num Set the number of the gradient
|
||||
* @param duty_cycle_num Set how many LEDC tick each time the gradient lasts
|
||||
@ -274,7 +306,7 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, ledc_timer_t timer_sel);
|
||||
* @brief Bind LEDC channel with the selected timer
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
*
|
||||
* @return
|
||||
@ -293,7 +325,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel
|
||||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. ,
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
|
||||
* @param scale Controls the increase or decrease step scale.
|
||||
* @param cycle_num increase or decrease the duty every cycle_num cycles
|
||||
@ -316,8 +348,8 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel
|
||||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. ,
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading.( 0 - (2 ** duty_resolution - 1)))
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
|
||||
* @param max_fade_time_ms The maximum time of the fading ( ms ).
|
||||
*
|
||||
* @return
|
||||
@ -368,8 +400,8 @@ esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_f
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1]
|
||||
* @param hpoint Set the LEDC hpoint value(max: 0xfffff)
|
||||
*
|
||||
*/
|
||||
@ -381,8 +413,8 @@ esp_err_t ledc_set_duty_and_update(ledc_mode_t speed_mode, ledc_channel_t channe
|
||||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading.( 0 - (2 ** duty_resolution - 1)))
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
|
||||
* @param max_fade_time_ms The maximum time of the fading ( ms ).
|
||||
* @param fade_mode choose blocking or non-blocking mode
|
||||
* @return
|
||||
@ -399,7 +431,7 @@ esp_err_t ledc_set_fade_time_and_start(ledc_mode_t speed_mode, ledc_channel_t ch
|
||||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
|
||||
* @param scale Controls the increase or decrease step scale.
|
||||
* @param cycle_num increase or decrease the duty every cycle_num cycles
|
||||
@ -414,3 +446,18 @@ esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t ch
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LEDC callback registration function
|
||||
* @note The callback is called from an ISR, it must never attempt to block, and any FreeRTOS API called must be ISR capable.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param cbs Group of LEDC callback functions
|
||||
* @param user_arg user registered data for the callback function
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_STATE Fade function not installed.
|
||||
* - ESP_FAIL Fade function init error
|
||||
*/
|
||||
esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg);
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "esp_err.h"
|
||||
#include "soc/soc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "hal/mcpwm_types.h"
|
||||
|
||||
@ -46,8 +45,7 @@ typedef enum {
|
||||
} mcpwm_io_signals_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM pin number for
|
||||
*
|
||||
* @brief pin number for MCPWM
|
||||
*/
|
||||
typedef struct {
|
||||
int mcpwm0a_out_num; /*!<MCPWM0A out pin*/
|
||||
@ -71,9 +69,9 @@ typedef struct {
|
||||
* @brief Select MCPWM unit
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_UNIT_0 = 0, /*!<MCPWM unit0 selected*/
|
||||
MCPWM_UNIT_1, /*!<MCPWM unit1 selected*/
|
||||
MCPWM_UNIT_MAX, /*!<Num of MCPWM units on ESP32*/
|
||||
MCPWM_UNIT_0, /*!<MCPWM unit0 selected*/
|
||||
MCPWM_UNIT_1, /*!<MCPWM unit1 selected*/
|
||||
MCPWM_UNIT_MAX, /*!<Max number of MCPWM units*/
|
||||
} mcpwm_unit_t;
|
||||
|
||||
_Static_assert(MCPWM_UNIT_MAX == SOC_MCPWM_GROUPS, "MCPWM unit number not equal to chip capabilities");
|
||||
@ -82,19 +80,19 @@ _Static_assert(MCPWM_UNIT_MAX == SOC_MCPWM_GROUPS, "MCPWM unit number not equal
|
||||
* @brief Select MCPWM timer
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_TIMER_0 = 0, /*!<Select MCPWM timer0*/
|
||||
MCPWM_TIMER_1, /*!<Select MCPWM timer1*/
|
||||
MCPWM_TIMER_2, /*!<Select MCPWM timer2*/
|
||||
MCPWM_TIMER_MAX, /*!<Num of MCPWM timers on ESP32*/
|
||||
MCPWM_TIMER_0, /*!<Select MCPWM timer0*/
|
||||
MCPWM_TIMER_1, /*!<Select MCPWM timer1*/
|
||||
MCPWM_TIMER_2, /*!<Select MCPWM timer2*/
|
||||
MCPWM_TIMER_MAX, /*!<Max number of timers in a unit*/
|
||||
} mcpwm_timer_t;
|
||||
|
||||
/**
|
||||
* @brief Select MCPWM operator
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_GEN_A = 0, /*!<Select MCPWMXA, where 'X' is operator number*/
|
||||
MCPWM_GEN_B, /*!<Select MCPWMXB, where 'X' is operator number*/
|
||||
MCPWM_GEN_MAX, /*!<Num of generators to each operator of MCPWM*/
|
||||
MCPWM_GEN_A, /*!<Select MCPWMXA, where 'X' is operator number*/
|
||||
MCPWM_GEN_B, /*!<Select MCPWMXB, where 'X' is operator number*/
|
||||
MCPWM_GEN_MAX, /*!<Num of generators to each operator of MCPWM*/
|
||||
} mcpwm_generator_t;
|
||||
|
||||
//definitions and macros to be back-compatible before IDFv4.1
|
||||
@ -107,25 +105,25 @@ typedef mcpwm_generator_t mcpwm_operator_t; ///< @deprecated
|
||||
* @brief MCPWM carrier oneshot mode, in this mode the width of the first pulse of carrier can be programmed
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_ONESHOT_MODE_DIS = 0, /*!<Enable oneshot mode*/
|
||||
MCPWM_ONESHOT_MODE_EN, /*!<Disable oneshot mode*/
|
||||
MCPWM_ONESHOT_MODE_DIS, /*!<Enable oneshot mode*/
|
||||
MCPWM_ONESHOT_MODE_EN, /*!<Disable oneshot mode*/
|
||||
} mcpwm_carrier_os_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM carrier output inversion, high frequency carrier signal active with MCPWM signal is high
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_CARRIER_OUT_IVT_DIS = 0, /*!<Enable carrier output inversion*/
|
||||
MCPWM_CARRIER_OUT_IVT_EN, /*!<Disable carrier output inversion*/
|
||||
MCPWM_CARRIER_OUT_IVT_DIS, /*!<Enable carrier output inversion*/
|
||||
MCPWM_CARRIER_OUT_IVT_EN, /*!<Disable carrier output inversion*/
|
||||
} mcpwm_carrier_out_ivt_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM select fault signal input
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_SELECT_F0 = 0, /*!<Select F0 as input*/
|
||||
MCPWM_SELECT_F1, /*!<Select F1 as input*/
|
||||
MCPWM_SELECT_F2, /*!<Select F2 as input*/
|
||||
MCPWM_SELECT_F0, /*!<Select F0 as input*/
|
||||
MCPWM_SELECT_F1, /*!<Select F1 as input*/
|
||||
MCPWM_SELECT_F2, /*!<Select F2 as input*/
|
||||
} mcpwm_fault_signal_t;
|
||||
|
||||
/**
|
||||
@ -141,8 +139,8 @@ typedef enum {
|
||||
* @brief MCPWM select triggering level of fault signal
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_LOW_LEVEL_TGR = 0, /*!<Fault condition occurs when fault input signal goes from high to low, currently not supported*/
|
||||
MCPWM_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
|
||||
MCPWM_LOW_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes from high to low, currently not supported*/
|
||||
MCPWM_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
|
||||
} mcpwm_fault_input_level_t;
|
||||
|
||||
/**
|
||||
@ -154,6 +152,16 @@ typedef enum {
|
||||
MCPWM_BOTH_EDGE = BIT(1) | BIT(0), /*!<Capture both edges*/
|
||||
} mcpwm_capture_on_edge_t;
|
||||
|
||||
/**
|
||||
* @brief Interrupt masks for MCPWM capture
|
||||
*/
|
||||
__attribute__ ((deprecated("please use callback function to avoid directly accessing registers")))
|
||||
typedef enum {
|
||||
MCPWM_LL_INTR_CAP0 = BIT(27), ///< Capture 0 happened
|
||||
MCPWM_LL_INTR_CAP1 = BIT(28), ///< Capture 1 happened
|
||||
MCPWM_LL_INTR_CAP2 = BIT(29), ///< Capture 2 happened
|
||||
} mcpwm_intr_t;
|
||||
|
||||
/**
|
||||
* @brief Select type of MCPWM counter
|
||||
*/
|
||||
@ -181,15 +189,15 @@ typedef enum {
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_DEADTIME_BYPASS = 0, /*!<Bypass the deadtime*/
|
||||
MCPWM_BYPASS_RED, /*!<MCPWMXA = no change, MCPWMXB = falling edge delay*/
|
||||
MCPWM_BYPASS_FED, /*!<MCPWMXA = rising edge delay, MCPWMXB = no change*/
|
||||
MCPWM_ACTIVE_HIGH_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = falling edge delay*/
|
||||
MCPWM_ACTIVE_LOW_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = compliment of falling edge delay*/
|
||||
MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = compliment of falling edge delay*/
|
||||
MCPWM_ACTIVE_LOW_COMPLIMENT_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = falling edge delay*/
|
||||
MCPWM_ACTIVE_RED_FED_FROM_PWMXA, /*!<MCPWMXA = MCPWMXB = rising edge delay as well as falling edge delay, generated from MCPWMXA*/
|
||||
MCPWM_ACTIVE_RED_FED_FROM_PWMXB, /*!<MCPWMXA = MCPWMXB = rising edge delay as well as falling edge delay, generated from MCPWMXB*/
|
||||
MCPWM_DEADTIME_TYPE_MAX,
|
||||
MCPWM_BYPASS_RED, /*!<MCPWMXA Out = MCPWMXA In with no delay, MCPWMXB Out = MCPWMXA In with falling edge delay*/
|
||||
MCPWM_BYPASS_FED, /*!<MCPWMXA Out = MCPWMXA In with rising edge delay, MCPWMXB Out = MCPWMXB In with no delay*/
|
||||
MCPWM_ACTIVE_HIGH_MODE, /*!<MCPWMXA Out = MCPWMXA In with rising edge delay, MCPWMXB Out = MCPWMXA In with falling edge delay*/
|
||||
MCPWM_ACTIVE_LOW_MODE, /*!<MCPWMXA Out = MCPWMXA In with compliment of rising edge delay, MCPWMXB Out = MCPWMXA In with compliment of falling edge delay*/
|
||||
MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, /*!<MCPWMXA Out = MCPWMXA In with rising edge delay, MCPWMXB = MCPWMXA In with compliment of falling edge delay*/
|
||||
MCPWM_ACTIVE_LOW_COMPLIMENT_MODE, /*!<MCPWMXA Out = MCPWMXA In with compliment of rising edge delay, MCPWMXB Out = MCPWMXA In with falling edge delay*/
|
||||
MCPWM_ACTIVE_RED_FED_FROM_PWMXA, /*!<MCPWMXA Out = MCPWMXB Out = MCPWMXA In with rising edge delay as well as falling edge delay*/
|
||||
MCPWM_ACTIVE_RED_FED_FROM_PWMXB, /*!<MCPWMXA Out = MCPWMXB Out = MCPWMXB In with rising edge delay as well as falling edge delay*/
|
||||
MCPWM_DEADTIME_TYPE_MAX, /*!<Maximum number of supported dead time modes*/
|
||||
} mcpwm_deadtime_type_t;
|
||||
|
||||
/**
|
||||
@ -220,11 +228,40 @@ typedef mcpwm_output_action_t mcpwm_action_on_pwmxb_t;
|
||||
* @brief MCPWM select capture signal input
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_SELECT_CAP0 = 0, /*!<Select CAP0 as input*/
|
||||
MCPWM_SELECT_CAP1, /*!<Select CAP1 as input*/
|
||||
MCPWM_SELECT_CAP2, /*!<Select CAP2 as input*/
|
||||
MCPWM_SELECT_CAP0, /*!<Select CAP0 as input*/
|
||||
MCPWM_SELECT_CAP1, /*!<Select CAP1 as input*/
|
||||
MCPWM_SELECT_CAP2, /*!<Select CAP2 as input*/
|
||||
} mcpwm_capture_signal_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM capture channel ID alias
|
||||
*/
|
||||
typedef mcpwm_capture_signal_t mcpwm_capture_channel_id_t;
|
||||
|
||||
/**
|
||||
* @brief event data that will be passed into ISR callback
|
||||
*/
|
||||
typedef struct {
|
||||
mcpwm_capture_on_edge_t cap_edge; /*!<Which signal edge is detected*/
|
||||
uint32_t cap_value; /*!<Corresponding timestamp when event occurs. Clock rate = APB(usually 80M)*/
|
||||
} cap_event_data_t;
|
||||
|
||||
/**
|
||||
* @brief Type of capture event callback
|
||||
* @param mcpwm MCPWM unit(0-1)
|
||||
* @param cap_channel capture channel ID
|
||||
* @param edata Capture event data, contains capture edge and capture value, fed by the driver
|
||||
* @param user_data User registered data, passed from `mcpwm_capture_config_t`
|
||||
*
|
||||
* @note Since this an ISR callback so do not do anything that may block and call APIs that is designed to be used within ISR(usually has '_ISR' postfix)
|
||||
*
|
||||
* @return Whether a task switch is needed after the callback function returns,
|
||||
* this is usually due to the callback wakes up some high priority task.
|
||||
*
|
||||
*/
|
||||
typedef bool (*cap_isr_cb_t)(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_channel, const cap_event_data_t *edata,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @brief MCPWM config structure
|
||||
*/
|
||||
@ -237,7 +274,7 @@ typedef struct {
|
||||
} mcpwm_config_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM config carrier structure
|
||||
* @brief MCPWM carrier configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t carrier_period; /*!<Set carrier period = (carrier_period + 1)*800ns, carrier_period should be < 16*/
|
||||
@ -247,10 +284,20 @@ typedef struct {
|
||||
mcpwm_carrier_out_ivt_t carrier_ivt_mode; /*!<Invert output of carrier*/
|
||||
} mcpwm_carrier_config_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM config capture structure
|
||||
*/
|
||||
typedef struct {
|
||||
mcpwm_capture_on_edge_t cap_edge; /*!<Set capture edge*/
|
||||
uint32_t cap_prescale; /*!<Prescale of capture signal, ranging from 1 to 256*/
|
||||
cap_isr_cb_t capture_cb; /*!<User defined capture event callback, running under interrupt context */
|
||||
void *user_data; /*!<User defined ISR callback function args*/
|
||||
} mcpwm_capture_config_t;
|
||||
|
||||
/**
|
||||
* @brief This function initializes each gpio signal for MCPWM
|
||||
* @note
|
||||
* This function initializes one gpio at a time.
|
||||
*
|
||||
* @note This function initializes one gpio at a time.
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param io_signal set MCPWM signals, each MCPWM unit has 6 output(MCPWMXA, MCPWMXB) and 9 input(SYNC_X, FAULT_X, CAP_X)
|
||||
@ -265,8 +312,8 @@ esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal,
|
||||
|
||||
/**
|
||||
* @brief Initialize MCPWM gpio structure
|
||||
* @note
|
||||
* This function can be used to initialize more then one gpio at a time.
|
||||
*
|
||||
* @note This function initialize a group of MCPWM GPIOs at a time.
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param mcpwm_pin MCPWM pin structure
|
||||
@ -279,6 +326,10 @@ esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_
|
||||
|
||||
/**
|
||||
* @brief Initialize MCPWM parameters
|
||||
* @note
|
||||
* The default resolution configured for MCPWM group and timer are 160M / 16 = 10M and 10M / 10 = 1M
|
||||
* The default resolution can be changed by calling mcpwm_group_set_resolution() and mcpwm_timer_set_resolution(),
|
||||
* before calling this function.
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers.
|
||||
@ -290,6 +341,39 @@ esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_
|
||||
*/
|
||||
esp_err_t mcpwm_init( mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpwm_config_t *mcpwm_conf);
|
||||
|
||||
/**
|
||||
* @brief Set resolution of the MCPWM group
|
||||
* @note
|
||||
* This will override default resolution of group(=10,000,000).
|
||||
* This WILL NOT automatically update frequency and duty. Call mcpwm_set_frequency() and mcpwm_set_duty() manually
|
||||
* to set them back.
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param resolution set expected frequency resolution
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, unsigned long int resolution);
|
||||
|
||||
/**
|
||||
* @brief Set resolution of each timer
|
||||
* @note
|
||||
* This WILL override default resolution of timer(=1,000,000).
|
||||
* This WILL NOT automatically update frequency and duty. Call mcpwm_set_frequency() and mcpwm_set_duty() manually
|
||||
* to set them back.
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
|
||||
* @param resolution set expected frequency resolution
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t mcpwm_timer_set_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, unsigned long int resolution);
|
||||
|
||||
/**
|
||||
* @brief Set frequency(in Hz) of MCPWM timer
|
||||
*
|
||||
@ -333,7 +417,7 @@ esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
|
||||
|
||||
/**
|
||||
* @brief Set duty either active high or active low(out of phase/inverted)
|
||||
* @note
|
||||
* @note
|
||||
* Call this function every time after mcpwm_set_signal_high or mcpwm_set_signal_low to resume with previously set duty cycle
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
@ -370,6 +454,18 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
|
||||
*/
|
||||
float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen);
|
||||
|
||||
/**
|
||||
* @brief Get duty cycle of each operator in us
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
|
||||
* @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
|
||||
*
|
||||
* @return
|
||||
* - duty cycle in us of each operator
|
||||
*/
|
||||
uint32_t mcpwm_get_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen);
|
||||
|
||||
/**
|
||||
* @brief Use this function to set MCPWM signal high
|
||||
*
|
||||
@ -570,7 +666,7 @@ esp_err_t mcpwm_fault_init(mcpwm_unit_t mcpwm_num, mcpwm_fault_input_level_t int
|
||||
|
||||
/**
|
||||
* @brief Set oneshot mode on fault detection, once fault occur in oneshot mode reset is required to resume MCPWM signals
|
||||
* @note
|
||||
* @note
|
||||
* currently low level triggering is not supported
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
@ -588,7 +684,7 @@ esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
|
||||
|
||||
/**
|
||||
* @brief Set cycle-by-cycle mode on fault detection, once fault occur in cyc mode MCPWM signal resumes as soon as fault signal becomes inactive
|
||||
* @note
|
||||
* @note
|
||||
* currently low level triggering is not supported
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
@ -619,20 +715,20 @@ esp_err_t mcpwm_fault_deinit(mcpwm_unit_t mcpwm_num, mcpwm_fault_signal_t fault_
|
||||
/**
|
||||
* @brief Initialize capture submodule
|
||||
*
|
||||
* @note Enabling capture feature could also enable the capture interrupt,
|
||||
* @note Enabling capture feature would also enable the capture interrupt event,
|
||||
* users have to register an interrupt handler by `mcpwm_isr_register`, and in there, query the capture data.
|
||||
* @note The capture timer uses APB_CLK (typically 80MHz) as the count source.
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param cap_edge set capture edge, BIT(0) - negative edge, BIT(1) - positive edge
|
||||
* @param cap_sig capture pin, which needs to be enabled
|
||||
* @param num_of_pulse count time between rising/falling edge between 2 *(pulses mentioned), counter uses APB_CLK
|
||||
* [0~MCPWM_LL_MAX_PRESCALE] (MCPWM_LL_MAX_PRESCALE = 255 on ESP32);
|
||||
* @param num_of_pulse Input capture signal prescaling, ranges from 0 to 255, representing prescaling from 1 to 256.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
|
||||
__attribute__((deprecated("please use mcpwm_capture_enable_channel instead")))
|
||||
esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig, mcpwm_capture_on_edge_t cap_edge,
|
||||
uint32_t num_of_pulse);
|
||||
|
||||
@ -646,13 +742,39 @@ esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t ca
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
__attribute__((deprecated("please use mcpwm_capture_disable_channel instead")))
|
||||
esp_err_t mcpwm_capture_disable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig);
|
||||
|
||||
/**
|
||||
* @brief Enable capture channel
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param cap_channel capture channel, which needs to be enabled
|
||||
* @param cap_conf capture channel configuration
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_channel_id_t cap_channel, const mcpwm_capture_config_t *cap_conf);
|
||||
|
||||
/**
|
||||
* @brief Disable capture channel
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param cap_channel capture channel, which needs to be disabled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t mcpwm_capture_disable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_channel_id_t cap_channel);
|
||||
|
||||
/**
|
||||
* @brief Get capture value
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param cap_sig capture pin on which value is to be measured
|
||||
* @param cap_sig capture channel on which value is to be measured
|
||||
*
|
||||
* @return
|
||||
* Captured value
|
||||
@ -663,7 +785,7 @@ uint32_t mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_si
|
||||
* @brief Get edge of capture signal
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param cap_sig capture pin of whose edge is to be determined
|
||||
* @param cap_sig capture channel of whose edge is to be determined
|
||||
*
|
||||
* @return
|
||||
* Capture signal edge: 1 - positive edge, 2 - negtive edge
|
||||
@ -713,8 +835,9 @@ esp_err_t mcpwm_sync_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Function pointer error.
|
||||
*/
|
||||
esp_err_t mcpwm_isr_register(mcpwm_unit_t mcpwm_num, void (*fn)(void *), void *arg, int intr_alloc_flags, intr_handle_t *handle);
|
||||
|
||||
__attribute__((deprecated("interrupt events are handled by driver, please use callback")))
|
||||
esp_err_t mcpwm_isr_register(mcpwm_unit_t mcpwm_num, void (*fn)(void *), void *arg, int intr_alloc_flags,
|
||||
intr_handle_t *handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -6,20 +6,104 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/pcnt_types.h"
|
||||
#include "soc/pcnt_periph.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */
|
||||
|
||||
typedef intr_handle_t pcnt_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief PCNT port number, the max port number is (PCNT_PORT_MAX - 1).
|
||||
*/
|
||||
typedef enum {
|
||||
PCNT_PORT_0, /*!< PCNT port 0 */
|
||||
PCNT_PORT_MAX, /*!< PCNT port max */
|
||||
} pcnt_port_t;
|
||||
|
||||
/**
|
||||
* @brief Selection of all available PCNT units
|
||||
*/
|
||||
typedef enum {
|
||||
PCNT_UNIT_0, /*!< PCNT unit 0 */
|
||||
PCNT_UNIT_1, /*!< PCNT unit 1 */
|
||||
PCNT_UNIT_2, /*!< PCNT unit 2 */
|
||||
PCNT_UNIT_3, /*!< PCNT unit 3 */
|
||||
#if SOC_PCNT_UNITS_PER_GROUP > 4
|
||||
PCNT_UNIT_4, /*!< PCNT unit 4 */
|
||||
PCNT_UNIT_5, /*!< PCNT unit 5 */
|
||||
PCNT_UNIT_6, /*!< PCNT unit 6 */
|
||||
PCNT_UNIT_7, /*!< PCNT unit 7 */
|
||||
#endif
|
||||
PCNT_UNIT_MAX,
|
||||
} pcnt_unit_t;
|
||||
|
||||
/**
|
||||
* @brief Selection of channels available for a single PCNT unit
|
||||
*/
|
||||
typedef enum {
|
||||
PCNT_CHANNEL_0, /*!< PCNT channel 0 */
|
||||
PCNT_CHANNEL_1, /*!< PCNT channel 1 */
|
||||
PCNT_CHANNEL_MAX,
|
||||
} pcnt_channel_t;
|
||||
|
||||
/**
|
||||
* @brief Selection of counter's events the may trigger an interrupt
|
||||
*/
|
||||
typedef enum {
|
||||
PCNT_EVT_THRES_1 = 1 << 2, /*!< PCNT watch point event: threshold1 value event */
|
||||
PCNT_EVT_THRES_0 = 1 << 3, /*!< PCNT watch point event: threshold0 value event */
|
||||
PCNT_EVT_L_LIM = 1 << 4, /*!< PCNT watch point event: Minimum counter value */
|
||||
PCNT_EVT_H_LIM = 1 << 5, /*!< PCNT watch point event: Maximum counter value */
|
||||
PCNT_EVT_ZERO = 1 << 6, /*!< PCNT watch point event: counter value zero event */
|
||||
PCNT_EVT_MAX
|
||||
} pcnt_evt_type_t;
|
||||
|
||||
/**
|
||||
* @brief Selection of available modes that determine the counter's action depending on the state of the control signal's input GPIO
|
||||
* @note Configuration covers two actions, one for high, and one for low level on the control input
|
||||
*/
|
||||
typedef pcnt_channel_level_action_t pcnt_ctrl_mode_t;
|
||||
#define PCNT_MODE_KEEP PCNT_CHANNEL_LEVEL_ACTION_KEEP /*!< Control mode: won't change counter mode*/
|
||||
#define PCNT_MODE_REVERSE PCNT_CHANNEL_LEVEL_ACTION_INVERSE /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase) */
|
||||
#define PCNT_MODE_DISABLE PCNT_CHANNEL_LEVEL_ACTION_HOLD /*!< Control mode: Inhibit counter(counter value will not change in this condition) */
|
||||
#define PCNT_MODE_MAX 3
|
||||
|
||||
/**
|
||||
* @brief Selection of available modes that determine the counter's action on the edge of the pulse signal's input GPIO
|
||||
* @note Configuration covers two actions, one for positive, and one for negative edge on the pulse input
|
||||
*/
|
||||
typedef pcnt_channel_edge_action_t pcnt_count_mode_t;
|
||||
#define PCNT_COUNT_DIS PCNT_CHANNEL_EDGE_ACTION_HOLD /*!< Counter mode: Inhibit counter(counter value will not change in this condition) */
|
||||
#define PCNT_COUNT_INC PCNT_CHANNEL_EDGE_ACTION_INCREASE /*!< Counter mode: Increase counter value */
|
||||
#define PCNT_COUNT_DEC PCNT_CHANNEL_EDGE_ACTION_DECREASE /*!< Counter mode: Decrease counter value */
|
||||
#define PCNT_COUNT_MAX 3
|
||||
|
||||
/**
|
||||
* @brief Pulse Counter configuration for a single channel
|
||||
*/
|
||||
typedef struct {
|
||||
int pulse_gpio_num; /*!< Pulse input GPIO number, if you want to use GPIO16, enter pulse_gpio_num = 16, a negative value will be ignored */
|
||||
int ctrl_gpio_num; /*!< Control signal input GPIO number, a negative value will be ignored */
|
||||
pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode */
|
||||
pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode */
|
||||
pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode */
|
||||
pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode */
|
||||
int16_t counter_h_lim; /*!< Maximum counter value */
|
||||
int16_t counter_l_lim; /*!< Minimum counter value */
|
||||
pcnt_unit_t unit; /*!< PCNT unit number */
|
||||
pcnt_channel_t channel; /*!< the PCNT channel */
|
||||
} pcnt_config_t;
|
||||
|
||||
/**
|
||||
* @brief Configure Pulse Counter unit
|
||||
* @note
|
||||
@ -173,7 +257,6 @@ esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16
|
||||
* @param unit PCNT unit number
|
||||
* @param status Pointer to accept event status word
|
||||
* @return
|
||||
*
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
@ -363,42 +446,6 @@ void pcnt_isr_service_uninstall(void);
|
||||
*/
|
||||
esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit);
|
||||
|
||||
/**
|
||||
* @addtogroup pcnt-examples
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* EXAMPLE OF PCNT CONFIGURATION
|
||||
* ==============================
|
||||
* @code{c}
|
||||
* //1. Config PCNT unit
|
||||
* pcnt_config_t pcnt_config = {
|
||||
* .pulse_gpio_num = 4, //set gpio4 as pulse input gpio
|
||||
* .ctrl_gpio_num = 5, //set gpio5 as control gpio
|
||||
* .channel = PCNT_CHANNEL_0, //use unit 0 channel 0
|
||||
* .lctrl_mode = PCNT_MODE_REVERSE, //when control signal is low, reverse the primary counter mode(inc->dec/dec->inc)
|
||||
* .hctrl_mode = PCNT_MODE_KEEP, //when control signal is high, keep the primary counter mode
|
||||
* .pos_mode = PCNT_COUNT_INC, //increment the counter
|
||||
* .neg_mode = PCNT_COUNT_DIS, //keep the counter value
|
||||
* .counter_h_lim = 10,
|
||||
* .counter_l_lim = -10,
|
||||
* };
|
||||
* pcnt_unit_config(&pcnt_config); //init unit
|
||||
* @endcode
|
||||
*
|
||||
* EXAMPLE OF PCNT EVENT SETTING
|
||||
* ==============================
|
||||
* @code{c}
|
||||
* //2. Configure PCNT watchpoint event.
|
||||
* pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, 5); //set thres1 value
|
||||
* pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1); //enable thres1 event
|
||||
* @endcode
|
||||
*
|
||||
* For more examples please refer to PCNT example code in IDF_PATH/examples
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -63,7 +63,8 @@ extern "C"
|
||||
#define SPICOMMON_BUSFLAG_DUAL (1<<6) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
|
||||
#define SPICOMMON_BUSFLAG_WPHD (1<<7) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
|
||||
#define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
|
||||
|
||||
#define SPICOMMON_BUSFLAG_IO4_IO7 (1<<8) ///< Check existing of IO4~IO7 pins. Or indicates IO4~IO7 pins initialized.
|
||||
#define SPICOMMON_BUSFLAG_OCTAL (SPICOMMON_BUSFLAG_QUAD|SPICOMMON_BUSFLAG_IO4_IO7) ///< Check existing of MOSI/MISO/WP/HD/SPIIO4/SPIIO5/SPIIO6/SPIIO7 pins as output. Or indicates bus able to work under octal mode.
|
||||
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
|
||||
|
||||
/**
|
||||
@ -95,18 +96,34 @@ typedef spi_common_dma_t spi_dma_chan_t;
|
||||
* @note Be advised that the slave driver does not use the quadwp/quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized.
|
||||
*/
|
||||
typedef struct {
|
||||
int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
|
||||
int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.
|
||||
int sclk_io_num; ///< GPIO pin for Spi CLocK signal, or -1 if not used.
|
||||
int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.
|
||||
int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
|
||||
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled, or to `SOC_SPI_MAXIMUM_BUFFER_SIZE` if DMA is disabled.
|
||||
uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
|
||||
int intr_flags; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
|
||||
* ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
|
||||
* by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
|
||||
* the driver, and their callee functions, should be put in the IRAM.
|
||||
*/
|
||||
union {
|
||||
int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
|
||||
int data0_io_num; ///< GPIO pin for spi data0 signal in quad/octal mode, or -1 if not used.
|
||||
};
|
||||
union {
|
||||
int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.
|
||||
int data1_io_num; ///< GPIO pin for spi data1 signal in quad/octal mode, or -1 if not used.
|
||||
};
|
||||
int sclk_io_num; ///< GPIO pin for SPI Clock signal, or -1 if not used.
|
||||
union {
|
||||
int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal, or -1 if not used.
|
||||
int data2_io_num; ///< GPIO pin for spi data2 signal in quad/octal mode, or -1 if not used.
|
||||
};
|
||||
union {
|
||||
int quadhd_io_num; ///< GPIO pin for HD (Hold) signal, or -1 if not used.
|
||||
int data3_io_num; ///< GPIO pin for spi data3 signal in quad/octal mode, or -1 if not used.
|
||||
};
|
||||
int data4_io_num; ///< GPIO pin for spi data4 signal in octal mode, or -1 if not used.
|
||||
int data5_io_num; ///< GPIO pin for spi data5 signal in octal mode, or -1 if not used.
|
||||
int data6_io_num; ///< GPIO pin for spi data6 signal in octal mode, or -1 if not used.
|
||||
int data7_io_num; ///< GPIO pin for spi data7 signal in octal mode, or -1 if not used.
|
||||
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled, or to `SOC_SPI_MAXIMUM_BUFFER_SIZE` if DMA is disabled.
|
||||
uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
|
||||
int intr_flags; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
|
||||
* ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
|
||||
* by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
|
||||
* the driver, and their callee functions, should be put in the IRAM.
|
||||
*/
|
||||
} spi_bus_config_t;
|
||||
|
||||
|
||||
|
@ -155,6 +155,8 @@ esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id);
|
||||
* - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable.
|
||||
* - ``SPICOMMON_BUSFLAG_WPHD`` Make sure WP and HD are set to valid output GPIOs.
|
||||
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
|
||||
* - ``SPICOMMON_BUSFLAG_IO4_IO7``: Make sure spi data4 ~ spi data7 are set to valid output GPIOs.
|
||||
* - ``SPICOMMON_BUSFLAG_OCTAL``: Combination of ``SPICOMMON_BUSFLAG_QUAL`` and ``SPICOMMON_BUSFLAG_IO4_IO7``.
|
||||
* @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address.
|
||||
* Leave to NULL if not needed.
|
||||
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: The bus is connected to iomux pins.
|
||||
@ -163,6 +165,8 @@ esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id);
|
||||
* - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode.
|
||||
* - ``SPICOMMON_BUSFLAG_WPHD`` The bus has WP and HD connected.
|
||||
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
|
||||
* - ``SPICOMMON_BUSFLAG_IO4_IO7``: The bus has spi data4 ~ spi data7 connected.
|
||||
* - ``SPICOMMON_BUSFLAG_OCTAL``: Combination of ``SPICOMMON_BUSFLAG_QUAL`` and ``SPICOMMON_BUSFLAG_IO4_IO7``.
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
|
@ -104,7 +104,10 @@ typedef struct {
|
||||
#define SPI_TRANS_VARIABLE_CMD (1<<5) ///< Use the ``command_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
|
||||
#define SPI_TRANS_VARIABLE_ADDR (1<<6) ///< Use the ``address_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
|
||||
#define SPI_TRANS_VARIABLE_DUMMY (1<<7) ///< Use the ``dummy_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
|
||||
#define SPI_TRANS_SET_CD (1<<7) ///< Set the CD pin
|
||||
#define SPI_TRANS_CS_KEEP_ACTIVE (1<<8) ///< Keep CS active after data transfer
|
||||
#define SPI_TRANS_MULTILINE_CMD (1<<9) ///< The data lines used at command phase is the same as data phase (otherwise, only one data line is used at command phase)
|
||||
#define SPI_TRANS_MODE_OCT (1<<10) ///< Transmit/receive data in 8-bit mode
|
||||
#define SPI_TRANS_MULTILINE_ADDR SPI_TRANS_MODE_DIOQIO_ADDR ///< The data lines used at address phase is the same as data phase (otherwise, only one data line is used at address phase)
|
||||
|
||||
/**
|
||||
* This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes.
|
||||
@ -148,7 +151,7 @@ typedef struct {
|
||||
} spi_transaction_ext_t ;
|
||||
|
||||
|
||||
typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a SPI bus
|
||||
typedef struct spi_device_t *spi_device_handle_t; ///< Handle for a device on a SPI bus
|
||||
/**
|
||||
* @brief Allocate a device on a SPI bus
|
||||
*
|
||||
@ -194,7 +197,8 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle);
|
||||
* @param ticks_to_wait Ticks to wait until there's room in the queue; use portMAX_DELAY to
|
||||
* never time out.
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid. This can happen if SPI_DEVICE_CS_KEEP_LOW flag is specified while
|
||||
* the bus was not acquired (`spi_device_acquire_bus()` should be called first)
|
||||
* - ESP_ERR_TIMEOUT if there was no room in the queue before ticks_to_wait expired
|
||||
* - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed
|
||||
* - ESP_ERR_INVALID_STATE if previous transactions are not finished
|
||||
@ -257,7 +261,8 @@ esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *tra
|
||||
* currently only portMAX_DELAY is supported.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid. This can happen if SPI_DEVICE_CS_KEEP_LOW flag is specified while
|
||||
* the bus was not acquired (`spi_device_acquire_bus()` should be called first)
|
||||
* - ESP_ERR_TIMEOUT if the device cannot get control of the bus before ``ticks_to_wait`` expired
|
||||
* - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed
|
||||
* - ESP_ERR_INVALID_STATE if previous transactions are not finished
|
||||
@ -339,7 +344,7 @@ void spi_device_release_bus(spi_device_handle_t dev);
|
||||
*
|
||||
* @return Actual working frequency that most fit.
|
||||
*/
|
||||
int spi_cal_clock(int fapb, int hz, int duty_cycle, uint32_t* reg_o) __attribute__((deprecated));
|
||||
int spi_cal_clock(int fapb, int hz, int duty_cycle, uint32_t *reg_o) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Calculate the working frequency that is most close to desired frequency.
|
||||
@ -366,7 +371,7 @@ int spi_get_actual_clock(int fapb, int hz, int duty_cycle);
|
||||
*
|
||||
* @note If **dummy_o* is not zero, it means dummy bits should be applied in half duplex mode, and full duplex mode may not work.
|
||||
*/
|
||||
void spi_get_timing(bool gpio_is_used, int input_delay_ns, int eff_clk, int* dummy_o, int* cycles_remain_o);
|
||||
void spi_get_timing(bool gpio_is_used, int input_delay_ns, int eff_clk, int *dummy_o, int *cycles_remain_o);
|
||||
|
||||
/**
|
||||
* @brief Get the frequency limit of current configurations.
|
||||
|
@ -130,8 +130,9 @@ esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num,
|
||||
esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload);
|
||||
|
||||
/**
|
||||
* @brief Set hardware timer source clock divider. Timer groups clock are divider from APB clock.
|
||||
*
|
||||
* @brief Set hardware divider of the source clock to the timer group.
|
||||
* By default, the source clock is APB clock running at 80 MHz.
|
||||
* For more information, please check Chapter Reset and Clock in Chip Technical Reference Manual.
|
||||
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
|
||||
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
|
||||
* @param divider Timer clock divider value. The divider's range is from from 2 to 65536.
|
||||
|
@ -28,7 +28,10 @@ extern "C" {
|
||||
#endif
|
||||
#define UART_NUM_MAX (SOC_UART_NUM) /*!< UART port max */
|
||||
|
||||
#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */
|
||||
/* @brief When calling `uart_set_pin`, instead of GPIO number, `UART_PIN_NO_CHANGE`
|
||||
* can be provided to keep the currently allocated pin.
|
||||
*/
|
||||
#define UART_PIN_NO_CHANGE (-1)
|
||||
|
||||
#define UART_FIFO_LEN SOC_UART_FIFO_LEN ///< Length of the UART HW FIFO
|
||||
#define UART_BITRATE_MAX SOC_UART_BITRATE_MAX ///< Maximum configurable bitrate
|
||||
@ -380,14 +383,23 @@ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg,
|
||||
esp_err_t uart_isr_free(uart_port_t uart_num);
|
||||
|
||||
/**
|
||||
* @brief Set UART pin number
|
||||
* @brief Assign signals of a UART peripheral to GPIO pins
|
||||
*
|
||||
* @note If the GPIO number configured for a UART signal matches one of the
|
||||
* IOMUX signals for that GPIO, the signal will be connected directly
|
||||
* via the IOMUX. Otherwise the GPIO and signal will be connected via
|
||||
* the GPIO Matrix. For example, if on an ESP32 the call
|
||||
* `uart_set_pin(0, 1, 3, -1, -1)` is performed, as GPIO1 is UART0's
|
||||
* default TX pin and GPIO3 is UART0's default RX pin, both will be
|
||||
* connected to respectively U0TXD and U0RXD through the IOMUX, totally
|
||||
* bypassing the GPIO matrix.
|
||||
* The check is performed on a per-pin basis. Thus, it is possible to have
|
||||
* RX pin binded to a GPIO through the GPIO matrix, whereas TX is binded
|
||||
* to its GPIO through the IOMUX.
|
||||
*
|
||||
* @note Internal signal can be output to multiple GPIO pads.
|
||||
* Only one GPIO pad can connect with input signal.
|
||||
*
|
||||
* @note Instead of GPIO number a macro 'UART_PIN_NO_CHANGE' may be provided
|
||||
to keep the currently allocated pin.
|
||||
*
|
||||
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
|
||||
* @param tx_io_num UART TX pin GPIO number.
|
||||
* @param rx_io_num UART RX pin GPIO number.
|
||||
|
48
components/driver/include/esp_private/i2s_platform.h
Normal file
48
components/driver/include/esp_private/i2s_platform.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// DO NOT USE THESE APIS IN YOUR APPLICATIONS
|
||||
// The following APIs are for internal use, public to other IDF components, but not for users' applications.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Register an I2S or I2S variant driver object to platform
|
||||
*
|
||||
* @note This private API is used to avoid applications from using the same I2S instance for different purpose.
|
||||
* @note This function will help enable the peripheral APB clock as well.
|
||||
*
|
||||
* @param driver_obj Driver object
|
||||
* @param port_id I2S port number
|
||||
* @return
|
||||
* - ESP_OK: The specific I2S port is free and register the new device object successfully
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument, e.g. wrong port_id
|
||||
* - ESP_ERR_NOT_FOUND: Specific I2S port is not available
|
||||
*/
|
||||
esp_err_t i2s_priv_register_object(void *driver_obj, int port_id);
|
||||
|
||||
/**
|
||||
* @brief Deregister I2S or I2S variant driver object from platform
|
||||
*
|
||||
* @note This function will help disable the peripheral APB clock as well.
|
||||
*
|
||||
* @param port_id I2S port number
|
||||
* @return
|
||||
* - ESP_OK: Deregister I2S port successfully (i.e. that I2S port can used used by other users after this function returns)
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument, e.g. wrong port_id
|
||||
* - ESP_ERR_INVALID_STATE: Specific I2S port is free already
|
||||
*/
|
||||
esp_err_t i2s_priv_deregister_object(int port_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -37,6 +37,8 @@ typedef struct {
|
||||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
StaticQueue_t ledc_fade_sem_storage;
|
||||
#endif
|
||||
ledc_cb_t ledc_fade_callback;
|
||||
void *cb_user_arg;
|
||||
} ledc_fade_t;
|
||||
|
||||
typedef struct {
|
||||
@ -551,6 +553,7 @@ static inline void ledc_calc_fade_end_channel(uint32_t *fade_end_status, uint32_
|
||||
|
||||
void IRAM_ATTR ledc_fade_isr(void* arg)
|
||||
{
|
||||
bool cb_yield = false;
|
||||
portBASE_TYPE HPTaskAwoken = pdFALSE;
|
||||
uint32_t speed_mode = 0;
|
||||
uint32_t channel = 0;
|
||||
@ -576,17 +579,21 @@ void IRAM_ATTR ledc_fade_isr(void* arg)
|
||||
|
||||
uint32_t duty_cur = 0;
|
||||
ledc_hal_get_duty(&(p_ledc_obj[speed_mode]->ledc_hal), channel, &duty_cur);
|
||||
if (duty_cur == s_ledc_fade_rec[speed_mode][channel]->target_duty) {
|
||||
xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken);
|
||||
if (HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
uint32_t duty_tar = s_ledc_fade_rec[speed_mode][channel]->target_duty;
|
||||
int scale = s_ledc_fade_rec[speed_mode][channel]->scale;
|
||||
if (scale == 0) {
|
||||
if (duty_cur == duty_tar || scale == 0) {
|
||||
xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken);
|
||||
|
||||
ledc_cb_param_t param = {
|
||||
.event = LEDC_FADE_END_EVT,
|
||||
.speed_mode = speed_mode,
|
||||
.channel = channel,
|
||||
.duty = duty_cur
|
||||
};
|
||||
ledc_cb_t fade_cb = s_ledc_fade_rec[speed_mode][channel]->ledc_fade_callback;
|
||||
if (fade_cb) {
|
||||
cb_yield |= fade_cb(¶m, s_ledc_fade_rec[speed_mode][channel]->cb_user_arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int cycle = s_ledc_fade_rec[speed_mode][channel]->cycle_num;
|
||||
@ -618,6 +625,9 @@ void IRAM_ATTR ledc_fade_isr(void* arg)
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
}
|
||||
}
|
||||
if (HPTaskAwoken == pdTRUE || cb_yield) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t ledc_fade_channel_deinit(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
@ -825,6 +835,17 @@ void ledc_fade_func_uninstall(void)
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg)
|
||||
{
|
||||
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
|
||||
LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
|
||||
LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
|
||||
LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK , LEDC_FADE_INIT_ERROR_STR, ESP_FAIL);
|
||||
s_ledc_fade_rec[speed_mode][channel]->ledc_fade_callback = cbs->fade_cb;
|
||||
s_ledc_fade_rec[speed_mode][channel]->cb_user_arg = user_arg;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The functions below are thread-safe version of APIs for duty and fade control.
|
||||
* These APIs can be called from different tasks.
|
||||
|
@ -34,8 +34,10 @@ static const char *TAG = "mcpwm";
|
||||
#define MCPWM_GPIO_ERROR "MCPWM GPIO NUM ERROR"
|
||||
#define MCPWM_GEN_ERROR "MCPWM GENERATOR ERROR"
|
||||
#define MCPWM_DT_ERROR "MCPWM DEADTIME TYPE ERROR"
|
||||
#define MCPWM_CAP_EXIST_ERROR "MCPWM USER CAP INT SERVICE ALREADY EXISTS"
|
||||
|
||||
#define MCPWM_GROUP_CLK_HZ (SOC_MCPWM_BASE_CLK_HZ / 16)
|
||||
#define MCPWM_GROUP_CLK_PRESCALE (16)
|
||||
#define MCPWM_GROUP_CLK_HZ (SOC_MCPWM_BASE_CLK_HZ / MCPWM_GROUP_CLK_PRESCALE)
|
||||
#define MCPWM_TIMER_CLK_HZ (MCPWM_GROUP_CLK_HZ / 10)
|
||||
|
||||
_Static_assert(SOC_MCPWM_OPERATORS_PER_GROUP >= SOC_MCPWM_TIMERS_PER_GROUP, "This driver assumes the timer num equals to the operator num.");
|
||||
@ -60,15 +62,43 @@ _Static_assert(SOC_MCPWM_GENERATORS_PER_OPERATOR == 2, "This driver assumes the
|
||||
ESP_RETURN_ON_FALSE((gen) < MCPWM_GEN_MAX, ESP_ERR_INVALID_ARG, TAG, MCPWM_GEN_ERROR); \
|
||||
} while (0)
|
||||
|
||||
typedef struct {
|
||||
cap_isr_cb_t fn; // isr function
|
||||
void *args; // isr function args
|
||||
} cap_isr_func_t;
|
||||
|
||||
typedef struct {
|
||||
mcpwm_hal_context_t hal;
|
||||
portMUX_TYPE spinlock;
|
||||
_lock_t mutex_lock;
|
||||
const int group_id;
|
||||
int group_pre_scale; // starts from 1, not 0. will be subtracted by 1 in ll driver
|
||||
int timer_pre_scale[SOC_MCPWM_TIMERS_PER_GROUP]; // same as above
|
||||
intr_handle_t mcpwm_intr_handle; // handler for ISR register, one per MCPWM group
|
||||
cap_isr_func_t cap_isr_func[SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER]; // handler for ISR callback, one for each cap ch
|
||||
} mcpwm_context_t;
|
||||
|
||||
static mcpwm_context_t context[SOC_MCPWM_GROUPS] = {
|
||||
[0 ... SOC_MCPWM_GROUPS - 1] = {
|
||||
.spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
}
|
||||
[0] = {
|
||||
.hal = {MCPWM_LL_GET_HW(0)},
|
||||
.spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
.group_id = 0,
|
||||
.group_pre_scale = SOC_MCPWM_BASE_CLK_HZ / MCPWM_GROUP_CLK_HZ,
|
||||
.timer_pre_scale = {[0 ... SOC_MCPWM_TIMERS_PER_GROUP - 1] =
|
||||
MCPWM_GROUP_CLK_HZ / MCPWM_TIMER_CLK_HZ},
|
||||
.mcpwm_intr_handle = NULL,
|
||||
.cap_isr_func = {[0 ... SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER - 1] = {NULL, NULL}},
|
||||
},
|
||||
[1] = {
|
||||
.hal = {MCPWM_LL_GET_HW(1)},
|
||||
.spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
.group_id = 1,
|
||||
.group_pre_scale = SOC_MCPWM_BASE_CLK_HZ / MCPWM_GROUP_CLK_HZ,
|
||||
.timer_pre_scale = {[0 ... SOC_MCPWM_TIMERS_PER_GROUP - 1] =
|
||||
MCPWM_GROUP_CLK_HZ / MCPWM_TIMER_CLK_HZ},
|
||||
.mcpwm_intr_handle = NULL,
|
||||
.cap_isr_func = {[0 ... SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER - 1] = {NULL, NULL}},
|
||||
}
|
||||
};
|
||||
|
||||
typedef void (*mcpwm_ll_gen_set_event_action_t)(mcpwm_dev_t *mcpwm, int op, int gen, int action);
|
||||
@ -83,6 +113,14 @@ static inline void mcpwm_critical_exit(mcpwm_unit_t mcpwm_num)
|
||||
portEXIT_CRITICAL(&context[mcpwm_num].spinlock);
|
||||
}
|
||||
|
||||
static inline void mcpwm_mutex_lock(mcpwm_unit_t mcpwm_num){
|
||||
_lock_acquire(&context[mcpwm_num].mutex_lock);
|
||||
}
|
||||
|
||||
static inline void mcpwm_mutex_unlock(mcpwm_unit_t mcpwm_num){
|
||||
_lock_release(&context[mcpwm_num].mutex_lock);
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal, int gpio_num)
|
||||
{
|
||||
if (gpio_num < 0) { // ignore on minus gpio number
|
||||
@ -100,12 +138,12 @@ esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal,
|
||||
esp_rom_gpio_connect_out_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].operators[operator_id].generators[generator_id].pwm_sig, 0, 0);
|
||||
} else if (io_signal <= MCPWM_SYNC_2) { // External sync input signal
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
|
||||
int ext_sync_id = io_signal - MCPWM_SYNC_0;
|
||||
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].ext_syncers[ext_sync_id].sync_sig, 0);
|
||||
int gpio_sync_id = io_signal - MCPWM_SYNC_0;
|
||||
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].gpio_synchros[gpio_sync_id].sync_sig, 0);
|
||||
} else if (io_signal <= MCPWM_FAULT_2) { // Fault input signal
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
|
||||
int fault_id = io_signal - MCPWM_FAULT_0;
|
||||
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].detectors[fault_id].fault_sig, 0);
|
||||
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].gpio_faults[fault_id].fault_sig, 0);
|
||||
} else if (io_signal >= MCPWM_CAP_0 && io_signal <= MCPWM_CAP_2) { // Capture input signal
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
|
||||
int capture_id = io_signal - MCPWM_CAP_0;
|
||||
@ -141,7 +179,7 @@ esp_err_t mcpwm_start(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_timer_set_operate_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_START_NO_STOP);
|
||||
mcpwm_ll_timer_set_execute_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_START_NO_STOP);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -151,7 +189,31 @@ esp_err_t mcpwm_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_timer_set_operate_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_STOP_AT_ZERO);
|
||||
mcpwm_ll_timer_set_execute_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_STOP_AT_ZERO);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, unsigned long int resolution) {
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
int pre_scale_temp = SOC_MCPWM_BASE_CLK_HZ / resolution;
|
||||
ESP_RETURN_ON_FALSE(pre_scale_temp >= 1, ESP_ERR_INVALID_ARG, TAG, "invalid resolution");
|
||||
context[mcpwm_num].group_pre_scale = pre_scale_temp;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, context[mcpwm_num].group_pre_scale);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_timer_set_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, unsigned long int resolution) {
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
int pre_scale_temp = SOC_MCPWM_BASE_CLK_HZ / context[mcpwm_num].group_pre_scale / resolution;
|
||||
ESP_RETURN_ON_FALSE(pre_scale_temp >= 1, ESP_ERR_INVALID_ARG, TAG, "invalid resolution");
|
||||
context[mcpwm_num].timer_pre_scale[timer_num] = pre_scale_temp;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, context[mcpwm_num].timer_pre_scale[timer_num]);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -167,7 +229,10 @@ esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, u
|
||||
|
||||
mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num);
|
||||
uint32_t previous_peak = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false);
|
||||
uint32_t new_peak = MCPWM_TIMER_CLK_HZ / frequency;
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
uint32_t new_peak = real_timer_clk_hz / frequency;
|
||||
mcpwm_ll_timer_set_peak(hal->dev, timer_num, new_peak, false);
|
||||
// keep the duty cycle unchanged
|
||||
float scale = ((float)new_peak) / previous_peak;
|
||||
@ -211,8 +276,10 @@ esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
// the timer resolution is fixed to 1us in the driver, so duty_in_us is the same to compare value
|
||||
mcpwm_ll_operator_set_compare_value(hal->dev, op, cmp, duty_in_us);
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
mcpwm_ll_operator_set_compare_value(hal->dev, op, cmp, duty_in_us * real_timer_clk_hz / 1000000);
|
||||
mcpwm_ll_operator_enable_update_compare_on_tez(hal->dev, op, cmp, true);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
@ -312,13 +379,16 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw
|
||||
mcpwm_hal_init(hal, &config);
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_group_set_clock(hal->dev, MCPWM_GROUP_CLK_HZ);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, context[mcpwm_num].group_pre_scale);
|
||||
mcpwm_ll_group_enable_shadow_mode(hal->dev);
|
||||
mcpwm_ll_group_flush_shadow(hal->dev);
|
||||
mcpwm_ll_timer_set_clock(hal->dev, timer_num, MCPWM_GROUP_CLK_HZ, MCPWM_TIMER_CLK_HZ);
|
||||
mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, context[mcpwm_num].timer_pre_scale[timer_num]);
|
||||
mcpwm_ll_timer_set_count_mode(hal->dev, timer_num, mcpwm_conf->counter_mode);
|
||||
mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num);
|
||||
mcpwm_ll_timer_set_peak(hal->dev, timer_num, MCPWM_TIMER_CLK_HZ / mcpwm_conf->frequency, false);
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
mcpwm_ll_timer_set_peak(hal->dev, timer_num, real_timer_clk_hz / mcpwm_conf->frequency, false);
|
||||
mcpwm_ll_operator_select_timer(hal->dev, timer_num, timer_num); //the driver currently always use the timer x for operator x
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
|
||||
@ -336,10 +406,13 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
unsigned long long group_clock = mcpwm_ll_group_get_clock(hal->dev);
|
||||
unsigned long long timer_clock = mcpwm_ll_timer_get_clock(hal->dev, timer_num, group_clock);
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
uint32_t peak = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false);
|
||||
uint32_t freq = real_timer_clk_hz / peak;
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return (uint32_t)timer_clock;
|
||||
return freq;
|
||||
}
|
||||
|
||||
float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen)
|
||||
@ -354,6 +427,20 @@ float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_gene
|
||||
return duty;
|
||||
}
|
||||
|
||||
uint32_t mcpwm_get_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen){
|
||||
//the driver currently always use the timer x for operator x
|
||||
const int op = timer_num;
|
||||
MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
uint32_t duty = mcpwm_ll_operator_get_compare_value(hal->dev, op, gen) * (1000000.0 / real_timer_clk_hz);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return duty;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_set_signal_high(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen)
|
||||
{
|
||||
//the driver currently always use the timer x for operator x
|
||||
@ -479,73 +566,74 @@ esp_err_t mcpwm_deadtime_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_deadtime_enable_update_delay_on_tez(hal->dev, op, true);
|
||||
mcpwm_ll_deadtime_set_resolution_same_to_timer(hal->dev, op, false);
|
||||
// The dead time delay unit equals to MCPWM group resolution
|
||||
mcpwm_ll_deadtime_resolution_to_timer(hal->dev, op, false);
|
||||
mcpwm_ll_deadtime_set_rising_delay(hal->dev, op, red + 1);
|
||||
mcpwm_ll_deadtime_set_falling_delay(hal->dev, op, fed + 1);
|
||||
switch (dt_mode) {
|
||||
case MCPWM_BYPASS_RED:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, true); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 1); // S5
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0=0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, true); // S1=1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3=0
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4=0
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5=0
|
||||
break;
|
||||
case MCPWM_BYPASS_FED:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, true); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, true); // S0=1
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3=0
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4=0
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5=0
|
||||
break;
|
||||
case MCPWM_ACTIVE_HIGH_MODE:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 1); // S5
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0=0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3=0
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4=0
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5=0
|
||||
break;
|
||||
case MCPWM_ACTIVE_LOW_MODE:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, true); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, true); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 1); // S5
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0=0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, true); // S2=1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, true); // S3=1
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4=0
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5=0
|
||||
break;
|
||||
case MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, true); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 1); // S5
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0=0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, true); // S3=1
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4=0
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5=0
|
||||
break;
|
||||
case MCPWM_ACTIVE_LOW_COMPLIMENT_MODE:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, true); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 1); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0=0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, true); // S2=1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3=0
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4=0
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5=0
|
||||
break;
|
||||
case MCPWM_ACTIVE_RED_FED_FROM_PWMXA:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 1); // S4
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 0, true); // S6
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 1, false); // S7
|
||||
mcpwm_ll_deadtime_enable_deb(hal->dev, op, true); // S8
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3=0
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4=0
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 0, true); // S6=1
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 1, false); // S7=0
|
||||
mcpwm_ll_deadtime_enable_deb(hal->dev, op, true); // S8=1
|
||||
break;
|
||||
case MCPWM_ACTIVE_RED_FED_FROM_PWMXB:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 0, true); // S6
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 1, false); // S7
|
||||
mcpwm_ll_deadtime_enable_deb(hal->dev, op, true); // S8
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0=0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3=0
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 1); // S4=1
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 0, true); // S6=1
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 1, false); // S7=0
|
||||
mcpwm_ll_deadtime_enable_deb(hal->dev, op, true); // S8=1
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
@ -611,11 +699,12 @@ esp_err_t mcpwm_fault_set_cyc_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_n
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_fault_enable_cbc_mode(hal->dev, op, fault_sig, true);
|
||||
mcpwm_ll_fault_enable_cbc_refresh_on_tez(hal->dev, op, true);
|
||||
mcpwm_ll_fault_enable_oneshot_mode(hal->dev, op, fault_sig, false);
|
||||
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_FAULT_REACTION_CBC, action_on_pwmxa);
|
||||
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_UP, MCPWM_FAULT_REACTION_CBC, action_on_pwmxa);
|
||||
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_FAULT_REACTION_CBC, action_on_pwmxb);
|
||||
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_UP, MCPWM_FAULT_REACTION_CBC, action_on_pwmxb);
|
||||
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TRIP_TYPE_CBC, action_on_pwmxa);
|
||||
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_UP, MCPWM_TRIP_TYPE_CBC, action_on_pwmxa);
|
||||
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TRIP_TYPE_CBC, action_on_pwmxb);
|
||||
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_UP, MCPWM_TRIP_TYPE_CBC, action_on_pwmxb);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -632,19 +721,43 @@ esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
|
||||
mcpwm_ll_fault_clear_ost(hal->dev, op);
|
||||
mcpwm_ll_fault_enable_oneshot_mode(hal->dev, op, fault_sig, true);
|
||||
mcpwm_ll_fault_enable_cbc_mode(hal->dev, op, fault_sig, false);
|
||||
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_FAULT_REACTION_OST, action_on_pwmxa);
|
||||
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_UP, MCPWM_FAULT_REACTION_OST, action_on_pwmxa);
|
||||
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_FAULT_REACTION_OST, action_on_pwmxb);
|
||||
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_UP, MCPWM_FAULT_REACTION_OST, action_on_pwmxb);
|
||||
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TRIP_TYPE_OST, action_on_pwmxa);
|
||||
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_UP, MCPWM_TRIP_TYPE_OST, action_on_pwmxa);
|
||||
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TRIP_TYPE_OST, action_on_pwmxb);
|
||||
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_UP, MCPWM_TRIP_TYPE_OST, action_on_pwmxb);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void mcpwm_default_isr_handler(void *arg) {
|
||||
mcpwm_context_t *curr_context = (mcpwm_context_t *) arg;
|
||||
uint32_t intr_status = mcpwm_ll_intr_get_capture_status(curr_context->hal.dev);
|
||||
mcpwm_ll_intr_clear_capture_status(curr_context->hal.dev, intr_status);
|
||||
bool need_yield = false;
|
||||
for (int i = 0; i < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER; ++i) {
|
||||
if ((intr_status >> i) & 0x1) {
|
||||
if (curr_context->cap_isr_func[i].fn != NULL) {
|
||||
cap_event_data_t edata;
|
||||
edata.cap_edge = mcpwm_ll_capture_is_negedge(curr_context->hal.dev, i) ? MCPWM_NEG_EDGE
|
||||
: MCPWM_POS_EDGE;
|
||||
edata.cap_value = mcpwm_ll_capture_get_value(curr_context->hal.dev, i);
|
||||
if (curr_context->cap_isr_func[i].fn(curr_context->group_id, i, &edata,
|
||||
curr_context->cap_isr_func[i].args)) {
|
||||
need_yield = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (need_yield) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig, mcpwm_capture_on_edge_t cap_edge,
|
||||
uint32_t num_of_pulse)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
ESP_RETURN_ON_FALSE(num_of_pulse <= MCPWM_LL_MAX_PRESCALE, ESP_ERR_INVALID_ARG, TAG, MCPWM_PRESCALE_ERROR);
|
||||
ESP_RETURN_ON_FALSE(num_of_pulse <= MCPWM_LL_MAX_CAPTURE_PRESCALE, ESP_ERR_INVALID_ARG, TAG, MCPWM_PRESCALE_ERROR);
|
||||
ESP_RETURN_ON_FALSE(cap_sig < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
// enable MCPWM module incase user don't use `mcpwm_init` at all
|
||||
@ -654,7 +767,7 @@ esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t ca
|
||||
};
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_init(hal, &init_config);
|
||||
mcpwm_ll_group_set_clock(hal->dev, MCPWM_GROUP_CLK_HZ);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, context[mcpwm_num].group_pre_scale);
|
||||
mcpwm_ll_capture_enable_timer(hal->dev, true);
|
||||
mcpwm_ll_capture_enable_channel(hal->dev, cap_sig, true);
|
||||
mcpwm_ll_capture_enable_negedge(hal->dev, cap_sig, cap_edge & MCPWM_NEG_EDGE);
|
||||
@ -681,6 +794,85 @@ esp_err_t mcpwm_capture_disable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t c
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_channel_id_t cap_channel, const mcpwm_capture_config_t *cap_conf)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
ESP_RETURN_ON_FALSE(cap_channel < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR);
|
||||
ESP_RETURN_ON_FALSE(context[mcpwm_num].cap_isr_func[cap_channel].fn == NULL, ESP_ERR_INVALID_STATE, TAG,
|
||||
MCPWM_CAP_EXIST_ERROR);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
// enable MCPWM module incase user don't use `mcpwm_init` at all. always increase reference count
|
||||
periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module);
|
||||
|
||||
mcpwm_hal_init_config_t init_config = {
|
||||
.host_id = mcpwm_num
|
||||
};
|
||||
mcpwm_hal_init(hal, &init_config);
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, context[mcpwm_num].group_pre_scale);
|
||||
mcpwm_ll_capture_enable_timer(hal->dev, true);
|
||||
mcpwm_ll_capture_enable_channel(hal->dev, cap_channel, true);
|
||||
mcpwm_ll_capture_enable_negedge(hal->dev, cap_channel, cap_conf->cap_edge & MCPWM_NEG_EDGE);
|
||||
mcpwm_ll_capture_enable_posedge(hal->dev, cap_channel, cap_conf->cap_edge & MCPWM_POS_EDGE);
|
||||
mcpwm_ll_capture_set_prescale(hal->dev, cap_channel, cap_conf->cap_prescale);
|
||||
// capture feature should be used with interupt, so enable it by default
|
||||
mcpwm_ll_intr_enable_capture(hal->dev, cap_channel, true);
|
||||
mcpwm_ll_intr_clear_capture_status(hal->dev, 1 << cap_channel);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
|
||||
mcpwm_mutex_lock(mcpwm_num);
|
||||
context[mcpwm_num].cap_isr_func[cap_channel].fn = cap_conf->capture_cb;
|
||||
context[mcpwm_num].cap_isr_func[cap_channel].args = cap_conf->user_data;
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (context[mcpwm_num].mcpwm_intr_handle == NULL) {
|
||||
ret = esp_intr_alloc(mcpwm_periph_signals.groups[mcpwm_num].irq_id, 0,
|
||||
mcpwm_default_isr_handler,
|
||||
(void *) (context + mcpwm_num), &(context[mcpwm_num].mcpwm_intr_handle));
|
||||
}
|
||||
mcpwm_mutex_unlock(mcpwm_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_capture_disable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_channel_id_t cap_channel)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
ESP_RETURN_ON_FALSE(cap_channel < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR);
|
||||
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_capture_enable_channel(hal->dev, cap_channel, false);
|
||||
mcpwm_ll_intr_enable_capture(hal->dev, cap_channel, false);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
|
||||
mcpwm_mutex_lock(mcpwm_num);
|
||||
context[mcpwm_num].cap_isr_func[cap_channel].fn = NULL;
|
||||
context[mcpwm_num].cap_isr_func[cap_channel].args = NULL;
|
||||
// if all user defined ISR callback is disabled, free the handle
|
||||
bool should_free_handle = true;
|
||||
for (int i = 0; i < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER; ++i) {
|
||||
if (context[mcpwm_num].cap_isr_func[i].fn != NULL) {
|
||||
should_free_handle = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (should_free_handle) {
|
||||
ret = esp_intr_free(context[mcpwm_num].mcpwm_intr_handle);
|
||||
if (ret != ESP_OK){
|
||||
ESP_LOGE(TAG, "failed to free interrupt handle");
|
||||
}
|
||||
context[mcpwm_num].mcpwm_intr_handle = NULL;
|
||||
}
|
||||
mcpwm_mutex_unlock(mcpwm_num);
|
||||
|
||||
// always decrease reference count
|
||||
periph_module_disable(mcpwm_periph_signals.groups[mcpwm_num].module);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
@ -707,9 +899,9 @@ esp_err_t mcpwm_sync_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcp
|
||||
uint32_t set_phase = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false) * phase_val / 1000;
|
||||
mcpwm_ll_timer_set_sync_phase_value(hal->dev, timer_num, set_phase);
|
||||
if (sync_sig >= MCPWM_SELECT_SYNC0) {
|
||||
mcpwm_ll_timer_enable_sync_from_external(hal->dev, timer_num, sync_sig - MCPWM_SELECT_SYNC0);
|
||||
mcpwm_ll_timer_set_timer_synchro(hal->dev, timer_num, sync_sig - MCPWM_SELECT_SYNC0);
|
||||
}
|
||||
mcpwm_ll_timer_sync_out_same_in(hal->dev, timer_num);
|
||||
mcpwm_ll_timer_sync_out_penetrate(hal->dev, timer_num);
|
||||
mcpwm_ll_timer_enable_sync_input(hal->dev, timer_num, true);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
|
@ -4,14 +4,15 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_PCNT_SUPPORTED
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "driver/pcnt.h"
|
||||
#include "hal/pcnt_hal.h"
|
||||
#include "hal/pcnt_ll.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "soc/pcnt_periph.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
#define PCNT_CHANNEL_ERR_STR "PCNT CHANNEL ERROR"
|
||||
@ -60,19 +61,20 @@ static portMUX_TYPE pcnt_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static inline esp_err_t _pcnt_set_mode(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_channel_t channel, pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode, pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK((pos_mode < PCNT_COUNT_MAX) && (neg_mode < PCNT_COUNT_MAX), PCNT_COUNT_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK((hctrl_mode < PCNT_MODE_MAX) && (lctrl_mode < PCNT_MODE_MAX), PCNT_CTRL_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
pcnt_hal_set_mode(&(p_pcnt_obj[pcnt_port]->hal), unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode);
|
||||
pcnt_ll_set_edge_action(p_pcnt_obj[pcnt_port]->hal.dev, unit, channel, pos_mode, neg_mode);
|
||||
pcnt_ll_set_level_action(p_pcnt_obj[pcnt_port]->hal.dev, unit, channel, hctrl_mode, lctrl_mode);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_set_pin(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(GPIO_IS_VALID_GPIO(pulse_io) || pulse_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(GPIO_IS_VALID_GPIO(ctrl_io) || ctrl_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
@ -81,14 +83,14 @@ static inline esp_err_t _pcnt_set_pin(pcnt_port_t pcnt_port, pcnt_unit_t unit, p
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[pulse_io], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(pulse_io, GPIO_MODE_INPUT);
|
||||
gpio_set_pull_mode(pulse_io, GPIO_PULLUP_ONLY);
|
||||
esp_rom_gpio_connect_in_signal(pulse_io, pcnt_periph_signals.units[unit].channels[channel].pulse_sig, 0);
|
||||
esp_rom_gpio_connect_in_signal(pulse_io, pcnt_periph_signals.groups[pcnt_port].units[unit].channels[channel].pulse_sig, 0);
|
||||
}
|
||||
|
||||
if (ctrl_io >= 0) {
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[ctrl_io], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(ctrl_io, GPIO_MODE_INPUT);
|
||||
gpio_set_pull_mode(ctrl_io, GPIO_PULLUP_ONLY);
|
||||
esp_rom_gpio_connect_in_signal(ctrl_io, pcnt_periph_signals.units[unit].channels[channel].control_sig, 0);
|
||||
esp_rom_gpio_connect_in_signal(ctrl_io, pcnt_periph_signals.groups[pcnt_port].units[unit].channels[channel].control_sig, 0);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
@ -97,18 +99,18 @@ static inline esp_err_t _pcnt_set_pin(pcnt_port_t pcnt_port, pcnt_unit_t unit, p
|
||||
static inline esp_err_t _pcnt_get_counter_value(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit, int16_t *count)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(pcnt_unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(count != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
pcnt_hal_get_counter_value(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit, count);
|
||||
*count = pcnt_ll_get_count(p_pcnt_obj[pcnt_port]->hal.dev, pcnt_unit);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_counter_pause(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(pcnt_unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
pcnt_hal_counter_pause(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit);
|
||||
pcnt_ll_stop_count(p_pcnt_obj[pcnt_port]->hal.dev, pcnt_unit);
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -116,9 +118,9 @@ static inline esp_err_t _pcnt_counter_pause(pcnt_port_t pcnt_port, pcnt_unit_t p
|
||||
static inline esp_err_t _pcnt_counter_resume(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(pcnt_unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
pcnt_hal_counter_resume(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit);
|
||||
pcnt_ll_start_count(p_pcnt_obj[pcnt_port]->hal.dev, pcnt_unit);
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -126,115 +128,136 @@ static inline esp_err_t _pcnt_counter_resume(pcnt_port_t pcnt_port, pcnt_unit_t
|
||||
static inline esp_err_t _pcnt_counter_clear(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(pcnt_unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
pcnt_hal_counter_clear(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit);
|
||||
pcnt_ll_clear_count(p_pcnt_obj[pcnt_port]->hal.dev, pcnt_unit);
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_intr_enable(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit)
|
||||
static inline esp_err_t _pcnt_intr_enable(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit, bool enable)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(pcnt_unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
pcnt_hal_intr_enable(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit);
|
||||
pcnt_ll_enable_intr(p_pcnt_obj[pcnt_port]->hal.dev, 1 << pcnt_unit, enable);
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_intr_disable(pcnt_port_t pcnt_port, pcnt_unit_t pcnt_unit)
|
||||
static inline esp_err_t _pcnt_event_enable(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type, bool enable)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
pcnt_hal_intr_disable(&(p_pcnt_obj[pcnt_port]->hal), pcnt_unit);
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_event_enable(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
pcnt_hal_event_enable(&(p_pcnt_obj[pcnt_port]->hal), unit, evt_type);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_event_disable(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
pcnt_hal_event_disable(&(p_pcnt_obj[pcnt_port]->hal), unit, evt_type);
|
||||
switch (evt_type) {
|
||||
case PCNT_EVT_THRES_1:
|
||||
pcnt_ll_enable_thres_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, 1, enable);
|
||||
break;
|
||||
case PCNT_EVT_THRES_0:
|
||||
pcnt_ll_enable_thres_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, 0, enable);
|
||||
break;
|
||||
case PCNT_EVT_L_LIM:
|
||||
pcnt_ll_enable_low_limit_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, enable);
|
||||
break;
|
||||
case PCNT_EVT_H_LIM:
|
||||
pcnt_ll_enable_high_limit_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, enable);
|
||||
break;
|
||||
case PCNT_EVT_ZERO:
|
||||
pcnt_ll_enable_zero_cross_event(p_pcnt_obj[pcnt_port]->hal.dev, unit, enable);
|
||||
break;
|
||||
default:
|
||||
PCNT_CHECK(false, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_set_event_value(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(!(evt_type == PCNT_EVT_L_LIM && value > 0), PCNT_LIMT_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(!(evt_type == PCNT_EVT_H_LIM && value < 0), PCNT_LIMT_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
pcnt_hal_set_event_value(&(p_pcnt_obj[pcnt_port]->hal), unit, evt_type, value);
|
||||
switch (evt_type) {
|
||||
case PCNT_EVT_THRES_1:
|
||||
pcnt_ll_set_thres_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, 1, value);
|
||||
break;
|
||||
case PCNT_EVT_THRES_0:
|
||||
pcnt_ll_set_thres_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, 0, value);
|
||||
break;
|
||||
case PCNT_EVT_L_LIM:
|
||||
pcnt_ll_set_low_limit_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, value);
|
||||
break;
|
||||
case PCNT_EVT_H_LIM:
|
||||
pcnt_ll_set_high_limit_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_get_event_value(pcnt_port_t pcnt_port, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(value != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
pcnt_hal_get_event_value(&(p_pcnt_obj[pcnt_port]->hal), unit, evt_type, value);
|
||||
switch (evt_type) {
|
||||
case PCNT_EVT_THRES_1:
|
||||
*value = pcnt_ll_get_thres_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, 1);
|
||||
break;
|
||||
case PCNT_EVT_THRES_0:
|
||||
*value = pcnt_ll_get_thres_value(p_pcnt_obj[pcnt_port]->hal.dev, unit, 0);
|
||||
break;
|
||||
case PCNT_EVT_L_LIM:
|
||||
*value = pcnt_ll_get_low_limit_value(p_pcnt_obj[pcnt_port]->hal.dev, unit);
|
||||
break;
|
||||
case PCNT_EVT_H_LIM:
|
||||
*value = pcnt_ll_get_high_limit_value(p_pcnt_obj[pcnt_port]->hal.dev, unit);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_get_event_status(pcnt_port_t pcnt_port, pcnt_unit_t unit, uint32_t *status)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(status != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
*status = pcnt_hal_get_event_status(&(p_pcnt_obj[pcnt_port]->hal), unit);
|
||||
*status = pcnt_ll_get_unit_status(p_pcnt_obj[pcnt_port]->hal.dev, unit);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_set_filter_value(pcnt_port_t pcnt_port, pcnt_unit_t unit, uint16_t filter_val)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(filter_val < 1024, PCNT_PARAM_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
pcnt_hal_set_filter_value(&(p_pcnt_obj[pcnt_port]->hal), unit, filter_val);
|
||||
pcnt_ll_set_glitch_filter_thres(p_pcnt_obj[pcnt_port]->hal.dev, unit, filter_val);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_get_filter_value(pcnt_port_t pcnt_port, pcnt_unit_t unit, uint16_t *filter_val)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(filter_val != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
pcnt_hal_get_filter_value(&(p_pcnt_obj[pcnt_port]->hal), unit, filter_val);
|
||||
*filter_val = (uint16_t)pcnt_ll_get_glitch_filter_thres(p_pcnt_obj[pcnt_port]->hal.dev, unit);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_filter_enable(pcnt_port_t pcnt_port, pcnt_unit_t unit)
|
||||
static inline esp_err_t _pcnt_filter_enable(pcnt_port_t pcnt_port, pcnt_unit_t unit, bool enable)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
pcnt_hal_filter_enable(&(p_pcnt_obj[pcnt_port]->hal), unit);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static inline esp_err_t _pcnt_filter_disable(pcnt_port_t pcnt_port, pcnt_unit_t unit)
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
pcnt_hal_filter_disable(&(p_pcnt_obj[pcnt_port]->hal), unit);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
pcnt_ll_enable_glitch_filter(p_pcnt_obj[pcnt_port]->hal.dev, unit, enable);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -242,16 +265,16 @@ static inline esp_err_t _pcnt_isr_handler_add(pcnt_port_t pcnt_port, pcnt_unit_t
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_isr_func != NULL, "ISR service is not installed, call pcnt_install_isr_service() first", ESP_ERR_INVALID_STATE);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, "PCNT unit error", ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, "PCNT unit error", ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
_pcnt_intr_disable(PCNT_PORT_0, unit);
|
||||
_pcnt_intr_enable(PCNT_PORT_0, unit, false);
|
||||
|
||||
if (pcnt_isr_func) {
|
||||
pcnt_isr_func[unit].fn = isr_handler;
|
||||
pcnt_isr_func[unit].args = args;
|
||||
}
|
||||
|
||||
_pcnt_intr_enable(PCNT_PORT_0, unit);
|
||||
_pcnt_intr_enable(PCNT_PORT_0, unit, true);
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -260,9 +283,9 @@ static inline esp_err_t _pcnt_isr_handler_remove(pcnt_port_t pcnt_port, pcnt_uni
|
||||
{
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_isr_func != NULL, "ISR service is not installed", ESP_ERR_INVALID_STATE);
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, "PCNT unit error", ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, "PCNT unit error", ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
_pcnt_intr_disable(PCNT_PORT_0, unit);
|
||||
_pcnt_intr_enable(PCNT_PORT_0, unit, false);
|
||||
|
||||
if (pcnt_isr_func) {
|
||||
pcnt_isr_func[unit].fn = NULL;
|
||||
@ -278,8 +301,8 @@ static void IRAM_ATTR pcnt_intr_service(void *arg)
|
||||
{
|
||||
uint32_t status = 0;
|
||||
pcnt_port_t pcnt_port = (pcnt_port_t)arg;
|
||||
pcnt_hal_get_intr_status(&(p_pcnt_obj[pcnt_port]->hal), &status);
|
||||
pcnt_hal_clear_intr_status(&(p_pcnt_obj[pcnt_port]->hal), status);
|
||||
status = pcnt_ll_get_intr_status(p_pcnt_obj[pcnt_port]->hal.dev);
|
||||
pcnt_ll_clear_intr_status(p_pcnt_obj[pcnt_port]->hal.dev, status);
|
||||
|
||||
while (status) {
|
||||
int unit = __builtin_ffs(status) - 1;
|
||||
@ -296,7 +319,7 @@ static inline esp_err_t _pcnt_isr_service_install(pcnt_port_t pcnt_port, int int
|
||||
PCNT_OBJ_CHECK(pcnt_port);
|
||||
PCNT_CHECK(pcnt_isr_func == NULL, "ISR service already installed", ESP_ERR_INVALID_STATE);
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
pcnt_isr_func = (pcnt_isr_func_t *) calloc(PCNT_UNIT_MAX, sizeof(pcnt_isr_func_t));
|
||||
pcnt_isr_func = (pcnt_isr_func_t *) calloc(SOC_PCNT_UNITS_PER_GROUP, sizeof(pcnt_isr_func_t));
|
||||
|
||||
if (pcnt_isr_func == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
@ -333,7 +356,7 @@ static inline esp_err_t _pcnt_unit_config(pcnt_port_t pcnt_port, const pcnt_conf
|
||||
int input_io = pcnt_config->pulse_gpio_num;
|
||||
int ctrl_io = pcnt_config->ctrl_gpio_num;
|
||||
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(unit < SOC_PCNT_UNITS_PER_GROUP, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(input_io < 0 || (GPIO_IS_VALID_GPIO(input_io) && (input_io != ctrl_io)), "PCNT pulse input io error", ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(ctrl_io < 0 || GPIO_IS_VALID_GPIO(ctrl_io), "PCNT ctrl io error", ESP_ERR_INVALID_ARG);
|
||||
@ -342,18 +365,18 @@ static inline esp_err_t _pcnt_unit_config(pcnt_port_t pcnt_port, const pcnt_conf
|
||||
/*Enalbe hardware module*/
|
||||
static bool pcnt_enable = false;
|
||||
if (pcnt_enable == false) {
|
||||
periph_module_reset(pcnt_periph_signals.module);
|
||||
periph_module_reset(pcnt_periph_signals.groups[pcnt_port].module);
|
||||
pcnt_enable = true;
|
||||
}
|
||||
periph_module_enable(pcnt_periph_signals.module);
|
||||
periph_module_enable(pcnt_periph_signals.groups[pcnt_port].module);
|
||||
/*Set counter range*/
|
||||
_pcnt_set_event_value(pcnt_port, unit, PCNT_EVT_H_LIM, pcnt_config->counter_h_lim);
|
||||
_pcnt_set_event_value(pcnt_port, unit, PCNT_EVT_L_LIM, pcnt_config->counter_l_lim);
|
||||
/*Default value after reboot is positive, we disable these events like others*/
|
||||
_pcnt_event_disable(pcnt_port, unit, PCNT_EVT_H_LIM);
|
||||
_pcnt_event_disable(pcnt_port, unit, PCNT_EVT_L_LIM);
|
||||
_pcnt_event_disable(pcnt_port, unit, PCNT_EVT_ZERO);
|
||||
_pcnt_filter_disable(pcnt_port, unit);
|
||||
_pcnt_event_enable(pcnt_port, unit, PCNT_EVT_H_LIM, false);
|
||||
_pcnt_event_enable(pcnt_port, unit, PCNT_EVT_L_LIM, false);
|
||||
_pcnt_event_enable(pcnt_port, unit, PCNT_EVT_ZERO, false);
|
||||
_pcnt_filter_enable(pcnt_port, unit, false);
|
||||
/*set pulse input and control mode*/
|
||||
_pcnt_set_mode(pcnt_port, unit, channel, pcnt_config->pos_mode, pcnt_config->neg_mode, pcnt_config->hctrl_mode, pcnt_config->lctrl_mode);
|
||||
/*Set pulse input and control pins*/
|
||||
@ -386,8 +409,6 @@ esp_err_t pcnt_init(pcnt_port_t pcnt_port)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// TODO: The following functions are wrappers, for compatibility with current API.
|
||||
|
||||
esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config)
|
||||
{
|
||||
esp_err_t ret;
|
||||
@ -433,22 +454,22 @@ esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit)
|
||||
|
||||
esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
return _pcnt_intr_enable(PCNT_PORT_0, pcnt_unit);
|
||||
return _pcnt_intr_enable(PCNT_PORT_0, pcnt_unit, true);
|
||||
}
|
||||
|
||||
esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
return _pcnt_intr_disable(PCNT_PORT_0, pcnt_unit);
|
||||
return _pcnt_intr_enable(PCNT_PORT_0, pcnt_unit, false);
|
||||
}
|
||||
|
||||
esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)
|
||||
{
|
||||
return _pcnt_event_enable(PCNT_PORT_0, unit, evt_type);
|
||||
return _pcnt_event_enable(PCNT_PORT_0, unit, evt_type, true);
|
||||
}
|
||||
|
||||
esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)
|
||||
{
|
||||
return _pcnt_event_disable(PCNT_PORT_0, unit, evt_type);
|
||||
return _pcnt_event_enable(PCNT_PORT_0, unit, evt_type, false);
|
||||
}
|
||||
|
||||
esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value)
|
||||
@ -478,12 +499,12 @@ esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val)
|
||||
|
||||
esp_err_t pcnt_filter_enable(pcnt_unit_t unit)
|
||||
{
|
||||
return _pcnt_filter_enable(PCNT_PORT_0, unit);
|
||||
return _pcnt_filter_enable(PCNT_PORT_0, unit, true);
|
||||
}
|
||||
|
||||
esp_err_t pcnt_filter_disable(pcnt_unit_t unit)
|
||||
{
|
||||
return _pcnt_filter_disable(PCNT_PORT_0, unit);
|
||||
return _pcnt_filter_enable(PCNT_PORT_0, unit, false);
|
||||
}
|
||||
|
||||
esp_err_t pcnt_isr_unregister(pcnt_isr_handle_t handle)
|
||||
@ -500,7 +521,7 @@ esp_err_t pcnt_isr_register(void (*fun)(void *), void *arg, int intr_alloc_flags
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
PCNT_CHECK(fun != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
ret = esp_intr_alloc(pcnt_periph_signals.irq, intr_alloc_flags, fun, arg, handle);
|
||||
ret = esp_intr_alloc(pcnt_periph_signals.groups[0].irq, intr_alloc_flags, fun, arg, handle);
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ret;
|
||||
}
|
||||
@ -515,7 +536,6 @@ esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit)
|
||||
return _pcnt_isr_handler_remove(PCNT_PORT_0, unit);
|
||||
}
|
||||
|
||||
|
||||
esp_err_t pcnt_isr_service_install(int intr_alloc_flags)
|
||||
{
|
||||
return _pcnt_isr_service_install(PCNT_PORT_0, intr_alloc_flags);
|
||||
|
@ -701,7 +701,8 @@ static esp_err_t recv_flush_data(void)
|
||||
static void sdio_intr_recv(void *arg)
|
||||
{
|
||||
portBASE_TYPE yield = 0;
|
||||
while (sdio_slave_hal_recv_done(context.hal)) {
|
||||
bool triggered = sdio_slave_hal_recv_done(context.hal);
|
||||
while (triggered) {
|
||||
portENTER_CRITICAL_ISR(&context.recv_spinlock);
|
||||
bool has_next_item = sdio_slave_hal_recv_has_next_item(context.hal);
|
||||
portEXIT_CRITICAL_ISR(&context.recv_spinlock);
|
||||
@ -710,8 +711,9 @@ static void sdio_intr_recv(void *arg)
|
||||
xSemaphoreGiveFromISR(context.recv_event, &yield);
|
||||
continue; //check the linked list again skip the interrupt checking
|
||||
}
|
||||
// if no more items on the list, go back and check again the interrupt,
|
||||
// if no more items on the list, check the interrupt again,
|
||||
// will loop until the interrupt bit is kept cleared.
|
||||
triggered = sdio_slave_hal_recv_done(context.hal);
|
||||
}
|
||||
if (yield) {
|
||||
portYIELD_FROM_ISR();
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/soc_pins.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
@ -350,32 +351,116 @@ esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------IO general-------------------------------------------------------//
|
||||
static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
static bool check_iomux_pins_oct(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
if (host != SPI2_HOST) {
|
||||
return false;
|
||||
}
|
||||
int io_nums[] = {bus_config->data0_io_num, bus_config->data1_io_num, bus_config->data2_io_num, bus_config->data3_io_num,
|
||||
bus_config->sclk_io_num, bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
|
||||
int io_mux_nums[] = {SPI2_IOMUX_PIN_NUM_MOSI_OCT, SPI2_IOMUX_PIN_NUM_MISO_OCT, SPI2_IOMUX_PIN_NUM_WP_OCT, SPI2_IOMUX_PIN_NUM_HD_OCT,
|
||||
SPI2_IOMUX_PIN_NUM_CLK_OCT, SPI2_IOMUX_PIN_NUM_IO4_OCT, SPI2_IOMUX_PIN_NUM_IO5_OCT, SPI2_IOMUX_PIN_NUM_IO6_OCT, SPI2_IOMUX_PIN_NUM_IO7_OCT};
|
||||
for (size_t i = 0; i < sizeof(io_nums)/sizeof(io_nums[0]); i++) {
|
||||
if (io_nums[i] >= 0 && io_nums[i] != io_mux_nums[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool check_iomux_pins_quad(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
if (bus_config->sclk_io_num>=0 &&
|
||||
bus_config->sclk_io_num != spi_periph_signal[host].spiclk_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (bus_config->quadwp_io_num>=0 &&
|
||||
bus_config->quadwp_io_num != spi_periph_signal[host].spiwp_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (bus_config->quadhd_io_num>=0 &&
|
||||
bus_config->quadhd_io_num != spi_periph_signal[host].spihd_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (bus_config->mosi_io_num >= 0 &&
|
||||
bus_config->mosi_io_num != spi_periph_signal[host].spid_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (bus_config->miso_io_num>=0 &&
|
||||
bus_config->miso_io_num != spi_periph_signal[host].spiq_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
//Check if SPI pins could be routed to iomux.
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
//The io mux pins available for Octal mode is not the same as the ones we use for non-Octal mode.
|
||||
if ((bus_config->flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
|
||||
return check_iomux_pins_oct(host, bus_config);
|
||||
}
|
||||
#endif
|
||||
return check_iomux_pins_quad(host, bus_config);
|
||||
}
|
||||
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
static void bus_iomux_pins_set_oct(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
assert(host == SPI2_HOST);
|
||||
int io_nums[] = {bus_config->data0_io_num, bus_config->data1_io_num, bus_config->data2_io_num, bus_config->data3_io_num,
|
||||
bus_config->sclk_io_num, bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
|
||||
int io_signals[] = {spi_periph_signal[host].spid_in, spi_periph_signal[host].spiq_in, spi_periph_signal[host].spiwp_in,
|
||||
spi_periph_signal[host].spihd_in,spi_periph_signal[host].spiclk_in, spi_periph_signal[host].spid4_out,
|
||||
spi_periph_signal[host].spid5_out, spi_periph_signal[host].spid6_out, spi_periph_signal[host].spid7_out};
|
||||
for (size_t i = 0; i < sizeof(io_nums)/sizeof(io_nums[0]); i++) {
|
||||
if (io_nums[i] > 0) {
|
||||
gpio_iomux_in(io_nums[i], io_signals[i]);
|
||||
// In Octal mode use function channel 2
|
||||
gpio_iomux_out(io_nums[i], SPI2_FUNC_NUM_OCT, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
|
||||
static void bus_iomux_pins_set_quad(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
|
||||
gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
|
||||
gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->quadwp_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
|
||||
gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->quadhd_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
|
||||
gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->sclk_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
|
||||
gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void bus_iomux_pins_set(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if ((bus_config->flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
|
||||
bus_iomux_pins_set_oct(host, bus_config);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
bus_iomux_pins_set_quad(host, bus_config);
|
||||
}
|
||||
|
||||
/*
|
||||
Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pins. Feed it a host number and a
|
||||
bus config struct and it'll set up the GPIO matrix and enable the device. If a pin is set to non-negative value,
|
||||
@ -383,6 +468,17 @@ it should be able to be initialized.
|
||||
*/
|
||||
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t* flags_o)
|
||||
{
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
// In the driver of previous version, spi data4 ~ spi data7 are not in spi_bus_config_t struct. So the new-added pins come as 0
|
||||
// if they are not really set. Add this boolean variable to check if the user has set spi data4 ~spi data7 pins .
|
||||
bool io4_7_is_blank = !bus_config->data4_io_num && !bus_config->data5_io_num && !bus_config->data6_io_num && !bus_config->data7_io_num;
|
||||
// This boolean variable specifies if user sets pins used for octal mode (users can set spi data4 ~ spi data7 to -1).
|
||||
bool io4_7_enabled = !io4_7_is_blank && bus_config->data4_io_num >= 0 && bus_config->data5_io_num >= 0 &&
|
||||
bus_config->data6_io_num >= 0 && bus_config->data7_io_num >= 0;
|
||||
SPI_CHECK((flags & SPICOMMON_BUSFLAG_MASTER) || !((flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL), "Octal SPI mode / OPI mode only works when SPI is used as Master", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(host == SPI2_HOST || !((flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL), "Only SPI2 supports Octal SPI mode / OPI mode", ESP_ERR_INVALID_ARG);
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
|
||||
uint32_t temp_flag = 0;
|
||||
|
||||
bool miso_need_output;
|
||||
@ -414,13 +510,36 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
if (bus_config->quadhd_io_num>=0) {
|
||||
SPI_CHECK_PIN(bus_config->quadhd_io_num, "hd", hd_need_output);
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
const bool io4_need_output = true;
|
||||
const bool io5_need_output = true;
|
||||
const bool io6_need_output = true;
|
||||
const bool io7_need_output = true;
|
||||
// set flags for OCTAL mode according to the existence of spi data4 ~ spi data7
|
||||
if (io4_7_enabled) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_IO4_IO7;
|
||||
if (bus_config->data4_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data4_io_num, "spi data4", io4_need_output);
|
||||
}
|
||||
if (bus_config->data5_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data5_io_num, "spi data5", io5_need_output);
|
||||
}
|
||||
if (bus_config->data6_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data6_io_num, "spi data6", io6_need_output);
|
||||
}
|
||||
if (bus_config->data7_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data7_io_num, "spi data7", io7_need_output);
|
||||
}
|
||||
}
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
|
||||
//set flags for QUAD mode according to the existence of wp and hd
|
||||
if (bus_config->quadhd_io_num >= 0 && bus_config->quadwp_io_num >= 0) temp_flag |= SPICOMMON_BUSFLAG_WPHD;
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_MOSI;
|
||||
SPI_CHECK_PIN(bus_config->mosi_io_num, "mosi", mosi_need_output);
|
||||
}
|
||||
if (bus_config->miso_io_num>=0) {
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_MISO;
|
||||
SPI_CHECK_PIN(bus_config->miso_io_num, "miso", miso_need_output);
|
||||
}
|
||||
@ -443,12 +562,29 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
|
||||
if (missing_flag != 0) {
|
||||
//check pins existence
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_SCLK) ESP_LOGE(SPI_TAG, "sclk pin required.");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_MOSI) ESP_LOGE(SPI_TAG, "mosi pin required.");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_MISO) ESP_LOGE(SPI_TAG, "miso pin required.");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_DUAL) ESP_LOGE(SPI_TAG, "not both mosi and miso output capable");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_WPHD) ESP_LOGE(SPI_TAG, "both wp and hd required.");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) ESP_LOGE(SPI_TAG, "not using iomux pins");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_SCLK) {
|
||||
ESP_LOGE(SPI_TAG, "sclk pin required.");
|
||||
}
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_MOSI) {
|
||||
ESP_LOGE(SPI_TAG, "mosi pin required.");
|
||||
}
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_MISO) {
|
||||
ESP_LOGE(SPI_TAG, "miso pin required.");
|
||||
}
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_DUAL) {
|
||||
ESP_LOGE(SPI_TAG, "not both mosi and miso output capable");
|
||||
}
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_WPHD) {
|
||||
ESP_LOGE(SPI_TAG, "both wp and hd required.");
|
||||
}
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) {
|
||||
ESP_LOGE(SPI_TAG, "not using iomux pins");
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_IO4_IO7) {
|
||||
ESP_LOGE(SPI_TAG, "spi data4 ~ spi data7 are required.");
|
||||
}
|
||||
#endif
|
||||
SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
|
||||
}
|
||||
|
||||
@ -456,27 +592,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
//All SPI iomux pin selections resolve to 1, so we put that here instead of trying to figure
|
||||
//out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host+1);
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
|
||||
gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
|
||||
gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->quadwp_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
|
||||
gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->quadhd_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
|
||||
gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->sclk_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
|
||||
gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
|
||||
bus_iomux_pins_set(host, bus_config);
|
||||
} else {
|
||||
//Use GPIO matrix
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
|
||||
@ -537,6 +653,26 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
#endif
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (flags & SPICOMMON_BUSFLAG_OCTAL) {
|
||||
int io_nums[] = {bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
|
||||
uint8_t io_signals[4][2] = {{spi_periph_signal[host].spid4_out, spi_periph_signal[host].spid4_in},
|
||||
{spi_periph_signal[host].spid5_out, spi_periph_signal[host].spid5_in},
|
||||
{spi_periph_signal[host].spid6_out, spi_periph_signal[host].spid6_in},
|
||||
{spi_periph_signal[host].spid7_out, spi_periph_signal[host].spid7_in}};
|
||||
for (size_t i = 0; i < sizeof(io_nums) / sizeof(io_nums[0]); i++) {
|
||||
if (io_nums[i] >= 0) {
|
||||
gpio_set_direction(io_nums[i], GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(io_nums[i], io_signals[i][0], false, false);
|
||||
esp_rom_gpio_connect_in_signal(io_nums[i], io_signals[i][1], false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_nums[i]]);
|
||||
#endif
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[io_nums[i]], FUNC_GPIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
}
|
||||
|
||||
if (flags_o) *flags_o = temp_flag;
|
||||
|
@ -18,7 +18,7 @@ complicated mode which combines the two modes above:
|
||||
|
||||
The idea is that to send something to a SPI device, you allocate a
|
||||
transaction descriptor. It contains some information about the transfer
|
||||
like the lenghth, address, command etc, plus pointers to transmit and
|
||||
like the length, address, command etc, plus pointers to transmit and
|
||||
receive buffer. The address of this block gets pushed into the transmit
|
||||
queue. The SPI driver does its magic, and sends and retrieves the data
|
||||
eventually. The data gets written to the receive buffers, if needed the
|
||||
@ -466,14 +466,13 @@ int spi_get_actual_clock(int fapb, int hz, int duty_cycle)
|
||||
static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev)
|
||||
{
|
||||
spi_bus_lock_dev_handle_t dev_lock = dev->dev_lock;
|
||||
|
||||
if (!spi_bus_lock_touch(dev_lock)) {
|
||||
//if the configuration is already applied, skip the following.
|
||||
return;
|
||||
}
|
||||
spi_hal_context_t *hal = &dev->host->hal;
|
||||
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
|
||||
spi_hal_setup_device(hal, hal_dev);
|
||||
|
||||
if (spi_bus_lock_touch(dev_lock)) {
|
||||
/* Configuration has not been applied yet. */
|
||||
spi_hal_setup_device(hal, hal_dev);
|
||||
}
|
||||
}
|
||||
|
||||
static SPI_MASTER_ISR_ATTR spi_device_t *get_acquiring_dev(spi_host_t *host)
|
||||
@ -497,13 +496,13 @@ static inline SPI_MASTER_ISR_ATTR bool spi_bus_device_is_polling(spi_device_t *d
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// The interrupt may get invoked by the bus lock.
|
||||
static void spi_bus_intr_enable(void *host)
|
||||
static void SPI_MASTER_ISR_ATTR spi_bus_intr_enable(void *host)
|
||||
{
|
||||
esp_intr_enable(((spi_host_t*)host)->intr);
|
||||
}
|
||||
|
||||
// The interrupt is always disabled by the ISR itself, not exposed
|
||||
static void spi_bus_intr_disable(void *host)
|
||||
static void SPI_MASTER_ISR_ATTR spi_bus_intr_disable(void *host)
|
||||
{
|
||||
esp_intr_disable(((spi_host_t*)host)->intr);
|
||||
}
|
||||
@ -512,12 +511,11 @@ static void spi_bus_intr_disable(void *host)
|
||||
// Setup the transaction-specified registers and linked-list used by the DMA (or FIFO if DMA is not used)
|
||||
static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_t *trans_buf)
|
||||
{
|
||||
spi_transaction_t *trans = NULL;
|
||||
spi_transaction_t *trans = trans_buf->trans;
|
||||
spi_host_t *host = dev->host;
|
||||
spi_hal_context_t *hal = &(host->hal);
|
||||
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
|
||||
|
||||
trans = trans_buf->trans;
|
||||
host->cur_cs = dev->id;
|
||||
|
||||
//Reconfigure according to device settings, the function only has effect when the dev_id is changed.
|
||||
@ -531,13 +529,18 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_
|
||||
hal_trans.send_buffer = (uint8_t*)host->cur_trans_buf.buffer_to_send;
|
||||
hal_trans.cmd = trans->cmd;
|
||||
hal_trans.addr = trans->addr;
|
||||
//Set up QIO/DIO if needed
|
||||
hal_trans.io_mode = (trans->flags & SPI_TRANS_MODE_DIO ?
|
||||
(trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_DIO : SPI_LL_IO_MODE_DUAL) :
|
||||
(trans->flags & SPI_TRANS_MODE_QIO ?
|
||||
(trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_QIO : SPI_LL_IO_MODE_QUAD) :
|
||||
SPI_LL_IO_MODE_NORMAL
|
||||
));
|
||||
hal_trans.cs_keep_active = (trans->flags & SPI_TRANS_CS_KEEP_ACTIVE) ? 1 : 0;
|
||||
|
||||
//Set up OIO/QIO/DIO if needed
|
||||
hal_trans.line_mode.data_lines = (trans->flags & SPI_TRANS_MODE_DIO) ? 2 :
|
||||
(trans->flags & SPI_TRANS_MODE_QIO) ? 4 : 1;
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (trans->flags & SPI_TRANS_MODE_OCT) {
|
||||
hal_trans.line_mode.data_lines = 8;
|
||||
}
|
||||
#endif
|
||||
hal_trans.line_mode.addr_lines = (trans->flags & SPI_TRANS_MULTILINE_ADDR) ? hal_trans.line_mode.data_lines : 1;
|
||||
hal_trans.line_mode.cmd_lines = (trans->flags & SPI_TRANS_MULTILINE_CMD) ? hal_trans.line_mode.data_lines : 1;
|
||||
|
||||
if (trans->flags & SPI_TRANS_VARIABLE_CMD) {
|
||||
hal_trans.cmd_bits = ((spi_transaction_ext_t *)trans)->command_bits;
|
||||
@ -687,8 +690,13 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
||||
SPI_CHECK(trans_desc->rxlength <= bus_attr->max_transfer_sz*8, "rxdata transfer > host maximum", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(is_half_duplex || trans_desc->rxlength <= trans_desc->length, "rx length > tx length in full duplex mode", ESP_ERR_INVALID_ARG);
|
||||
//check working mode
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && !is_half_duplex), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
SPI_CHECK(!(host->id == SPI3_HOST && trans_desc->flags & SPI_TRANS_MODE_OCT), "SPI3 does not support octal mode", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!((trans_desc->flags & SPI_TRANS_MODE_OCT) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "Incompatible when setting to both Octal mode and 3-wire-mode", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!((trans_desc->flags & SPI_TRANS_MODE_OCT) && !is_half_duplex), "Incompatible when setting to both Octal mode and half duplex mode", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "Incompatible when setting to both multi-line mode and 3-wire-mode", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && !is_half_duplex), "Incompatible when setting to both multi-line mode and half duplex mode", ESP_ERR_INVALID_ARG);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
SPI_CHECK(!is_half_duplex || !bus_attr->dma_enabled || !rx_enabled || !tx_enabled, "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG );
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
@ -784,6 +792,12 @@ esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi
|
||||
|
||||
SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot queue new transaction while previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE );
|
||||
|
||||
/* Even when using interrupt transfer, the CS can only be kept activated if the bus has been
|
||||
* acquired with `spi_device_acquire_bus()` first. */
|
||||
if (host->device_acquiring_lock != handle && (trans_desc->flags & SPI_TRANS_CS_KEEP_ACTIVE)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
spi_trans_priv_t trans_buf;
|
||||
ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled));
|
||||
if (ret != ESP_OK) return ret;
|
||||
@ -914,15 +928,21 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl
|
||||
{
|
||||
esp_err_t ret;
|
||||
SPI_CHECK(ticks_to_wait == portMAX_DELAY, "currently timeout is not available for polling transactions", ESP_ERR_INVALID_ARG);
|
||||
|
||||
spi_host_t *host = handle->host;
|
||||
ret = check_trans_valid(handle, trans_desc);
|
||||
if (ret!=ESP_OK) return ret;
|
||||
|
||||
SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot send polling transaction while the previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE );
|
||||
|
||||
/* If device_acquiring_lock is set to handle, it means that the user has already
|
||||
* acquired the bus thanks to the function `spi_device_acquire_bus()`.
|
||||
* In that case, we don't need to take the lock again. */
|
||||
spi_host_t *host = handle->host;
|
||||
if (host->device_acquiring_lock != handle) {
|
||||
ret = spi_bus_lock_acquire_start(handle->dev_lock, ticks_to_wait);
|
||||
/* The user cannot ask for the CS to keep active has the bus is not locked/acquired. */
|
||||
if ((trans_desc->flags & SPI_TRANS_CS_KEEP_ACTIVE) != 0) {
|
||||
ret = ESP_ERR_INVALID_ARG;
|
||||
} else {
|
||||
ret = spi_bus_lock_acquire_start(handle->dev_lock, ticks_to_wait);
|
||||
}
|
||||
} else {
|
||||
ret = spi_bus_lock_wait_bg_done(handle->dev_lock, ticks_to_wait);
|
||||
}
|
||||
@ -963,6 +983,9 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_end(spi_device_handle_t handle,
|
||||
uninstall_priv_desc(&host->cur_trans_buf);
|
||||
|
||||
host->polling = false;
|
||||
/* Once again here, if device_acquiring_lock is set to `handle`, it means that the user has already
|
||||
* acquired the bus thanks to the function `spi_device_acquire_bus()`.
|
||||
* In that case, the lock must not be released now because . */
|
||||
if (host->device_acquiring_lock != handle) {
|
||||
assert(host->device_acquiring_lock == NULL);
|
||||
spi_bus_lock_acquire_end(handle->dev_lock);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user