forked from espressif/esp-idf
Compare commits
281 Commits
fixes
...
v4.3-beta3
Author | SHA1 | Date | |
---|---|---|---|
e9cf9e2978 | |||
6463dd9630 | |||
c9f1b55287 | |||
e16ec9a574 | |||
16cf160d57 | |||
58160d46c6 | |||
776906dc84 | |||
bd03a0e66a | |||
693aaef039 | |||
7703fcbd8d | |||
9a7deae742 | |||
84dc42c4b0 | |||
d7e680828a | |||
da47503c14 | |||
e490fdafbe | |||
94e3141a32 | |||
fd34406960 | |||
4544b709e5 | |||
a95c1c302d | |||
1ef91c72e2 | |||
90696dad89 | |||
e310fb1393 | |||
71de11e89d | |||
bda9e1fda7 | |||
97df333a3b | |||
6dfff2fdbd | |||
2ed3e8b344 | |||
e4dd9053c2 | |||
ff5e0d0d38 | |||
03b0540bc6 | |||
17e30c9e89 | |||
00cfcde385 | |||
0839fd08dd | |||
220f3d2198 | |||
904933745b | |||
ea4a8d5e4f | |||
10cce6b74a | |||
e36e433519 | |||
76ff1724b3 | |||
9f1ae278e0 | |||
54908d3a42 | |||
19b90e8ba9 | |||
a5e27d73a5 | |||
1e6a6ffa0d | |||
dbf2a64adb | |||
11970e65a1 | |||
670b057b04 | |||
ae3b4819da | |||
b0684e8b3c | |||
322cba0bf0 | |||
f5c6595cb4 | |||
e9e2b68587 | |||
73d40cb813 | |||
bf6ddf2557 | |||
d761226f36 | |||
5036ec363b | |||
c724236623 | |||
f7034e7767 | |||
7e75d7f748 | |||
e5437afa7f | |||
319eecc793 | |||
d17923151b | |||
0a0b3bb23f | |||
2a5cf2c3e0 | |||
ae15a0cab8 | |||
0c7f286a87 | |||
3e26049a05 | |||
dece3abd9c | |||
1af5bc2f7d | |||
278cfc2047 | |||
1790aa6bc6 | |||
b75a5fd03a | |||
cbf2858450 | |||
868c96c59f | |||
60d5dcb000 | |||
62787fc277 | |||
9e97133481 | |||
c9087c205b | |||
736b87db6d | |||
c2eaa3d844 | |||
2a715c811b | |||
17aa9c5ec4 | |||
c93211db62 | |||
be56456add | |||
413bbe4de4 | |||
4906779d50 | |||
7d5d57ec03 | |||
67a1858bb1 | |||
fb9de62f74 | |||
f48346f22f | |||
79ce133ed7 | |||
a59a5cb2cc | |||
2d26c24e3a | |||
2792c333bc | |||
7c5e920c37 | |||
d4ac30a978 | |||
2596c7e2cc | |||
e6b7c933d5 | |||
8fe99aff96 | |||
4866027391 | |||
a6ed4611a2 | |||
d457641f90 | |||
1509264f2e | |||
271b84f5b6 | |||
f1be501271 | |||
ea20966c29 | |||
f25c996b06 | |||
745bb2123f | |||
143bb1edf4 | |||
f1737a630d | |||
83087f15fa | |||
a9d1d44d4d | |||
72b27f1782 | |||
8e482c9423 | |||
1fb45977fa | |||
257728feab | |||
26d362040e | |||
f6a794cf51 | |||
974db3016b | |||
9c4c377f2d | |||
e6b8bc6ecb | |||
718f296587 | |||
6c74618bff | |||
974f345316 | |||
f2ca74b139 | |||
ac8ea9e9e5 | |||
48890daab1 | |||
f1aabb2894 | |||
cc8ef3660a | |||
67402f035f | |||
7dd5568cb7 | |||
f00d7ee9d0 | |||
dba5597edf | |||
5019a6571e | |||
4f8d784753 | |||
a697377871 | |||
6ceee165b5 | |||
4a20f68f5c | |||
8ec0ffe751 | |||
5d0ce8b52f | |||
2313683b58 | |||
c41822dc7c | |||
21909d7823 | |||
651a939643 | |||
3bf9d389ef | |||
6238c49479 | |||
fe1126cccb | |||
4725249385 | |||
6cfef8ce93 | |||
a643ea9432 | |||
f54dfe2912 | |||
c2ba180de3 | |||
d6f76f8a5f | |||
1d778c941c | |||
87b613fd2f | |||
f5f7d21c83 | |||
502a819757 | |||
802a01c0b7 | |||
a479ee30c9 | |||
46e85ed021 | |||
0862fe815b | |||
918875424e | |||
5490c0a243 | |||
a71d9cc466 | |||
c75a8b11bb | |||
9c884b3ba9 | |||
9a2d251912 | |||
3b9af23290 | |||
ff12b50e45 | |||
f6336516d1 | |||
4d80dd1238 | |||
8a2155f95e | |||
367190deaf | |||
dbb632fe34 | |||
1329747dc1 | |||
f9e1942252 | |||
82ffb33085 | |||
9fd12182de | |||
d42958439d | |||
37946ab300 | |||
2b7a3f6d85 | |||
60642e580c | |||
4235e80008 | |||
a8e0989648 | |||
28f50addda | |||
9393a402eb | |||
268787c5fb | |||
d92ac450a2 | |||
233f3f80e5 | |||
d01efe4b8c | |||
e48935d187 | |||
12bbd1f051 | |||
0305d13467 | |||
e6ace495b4 | |||
b449909b35 | |||
0253d825e9 | |||
32b0836485 | |||
7dca6b7428 | |||
b180c2a146 | |||
113bf479a4 | |||
774f010196 | |||
22a8fe5b6f | |||
d36c72fba0 | |||
1c8fd4041e | |||
d4263c2558 | |||
ea49545269 | |||
9ca05c17ae | |||
fd93c475b6 | |||
27c72a4105 | |||
5c8b1d6ab8 | |||
c5f8fbea02 | |||
cf7891cb93 | |||
1e77586120 | |||
1ea548ecb3 | |||
962ea61d53 | |||
d61ee580d5 | |||
947e445e02 | |||
1821fd766b | |||
d508182429 | |||
58c9a2eaba | |||
07b62da0d4 | |||
fb82bdb9da | |||
f3be9976b9 | |||
b639514793 | |||
f12b571f82 | |||
c0f06115d4 | |||
20b25a9667 | |||
1d9d444c07 | |||
060a829091 | |||
78314df2a5 | |||
8ceb462993 | |||
6accffecea | |||
de79e482c9 | |||
6638b81f8e | |||
d92b647199 | |||
965daf977a | |||
aa652adc12 | |||
5795075460 | |||
198d350fe5 | |||
24f3341a2d | |||
5a429f644f | |||
9aae8e0ce3 | |||
e5e47ebae6 | |||
436c3c289e | |||
2aa6aa8b88 | |||
3e9cd49d32 | |||
2c1845995b | |||
0c77299c34 | |||
9ac3e7c5d1 | |||
c42ce05941 | |||
ea2eb9d833 | |||
dec52a93d4 | |||
41bee7831f | |||
bd1b4dbda1 | |||
1de12526eb | |||
f0f2799946 | |||
5aabdd8abf | |||
8a2f91b48a | |||
ed6fb33726 | |||
66d10f0eec | |||
97f248d22c | |||
ffc4ff5a8c | |||
326d76ebdf | |||
c6ed522d60 | |||
8e187e7157 | |||
19f18aaa11 | |||
626a861115 | |||
a0fdf4b06c | |||
3d9523724d | |||
813b6c4ef6 | |||
1b849d59de | |||
87576aba28 | |||
57fb076590 | |||
360e7c4d51 | |||
9083ef97e5 | |||
a7a1e4dfba | |||
8ad92a92b9 | |||
321ee21c4c | |||
33820657c5 | |||
33892aadb9 | |||
ad669801ae |
@ -41,16 +41,6 @@
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/crc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/crc.h"
|
||||
#include "esp32s2/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/crc.h"
|
||||
#include "esp32c3/rom/secure_boot.h"
|
||||
#endif
|
||||
|
||||
#define SUB_TYPE_ID(i) (i & 0x0F)
|
||||
|
||||
/* Partial_data is word aligned so no reallocation is necessary for encrypted flash write */
|
||||
|
@ -274,6 +274,10 @@ menu "Bootloader config"
|
||||
|
||||
config BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
|
||||
bool "Skip image validation when exiting deep sleep"
|
||||
# note: dependencies for this config item are different to other "skip image validation"
|
||||
# options, allowing to turn on "allow insecure options" and have secure boot with
|
||||
# "skip validation when existing deep sleep". Keeping this to avoid a breaking change,
|
||||
# but - as noted in help - it invalidates the integrity of Secure Boot checks
|
||||
depends on (SECURE_BOOT && SECURE_BOOT_INSECURE) || !SECURE_BOOT
|
||||
default n
|
||||
help
|
||||
@ -286,6 +290,48 @@ menu "Bootloader config"
|
||||
partition as this would skip the validation upon first load of the new
|
||||
OTA partition.
|
||||
|
||||
It is possible to enable this option with Secure Boot if "allow insecure
|
||||
options" is enabled, however it's strongly recommended to NOT enable it as
|
||||
it may allow a Secure Boot bypass.
|
||||
|
||||
config BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON
|
||||
bool "Skip image validation from power on reset (READ HELP FIRST)"
|
||||
# only available if both Secure Boot and Check Signature on Boot are disabled
|
||||
depends on !SECURE_SIGNED_ON_BOOT
|
||||
default n
|
||||
help
|
||||
Some applications need to boot very quickly from power on. By default, the entire app binary
|
||||
is read from flash and verified which takes up a significant portion of the boot time.
|
||||
|
||||
Enabling this option will skip validation of the app when the SoC boots from power on.
|
||||
Note that in this case it's not possible for the bootloader to detect if an app image is
|
||||
corrupted in the flash, therefore it's not possible to safely fall back to a different app
|
||||
partition. Flash corruption of this kind is unlikely but can happen if there is a serious
|
||||
firmware bug or physical damage.
|
||||
|
||||
Following other reset types, the bootloader will still validate the app image. This increases
|
||||
the chances that flash corruption resulting in a crash can be detected following soft reset, and
|
||||
the bootloader will fall back to a valid app image. To increase the chances of successfully recovering
|
||||
from a flash corruption event, keep the option BOOTLOADER_WDT_ENABLE enabled and consider also enabling
|
||||
BOOTLOADER_WDT_DISABLE_IN_USER_CODE - then manually disable the RTC Watchdog once the app is running.
|
||||
In addition, enable both the Task and Interrupt watchdog timers with reset options set.
|
||||
|
||||
config BOOTLOADER_SKIP_VALIDATE_ALWAYS
|
||||
bool "Skip image validation always (READ HELP FIRST)"
|
||||
# only available if both Secure Boot and Check Signature on Boot are disabled
|
||||
depends on !SECURE_SIGNED_ON_BOOT
|
||||
default n
|
||||
select BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
|
||||
select BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON
|
||||
help
|
||||
Selecting this option prevents the bootloader from ever validating the app image before
|
||||
booting it. Any flash corruption of the selected app partition will make the entire SoC
|
||||
unbootable.
|
||||
|
||||
Although flash corruption is a very rare case, it is not recommended to select this option.
|
||||
Consider selecting "Skip image validation from power on reset" instead. However, if boot time
|
||||
is the only important factor then it can be enabled.
|
||||
|
||||
config BOOTLOADER_RESERVE_RTC_SIZE
|
||||
hex
|
||||
default 0x10 if BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP || BOOTLOADER_CUSTOM_RESERVE_RTC
|
||||
@ -378,7 +424,7 @@ menu "Security features"
|
||||
1. ECDSA based secure boot scheme. (Only choice for Secure Boot V1)
|
||||
Supported in ESP32 and ESP32-ECO3.
|
||||
2. The RSA based secure boot scheme. (Only choice for Secure Boot V2)
|
||||
Supported in ESP32-ECO3. (ESP32 Chip Revision 3 onwards)
|
||||
Supported in ESP32-ECO3 (ESP32 Chip Revision 3 onwards), ESP32-S2, ESP32-C3, ESP32-S3.
|
||||
|
||||
config SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
bool "ECDSA"
|
||||
@ -390,7 +436,7 @@ menu "Security features"
|
||||
|
||||
config SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bool "RSA"
|
||||
depends on SECURE_BOOT_SUPPORTS_RSA && SECURE_BOOT_V2_ENABLED
|
||||
depends on SECURE_BOOT_SUPPORTS_RSA && (SECURE_SIGNED_APPS_NO_SECURE_BOOT || SECURE_BOOT_V2_ENABLED)
|
||||
help
|
||||
Appends the RSA-3072 based Signature block to the application.
|
||||
Refer to <Secure Boot Version 2 documentation link> before enabling.
|
||||
@ -399,7 +445,7 @@ menu "Security features"
|
||||
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
|
||||
bool "Bootloader verifies app signatures"
|
||||
default n
|
||||
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT && SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
help
|
||||
If this option is set, the bootloader will be compiled with code to verify that an app is signed before
|
||||
booting it.
|
||||
@ -425,7 +471,7 @@ menu "Security features"
|
||||
config SECURE_BOOT
|
||||
bool "Enable hardware Secure Boot in bootloader (READ DOCS FIRST)"
|
||||
default n
|
||||
depends on !IDF_TARGET_ESP32C3 # IDF-2647
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || ESP32C3_REV_MIN_3
|
||||
help
|
||||
Build a bootloader which enables Secure Boot on first boot.
|
||||
|
||||
@ -442,7 +488,7 @@ menu "Security features"
|
||||
help
|
||||
Select the Secure Boot Version. Depends on the Chip Revision.
|
||||
Secure Boot V2 is the new RSA based secure boot scheme.
|
||||
Supported in ESP32-ECO3. (ESP32 Chip Revision 3 onwards)
|
||||
Supported in ESP32-ECO3 (ESP32 Chip Revision 3 onwards), ESP32-S2, ESP32-C3 ECO3.
|
||||
Secure Boot V1 is the AES based secure boot scheme.
|
||||
Supported in ESP32 and ESP32-ECO3.
|
||||
|
||||
@ -456,8 +502,6 @@ menu "Security features"
|
||||
config SECURE_BOOT_V2_ENABLED
|
||||
bool "Enable Secure Boot version 2"
|
||||
depends on SECURE_BOOT_SUPPORTS_RSA
|
||||
select SECURE_ENABLE_SECURE_ROM_DL_MODE if !IDF_TARGET_ESP32 && !SECURE_INSECURE_ALLOW_DL_MODE && !SECURE_DISABLE_ROM_DL_MODE # NOERROR
|
||||
select SECURE_DISABLE_ROM_DL_MODE if ESP32_REV_MIN_3 && !SECURE_INSECURE_ALLOW_DL_MODE
|
||||
help
|
||||
Build a bootloader which enables Secure Boot version 2 on first boot.
|
||||
Refer to Secure Boot V2 section of the ESP-IDF Programmer's Guide for this version before enabling.
|
||||
@ -626,8 +670,6 @@ menu "Security features"
|
||||
|
||||
config SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
bool "Release"
|
||||
select SECURE_ENABLE_SECURE_ROM_DL_MODE if SECURE_TARGET_HAS_SECURE_ROM_DL_MODE && !SECURE_DISABLE_ROM_DL_MODE # NOERROR
|
||||
|
||||
endchoice
|
||||
|
||||
menu "Potentially insecure options"
|
||||
@ -692,19 +734,6 @@ menu "Security features"
|
||||
key digest, causing an immediate denial of service and possibly allowing an additional fault
|
||||
injection attack to bypass the signature protection.
|
||||
|
||||
config SECURE_INSECURE_ALLOW_DL_MODE
|
||||
bool "Don't automatically restrict UART download mode"
|
||||
depends on SECURE_BOOT_INSECURE && SECURE_BOOT_V2_ENABLED
|
||||
default N
|
||||
help
|
||||
By default, enabling either flash encryption in release mode or secure boot will automatically
|
||||
disable UART download mode on ESP32 ECO3, or enable secure download mode on newer chips.
|
||||
This is recommended to reduce the attack surface of the chip.
|
||||
|
||||
To allow the full UART download mode to stay enabled, enable this option and ensure
|
||||
the options SECURE_DISABLE_ROM_DL_MODE and SECURE_ENABLE_SECURE_ROM_DL_MODE are disabled as applicable.
|
||||
This is not recommended.
|
||||
|
||||
config SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
bool "Leave UART bootloader encryption enabled"
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
@ -752,47 +781,58 @@ menu "Security features"
|
||||
|
||||
endmenu # Potentially Insecure
|
||||
|
||||
config SECURE_DISABLE_ROM_DL_MODE
|
||||
bool "Permanently disable ROM Download Mode"
|
||||
choice SECURE_UART_ROM_DL_MODE
|
||||
bool "UART ROM download mode"
|
||||
default SECURE_ENABLE_SECURE_ROM_DL_MODE if SECURE_TARGET_HAS_SECURE_ROM_DL_MODE && !SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT # NOERROR
|
||||
default SECURE_INSECURE_ALLOW_DL_MODE
|
||||
depends on SECURE_BOOT_V2_ENABLED || SECURE_FLASH_ENC_ENABLED
|
||||
depends on !IDF_TARGET_ESP32 || ESP32_REV_MIN_3
|
||||
default n
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently disable the UART ROM
|
||||
Download Mode. This prevents any future use of esptool.py, espefuse.py and similar tools.
|
||||
|
||||
Once disabled, if the SoC is booted with strapping pins set for ROM Download Mode
|
||||
then an error is printed instead.
|
||||
config SECURE_DISABLE_ROM_DL_MODE
|
||||
bool "UART ROM download mode (Permanently disabled (recommended))"
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently disable the UART ROM
|
||||
Download Mode. This prevents any future use of esptool.py, espefuse.py and similar tools.
|
||||
|
||||
It is recommended to enable this option in any production application where Flash
|
||||
Encryption and/or Secure Boot is enabled and access to Download Mode is not required.
|
||||
Once disabled, if the SoC is booted with strapping pins set for ROM Download Mode
|
||||
then an error is printed instead.
|
||||
|
||||
It is also possible to permanently disable Download Mode by calling
|
||||
esp_efuse_disable_rom_download_mode() at runtime.
|
||||
It is recommended to enable this option in any production application where Flash
|
||||
Encryption and/or Secure Boot is enabled and access to Download Mode is not required.
|
||||
|
||||
config SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
bool "Permanently switch to ROM UART Secure Download mode"
|
||||
depends on SECURE_TARGET_HAS_SECURE_ROM_DL_MODE && !SECURE_DISABLE_ROM_DL_MODE
|
||||
select ESPTOOLPY_NO_STUB
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently switch the UART ROM
|
||||
Download Mode into a separate Secure Download mode. This option can only work if
|
||||
Download Mode is not already disabled by eFuse.
|
||||
It is also possible to permanently disable Download Mode by calling
|
||||
esp_efuse_disable_rom_download_mode() at runtime.
|
||||
|
||||
Secure Download mode limits the use of Download Mode functions to simple flash read,
|
||||
write and erase operations, plus a command to return a summary of currently enabled
|
||||
security features.
|
||||
config SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
bool "UART ROM download mode (Permanently switch to Secure mode (recommended))"
|
||||
depends on SECURE_TARGET_HAS_SECURE_ROM_DL_MODE
|
||||
select ESPTOOLPY_NO_STUB
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently switch the UART ROM
|
||||
Download Mode into a separate Secure Download mode. This option can only work if
|
||||
Download Mode is not already disabled by eFuse.
|
||||
|
||||
Secure Download mode is not compatible with the esptool.py flasher stub feature,
|
||||
espefuse.py, read/writing memory or registers, encrypted download, or any other
|
||||
features that interact with unsupported Download Mode commands.
|
||||
Secure Download mode limits the use of Download Mode functions to simple flash read,
|
||||
write and erase operations, plus a command to return a summary of currently enabled
|
||||
security features.
|
||||
|
||||
Secure Download mode should be enabled in any application where Flash Encryption
|
||||
and/or Secure Boot is enabled. Disabling this option does not immediately cancel
|
||||
the benefits of the security features, but it increases the potential "attack
|
||||
surface" for an attacker to try and bypass them with a successful physical attack.
|
||||
Secure Download mode is not compatible with the esptool.py flasher stub feature,
|
||||
espefuse.py, read/writing memory or registers, encrypted download, or any other
|
||||
features that interact with unsupported Download Mode commands.
|
||||
|
||||
It is also possible to enable secure download mode at runtime by calling
|
||||
esp_efuse_enable_rom_secure_download_mode()
|
||||
Secure Download mode should be enabled in any application where Flash Encryption
|
||||
and/or Secure Boot is enabled. Disabling this option does not immediately cancel
|
||||
the benefits of the security features, but it increases the potential "attack
|
||||
surface" for an attacker to try and bypass them with a successful physical attack.
|
||||
|
||||
It is also possible to enable secure download mode at runtime by calling
|
||||
esp_efuse_enable_rom_secure_download_mode()
|
||||
|
||||
config SECURE_INSECURE_ALLOW_DL_MODE
|
||||
bool "UART ROM download mode (Enabled (not recommended))"
|
||||
help
|
||||
This is a potentially insecure option.
|
||||
Enabling this option will allow the full UART download mode to stay enabled.
|
||||
This option SHOULD NOT BE ENABLED for production use cases.
|
||||
endchoice
|
||||
endmenu # Security features
|
||||
|
@ -28,10 +28,11 @@ set(COMPONENTS
|
||||
micro-ecc
|
||||
main
|
||||
efuse
|
||||
esp_system)
|
||||
esp_system
|
||||
newlib)
|
||||
set(BOOTLOADER_BUILD 1)
|
||||
include("${IDF_PATH}/tools/cmake/project.cmake")
|
||||
set(common_req log esp_rom esp_common esp_hw_support hal)
|
||||
set(common_req log esp_rom esp_common esp_hw_support hal newlib)
|
||||
if(LEGACY_INCLUDE_COMMON_HEADERS)
|
||||
list(APPEND common_req soc hal)
|
||||
endif()
|
||||
|
@ -52,7 +52,7 @@ SECTIONS
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
@ -167,6 +167,14 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
@ -40,7 +40,7 @@ SECTIONS
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
@ -156,6 +156,14 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
@ -39,7 +39,7 @@ SECTIONS
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
@ -155,6 +155,14 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
@ -40,7 +40,7 @@ SECTIONS
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures_bootloader.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
@ -156,6 +156,14 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
@ -9,6 +9,7 @@ set(srcs
|
||||
"src/bootloader_utility.c"
|
||||
"src/esp_image_format.c"
|
||||
"src/flash_encrypt.c"
|
||||
"src/secure_boot.c"
|
||||
"src/flash_partitions.c"
|
||||
"src/flash_qio_mode.c"
|
||||
"src/bootloader_flash_config_${IDF_TARGET}.c"
|
||||
@ -34,16 +35,28 @@ else()
|
||||
"src/idf/bootloader_sha.c")
|
||||
set(include_dirs "include")
|
||||
set(priv_include_dirs "include_bootloader")
|
||||
set(priv_requires spi_flash mbedtls efuse)
|
||||
set(priv_requires spi_flash mbedtls efuse app_update)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
if(BOOTLOADER_BUILD)
|
||||
list(APPEND srcs
|
||||
"src/${IDF_TARGET}/secure_boot_signatures.c")
|
||||
else()
|
||||
list(APPEND srcs
|
||||
"src/idf/secure_boot_signatures.c")
|
||||
if(BOOTLOADER_BUILD)
|
||||
if(CONFIG_SECURE_SIGNED_ON_BOOT)
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v1/secure_boot_signatures_bootloader.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_bootloader.c")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(CONFIG_SECURE_SIGNED_ON_UPDATE)
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v1/secure_boot_signatures_app.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_app.c")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -34,10 +34,13 @@ COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \
|
||||
src/bootloader_random_esp32c3.o
|
||||
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/$(IDF_TARGET)/secure_boot_signatures.o \
|
||||
src/idf/secure_boot_signatures.o
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v1/secure_boot_signatures_bootloader.o \
|
||||
src/secure_boot_v1/secure_boot_signatures_app.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
COMPONENT_OBJEXCLUDE += src/secure_boot_v2/secure_boot_signatures_bootloader.o \
|
||||
src/secure_boot_v2/secure_boot_signatures_app.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_BOOT
|
||||
|
@ -106,6 +106,20 @@ _Static_assert(sizeof(rtc_retain_mem_t) <= ESP_BOOTLOADER_RESERVE_RTC, "Reserved
|
||||
*/
|
||||
esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data);
|
||||
|
||||
/**
|
||||
* @brief Get metadata of app
|
||||
*
|
||||
* If encryption is enabled, data will be transparently decrypted.
|
||||
*
|
||||
* @param part Partition to load the app from.
|
||||
* @param[out] metadata Pointer to the image metadata structure which is be filled in by this function.
|
||||
* Fields will all be initialised by this function.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if filling of metadata was successful
|
||||
*/
|
||||
esp_err_t esp_image_get_metadata(const esp_partition_pos_t *part, esp_image_metadata_t *metadata);
|
||||
|
||||
/**
|
||||
* @brief Verify and load an app image (available only in space of bootloader).
|
||||
*
|
||||
|
@ -19,17 +19,22 @@
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_rom_efuse.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_rom_crc.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/efuse.h"
|
||||
#include "esp32/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/efuse.h"
|
||||
#include "esp32s2/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/efuse.h"
|
||||
#include "esp32c3/rom/secure_boot.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/efuse.h"
|
||||
#include "esp32s3/rom/secure_boot.h"
|
||||
#endif
|
||||
|
||||
typedef struct ets_secure_boot_signature ets_secure_boot_signature_t;
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
|
||||
#if !defined(CONFIG_SECURE_SIGNED_ON_BOOT) || !defined(CONFIG_SECURE_SIGNED_ON_UPDATE) || !defined(CONFIG_SECURE_SIGNED_APPS)
|
||||
#error "internal sdkconfig error, secure boot should always enable all signature options"
|
||||
@ -45,6 +50,8 @@ extern "C" {
|
||||
Can be compiled as part of app or bootloader code.
|
||||
*/
|
||||
|
||||
#define ESP_SECURE_BOOT_DIGEST_LEN 32
|
||||
|
||||
/** @brief Is secure boot currently enabled in hardware?
|
||||
*
|
||||
* This means that the ROM bootloader code will only boot
|
||||
@ -181,6 +188,16 @@ typedef struct {
|
||||
*/
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest);
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32 || CONFIG_ESP32_REV_MIN_3
|
||||
/**
|
||||
* @brief Structure to hold public key digests calculated from the signature blocks of a single image.
|
||||
*
|
||||
* Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block includes a public key.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SECURE_BOOT_NUM_BLOCKS][ESP_SECURE_BOOT_DIGEST_LEN]; /* SHA of the public key components in the signature block */
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} esp_image_sig_public_key_digests_t;
|
||||
|
||||
/** @brief Verify the RSA secure boot signature block for Secure Boot V2.
|
||||
*
|
||||
@ -194,6 +211,7 @@ esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest);
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32 || CONFIG_ESP32_REV_MIN_3
|
||||
|
||||
/** @brief Legacy ECDSA verification function
|
||||
*
|
||||
@ -214,6 +232,45 @@ typedef struct {
|
||||
uint8_t digest[64];
|
||||
} esp_secure_boot_iv_digest_t;
|
||||
|
||||
/** @brief Check the secure boot V2 during startup
|
||||
*
|
||||
* @note This function is called automatically during app startup,
|
||||
* it doesn't need to be called from the app.
|
||||
*
|
||||
* Verifies the secure boot config during startup:
|
||||
*
|
||||
* - Correct any insecure secure boot settings
|
||||
*/
|
||||
void esp_secure_boot_init_checks(void);
|
||||
|
||||
#if !BOOTLOADER_BUILD && CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
|
||||
/** @brief Scan the current running app for signature blocks
|
||||
*
|
||||
* @note This function doesn't verify that the signatures are valid or the
|
||||
* corresponding public keys are trusted, it only reads the number of signature
|
||||
* blocks present and optionally calculates the digests of the public keys
|
||||
* provided in the signature blocks.
|
||||
*
|
||||
* @param digest_public_keys If true, the key_digests fields in the
|
||||
* public_key_digests structure will be filled with the digests of the public
|
||||
* key provided in each signature block. Note that if Secure Boot V2 is enabled,
|
||||
* each public key will only be trusted if the same digest is also present in
|
||||
* eFuse (but this is not checked by this function).
|
||||
*
|
||||
* @param public_key_digests[out] Structure is initialized with the num_digests
|
||||
* field set to the number of signatures found. If digest_public_keys is set,
|
||||
* the public key digests are also calculated and stored here.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK - At least one signature was found
|
||||
* - ESP_ERR_NOT_FOUND - No signatures were found, num_digests value will be zero
|
||||
* - ESP_FAIL - An error occured trying to read the signature blocks from flash
|
||||
*/
|
||||
esp_err_t esp_secure_boot_get_signature_blocks_for_running_app(bool digest_public_keys, esp_image_sig_public_key_digests_t *public_key_digests);
|
||||
|
||||
#endif // !BOOTLOADER_BUILD && CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
@ -138,7 +139,18 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t
|
||||
|
||||
#if defined( CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP ) || defined( CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC )
|
||||
|
||||
rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)(SOC_RTC_DRAM_HIGH - sizeof(rtc_retain_mem_t));
|
||||
#define RTC_RETAIN_MEM_ADDR (SOC_RTC_DATA_HIGH - sizeof(rtc_retain_mem_t))
|
||||
|
||||
rtc_retain_mem_t *const rtc_retain_mem = (rtc_retain_mem_t *)RTC_RETAIN_MEM_ADDR;
|
||||
|
||||
#if !IS_BOOTLOADER_BUILD
|
||||
/* 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
|
||||
this feature is otherwise 100% part of the bootloader. However this seems to happen in all apps.
|
||||
*/
|
||||
SOC_RESERVE_MEMORY_REGION(RTC_RETAIN_MEM_ADDR, RTC_RETAIN_MEM_ADDR + sizeof(rtc_retain_mem_t), rtc_retain_mem);
|
||||
#endif
|
||||
|
||||
static bool check_rtc_retain_mem(void)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/clk_gate_ll.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/usb/cdc_acm.h"
|
||||
#include "esp32s2/rom/usb/usb_common.h"
|
||||
@ -69,8 +70,8 @@ void bootloader_console_init(void)
|
||||
uart_tx_gpio != UART_NUM_0_TXD_DIRECT_GPIO_NUM ||
|
||||
uart_rx_gpio != UART_NUM_0_RXD_DIRECT_GPIO_NUM) {
|
||||
// Change default UART pins back to GPIOs
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, PIN_FUNC_GPIO);
|
||||
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;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/soc_pins.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "flash_qio_mode.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
@ -87,7 +88,7 @@ void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr)
|
||||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302) {
|
||||
// For ESP32D2WD or ESP32-PICO series,the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else {
|
||||
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
|
||||
@ -102,14 +103,14 @@ void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr)
|
||||
esp_rom_gpio_connect_out_signal(SPI_IOMUX_PIN_NUM_HD, SPIHD_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(SPI_IOMUX_PIN_NUM_HD, SPIHD_IN_IDX, 0);
|
||||
//select pin function gpio
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
// flash clock signal should come from IO MUX.
|
||||
// set drive ability for clock
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
|
||||
uint32_t flash_id = g_rom_flashchip.device_id;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
@ -61,7 +62,7 @@ void bootloader_configure_spi_pins(int drv)
|
||||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302) {
|
||||
// For ESP32D2WD or ESP32-PICO series,the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else {
|
||||
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
|
||||
@ -76,14 +77,14 @@ void bootloader_configure_spi_pins(int drv)
|
||||
esp_rom_gpio_connect_out_signal(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
|
||||
//select pin function gpio
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
// flash clock signal should come from IO MUX.
|
||||
// set drive ability for clock
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
|
||||
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32 || CONFIG_SPIRAM_TYPE_ESPPSRAM64
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp_rom_crc.h"
|
||||
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
@ -223,16 +222,12 @@ esp_err_t esp_secure_boot_permanently_enable(void)
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
|
||||
#define SIG_BLOCK_MAGIC_BYTE 0xe7
|
||||
#define CRC_SIGN_BLOCK_LEN 1196
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_signature_t *sig_block, uint8_t *digest)
|
||||
{
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)sig_block, CRC_SIGN_BLOCK_LEN);
|
||||
if (sig_block->block[0].magic_byte == SIG_BLOCK_MAGIC_BYTE && sig_block->block[0].block_crc == crc && !memcmp(digest, sig_block->block[0].image_digest, DIGEST_LEN)) {
|
||||
if (sig_block->block[0].magic_byte == ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
|
||||
&& sig_block->block[0].block_crc == crc
|
||||
&& !memcmp(digest, sig_block->block[0].image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "valid signature block found");
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -243,7 +238,7 @@ static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
|
||||
uint8_t image_digest[DIGEST_LEN] = {0};
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
@ -266,7 +261,7 @@ static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t
|
||||
}
|
||||
|
||||
/* Verifying Signature block */
|
||||
uint8_t verified_digest[DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
|
||||
/* Generating the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha;
|
||||
@ -318,7 +313,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t boot_pub_key_digest[DIGEST_LEN];
|
||||
uint8_t boot_pub_key_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
|
||||
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
|
||||
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
|
||||
@ -350,7 +345,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Burning public key hash to efuse.");
|
||||
ret = esp_efuse_write_block(EFUSE_BLK2, boot_pub_key_digest, 0, (DIGEST_LEN * 8));
|
||||
ret = esp_efuse_write_block(EFUSE_BLK2, boot_pub_key_digest, 0, (ESP_SECURE_BOOT_DIGEST_LEN * 8));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Writing public key hash to efuse failed.");
|
||||
return ret;
|
||||
@ -366,7 +361,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
efuse_blk2_digest[5] = efuse_blk2_r5;
|
||||
efuse_blk2_digest[6] = efuse_blk2_r6;
|
||||
efuse_blk2_digest[7] = efuse_blk2_r7;
|
||||
memcpy(boot_pub_key_digest, efuse_blk2_digest, DIGEST_LEN);
|
||||
memcpy(boot_pub_key_digest, efuse_blk2_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
ESP_LOGW(TAG, "Using pre-loaded secure boot v2 public key digest in EFUSE block 2");
|
||||
}
|
||||
|
||||
@ -380,7 +375,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
efuse_key_write_protected = true;
|
||||
}
|
||||
|
||||
uint8_t app_pub_key_digest[DIGEST_LEN];
|
||||
uint8_t app_pub_key_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
ret = secure_boot_v2_digest_generate(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, app_pub_key_digest);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Application signature block is invalid.");
|
||||
@ -388,7 +383,7 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
|
||||
}
|
||||
|
||||
/* Confirming if the public key in the bootloader's signature block matches with the one in the application's signature block */
|
||||
if (memcmp(boot_pub_key_digest, app_pub_key_digest, DIGEST_LEN) != 0) {
|
||||
if (memcmp(boot_pub_key_digest, app_pub_key_digest, ESP_SECURE_BOOT_DIGEST_LEN) != 0) {
|
||||
ESP_LOGE(TAG, "Application not signed with a valid private key.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
@ -1,184 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_fault.h"
|
||||
#include "esp32/rom/sha.h"
|
||||
#include "uECC_verify_antifault.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "secure_boot";
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* ignored in this function */
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block
|
||||
sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if(!sigblock) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// Verify the signature
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
// Unmap
|
||||
bootloader_munmap(sigblock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
|
||||
{
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 };
|
||||
return esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ptrdiff_t keylen;
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
bool is_valid;
|
||||
is_valid = uECC_verify_antifault(signature_verification_key_start,
|
||||
image_digest,
|
||||
DIGEST_LEN,
|
||||
sig_block->signature,
|
||||
uECC_secp256r1(),
|
||||
verified_digest);
|
||||
ESP_LOGD(TAG, "Verification result %d", is_valid);
|
||||
|
||||
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[DIGEST_LEN] = {0}; // ignored in this function
|
||||
const uint8_t *data;
|
||||
|
||||
/* Padding to round off the input to the nearest 4k boundary */
|
||||
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
|
||||
|
||||
data = bootloader_mmap(src_addr, padded_length + sizeof(ets_secure_boot_signature_t));
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = (const ets_secure_boot_signature_t *)(data + padded_length);
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
secure_boot_v2_status_t r;
|
||||
uint8_t efuse_trusted_digest[DIGEST_LEN] = {0}, sig_block_trusted_digest[DIGEST_LEN] = {0};
|
||||
|
||||
memcpy(efuse_trusted_digest, (uint8_t *)EFUSE_BLK2_RDATA0_REG, DIGEST_LEN); /* EFUSE_BLK2_RDATA0_REG - Stores the Secure Boot Public Key Digest */
|
||||
|
||||
if (!ets_use_secure_boot_v2()) {
|
||||
ESP_LOGI(TAG, "Secure Boot eFuse bit(ABS_DONE_1) not yet programmed.");
|
||||
|
||||
/* Generating the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha;
|
||||
sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[0].key, sizeof(sig_block->block[0].key));
|
||||
bootloader_sha256_finish(sig_block_sha, (unsigned char *)sig_block_trusted_digest);
|
||||
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
if (memcmp(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN) != 0) {
|
||||
/* Most likely explanation for this is that BLK2 is empty, and we're going to burn it
|
||||
after we verify that the signature is valid. However, if BLK2 is not empty then we need to
|
||||
fail here.
|
||||
*/
|
||||
bool all_zeroes = true;
|
||||
for (int i = 0; i < DIGEST_LEN; i++) {
|
||||
all_zeroes = all_zeroes && (efuse_trusted_digest[i] == 0);
|
||||
}
|
||||
if (!all_zeroes) {
|
||||
ESP_LOGE(TAG, "Different public key digest burned to eFuse BLK2");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_FAULT_ASSERT(!ets_use_secure_boot_v2());
|
||||
#endif
|
||||
|
||||
memcpy(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
r = ets_secure_boot_verify_signature(sig_block, image_digest, efuse_trusted_digest, verified_digest);
|
||||
if (r != SBV2_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
|
||||
return (r == SBV2_SUCCESS) ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
#endif
|
@ -262,27 +262,32 @@ static void bootloader_super_wdt_auto_feed(void)
|
||||
REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, 0);
|
||||
}
|
||||
|
||||
#if CONFIG_ESP32C3_REV_MIN < 3
|
||||
static inline void bootloader_hardware_init(void)
|
||||
{
|
||||
// TODO ESP32-C3 IDF-2452
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1);
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12);
|
||||
if (bootloader_common_get_chip_revision() < 3) {
|
||||
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1);
|
||||
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* There happend clock glitch reset for some chip when testing wifi[BIT0] and brownout reset when chip startup[BIT1].
|
||||
* But super_watch_dog_reset function is ok, so open it[BIT2].
|
||||
* Whether this api will deleted or not depends on analog design & test result when ECO chip come back.
|
||||
*/
|
||||
static inline void bootloader_glitch_reset_disable(void)
|
||||
{
|
||||
// TODO ESP32-C3 IDF-2453
|
||||
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, BIT2);
|
||||
uint8_t chip_version = bootloader_common_get_chip_revision();
|
||||
if (chip_version < 2) {
|
||||
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST);
|
||||
} else {
|
||||
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST | RTC_CNTL_FIB_BOR_RST);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
#if CONFIG_ESP32C3_REV_MIN < 3
|
||||
bootloader_hardware_init();
|
||||
#endif
|
||||
bootloader_glitch_reset_disable();
|
||||
bootloader_super_wdt_auto_feed();
|
||||
// protect memory region
|
||||
|
@ -31,17 +31,11 @@
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#define SIG_BLOCK_MAGIC_BYTE 0xe7
|
||||
#define CRC_SIGN_BLOCK_LEN 1196
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc and image digest. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
|
||||
{
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
|
||||
if (block->magic_byte != SIG_BLOCK_MAGIC_BYTE) {
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
|
||||
// All signature blocks have been parsed, no new signature block present.
|
||||
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
|
||||
return ESP_FAIL;
|
||||
@ -50,7 +44,7 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (memcmp(image_digest, block->image_digest, DIGEST_LEN)) {
|
||||
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
@ -61,19 +55,6 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Structure to hold public key digests calculated from the signature blocks of a single image.
|
||||
|
||||
Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block
|
||||
includes a public key.
|
||||
|
||||
Different to the ROM ets_secure_boot_key_digests_t structure which holds pointers to eFuse data with digests,
|
||||
in this data structure the digest data is included.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN];
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} image_sig_public_key_digests_t;
|
||||
|
||||
/* Generates the public key digests of the valid public keys in an image's
|
||||
signature block, verifies each signature, and stores the key digests in the
|
||||
public_key_digests structure.
|
||||
@ -89,16 +70,16 @@ typedef struct {
|
||||
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
|
||||
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
|
||||
*/
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, image_sig_public_key_digests_t *public_key_digests)
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t image_digest[DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[DIGEST_LEN] = {0};
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(image_sig_public_key_digests_t));
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
@ -129,7 +110,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[DIGEST_LEN];
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
|
||||
|
||||
if (!verified) {
|
||||
@ -142,7 +123,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, DIGEST_LEN);
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
|
||||
@ -173,8 +154,8 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
|
||||
|
||||
if (!has_secure_boot_digest) {
|
||||
image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
image_sig_public_key_digests_t app_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t app_key_digests = {0};
|
||||
|
||||
/* Generate the bootloader public key digests */
|
||||
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
|
||||
@ -234,7 +215,7 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
}
|
||||
|
||||
for (int j = 0; j < app_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], DIGEST_LEN)) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
|
||||
match = true;
|
||||
}
|
||||
|
@ -1,94 +0,0 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp32c3/rom/secure_boot.h"
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
const uint8_t *data;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
/* Padding to round off the input to the nearest 4k boundary */
|
||||
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
|
||||
|
||||
data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block));
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(ets_secure_boot_signature_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length);
|
||||
int r = esp_secure_boot_verify_rsa_signature_block(sig, digest, verified_digest);
|
||||
bootloader_munmap(data);
|
||||
|
||||
return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ets_secure_boot_key_digests_t trusted_keys;
|
||||
ets_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
ETS_STATUS r;
|
||||
ets_secure_boot_status_t sb_result;
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
r = ets_secure_boot_read_key_digests(&trusted_keys);
|
||||
if (r != ETS_OK) {
|
||||
ESP_LOGI(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS boot...");
|
||||
sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
|
||||
return (sb_result == SB_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
@ -31,17 +31,11 @@
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#define SIG_BLOCK_MAGIC_BYTE 0xe7
|
||||
#define CRC_SIGN_BLOCK_LEN 1196
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc and image digest. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
|
||||
{
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
|
||||
if (block->magic_byte != SIG_BLOCK_MAGIC_BYTE) {
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
|
||||
// All signature blocks have been parsed, no new signature block present.
|
||||
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
|
||||
return ESP_FAIL;
|
||||
@ -50,7 +44,7 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (memcmp(image_digest, block->image_digest, DIGEST_LEN)) {
|
||||
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
@ -61,19 +55,6 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Structure to hold public key digests calculated from the signature blocks of a single image.
|
||||
|
||||
Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block
|
||||
includes a public key.
|
||||
|
||||
Different to the ROM ets_secure_boot_key_digests_t structure which holds pointers to eFuse data with digests,
|
||||
in this data structure the digest data is included.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN];
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} image_sig_public_key_digests_t;
|
||||
|
||||
/* Generates the public key digests of the valid public keys in an image's
|
||||
signature block, verifies each signature, and stores the key digests in the
|
||||
public_key_digests structure.
|
||||
@ -89,16 +70,16 @@ typedef struct {
|
||||
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
|
||||
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
|
||||
*/
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, image_sig_public_key_digests_t *public_key_digests)
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t image_digest[DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[DIGEST_LEN] = {0};
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(image_sig_public_key_digests_t));
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
@ -129,7 +110,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[DIGEST_LEN];
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
|
||||
|
||||
if (!verified) {
|
||||
@ -142,7 +123,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, DIGEST_LEN);
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
|
||||
@ -173,8 +154,8 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
|
||||
|
||||
if (!has_secure_boot_digest) {
|
||||
image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
image_sig_public_key_digests_t app_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t app_key_digests = {0};
|
||||
|
||||
/* Generate the bootloader public key digests */
|
||||
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
|
||||
@ -234,7 +215,7 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
}
|
||||
|
||||
for (int j = 0; j < app_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], DIGEST_LEN)) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
|
||||
match = true;
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp32s2/rom/secure_boot.h"
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
const uint8_t *data;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
/* Padding to round off the input to the nearest 4k boundary */
|
||||
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
|
||||
|
||||
data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block));
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(ets_secure_boot_signature_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length);
|
||||
int r = esp_secure_boot_verify_rsa_signature_block(sig, digest, verified_digest);
|
||||
bootloader_munmap(data);
|
||||
|
||||
return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ets_secure_boot_key_digests_t trusted_keys;
|
||||
ets_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
ETS_STATUS r;
|
||||
ets_secure_boot_status_t sb_result;
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
r = ets_secure_boot_read_key_digests(&trusted_keys);
|
||||
if (r != ETS_OK) {
|
||||
ESP_LOGI(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS boot...");
|
||||
sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
|
||||
return (sb_result == SB_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
@ -31,17 +31,11 @@
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#define SIG_BLOCK_MAGIC_BYTE 0xe7
|
||||
#define CRC_SIGN_BLOCK_LEN 1196
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc and image digest. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block, int block_num, const uint8_t *image_digest)
|
||||
{
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN);
|
||||
if (block->magic_byte != SIG_BLOCK_MAGIC_BYTE) {
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC) {
|
||||
// All signature blocks have been parsed, no new signature block present.
|
||||
ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
|
||||
return ESP_FAIL;
|
||||
@ -50,7 +44,7 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (memcmp(image_digest, block->image_digest, DIGEST_LEN)) {
|
||||
if (memcmp(image_digest, block->image_digest, ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
@ -61,19 +55,6 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Structure to hold public key digests calculated from the signature blocks of a single image.
|
||||
|
||||
Each image can have one or more signature blocks (up to SECURE_BOOT_NUM_BLOCKS). Each signature block
|
||||
includes a public key.
|
||||
|
||||
Different to the ROM ets_secure_boot_key_digests_t structure which holds pointers to eFuse data with digests,
|
||||
in this data structure the digest data is included.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_digests[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN];
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} image_sig_public_key_digests_t;
|
||||
|
||||
/* Generates the public key digests of the valid public keys in an image's
|
||||
signature block, verifies each signature, and stores the key digests in the
|
||||
public_key_digests structure.
|
||||
@ -89,16 +70,16 @@ typedef struct {
|
||||
@return - ESP_OK if no signatures failed to verify, or if no valid signature blocks are found at all.
|
||||
- ESP_FAIL if there's a valid signature block that doesn't verify using the included public key (unexpected!)
|
||||
*/
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, image_sig_public_key_digests_t *public_key_digests)
|
||||
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t image_digest[DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[DIGEST_LEN] = {0};
|
||||
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
|
||||
|
||||
ESP_LOGD(TAG, "calculating public key digests for sig blocks of image offset 0x%x (sig block offset 0x%x)", flash_offset, sig_block_addr);
|
||||
|
||||
bzero(public_key_digests, sizeof(image_sig_public_key_digests_t));
|
||||
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
|
||||
if (ret != ESP_OK) {
|
||||
@ -129,7 +110,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[DIGEST_LEN];
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
|
||||
|
||||
if (!verified) {
|
||||
@ -142,7 +123,7 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
}
|
||||
ESP_LOGD(TAG, "Signature block (%d) is verified", i);
|
||||
/* Copy the key digest to the buffer provided by the caller */
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, DIGEST_LEN);
|
||||
memcpy((void *)public_key_digests->key_digests[i], key_digest, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
|
||||
@ -173,8 +154,8 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
|
||||
|
||||
if (!has_secure_boot_digest) {
|
||||
image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
image_sig_public_key_digests_t app_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t boot_key_digests = {0};
|
||||
esp_image_sig_public_key_digests_t app_key_digests = {0};
|
||||
|
||||
/* Generate the bootloader public key digests */
|
||||
ret = s_calculate_image_public_key_digests(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_key_digests);
|
||||
@ -234,7 +215,7 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
}
|
||||
|
||||
for (int j = 0; j < app_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], DIGEST_LEN)) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], app_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
|
||||
match = true;
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp32s3/rom/secure_boot.h"
|
||||
|
||||
static const char* TAG = "secure_boot";
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
const uint8_t *data;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
/* Padding to round off the input to the nearest 4k boundary */
|
||||
int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
|
||||
|
||||
data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block));
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(ets_secure_boot_signature_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
bootloader_munmap(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length);
|
||||
int r = esp_secure_boot_verify_rsa_signature_block(sig, digest, verified_digest);
|
||||
bootloader_munmap(data);
|
||||
|
||||
return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ets_secure_boot_key_digests_t trusted_keys;
|
||||
ets_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
ETS_STATUS r;
|
||||
ets_secure_boot_status_t sb_result;
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
r = ets_secure_boot_read_key_digests(&trusted_keys);
|
||||
if (r != ETS_OK) {
|
||||
ESP_LOGI(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS boot...");
|
||||
sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
|
||||
return (sb_result == SB_SUCCESS) ? ESP_OK : ESP_FAIL;
|
||||
}
|
@ -327,11 +327,24 @@ err:
|
||||
|
||||
esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data)
|
||||
{
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
return image_load(ESP_IMAGE_LOAD, part, data);
|
||||
#else
|
||||
#if !defined(BOOTLOADER_BUILD)
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
#else
|
||||
esp_image_load_mode_t mode = ESP_IMAGE_LOAD;
|
||||
|
||||
#if !defined(CONFIG_SECURE_BOOT)
|
||||
/* Skip validation under particular configurations */
|
||||
#if CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS
|
||||
mode = ESP_IMAGE_LOAD_NO_VALIDATE;
|
||||
#elif CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON
|
||||
if (rtc_get_reset_reason(0) == POWERON_RESET) {
|
||||
mode = ESP_IMAGE_LOAD_NO_VALIDATE;
|
||||
}
|
||||
#endif // CONFIG_BOOTLOADER_SKIP_...
|
||||
#endif // CONFIG_SECURE_BOOT
|
||||
|
||||
return image_load(mode, part, data);
|
||||
#endif // BOOTLOADER_BUILD
|
||||
}
|
||||
|
||||
esp_err_t bootloader_load_image_no_verify(const esp_partition_pos_t *part, esp_image_metadata_t *data)
|
||||
@ -348,6 +361,45 @@ esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t
|
||||
return image_load(mode, part, data);
|
||||
}
|
||||
|
||||
esp_err_t esp_image_get_metadata(const esp_partition_pos_t *part, esp_image_metadata_t *metadata)
|
||||
{
|
||||
if (metadata == NULL || part == NULL || part->size > SIXTEEN_MB) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
memset(metadata, 0, sizeof(esp_image_metadata_t));
|
||||
metadata->start_addr = part->offset;
|
||||
|
||||
esp_err_t err = bootloader_flash_read(metadata->start_addr, &metadata->image, sizeof(esp_image_header_t), true);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
uint32_t next_addr = metadata->start_addr + sizeof(esp_image_header_t);
|
||||
for (int i = 0; i < metadata->image.segment_count; i++) {
|
||||
esp_image_segment_header_t *header = &metadata->segments[i];
|
||||
err = process_segment(i, next_addr, header, true, false, NULL, NULL);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
next_addr += sizeof(esp_image_segment_header_t);
|
||||
metadata->segment_data[i] = next_addr;
|
||||
next_addr += header->data_len;
|
||||
}
|
||||
metadata->image_len = next_addr - metadata->start_addr;
|
||||
|
||||
// checksum
|
||||
uint32_t unpadded_length = metadata->image_len;
|
||||
uint32_t length = unpadded_length + 1; // Add a byte for the checksum
|
||||
length = (length + 15) & ~15; // Pad to next full 16 byte block
|
||||
if (metadata->image.hash_appended) {
|
||||
// Account for the hash in the total image length
|
||||
length += HASH_LEN;
|
||||
}
|
||||
metadata->image_len = length;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
@ -808,18 +860,18 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
|
||||
|
||||
// Use hash to verify signature block
|
||||
esp_err_t err = ESP_ERR_IMAGE_INVALID;
|
||||
#if defined(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME) || defined(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
const void *sig_block;
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
|
||||
#else
|
||||
sig_block = bootloader_mmap(end, sizeof(ets_secure_boot_signature_t));
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
#endif
|
||||
|
||||
bootloader_munmap(sig_block);
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME or CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure boot signature verification failed");
|
||||
|
||||
|
@ -1,339 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
#include <esp32s2/rom/secure_boot.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include <esp32c3/rom/secure_boot.h>
|
||||
#endif
|
||||
|
||||
#define DIGEST_LEN 32
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
static const char *TAG = "secure_boot_v1";
|
||||
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN];
|
||||
uint8_t verified_digest[DIGEST_LEN];
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, length);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block and verify the signature
|
||||
sigblock = (const esp_secure_boot_sig_block_t *)bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if (sigblock == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
bootloader_munmap(sigblock);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
#if !(defined(CONFIG_MBEDTLS_ECDSA_C) && defined(CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED))
|
||||
ESP_LOGE(TAG, "Signature verification requires ECDSA & SECP256R1 curve enabled");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#else
|
||||
ptrdiff_t keylen;
|
||||
|
||||
/* Note: in IDF app image verification we don't add any fault injection resistance, boot-time checks only */
|
||||
memset(verified_digest, 0, DIGEST_LEN);
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
int ret;
|
||||
mbedtls_mpi r, s;
|
||||
|
||||
mbedtls_mpi_init(&r);
|
||||
mbedtls_mpi_init(&s);
|
||||
|
||||
/* Extract r and s components from RAW ECDSA signature of 64 bytes */
|
||||
#define ECDSA_INTEGER_LEN 32
|
||||
ret = mbedtls_mpi_read_binary(&r, &sig_block->signature[0], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(1), err:%d", ret);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = mbedtls_mpi_read_binary(&s, &sig_block->signature[ECDSA_INTEGER_LEN], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(2), err:%d", ret);
|
||||
mbedtls_mpi_free(&r);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Initialise ECDSA context */
|
||||
mbedtls_ecdsa_context ecdsa_context;
|
||||
mbedtls_ecdsa_init(&ecdsa_context);
|
||||
|
||||
mbedtls_ecp_group_load(&ecdsa_context.grp, MBEDTLS_ECP_DP_SECP256R1);
|
||||
size_t plen = mbedtls_mpi_size(&ecdsa_context.grp.P);
|
||||
if (keylen != 2 * plen) {
|
||||
ESP_LOGE(TAG, "Incorrect ECDSA key length %d", keylen);
|
||||
ret = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Extract X and Y components from ECDSA public key */
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.X, signature_verification_key_start, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.Y, signature_verification_key_start + plen, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ecdsa_context.Q.Z, 1));
|
||||
|
||||
ret = mbedtls_ecdsa_verify(&ecdsa_context.grp, image_digest, DIGEST_LEN, &ecdsa_context.Q, &r, &s);
|
||||
ESP_LOGD(TAG, "Verification result %d", ret);
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
mbedtls_ecdsa_free(&ecdsa_context);
|
||||
return ret == 0 ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
#endif // CONFIG_MBEDTLS_ECDSA_C && CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
}
|
||||
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
#define RSA_KEY_SIZE 384 /* RSA 3072 Bits */
|
||||
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
inline static bool digest_matches(const void *trusted, const void *computed)
|
||||
{
|
||||
if (trusted == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 'trusted' is probably a pointer to read-only efuse registers,
|
||||
// which only support word reads. memcmp() cannot be guaranteed
|
||||
// to do word reads, so we make a local copy here (we know that
|
||||
// memcpy() will do word operations if it can).
|
||||
uint8_t __attribute__((aligned(4))) trusted_local[ETS_DIGEST_LEN];
|
||||
uint8_t __attribute__((aligned(4))) computed_local[ETS_DIGEST_LEN];
|
||||
|
||||
memcpy(trusted_local, trusted, ETS_DIGEST_LEN);
|
||||
memcpy(computed_local, computed, ETS_DIGEST_LEN);
|
||||
return memcmp(trusted_local, computed_local, ETS_DIGEST_LEN) == 0;
|
||||
}
|
||||
#endif /* SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1 */
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[DIGEST_LEN] = {0};
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
|
||||
if (sig_block == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", src_addr + padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
bootloader_munmap(sig_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED /* Verify key against efuse block */
|
||||
uint8_t sig_block_key_digest[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN] = {0};
|
||||
|
||||
/* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
|
||||
during boot-time verification. */
|
||||
memset(verified_digest, 0, DIGEST_LEN);
|
||||
|
||||
/* Generating the SHA of the public key components in the signature block */
|
||||
for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
bootloader_sha256_handle_t sig_block_sha;
|
||||
sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[i].key, sizeof(sig_block->block[i].key));
|
||||
bootloader_sha256_finish(sig_block_sha, (unsigned char *)sig_block_key_digest[i]);
|
||||
}
|
||||
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
uint8_t efuse_trusted_digest[DIGEST_LEN] = {0};
|
||||
memcpy(efuse_trusted_digest, (uint8_t *) EFUSE_BLK2_RDATA0_REG, sizeof(efuse_trusted_digest));
|
||||
|
||||
if (memcmp(efuse_trusted_digest, sig_block_key_digest[0], DIGEST_LEN) != 0) {
|
||||
const uint8_t zeroes[DIGEST_LEN] = {0};
|
||||
/* Can't continue if secure boot is enabled, OR if a different digest is already written in efuse BLK2
|
||||
|
||||
(If BLK2 is empty and Secure Boot is disabled then we assume that it will be enabled later.)
|
||||
*/
|
||||
if (esp_secure_boot_enabled() || memcmp(efuse_trusted_digest, zeroes, DIGEST_LEN) != 0) {
|
||||
ESP_LOGE(TAG, "Public key digest in eFuse BLK2 and the signature block don't match.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
#elif SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
bool match = false;
|
||||
ets_secure_boot_key_digests_t efuse_trusted_digest;
|
||||
ETS_STATUS r;
|
||||
r = ets_secure_boot_read_key_digests(&efuse_trusted_digest);
|
||||
if (r != 0) {
|
||||
ESP_LOGI(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif /* SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS */
|
||||
#endif /* CONFIG_SECURE_BOOT_V2_ENABLED */
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
int ret = 0;
|
||||
mbedtls_rsa_context pk;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
unsigned char *sig_be = calloc(1, RSA_KEY_SIZE);
|
||||
unsigned char *buf = calloc(1, RSA_KEY_SIZE);
|
||||
if (sig_be == NULL || buf == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
for (uint8_t j = 0; j < SECURE_BOOT_NUM_BLOCKS; j++) {
|
||||
if (digest_matches(efuse_trusted_digest.key_digests[j], sig_block_key_digest[i])) {
|
||||
ESP_LOGI(TAG, "eFuse key matches(%d) matches the application key(%d).", j, i);
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match == false) {
|
||||
continue; // Skip the public keys whose digests don't match.
|
||||
}
|
||||
# endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
|
||||
const mbedtls_mpi N = { .s = 1,
|
||||
.n = sizeof(sig_block->block[i].key.n)/sizeof(mbedtls_mpi_uint),
|
||||
.p = (void *)sig_block->block[i].key.n,
|
||||
};
|
||||
const mbedtls_mpi e = { .s = 1,
|
||||
.n = sizeof(sig_block->block[i].key.e)/sizeof(mbedtls_mpi_uint), // 1
|
||||
.p = (void *)&sig_block->block[i].key.e,
|
||||
};
|
||||
mbedtls_rsa_init(&pk, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
|
||||
ret = mbedtls_rsa_import(&pk, &N, NULL, NULL, NULL, &e);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_import, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_complete(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_check_pubkey(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Signature needs to be byte swapped into BE representation */
|
||||
for (int j = 0; j < RSA_KEY_SIZE; j++) {
|
||||
sig_be[RSA_KEY_SIZE- j - 1] = sig_block->block[i].signature[j];
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_public( &pk, sig_be, buf);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_rsa_public failed, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_rsassa_pss_verify( &pk, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, DIGEST_LEN,
|
||||
image_digest, sig_be);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_rsassa_pss_verify, err: %d", ret);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
}
|
||||
exit:
|
||||
mbedtls_rsa_free(&pk);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(sig_be);
|
||||
free(buf);
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
return (ret != 0) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
|
||||
#elif SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
return (ret != 0 || match == false) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32 */
|
||||
}
|
||||
#endif
|
57
components/bootloader_support/src/secure_boot.c
Normal file
57
components/bootloader_support/src/secure_boot.c
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <strings.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
static __attribute__((unused)) const char *TAG = "secure_boot";
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
static void rsa_check_signature_on_update_check(void)
|
||||
{
|
||||
// We rely on the keys used to sign this app to verify the next app on OTA, so make sure there is at
|
||||
// least one to avoid a stuck firmware
|
||||
esp_image_sig_public_key_digests_t digests = { 0 };
|
||||
|
||||
esp_err_t err = esp_secure_boot_get_signature_blocks_for_running_app(false, &digests);
|
||||
|
||||
if (err != ESP_OK || digests.num_digests == 0) {
|
||||
ESP_LOGE(TAG, "This app is not signed, but check signature on update is enabled in config. It won't be possible to verify any update.");
|
||||
abort();
|
||||
}
|
||||
#if CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT && SECURE_BOOT_NUM_BLOCKS > 1
|
||||
if (digests.num_digests > 1) {
|
||||
ESP_LOGW(TAG, "App has %d signatures. Only the first position of signature blocks is used to verify any update", digests.num_digests);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
void esp_secure_boot_init_checks(void)
|
||||
{
|
||||
|
||||
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
rsa_check_signature_on_update_check();
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
}
|
||||
#endif // not BOOTLOADER_BUILD
|
@ -0,0 +1,136 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
static const char *TAG = "secure_boot_v1";
|
||||
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, length);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block and verify the signature
|
||||
sigblock = (const esp_secure_boot_sig_block_t *)bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if (sigblock == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
bootloader_munmap(sigblock);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
#if !(defined(CONFIG_MBEDTLS_ECDSA_C) && defined(CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED))
|
||||
ESP_LOGE(TAG, "Signature verification requires ECDSA & SECP256R1 curve enabled");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#else
|
||||
ptrdiff_t keylen;
|
||||
|
||||
/* Note: in IDF app image verification we don't add any fault injection resistance, boot-time checks only */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
int ret;
|
||||
mbedtls_mpi r, s;
|
||||
|
||||
mbedtls_mpi_init(&r);
|
||||
mbedtls_mpi_init(&s);
|
||||
|
||||
/* Extract r and s components from RAW ECDSA signature of 64 bytes */
|
||||
#define ECDSA_INTEGER_LEN 32
|
||||
ret = mbedtls_mpi_read_binary(&r, &sig_block->signature[0], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(1), err:%d", ret);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = mbedtls_mpi_read_binary(&s, &sig_block->signature[ECDSA_INTEGER_LEN], ECDSA_INTEGER_LEN);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(2), err:%d", ret);
|
||||
mbedtls_mpi_free(&r);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Initialise ECDSA context */
|
||||
mbedtls_ecdsa_context ecdsa_context;
|
||||
mbedtls_ecdsa_init(&ecdsa_context);
|
||||
|
||||
mbedtls_ecp_group_load(&ecdsa_context.grp, MBEDTLS_ECP_DP_SECP256R1);
|
||||
size_t plen = mbedtls_mpi_size(&ecdsa_context.grp.P);
|
||||
if (keylen != 2 * plen) {
|
||||
ESP_LOGE(TAG, "Incorrect ECDSA key length %d", keylen);
|
||||
ret = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Extract X and Y components from ECDSA public key */
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.X, signature_verification_key_start, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.Q.Y, signature_verification_key_start + plen, plen));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ecdsa_context.Q.Z, 1));
|
||||
|
||||
ret = mbedtls_ecdsa_verify(&ecdsa_context.grp, image_digest, ESP_SECURE_BOOT_DIGEST_LEN, &ecdsa_context.Q, &r, &s);
|
||||
ESP_LOGD(TAG, "Verification result %d", ret);
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
mbedtls_ecdsa_free(&ecdsa_context);
|
||||
return ret == 0 ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
#endif // CONFIG_MBEDTLS_ECDSA_C && CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
@ -0,0 +1,100 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_fault.h"
|
||||
#include "esp32/rom/sha.h"
|
||||
#include "uECC_verify_antifault.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "secure_boot";
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
|
||||
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
|
||||
|
||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 }; /* ignored in this function */
|
||||
const esp_secure_boot_sig_block_t *sigblock;
|
||||
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Map the signature block
|
||||
sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
if(!sigblock) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// Verify the signature
|
||||
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
|
||||
// Unmap
|
||||
bootloader_munmap(sigblock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
|
||||
{
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 };
|
||||
return esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
ptrdiff_t keylen;
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
if (keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (sig_block->version != 0) {
|
||||
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying secure boot signature");
|
||||
|
||||
bool is_valid;
|
||||
is_valid = uECC_verify_antifault(signature_verification_key_start,
|
||||
image_digest,
|
||||
ESP_SECURE_BOOT_DIGEST_LEN,
|
||||
sig_block->signature,
|
||||
uECC_secp256r1(),
|
||||
verified_digest);
|
||||
ESP_LOGD(TAG, "Verification result %d", is_valid);
|
||||
|
||||
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
@ -0,0 +1,294 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
// Secure boot V2 for app
|
||||
|
||||
_Static_assert(SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == SECURE_BOOT_NUM_BLOCKS,
|
||||
"Parts of this code rely on the max number of signatures appended to an image"
|
||||
"being the same as the max number of trusted keys.");
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block)
|
||||
{
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
|
||||
|| block->block_crc != esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_get_signature_blocks_for_running_app(bool digest_public_keys, esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
esp_image_metadata_t metadata;
|
||||
const esp_partition_t* running_app_part = esp_ota_get_running_partition();
|
||||
if (running_app_part == NULL) {
|
||||
ESP_LOGE(TAG, "Cannot get running partition");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
const esp_partition_pos_t part_pos = {
|
||||
.offset = running_app_part->address,
|
||||
.size = running_app_part->size,
|
||||
};
|
||||
esp_err_t err = esp_image_get_metadata(&part_pos, &metadata);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error reading metadata from running app (err=0x%x)", err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
memset(public_key_digests, 0, sizeof(esp_image_sig_public_key_digests_t));
|
||||
|
||||
// Generating the SHA of the public key components in the signature block
|
||||
|
||||
// metadata.image_len doesn't include any padding to start of the signature sector, so pad it here
|
||||
size_t sig_block_addr = metadata.start_addr + ALIGN_UP(metadata.image_len, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "reading signatures for app address 0x%x sig block address 0x%x", part_pos.offset, sig_block_addr);
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
ets_secure_boot_sig_block_t block;
|
||||
size_t addr = sig_block_addr + sizeof(ets_secure_boot_sig_block_t) * i;
|
||||
esp_err_t err = bootloader_flash_read(addr, &block, sizeof(ets_secure_boot_sig_block_t), true);
|
||||
if (err == ESP_OK) {
|
||||
if (validate_signature_block(&block) == ESP_OK) {
|
||||
if (digest_public_keys) {
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &block.key, sizeof(block.key));
|
||||
bootloader_sha256_finish(sig_block_sha, public_key_digests->key_digests[i]);
|
||||
}
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Secure boot sign blocks cannot be read from a running app (err=0x%x)", err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
if (public_key_digests->num_digests > 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
ESP_LOGE(TAG, "No signatures were found for the running app");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
// Gets key digests from running app
|
||||
ESP_LOGI(TAG, "Take trusted digest key(s) from running app");
|
||||
return esp_secure_boot_get_signature_blocks_for_running_app(true, public_key_digests);
|
||||
#elif CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
ESP_LOGI(TAG, "Take trusted digest key(s) from eFuse block(s)");
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
// Read key digests from efuse
|
||||
ets_secure_boot_key_digests_t efuse_trusted;
|
||||
if (ets_secure_boot_read_key_digests(&efuse_trusted) == ETS_OK) {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (efuse_trusted.key_digests[i] != NULL) {
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)efuse_trusted.key_digests[i], ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (public_key_digests->num_digests > 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
#else
|
||||
memcpy(public_key_digests->key_digests[0], (uint8_t *)EFUSE_BLK2_RDATA0_REG, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests = 1;
|
||||
return ESP_OK;
|
||||
#endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
|
||||
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
}
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
|
||||
if (sig_block == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", src_addr + padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
bootloader_munmap(sig_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
// This verify function is called only from app, during ota update.
|
||||
// This function is compiled in case when CONFIG_SECURE_BOOT_V2_ENABLED==y or CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT==y.
|
||||
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then FAIL (eFuse blocks should be set).
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
bool any_trusted_key = false;
|
||||
|
||||
/* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
|
||||
during boot-time verification. */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
|
||||
if (get_secure_boot_key_digests(&trusted) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not read secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
int ret = 0;
|
||||
mbedtls_rsa_context pk;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
const unsigned rsa_key_size = sizeof(sig_block->block[0].signature);
|
||||
unsigned char *sig_be = calloc(1, rsa_key_size);
|
||||
unsigned char *buf = calloc(1, rsa_key_size);
|
||||
if (sig_be == NULL || buf == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
const unsigned secure_boot_num_blocks = 1;
|
||||
#else
|
||||
const unsigned secure_boot_num_blocks = SECURE_BOOT_NUM_BLOCKS;
|
||||
#endif
|
||||
|
||||
for (unsigned app_blk_idx = 0; app_blk_idx < secure_boot_num_blocks; app_blk_idx++) {
|
||||
uint8_t app_blk_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 };
|
||||
const ets_secure_boot_sig_block_t *app_blk = &sig_block->block[app_blk_idx];
|
||||
const ets_secure_boot_sig_block_t *trusted_block = NULL;
|
||||
|
||||
if (validate_signature_block(app_blk) != ESP_OK) {
|
||||
continue; // Skip invalid signature blocks
|
||||
}
|
||||
|
||||
/* Generate the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &app_blk->key, sizeof(app_blk->key));
|
||||
bootloader_sha256_finish(sig_block_sha, app_blk_digest);
|
||||
|
||||
/* Check if the key is one we trust */
|
||||
for (unsigned trusted_key_idx = 0; trusted_key_idx < secure_boot_num_blocks; trusted_key_idx++) {
|
||||
if (memcmp(app_blk_digest, trusted.key_digests[trusted_key_idx], ESP_SECURE_BOOT_DIGEST_LEN) == 0) {
|
||||
ESP_LOGI(TAG, "#%d app key digest == #%d trusted key digest", app_blk_idx, trusted_key_idx);
|
||||
trusted_block = app_blk;
|
||||
any_trusted_key = true;
|
||||
break;
|
||||
}
|
||||
ESP_LOGV(TAG, "not trusting app sig %d trust idx %d", app_blk_idx, trusted_key_idx);
|
||||
}
|
||||
|
||||
if (trusted_block == NULL) {
|
||||
continue; // Skip the signature blocks with no trusted digest
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
|
||||
const mbedtls_mpi N = { .s = 1,
|
||||
.n = sizeof(trusted_block->key.n)/sizeof(mbedtls_mpi_uint),
|
||||
.p = (void *)trusted_block->key.n,
|
||||
};
|
||||
const mbedtls_mpi e = { .s = 1,
|
||||
.n = sizeof(trusted_block->key.e)/sizeof(mbedtls_mpi_uint), // 1
|
||||
.p = (void *)&trusted_block->key.e,
|
||||
};
|
||||
mbedtls_rsa_init(&pk, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
|
||||
ret = mbedtls_rsa_import(&pk, &N, NULL, NULL, NULL, &e);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_import, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_complete(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_check_pubkey(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Signature needs to be byte swapped into BE representation */
|
||||
for (int j = 0; j < rsa_key_size; j++) {
|
||||
sig_be[rsa_key_size - j - 1] = trusted_block->signature[j];
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_public( &pk, sig_be, buf);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_rsa_public failed, err: %d", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_rsassa_pss_verify( &pk, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, ESP_SECURE_BOOT_DIGEST_LEN,
|
||||
image_digest, sig_be);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_rsassa_pss_verify, err: %d", ret);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
}
|
||||
exit:
|
||||
mbedtls_rsa_free(&pk);
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(sig_be);
|
||||
free(buf);
|
||||
return (ret != 0 || any_trusted_key == false) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
@ -0,0 +1,172 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_fault.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
|
||||
// Secure boot V2 for bootloader.
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
static const char* TAG = "secure_boot_v2";
|
||||
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||
|
||||
/* Calculate digest of main image */
|
||||
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
|
||||
return err;
|
||||
}
|
||||
|
||||
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
|
||||
if (sig_block == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", src_addr + padded_length);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
bootloader_munmap(sig_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* A signature block is valid when it has correct magic byte, crc. */
|
||||
static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *block)
|
||||
{
|
||||
if (block->magic_byte != ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC
|
||||
|| block->block_crc != esp_rom_crc32_le(0, (uint8_t *)block, CRC_SIGN_BLOCK_LEN)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t *public_key_digests)
|
||||
{
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS > 1
|
||||
// Read key digests from efuse
|
||||
ets_secure_boot_key_digests_t trusted_keys;
|
||||
ets_secure_boot_key_digests_t trusted_key_copies[2];
|
||||
ETS_STATUS ets_ret;
|
||||
|
||||
memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
|
||||
memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
|
||||
|
||||
|
||||
ets_ret = ets_secure_boot_read_key_digests(&trusted_keys);
|
||||
|
||||
// Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
|
||||
ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
|
||||
|
||||
if (ets_ret == ETS_OK) {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (trusted_keys.key_digests[i] != NULL) {
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)trusted_keys.key_digests[i], ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
}
|
||||
if (public_key_digests->num_digests > 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
#else
|
||||
bool all_zeroes = true;
|
||||
uint32_t *reg = (uint32_t*)&public_key_digests->key_digests[0];
|
||||
for (int i = 0; i < ESP_SECURE_BOOT_DIGEST_LEN / 4; i++) {
|
||||
*(reg + i) = REG_READ(EFUSE_BLK2_RDATA0_REG + i * 4);
|
||||
all_zeroes = all_zeroes && (*(reg + i) == 0);
|
||||
}
|
||||
if (all_zeroes) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
public_key_digests->num_digests = 1;
|
||||
return ESP_OK;
|
||||
#endif // SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS
|
||||
}
|
||||
|
||||
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then it is the first boot,
|
||||
// trusted.key_digests are filled from app sig_block.
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
bool efuse_keys_are_not_set = false;
|
||||
if (get_secure_boot_key_digests(&trusted) != ESP_OK) {
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGE(TAG, "Could not read eFuse secure boot digests!");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Secure boot V2 is not enabled yet and eFuse digest keys are not set");
|
||||
efuse_keys_are_not_set = true;
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled());
|
||||
}
|
||||
}
|
||||
|
||||
if (!esp_secure_boot_enabled()) {
|
||||
// It is the first boot. eFuse secure boot bit is not set yet. eFuse block(s) can be written or not.
|
||||
// Generating the SHA of the public key components in the signature block
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (validate_signature_block(&sig_block->block[i]) == ESP_OK) {
|
||||
if (efuse_keys_are_not_set) {
|
||||
// if efuse key digests are not in eFuse yet due to it is the first boot
|
||||
// then use digests from app to skip error in ets_secure_boot_verify_signature().
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[i].key, sizeof(sig_block->block[i].key));
|
||||
bootloader_sha256_finish(sig_block_sha, trusted.key_digests[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled());
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
int sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, trusted.key_digests[0], verified_digest);
|
||||
#else
|
||||
ets_secure_boot_key_digests_t trusted_key_digests;
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
trusted_key_digests.key_digests[i] = &trusted.key_digests[i];
|
||||
}
|
||||
int sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_key_digests, verified_digest);
|
||||
#endif
|
||||
if (sb_result != SB_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_BOOT_V2_ENABLED
|
@ -176,6 +176,14 @@ struct osi_funcs_t {
|
||||
int (* _coex_register_bt_cb)(coex_func_cb_t cb);
|
||||
uint32_t (* _coex_bb_reset_lock)(void);
|
||||
void (* _coex_bb_reset_unlock)(uint32_t restore);
|
||||
int (* _coex_schm_register_btdm_callback)(void *callback);
|
||||
void (* _coex_schm_status_bit_clear)(uint32_t type, uint32_t status);
|
||||
void (* _coex_schm_status_bit_set)(uint32_t type, uint32_t status);
|
||||
uint32_t (* _coex_schm_interval_get)(void);
|
||||
uint8_t (* _coex_schm_curr_period_get)(void);
|
||||
void *(* _coex_schm_curr_phase_get)(void);
|
||||
int (* _coex_wifi_channel_get)(uint8_t *primary, uint8_t *secondary);
|
||||
int (* _coex_register_wifi_channel_change_callback)(void *cb);
|
||||
uint32_t _magic;
|
||||
};
|
||||
|
||||
@ -224,6 +232,14 @@ extern int coex_bt_release(uint32_t event);
|
||||
extern int coex_register_bt_cb(coex_func_cb_t cb);
|
||||
extern uint32_t coex_bb_reset_lock(void);
|
||||
extern void coex_bb_reset_unlock(uint32_t restore);
|
||||
extern int coex_schm_register_btdm_callback(void *callback);
|
||||
extern void coex_schm_status_bit_clear(uint32_t type, uint32_t status);
|
||||
extern void coex_schm_status_bit_set(uint32_t type, uint32_t status);
|
||||
extern uint32_t coex_schm_interval_get(void);
|
||||
extern uint8_t coex_schm_curr_period_get(void);
|
||||
extern void * coex_schm_curr_phase_get(void);
|
||||
extern int coex_wifi_channel_get(uint8_t *primary, uint8_t *secondary);
|
||||
extern int coex_register_wifi_channel_change_callback(void *cb);
|
||||
extern void coex_ble_adv_priority_high_set(bool high);
|
||||
|
||||
extern char _bss_start_btdm;
|
||||
@ -294,7 +310,14 @@ static int coex_bt_release_wrapper(uint32_t event);
|
||||
static int coex_register_bt_cb_wrapper(coex_func_cb_t cb);
|
||||
static uint32_t coex_bb_reset_lock_wrapper(void);
|
||||
static void coex_bb_reset_unlock_wrapper(uint32_t restore);
|
||||
|
||||
static int coex_schm_register_btdm_callback_wrapper(void *callback);
|
||||
static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status);
|
||||
static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status);
|
||||
static uint32_t coex_schm_interval_get_wrapper(void);
|
||||
static uint8_t coex_schm_curr_period_get_wrapper(void);
|
||||
static void * coex_schm_curr_phase_get_wrapper(void);
|
||||
static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary);
|
||||
static int coex_register_wifi_channel_change_callback_wrapper(void *cb);
|
||||
/* Local variable definition
|
||||
***************************************************************************
|
||||
*/
|
||||
@ -348,6 +371,14 @@ static const struct osi_funcs_t osi_funcs_ro = {
|
||||
._coex_register_bt_cb = coex_register_bt_cb_wrapper,
|
||||
._coex_bb_reset_lock = coex_bb_reset_lock_wrapper,
|
||||
._coex_bb_reset_unlock = coex_bb_reset_unlock_wrapper,
|
||||
._coex_schm_register_btdm_callback = coex_schm_register_btdm_callback_wrapper,
|
||||
._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper,
|
||||
._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper,
|
||||
._coex_schm_interval_get = coex_schm_interval_get_wrapper,
|
||||
._coex_schm_curr_period_get = coex_schm_curr_period_get_wrapper,
|
||||
._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper,
|
||||
._coex_wifi_channel_get = coex_wifi_channel_get_wrapper,
|
||||
._coex_register_wifi_channel_change_callback = coex_register_wifi_channel_change_callback_wrapper,
|
||||
._magic = OSI_MAGIC_VALUE,
|
||||
};
|
||||
|
||||
@ -1001,7 +1032,7 @@ static void coex_bt_wakeup_request_end(void)
|
||||
return;
|
||||
}
|
||||
|
||||
int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
|
||||
static int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_bt_request(event, latency, duration);
|
||||
@ -1010,7 +1041,7 @@ int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t
|
||||
#endif
|
||||
}
|
||||
|
||||
int IRAM_ATTR coex_bt_release_wrapper(uint32_t event)
|
||||
static int IRAM_ATTR coex_bt_release_wrapper(uint32_t event)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_bt_release(event);
|
||||
@ -1019,7 +1050,7 @@ int IRAM_ATTR coex_bt_release_wrapper(uint32_t event)
|
||||
#endif
|
||||
}
|
||||
|
||||
int coex_register_bt_cb_wrapper(coex_func_cb_t cb)
|
||||
static int coex_register_bt_cb_wrapper(coex_func_cb_t cb)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_register_bt_cb(cb);
|
||||
@ -1028,7 +1059,7 @@ int coex_register_bt_cb_wrapper(coex_func_cb_t cb)
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void)
|
||||
static uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_bb_reset_lock();
|
||||
@ -1037,13 +1068,81 @@ uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore)
|
||||
static void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
coex_bb_reset_unlock(restore);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int coex_schm_register_btdm_callback_wrapper(void *callback)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_schm_register_btdm_callback(callback);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
coex_schm_status_bit_clear(type, status);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
coex_schm_status_bit_set(type, status);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t coex_schm_interval_get_wrapper(void)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_schm_interval_get();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t coex_schm_curr_period_get_wrapper(void)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_schm_curr_period_get();
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void * coex_schm_curr_phase_get_wrapper(void)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_schm_curr_phase_get();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_wifi_channel_get(primary, secondary);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int coex_register_wifi_channel_change_callback_wrapper(void *cb)
|
||||
{
|
||||
#if CONFIG_SW_COEXIST_ENABLE
|
||||
return coex_register_wifi_channel_change_callback(cb);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool esp_vhci_host_check_send_available(void)
|
||||
{
|
||||
return API_vhci_host_check_send_available();
|
||||
@ -1442,16 +1541,12 @@ esp_err_t esp_bt_controller_deinit(void)
|
||||
static void bt_shutdown(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_LOGD(BTDM_LOG_TAG, "stop/deinit bt");
|
||||
ESP_LOGD(BTDM_LOG_TAG, "stop Bluetooth");
|
||||
|
||||
ret = esp_bt_controller_disable();
|
||||
if (ESP_OK != ret) {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "controller disable ret=%d", ret);
|
||||
}
|
||||
ret = esp_bt_controller_deinit();
|
||||
if (ESP_OK != ret) {
|
||||
ESP_LOGW(BTDM_LOG_TAG, "controller deinit ret=%d", ret);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,8 @@ config BT_CTRL_BLE_MAX_ACT
|
||||
default 10
|
||||
range 1 10
|
||||
help
|
||||
BLE maximum instances of bluetooth controller.
|
||||
BLE maximum activities of bluetooth controller,both of connections,
|
||||
scan , sync and adv(periodic adv, multi-adv).
|
||||
|
||||
config BT_CTRL_BLE_MAX_ACT_EFF
|
||||
int
|
||||
@ -126,10 +127,20 @@ config BT_CTRL_RX_ANTENNA_INDEX_EFF
|
||||
|
||||
choice BT_CTRL_DFT_TX_POWER_LEVEL
|
||||
prompt "BLE default Tx power level"
|
||||
default BT_CTRL_DFT_TX_POWER_LEVEL_P9
|
||||
default BT_CTRL_DFT_TX_POWER_LEVEL_P3
|
||||
help
|
||||
Specify default Tx power level
|
||||
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N27
|
||||
bool "-27dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N24
|
||||
bool "-24dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N21
|
||||
bool "-21dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N18
|
||||
bool "-18dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N15
|
||||
bool "-15dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N12
|
||||
bool "-12dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_N9
|
||||
@ -146,18 +157,32 @@ choice BT_CTRL_DFT_TX_POWER_LEVEL
|
||||
bool "+6dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_P9
|
||||
bool "+9dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_P12
|
||||
bool "+12dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_P15
|
||||
bool "+15dBm"
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_P18
|
||||
bool "+18dBm"
|
||||
endchoice
|
||||
|
||||
config BT_CTRL_DFT_TX_POWER_LEVEL_EFF
|
||||
int
|
||||
default 0 if BT_CTRL_DFT_TX_POWER_LEVEL_N12
|
||||
default 1 if BT_CTRL_DFT_TX_POWER_LEVEL_N9
|
||||
default 2 if BT_CTRL_DFT_TX_POWER_LEVEL_N6
|
||||
default 3 if BT_CTRL_DFT_TX_POWER_LEVEL_N3
|
||||
default 4 if BT_CTRL_DFT_TX_POWER_LEVEL_N0
|
||||
default 5 if BT_CTRL_DFT_TX_POWER_LEVEL_P3
|
||||
default 6 if BT_CTRL_DFT_TX_POWER_LEVEL_P6
|
||||
default 7 if BT_CTRL_DFT_TX_POWER_LEVEL_P9
|
||||
default 0 if BT_CTRL_DFT_TX_POWER_LEVEL_N27
|
||||
default 1 if BT_CTRL_DFT_TX_POWER_LEVEL_N24
|
||||
default 2 if BT_CTRL_DFT_TX_POWER_LEVEL_N21
|
||||
default 3 if BT_CTRL_DFT_TX_POWER_LEVEL_N18
|
||||
default 4 if BT_CTRL_DFT_TX_POWER_LEVEL_N15
|
||||
default 5 if BT_CTRL_DFT_TX_POWER_LEVEL_N12
|
||||
default 6 if BT_CTRL_DFT_TX_POWER_LEVEL_N9
|
||||
default 7 if BT_CTRL_DFT_TX_POWER_LEVEL_N6
|
||||
default 8 if BT_CTRL_DFT_TX_POWER_LEVEL_N3
|
||||
default 9 if BT_CTRL_DFT_TX_POWER_LEVEL_N0
|
||||
default 10 if BT_CTRL_DFT_TX_POWER_LEVEL_P3
|
||||
default 11 if BT_CTRL_DFT_TX_POWER_LEVEL_P6
|
||||
default 12 if BT_CTRL_DFT_TX_POWER_LEVEL_P9
|
||||
default 13 if BT_CTRL_DFT_TX_POWER_LEVEL_P12
|
||||
default 14 if BT_CTRL_DFT_TX_POWER_LEVEL_P15
|
||||
default 15 if BT_CTRL_DFT_TX_POWER_LEVEL_P18
|
||||
default 0
|
||||
|
||||
config BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP
|
||||
|
@ -212,6 +212,7 @@ extern void btdm_controller_disable(void);
|
||||
extern uint8_t btdm_controller_get_mode(void);
|
||||
extern const char *btdm_controller_get_compile_version(void);
|
||||
extern void btdm_rf_bb_init_phase2(void); // shall be called after PHY/RF is enabled
|
||||
|
||||
/* Sleep */
|
||||
extern void btdm_controller_enable_sleep(bool enable);
|
||||
extern uint8_t btdm_controller_get_sleep_mode(void);
|
||||
@ -740,13 +741,16 @@ static void IRAM_ATTR btdm_sleep_exit_phase0(void *param)
|
||||
}
|
||||
#endif
|
||||
|
||||
btdm_wakeup_request();
|
||||
int event = (int) param;
|
||||
if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) {
|
||||
btdm_wakeup_request();
|
||||
}
|
||||
|
||||
if (s_lp_cntl.wakeup_timer_required && s_lp_stat.wakeup_timer_started) {
|
||||
esp_timer_stop(s_btdm_slp_tmr);
|
||||
s_lp_stat.wakeup_timer_started = 0;
|
||||
}
|
||||
int event = (int) param;
|
||||
|
||||
if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) {
|
||||
semphr_give_wrapper(s_wakeup_req_sem);
|
||||
}
|
||||
@ -1331,14 +1335,51 @@ esp_bt_controller_status_t esp_bt_controller_get_status(void)
|
||||
/* extra functions */
|
||||
esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level)
|
||||
{
|
||||
ESP_LOGW(BTDM_LOG_TAG, "%s not implemented, return OK", __func__);
|
||||
return ESP_OK;
|
||||
esp_err_t stat = ESP_FAIL;
|
||||
|
||||
switch (power_type) {
|
||||
case ESP_BLE_PWR_TYPE_ADV:
|
||||
case ESP_BLE_PWR_TYPE_SCAN:
|
||||
case ESP_BLE_PWR_TYPE_DEFAULT:
|
||||
if (ble_txpwr_set(power_type, power_level) == 0) {
|
||||
stat = ESP_OK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
stat = ESP_ERR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type)
|
||||
{
|
||||
ESP_LOGW(BTDM_LOG_TAG, "%s not implemented, return 0", __func__);
|
||||
return 0;
|
||||
esp_power_level_t lvl;
|
||||
|
||||
switch (power_type) {
|
||||
case ESP_BLE_PWR_TYPE_ADV:
|
||||
case ESP_BLE_PWR_TYPE_SCAN:
|
||||
lvl = (esp_power_level_t)ble_txpwr_get(power_type);
|
||||
break;
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL0:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL1:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL2:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL3:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL4:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL5:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL6:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL7:
|
||||
case ESP_BLE_PWR_TYPE_CONN_HDL8:
|
||||
case ESP_BLE_PWR_TYPE_DEFAULT:
|
||||
lvl = (esp_power_level_t)ble_txpwr_get(ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
break;
|
||||
default:
|
||||
lvl = ESP_PWR_LVL_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
return lvl;
|
||||
}
|
||||
|
||||
esp_err_t esp_bt_sleep_enable (void)
|
||||
|
Submodule components/bt/controller/lib updated: d1115cabc2...2b7816260e
@ -1004,10 +1004,20 @@ config BT_BLE_ESTAB_LINK_CONN_TOUT
|
||||
|
||||
config BT_BLE_RPA_SUPPORTED
|
||||
bool "Update RPA to Controller"
|
||||
depends on (BT_BLUEDROID_ENABLED && (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3))
|
||||
default y
|
||||
depends on BT_BLUEDROID_ENABLED
|
||||
default y if (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3)
|
||||
default n if IDF_TARGET_ESP32
|
||||
help
|
||||
This enables controller RPA list function.
|
||||
For ESP32, ESP32 only support network privacy mode. If this option is enabled, ESP32 will only accept
|
||||
advertising packets from peer devices that contain private address, HW will not receive the advertising
|
||||
packets contain identity address after IRK changed. If this option is disabled, address resolution will
|
||||
be performed in the host, so the functions that require controller to resolve address in the white list
|
||||
cannot be used. This option is disabled by default on ESP32, please enable or disable this option according
|
||||
to your own needs.
|
||||
|
||||
For ESP32C3 and esp32s3, devices support network privacy mode and device privacy mode, users can switch the
|
||||
two modes according to their own needs. So this option is enabled by default.
|
||||
|
||||
config BT_BLE_50_FEATURES_SUPPORTED
|
||||
bool "Enable BLE 5.0 features"
|
||||
|
@ -133,7 +133,8 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
|
||||
btc_spp_args_t arg;
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
if (strlen(name) > ESP_SPP_SERVER_NAME_MAX) {
|
||||
if (name == NULL || strlen(name) > ESP_SPP_SERVER_NAME_MAX) {
|
||||
LOG_ERROR("Invalid server name!\n");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
@ -157,13 +158,34 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
|
||||
esp_err_t esp_spp_stop_srv(void)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_spp_args_t arg;
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_SPP;
|
||||
msg.act = BTC_SPP_ACT_STOP_SRV;
|
||||
arg.stop_srv.scn = BTC_SPP_INVALID_SCN;
|
||||
|
||||
return (btc_transfer_context(&msg, NULL, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_spp_stop_srv_scn(uint8_t scn)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_spp_args_t arg;
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) {
|
||||
LOG_ERROR("Invalid SCN!\n");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_SPP;
|
||||
msg.act = BTC_SPP_ACT_STOP_SRV;
|
||||
arg.stop_srv.scn = scn;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -301,6 +301,7 @@ typedef void (* esp_blufi_event_cb_t)(esp_blufi_cb_event_t event, esp_blufi_cb_p
|
||||
* @param len : length of data from phone
|
||||
* @param output_data : data want to send to phone
|
||||
* @param output_len : length of data want to send to phone
|
||||
* @param need_free : output reporting if memory needs to be freed or not *
|
||||
*/
|
||||
typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free);
|
||||
|
||||
@ -311,7 +312,7 @@ typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8
|
||||
* @param crypt_len : length of plain text
|
||||
* @return Nonnegative number is encrypted length, if error, return negative number;
|
||||
*/
|
||||
typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int cyprt_len);
|
||||
typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len);
|
||||
|
||||
/**
|
||||
* @brief BLUFI decrypt the data after negotiate a share key
|
||||
|
@ -259,7 +259,7 @@ typedef union {
|
||||
/**
|
||||
* @brief GATT Client callback function type
|
||||
* @param event : Event type
|
||||
* @param gatts_if : GATT client access interface, normally
|
||||
* @param gattc_if : GATT client access interface, normally
|
||||
* different gattc_if correspond to different profile
|
||||
* @param param : Point to callback parameter, currently is union type
|
||||
*/
|
||||
@ -313,7 +313,7 @@ esp_err_t esp_ble_gattc_app_unregister(esp_gatt_if_t gattc_if);
|
||||
* @param[in] gattc_if: Gatt client access interface.
|
||||
* @param[in] remote_bda: remote device bluetooth device address.
|
||||
* @param[in] remote_addr_type: remote device bluetooth device the address type.
|
||||
* @param[in] is_direct: direct connection or background auto connection
|
||||
* @param[in] is_direct: direct connection or background auto connection(by now, background auto connection is not supported).
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
|
@ -188,7 +188,7 @@ typedef void (* esp_hf_incoming_data_cb_t)(const uint8_t *buf, uint32_t len);
|
||||
*
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
*
|
||||
* @param[out] length of data successfully read
|
||||
* @return length of data successfully read
|
||||
*/
|
||||
typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len);
|
||||
|
||||
|
@ -273,7 +273,7 @@ typedef void (* esp_hf_client_incoming_data_cb_t)(const uint8_t *buf, uint32_t l
|
||||
*
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
*
|
||||
* @param[out] length of data successfully read
|
||||
* @return length of data successfully read
|
||||
*
|
||||
*/
|
||||
typedef uint32_t (* esp_hf_client_outgoing_data_cb_t)(uint8_t *buf, uint32_t len);
|
||||
|
@ -26,11 +26,12 @@ typedef enum {
|
||||
ESP_SPP_SUCCESS = 0, /*!< Successful operation. */
|
||||
ESP_SPP_FAILURE, /*!< Generic failure. */
|
||||
ESP_SPP_BUSY, /*!< Temporarily can not handle this request. */
|
||||
ESP_SPP_NO_DATA, /*!< no data. */
|
||||
ESP_SPP_NO_DATA, /*!< No data */
|
||||
ESP_SPP_NO_RESOURCE, /*!< No more resource */
|
||||
ESP_SPP_NEED_INIT, /*!< SPP module shall init first */
|
||||
ESP_SPP_NEED_DEINIT, /*!< SPP module shall deinit first */
|
||||
ESP_SPP_NO_CONNECTION, /*!< connection may have been closed */
|
||||
ESP_SPP_NO_CONNECTION, /*!< Connection may have been closed */
|
||||
ESP_SPP_NO_SERVER, /*!< No SPP server */
|
||||
} esp_spp_status_t;
|
||||
|
||||
/* Security Setting Mask
|
||||
@ -101,9 +102,10 @@ typedef union {
|
||||
* @brief SPP_DISCOVERY_COMP_EVT
|
||||
*/
|
||||
struct spp_discovery_comp_evt_param {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint8_t scn_num; /*!< The num of scn_num */
|
||||
uint8_t scn[ESP_SPP_MAX_SCN]; /*!< channel # */
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint8_t scn_num; /*!< The num of scn_num */
|
||||
uint8_t scn[ESP_SPP_MAX_SCN]; /*!< channel # */
|
||||
const char *service_name[ESP_SPP_MAX_SCN]; /*!< service_name */
|
||||
} disc_comp; /*!< SPP callback param of SPP_DISCOVERY_COMP_EVT */
|
||||
|
||||
/**
|
||||
@ -143,6 +145,7 @@ typedef union {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint32_t handle; /*!< The connection handle */
|
||||
uint8_t sec_id; /*!< security ID used by this server */
|
||||
uint8_t scn; /*!< Server channel number */
|
||||
bool use_co; /*!< TRUE to use co_rfc_data */
|
||||
} start; /*!< SPP callback param of ESP_SPP_START_EVT */
|
||||
|
||||
@ -151,6 +154,7 @@ typedef union {
|
||||
*/
|
||||
struct spp_srv_stop_evt_param {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint8_t scn; /*!< Server channel number */
|
||||
} srv_stop; /*!< SPP callback param of ESP_SPP_SRV_STOP_EVT */
|
||||
|
||||
/**
|
||||
@ -304,7 +308,7 @@ esp_err_t esp_spp_disconnect(uint32_t handle);
|
||||
esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t local_scn, const char *name);
|
||||
|
||||
/**
|
||||
* @brief This function stops a SPP server.
|
||||
* @brief This function stops all SPP servers.
|
||||
* The operation will close all active SPP connection first, then the callback function will be called
|
||||
* with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
|
||||
* When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT.
|
||||
@ -314,8 +318,24 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
|
||||
esp_err_t esp_spp_stop_srv(void);
|
||||
|
||||
/**
|
||||
* @brief This function stops a specific SPP server.
|
||||
* The operation will close all active SPP connection first on the specific SPP server, then the callback function will be called
|
||||
* with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
|
||||
* When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT.
|
||||
* This funciton must be called after esp_spp_init() successful and before esp_spp_deinit().
|
||||
*
|
||||
* @param[in] scn: Server channel number.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_spp_stop_srv_scn(uint8_t scn);
|
||||
|
||||
/**
|
||||
* @brief This function is used to write data, only for ESP_SPP_MODE_CB.
|
||||
* When this function need to be called repeatedly, it is strongly recommended to call this function again after
|
||||
|
@ -1683,8 +1683,7 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id,
|
||||
tBTA_GATTC_DATA *p_buf;
|
||||
|
||||
if (reason != 0) {
|
||||
APPL_TRACE_WARNING("%s() - cif=%d connected=%d conn_id=%d reason=0x%04x",
|
||||
__FUNCTION__, gattc_if, connected, conn_id, reason);
|
||||
APPL_TRACE_WARNING("gattc_conn_cb: if=%d st=%d id=%d rsn=0x%x", gattc_if, connected, conn_id, reason);
|
||||
}
|
||||
|
||||
bt_bdaddr_t bdaddr;
|
||||
@ -1702,7 +1701,7 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id,
|
||||
p_buf->int_conn.conn_params.latency = p_lcb->current_used_conn_latency;
|
||||
p_buf->int_conn.conn_params.timeout = p_lcb->current_used_conn_timeout;
|
||||
} else {
|
||||
APPL_TRACE_WARNING("%s not found connection parameters of the device ", __func__);
|
||||
APPL_TRACE_WARNING("gattc_conn_cb: conn params not found");
|
||||
}
|
||||
}
|
||||
p_buf->int_conn.hdr.layer_specific = conn_id;
|
||||
|
@ -172,9 +172,10 @@ typedef struct {
|
||||
|
||||
/* data associated with BTA_JV_DISCOVERY_COMP_EVT_ */
|
||||
typedef struct {
|
||||
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
|
||||
UINT8 scn_num; /* num of channel */
|
||||
UINT8 scn[BTA_JV_MAX_SCN]; /* channel # */
|
||||
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
|
||||
UINT8 scn_num; /* num of channel */
|
||||
UINT8 scn[BTA_JV_MAX_SCN]; /* channel # */
|
||||
const char *service_name[BTA_JV_MAX_SCN]; /* service_name */
|
||||
} tBTA_JV_DISCOVERY_COMP;
|
||||
|
||||
/* data associated with BTA_JV_CREATE_RECORD_EVT */
|
||||
@ -305,6 +306,7 @@ typedef struct {
|
||||
tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
|
||||
UINT32 handle; /* The connection handle */
|
||||
UINT8 sec_id; /* security ID used by this server */
|
||||
UINT8 scn; /* Server channe number */
|
||||
BOOLEAN use_co; /* TRUE to use co_rfc_data */
|
||||
} tBTA_JV_RFCOMM_START;
|
||||
|
||||
@ -376,8 +378,9 @@ typedef struct {
|
||||
|
||||
/* data associated with BTA_JV_FREE_SCN_EVT */
|
||||
typedef struct {
|
||||
tBTA_JV_STATUS status; /* Status of the operation */
|
||||
tBTA_JV_SERVER_STATUS server_status;
|
||||
tBTA_JV_STATUS status; /* Status of the operation */
|
||||
tBTA_JV_SERVER_STATUS server_status; /* Server status */
|
||||
UINT8 scn; /* Server channe number */
|
||||
} tBTA_JV_FREE_SCN;
|
||||
|
||||
|
||||
|
@ -856,6 +856,7 @@ void bta_jv_free_scn(tBTA_JV_MSG *p_data)
|
||||
tBTA_JV_FREE_SCN evt_data = {
|
||||
.status = BTA_JV_SUCCESS,
|
||||
.server_status = BTA_JV_SERVER_STATUS_MAX,
|
||||
.scn = scn
|
||||
};
|
||||
|
||||
tBTA_JV_FREE_SCN_USER_DATA *user_data = NULL;
|
||||
@ -949,6 +950,7 @@ static void bta_jv_start_discovery_cback(UINT16 result, void *user_data)
|
||||
status = BTA_JV_FAILURE;
|
||||
if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
|
||||
tSDP_DISC_REC *p_sdp_rec = NULL;
|
||||
tSDP_DISC_ATTR *p_attr = NULL;
|
||||
tSDP_PROTOCOL_ELEM pe;
|
||||
logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128);
|
||||
tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid);
|
||||
@ -957,7 +959,13 @@ static void bta_jv_start_discovery_cback(UINT16 result, void *user_data)
|
||||
p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec);
|
||||
APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec);
|
||||
if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)){
|
||||
dcomp.scn[dcomp.scn_num++] = (UINT8) pe.params[0];
|
||||
dcomp.scn[dcomp.scn_num] = (UINT8) pe.params[0];
|
||||
if ((p_attr = SDP_FindAttributeInRec(p_sdp_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
|
||||
dcomp.service_name[dcomp.scn_num] = (char *)p_attr->attr_value.v.array;
|
||||
} else {
|
||||
dcomp.service_name[dcomp.scn_num] = NULL;
|
||||
}
|
||||
dcomp.scn_num++;
|
||||
status = BTA_JV_SUCCESS;
|
||||
}
|
||||
} while (p_sdp_rec);
|
||||
@ -2154,6 +2162,7 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
|
||||
evt_data.status = BTA_JV_SUCCESS;
|
||||
evt_data.handle = p_pcb->handle;
|
||||
evt_data.sec_id = sec_id;
|
||||
evt_data.scn = rs->local_scn;
|
||||
evt_data.use_co = TRUE;
|
||||
|
||||
PORT_ClearKeepHandleFlag(handle);
|
||||
|
@ -917,6 +917,10 @@ void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
|
||||
case BTC_HF_COPS_RESPONSE_EVT:
|
||||
{
|
||||
if (src->cops_rep.name == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst->cops_rep.name = (char *)osi_malloc(strlen(src->cops_rep.name)+1);
|
||||
if(dst->cops_rep.name) {
|
||||
memcpy(dst->cops_rep.name, src->cops_rep.name, strlen(src->cops_rep.name)+1);
|
||||
@ -930,6 +934,10 @@ void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
|
||||
case BTC_HF_CLCC_RESPONSE_EVT:
|
||||
{
|
||||
if (src->clcc_rep.number == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst->clcc_rep.number = (char *)osi_malloc(strlen(src->clcc_rep.number)+1);
|
||||
if(dst->clcc_rep.number) {
|
||||
memcpy(dst->clcc_rep.number, src->clcc_rep.number, strlen(src->clcc_rep.number)+1);
|
||||
@ -943,6 +951,10 @@ void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
|
||||
case BTC_HF_CNUM_RESPONSE_EVT:
|
||||
{
|
||||
if (src->cnum_rep.number == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst->cnum_rep.number = (char *)osi_malloc(strlen(src->cnum_rep.number)+1);
|
||||
if(dst->cnum_rep.number) {
|
||||
memcpy(dst->cnum_rep.number, src->cnum_rep.number, strlen(src->cnum_rep.number)+1);
|
||||
@ -959,6 +971,10 @@ void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
case BTC_HF_OUT_CALL_EVT:
|
||||
case BTC_HF_END_CALL_EVT:
|
||||
{
|
||||
if (src->phone.number == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst->phone.number = (char *)osi_malloc(strlen(src->phone.number)+1);
|
||||
if(dst->phone.number) {
|
||||
memcpy(dst->phone.number, src->phone.number, strlen(src->phone.number)+1);
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#define ESP_SPP_RINGBUF_SIZE 1000
|
||||
|
||||
#define BTC_SPP_INVALID_SCN 0x00
|
||||
|
||||
typedef enum {
|
||||
BTC_SPP_ACT_INIT = 0,
|
||||
BTC_SPP_ACT_UNINIT,
|
||||
@ -74,6 +76,10 @@ typedef union {
|
||||
UINT8 max_session;
|
||||
char name[ESP_SPP_SERVER_NAME_MAX + 1];
|
||||
} start_srv;
|
||||
//BTC_SPP_ACT_STOP_SRV
|
||||
struct stop_srv_arg {
|
||||
UINT8 scn;
|
||||
} stop_srv;
|
||||
//BTC_SPP_ACT_WRITE
|
||||
struct write_arg {
|
||||
UINT32 handle;
|
||||
|
@ -265,6 +265,10 @@ static void btc_create_server_fail_cb(void)
|
||||
{
|
||||
esp_spp_cb_param_t param;
|
||||
param.start.status = ESP_SPP_FAILURE;
|
||||
param.start.handle = 0;
|
||||
param.start.sec_id = 0;
|
||||
param.start.scn = BTC_SPP_INVALID_SCN;
|
||||
param.start.use_co = FALSE;
|
||||
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
|
||||
}
|
||||
|
||||
@ -531,6 +535,7 @@ static void btc_spp_uninit(void)
|
||||
esp_spp_cb_param_t param;
|
||||
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
|
||||
param.srv_stop.status = ESP_SPP_NO_RESOURCE;
|
||||
param.srv_stop.scn = spp_local_param.spp_slots[i]->scn;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
}
|
||||
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
|
||||
@ -672,61 +677,117 @@ static void btc_spp_start_srv(btc_spp_args_t *arg)
|
||||
if (ret != ESP_SPP_SUCCESS) {
|
||||
esp_spp_cb_param_t param;
|
||||
param.start.status = ret;
|
||||
param.start.handle = 0;
|
||||
param.start.sec_id = 0;
|
||||
param.start.scn = BTC_SPP_INVALID_SCN;
|
||||
param.start.use_co = FALSE;
|
||||
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_spp_stop_srv(void)
|
||||
static void btc_spp_stop_srv(btc_spp_args_t *arg)
|
||||
{
|
||||
esp_spp_status_t ret = ESP_SPP_SUCCESS;
|
||||
bool is_remove_all = false;
|
||||
uint8_t i, j, srv_cnt = 0;
|
||||
uint8_t *srv_scn_arr = osi_malloc(MAX_RFC_PORTS);
|
||||
if (arg->stop_srv.scn == BTC_SPP_INVALID_SCN) {
|
||||
is_remove_all = true;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!is_spp_init()) {
|
||||
BTC_TRACE_ERROR("%s SPP have not been init\n", __func__);
|
||||
ret = ESP_SPP_NEED_INIT;
|
||||
break;
|
||||
}
|
||||
if (srv_scn_arr == NULL) {
|
||||
BTC_TRACE_ERROR("%s malloc srv_scn_arr failed\n", __func__);
|
||||
ret = ESP_SPP_NO_RESOURCE;
|
||||
break;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
// first, remove all connection
|
||||
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected) {
|
||||
BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb,
|
||||
(void *)spp_local_param.spp_slots[i]->id);
|
||||
// [1] find all server
|
||||
for (i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected &&
|
||||
spp_local_param.spp_slots[i]->sdp_handle > 0) {
|
||||
if (is_remove_all) {
|
||||
srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn;
|
||||
} else if (spp_local_param.spp_slots[i]->scn == arg->stop_srv.scn) {
|
||||
srv_scn_arr[srv_cnt++] = spp_local_param.spp_slots[i]->scn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// second, remove all server
|
||||
for (size_t i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected) {
|
||||
if (spp_local_param.spp_slots[i]->sdp_handle > 0) {
|
||||
BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
|
||||
}
|
||||
if (srv_cnt == 0) {
|
||||
if (is_remove_all) {
|
||||
BTC_TRACE_ERROR("%s can not find any server!\n", __func__);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s can not find server:%d!\n", __func__, arg->stop_srv.scn);
|
||||
}
|
||||
ret = ESP_SPP_NO_SERVER;
|
||||
break;
|
||||
}
|
||||
|
||||
if (spp_local_param.spp_slots[i]->rfc_handle > 0) {
|
||||
BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle,
|
||||
(void *)spp_local_param.spp_slots[i]->id);
|
||||
// [2] remove all local related connection
|
||||
for (j = 0; j < srv_cnt; j++) {
|
||||
for (i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected &&
|
||||
spp_local_param.spp_slots[i]->sdp_handle > 0 &&
|
||||
spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) {
|
||||
BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle,
|
||||
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb,
|
||||
(void *)spp_local_param.spp_slots[i]->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
|
||||
if (user_data) {
|
||||
user_data->server_status = BTA_JV_SERVER_RUNNING;
|
||||
user_data->slot_id = spp_local_param.spp_slots[i]->id;
|
||||
} else {
|
||||
esp_spp_cb_param_t param;
|
||||
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
|
||||
param.srv_stop.status = ESP_SPP_NO_RESOURCE;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
// [3] remove all server
|
||||
for (j = 0; j < srv_cnt; j++) {
|
||||
for (i = 1; i <= MAX_RFC_PORTS; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && !spp_local_param.spp_slots[i]->connected &&
|
||||
spp_local_param.spp_slots[i]->sdp_handle > 0 &&
|
||||
spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) {
|
||||
if (spp_local_param.spp_slots[i]->sdp_handle > 0) {
|
||||
BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
|
||||
}
|
||||
|
||||
if (spp_local_param.spp_slots[i]->rfc_handle > 0) {
|
||||
BTA_JvRfcommStopServer(spp_local_param.spp_slots[i]->rfc_handle,
|
||||
(void *)spp_local_param.spp_slots[i]->id);
|
||||
}
|
||||
|
||||
tBTA_JV_FREE_SCN_USER_DATA *user_data = osi_malloc(sizeof(tBTA_JV_FREE_SCN_USER_DATA));
|
||||
if (user_data) {
|
||||
user_data->server_status = BTA_JV_SERVER_RUNNING;
|
||||
user_data->slot_id = spp_local_param.spp_slots[i]->id;
|
||||
} else {
|
||||
esp_spp_cb_param_t param;
|
||||
BTC_TRACE_ERROR("%s unable to malloc user data!", __func__);
|
||||
param.srv_stop.status = ESP_SPP_NO_RESOURCE;
|
||||
param.srv_stop.scn = spp_local_param.spp_slots[i]->scn;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
}
|
||||
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
|
||||
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
|
||||
}
|
||||
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM,
|
||||
(tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)user_data);
|
||||
}
|
||||
}
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
} while(0);
|
||||
} while (0);
|
||||
|
||||
if (ret != ESP_SPP_SUCCESS) {
|
||||
esp_spp_cb_param_t param;
|
||||
param.srv_stop.status = ret;
|
||||
param.srv_stop.scn = BTC_SPP_INVALID_SCN;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
}
|
||||
|
||||
if (srv_scn_arr) {
|
||||
osi_free(srv_scn_arr);
|
||||
srv_scn_arr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_spp_write(btc_spp_args_t *arg)
|
||||
@ -849,7 +910,7 @@ void btc_spp_call_handler(btc_msg_t *msg)
|
||||
btc_spp_start_srv(arg);
|
||||
break;
|
||||
case BTC_SPP_ACT_STOP_SRV:
|
||||
btc_spp_stop_srv();
|
||||
btc_spp_stop_srv(arg);
|
||||
break;
|
||||
case BTC_SPP_ACT_WRITE:
|
||||
btc_spp_write(arg);
|
||||
@ -876,6 +937,8 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
param.disc_comp.status = p_data->disc_comp.status;
|
||||
param.disc_comp.scn_num = p_data->disc_comp.scn_num;
|
||||
memcpy(param.disc_comp.scn, p_data->disc_comp.scn, p_data->disc_comp.scn_num);
|
||||
memcpy(param.disc_comp.service_name, p_data->disc_comp.service_name,
|
||||
p_data->disc_comp.scn_num * sizeof(const char *));
|
||||
btc_spp_cb_to_app(ESP_SPP_DISCOVERY_COMP_EVT, ¶m);
|
||||
break;
|
||||
case BTA_JV_RFCOMM_CL_INIT_EVT:
|
||||
@ -909,6 +972,7 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
param.start.status = p_data->rfc_start.status;
|
||||
param.start.handle = p_data->rfc_start.handle;
|
||||
param.start.sec_id = p_data->rfc_start.sec_id;
|
||||
param.start.scn = p_data->rfc_start.scn;
|
||||
param.start.use_co = p_data->rfc_start.use_co;
|
||||
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
|
||||
break;
|
||||
@ -1130,6 +1194,7 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
case BTA_JV_FREE_SCN_EVT:
|
||||
if (p_data->free_scn.server_status == BTA_JV_SERVER_RUNNING) {
|
||||
param.srv_stop.status = p_data->free_scn.status;
|
||||
param.srv_stop.scn = p_data->free_scn.scn;
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_STOP_EVT, ¶m);
|
||||
}
|
||||
break;
|
||||
|
@ -341,8 +341,7 @@ tBTM_STATUS BTM_BleSetExtendedAdvParams(UINT8 instance, tBTM_BLE_GAP_EXT_ADV_PAR
|
||||
params->peer_addr, params->filter_policy, params->tx_power,
|
||||
params->primary_phy, params->max_skip,
|
||||
params->secondary_phy, params->sid, params->scan_req_notif)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE EA SetParams: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
goto end;
|
||||
}
|
||||
@ -390,14 +389,12 @@ tBTM_STATUS BTM_BleConfigExtendedAdvDataRaw(BOOLEAN is_scan_rsp, UINT8 instance,
|
||||
}
|
||||
if (!is_scan_rsp) {
|
||||
if ((err = btsnd_hcic_ble_set_ext_adv_data(instance, operation, 0, send_data_len, &data[data_offset])) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, line %d, fail to send the hci command, the error code = %s",
|
||||
__func__, __LINE__, btm_ble_hci_status_to_str(err));
|
||||
BTM_TRACE_ERROR("LE EA SetAdvData: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
} else {
|
||||
if ((err = btsnd_hcic_ble_set_ext_adv_scan_rsp_data(instance, operation, 0, send_data_len, &data[data_offset])) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, line %d, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, __LINE__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE EA SetScanRspData: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
}
|
||||
@ -452,8 +449,7 @@ tBTM_STATUS BTM_BleStartExtAdv(BOOLEAN enable, UINT8 num, tBTM_BLE_EXT_ADV *ext_
|
||||
|
||||
if ((err = btsnd_hcic_ble_ext_adv_enable(enable, num, instance,
|
||||
duration, max_events)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE EA En=%d: cmd err=0x%x", enable, err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -464,9 +460,8 @@ tBTM_STATUS BTM_BleStartExtAdv(BOOLEAN enable, UINT8 num, tBTM_BLE_EXT_ADV *ext_
|
||||
// enable = false, num == 0 or ext_adv = NULL
|
||||
|
||||
if ((err = btsnd_hcic_ble_ext_adv_enable(enable, num, NULL, NULL, NULL)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
BTM_TRACE_ERROR("LE EA En=%d: cmd err=0x%x", enable, err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
@ -504,8 +499,7 @@ tBTM_STATUS BTM_BleExtAdvSetRemove(UINT8 instance)
|
||||
}
|
||||
|
||||
if ((err = btsnd_hcic_ble_remove_adv_set(instance)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE EAS Rm: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -527,8 +521,7 @@ tBTM_STATUS BTM_BleExtAdvSetClear(void)
|
||||
tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
|
||||
|
||||
if ((err = btsnd_hcic_ble_clear_adv_set()) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE EAS Clr: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -559,15 +552,14 @@ tBTM_STATUS BTM_BlePeriodicAdvSetParams(UINT8 instance, tBTM_BLE_Periodic_Adv_Pa
|
||||
extend_adv_cb.inst[instance].connetable ||
|
||||
extend_adv_cb.inst[instance].legacy_pdu) {
|
||||
BTM_TRACE_ERROR("%s, instance = %d, Before set the periodic adv parameters, please configure the the \
|
||||
extend adv to nonscannable and nonconnectable fisrt, and it shouldn't include the legacy bit.", __func__, instance);
|
||||
extend adv to nonscannable and nonconnectable first, and it shouldn't include the legacy bit.", __func__, instance);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((err= btsnd_hcic_ble_set_periodic_adv_params(instance, params->interval_min,
|
||||
params->interval_max, params->properties)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE PA SetParams: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -619,8 +611,7 @@ tBTM_STATUS BTM_BlePeriodicAdvCfgDataRaw(UINT8 instance, UINT16 len, UINT8 *data
|
||||
}
|
||||
|
||||
if ((err = btsnd_hcic_ble_set_periodic_adv_data(instance, operation, send_data_len, &data[data_offset])) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE PA SetData: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
rem_len -= send_data_len;
|
||||
@ -643,14 +634,13 @@ tBTM_STATUS BTM_BlePeriodicAdvEnable(UINT8 instance, BOOLEAN enable)
|
||||
tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
|
||||
|
||||
if (instance >= MAX_BLE_ADV_INSTANCE) {
|
||||
BTM_TRACE_ERROR("%s, invalid insatnce %d", __func__, instance);
|
||||
BTM_TRACE_ERROR("%s, invalid instance %d", __func__, instance);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((err = btsnd_hcic_ble_periodic_adv_enable(enable, instance)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE PA En=%d: cmd err=0x%x", enable, err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -688,7 +678,7 @@ tBTM_STATUS BTM_BlePeriodicAdvCreateSync(tBTM_BLE_Periodic_Sync_Params *params)
|
||||
|
||||
if (!btsnd_hcic_ble_periodic_adv_create_sync(params->filter_policy, params->sid, params->addr_type,
|
||||
params->addr, params->sync_timeout, 0)) {
|
||||
BTM_TRACE_ERROR("%s, send cmd failed", __func__);
|
||||
BTM_TRACE_ERROR("LE PA CreateSync cmd failed");
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -749,8 +739,7 @@ tBTM_STATUS BTM_BlePeriodicAdvSyncCancel(void)
|
||||
tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
|
||||
|
||||
if ((err = btsnd_hcic_ble_periodic_adv_create_sync_cancel()) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE PA SyncCancel, cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -770,8 +759,7 @@ tBTM_STATUS BTM_BlePeriodicAdvSyncTerm(UINT16 sync_handle)
|
||||
tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
|
||||
|
||||
if (( err = btsnd_hcic_ble_periodic_adv_term_sync(sync_handle)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE PA SyncTerm: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -797,8 +785,7 @@ tBTM_STATUS BTM_BlePeriodicAdvAddDevToList(tBLE_ADDR_TYPE addr_type, BD_ADDR add
|
||||
}
|
||||
|
||||
if ((err = btsnd_hcic_ble_add_dev_to_periodic_adv_list(addr_type, addr, sid)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE PA AddDevToList: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -824,8 +811,7 @@ tBTM_STATUS BTM_BlePeriodicAdvRemoveDevFromList(tBLE_ADDR_TYPE addr_type, BD_ADD
|
||||
}
|
||||
|
||||
if ((err = btsnd_hcic_ble_rm_dev_from_periodic_adv_list(addr_type, addr, sid)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE PA RmDevFromList: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -845,8 +831,7 @@ tBTM_STATUS BTM_BlePeriodicAdvClearDev(void)
|
||||
tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
|
||||
|
||||
if ((err = btsnd_hcic_ble_clear_periodic_adv_list()) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE PA ClrDev: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -894,8 +879,7 @@ tBTM_STATUS BTM_BleSetExtendedScanParams(tBTM_BLE_EXT_SCAN_PARAMS *params)
|
||||
|
||||
if ((err = btsnd_hcic_ble_set_ext_scan_params(params->own_addr_type, params->filter_policy, phy_mask, phy_count,
|
||||
hci_params)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE ES SetParams: cmd err=0x%x", err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -923,8 +907,7 @@ tBTM_STATUS BTM_BleExtendedScan(BOOLEAN enable, UINT16 duration, UINT16 period)
|
||||
}
|
||||
|
||||
if ((err = btsnd_hcic_ble_ext_scan_enable(enable, extend_adv_cb.scan_duplicate, duration, period)) != HCI_SUCCESS) {
|
||||
BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
|
||||
__func__, btm_ble_hci_status_to_str(err), err);
|
||||
BTM_TRACE_ERROR("LE ES En=%d: cmd err=0x%x", enable, err);
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
|
@ -414,12 +414,13 @@ void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK *p_c
|
||||
/* start to resolve random address */
|
||||
/* check for next security record */
|
||||
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
|
||||
p_dev_rec = list_node(p_node);
|
||||
p_dev_rec = list_node(p_node);
|
||||
p_mgnt_cb->p_dev_rec = p_dev_rec;
|
||||
if (btm_ble_match_random_bda(p_dev_rec)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
p_mgnt_cb->p_dev_rec = NULL;
|
||||
}
|
||||
btm_ble_resolve_address_cmpl();
|
||||
} else {
|
||||
(*p_cback)(NULL, p);
|
||||
|
@ -4589,26 +4589,6 @@ void btm_sec_disconnected (UINT16 handle, UINT8 reason)
|
||||
#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
|
||||
BTM_TRACE_EVENT("%s before update sec_flags=0x%x\n", __func__, p_dev_rec->sec_flags);
|
||||
|
||||
/* If we are in the process of bonding we need to tell client that auth failed */
|
||||
if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
|
||||
&& (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)) {
|
||||
btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
|
||||
p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
|
||||
if (btm_cb.api.p_auth_complete_callback) {
|
||||
/* If the disconnection reason is REPEATED_ATTEMPTS,
|
||||
send this error message to complete callback function
|
||||
to display the error message of Repeated attempts.
|
||||
All others, send HCI_ERR_AUTH_FAILURE. */
|
||||
if (reason == HCI_ERR_REPEATED_ATTEMPTS) {
|
||||
result = HCI_ERR_REPEATED_ATTEMPTS;
|
||||
} else if (old_pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
|
||||
result = HCI_ERR_HOST_REJECT_SECURITY;
|
||||
}
|
||||
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
|
||||
p_dev_rec->sec_bd_name, result);
|
||||
}
|
||||
}
|
||||
|
||||
#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
|
||||
btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, p_dev_rec->bd_addr, HCI_SUCCESS);
|
||||
/* see sec_flags processing in btm_acl_removed */
|
||||
@ -4645,6 +4625,26 @@ void btm_sec_disconnected (UINT16 handle, UINT8 reason)
|
||||
}
|
||||
|
||||
BTM_TRACE_EVENT("%s after update sec_flags=0x%x\n", __func__, p_dev_rec->sec_flags);
|
||||
|
||||
/* If we are in the process of bonding we need to tell client that auth failed */
|
||||
if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
|
||||
&& (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)) {
|
||||
btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
|
||||
p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
|
||||
if (btm_cb.api.p_auth_complete_callback) {
|
||||
/* If the disconnection reason is REPEATED_ATTEMPTS,
|
||||
send this error message to complete callback function
|
||||
to display the error message of Repeated attempts.
|
||||
All others, send HCI_ERR_AUTH_FAILURE. */
|
||||
if (reason == HCI_ERR_REPEATED_ATTEMPTS) {
|
||||
result = HCI_ERR_REPEATED_ATTEMPTS;
|
||||
} else if (old_pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
|
||||
result = HCI_ERR_HOST_REJECT_SECURITY;
|
||||
}
|
||||
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
|
||||
p_dev_rec->sec_bd_name, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -707,6 +707,10 @@ static void btu_hcif_disconnection_comp_evt (UINT8 *p)
|
||||
|
||||
handle = HCID_GET_HANDLE (handle);
|
||||
|
||||
if (reason != HCI_ERR_PEER_USER && reason != HCI_ERR_CONN_CAUSE_LOCAL_HOST) {
|
||||
HCI_TRACE_WARNING("DiscCmpl evt: hdl=%d, rsn=0x%x", handle, reason);
|
||||
}
|
||||
|
||||
#if BTM_SCO_INCLUDED == TRUE
|
||||
/* If L2CAP doesn't know about it, send it to SCO */
|
||||
if (!l2c_link_hci_disc_comp (handle, reason)) {
|
||||
@ -1126,7 +1130,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l
|
||||
uint8_t status;
|
||||
STREAM_TO_UINT8 (status, p);
|
||||
if(status != HCI_SUCCESS) {
|
||||
HCI_TRACE_ERROR("%s opcode 0x%x status 0x%x", __func__, opcode, status);
|
||||
HCI_TRACE_ERROR("CC evt: op=0x%x, status=0x%x", opcode, status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1259,7 +1263,7 @@ static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_c
|
||||
{
|
||||
uint8_t btm_status = BTM_SUCCESS;
|
||||
if(status != HCI_SUCCESS) {
|
||||
HCI_TRACE_ERROR("%s, Create sync error, the error code = 0x%x", __func__, status);
|
||||
HCI_TRACE_ERROR("CS evt: LE PA CreateSync status=0x%x", status);
|
||||
btm_status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
btm_create_sync_callback(btm_status);
|
||||
@ -1269,7 +1273,7 @@ static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_c
|
||||
{
|
||||
uint8_t btm_status = BTM_SUCCESS;
|
||||
if(status != HCI_SUCCESS) {
|
||||
HCI_TRACE_ERROR("%s, Set phy error, the error code = 0x%x", __func__, status);
|
||||
HCI_TRACE_ERROR("CS evt: LE SetPhy status=0x%x", status);
|
||||
btm_status = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
btm_set_phy_callback(btm_status);
|
||||
|
@ -1833,7 +1833,7 @@ UINT16 L2CA_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf)
|
||||
}
|
||||
|
||||
// If already congested, do not accept any more packets
|
||||
if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent) {
|
||||
if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent && fixed_cid != L2CAP_SMP_CID) {
|
||||
L2CAP_TRACE_DEBUG ("L2CAP - CID: 0x%04x cannot send, already congested\
|
||||
xmit_hold_q.count: %u buff_quota: %u", fixed_cid,
|
||||
fixed_queue_length(p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->xmit_hold_q),
|
||||
|
@ -591,7 +591,7 @@ void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status, UINT16 conn_in
|
||||
/* See if we have a link control block for the remote device */
|
||||
p_lcb = l2cu_find_lcb_by_handle(handle);
|
||||
if (!p_lcb) {
|
||||
L2CAP_TRACE_WARNING("l2cble_process_conn_update_evt: Invalid handle: %d", handle);
|
||||
L2CAP_TRACE_WARNING("le con upd: inv hdl=%d", handle);
|
||||
return;
|
||||
}
|
||||
if (status == HCI_SUCCESS){
|
||||
@ -599,7 +599,7 @@ void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status, UINT16 conn_in
|
||||
p_lcb->current_used_conn_latency = conn_latency;
|
||||
p_lcb->current_used_conn_timeout = conn_timeout;
|
||||
}else{
|
||||
L2CAP_TRACE_WARNING("l2cble_process_conn_update_evt: Error status: %d", status);
|
||||
L2CAP_TRACE_WARNING("le con upd: err_stat=0x%x", status);
|
||||
}
|
||||
|
||||
p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PENDING;
|
||||
@ -617,7 +617,7 @@ void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status, UINT16 conn_in
|
||||
|
||||
btu_stop_timer (&p_lcb->timer_entry);
|
||||
|
||||
L2CAP_TRACE_DEBUG("l2cble_process_conn_update_evt: conn_update_mask=%d", p_lcb->conn_update_mask);
|
||||
L2CAP_TRACE_DEBUG("le con upd: conn_update_mask=%d", p_lcb->conn_update_mask);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -1456,9 +1456,11 @@ void l2cu_change_pri_ccb (tL2C_CCB *p_ccb, tL2CAP_CHNL_PRIORITY priority)
|
||||
** Returns pointer to CCB, or NULL if none
|
||||
**
|
||||
*******************************************************************************/
|
||||
bool l2cu_find_ccb_in_list(void *p_ccb_node, void *p_local_cid);
|
||||
tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid)
|
||||
{
|
||||
tL2C_CCB *p_ccb = NULL;
|
||||
uint16_t tmp_cid = L2CAP_BASE_APPL_CID;
|
||||
L2CAP_TRACE_DEBUG ("l2cu_allocate_ccb: cid 0x%04x", cid);
|
||||
|
||||
p_ccb = l2cu_find_free_ccb ();
|
||||
@ -1481,7 +1483,13 @@ tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid)
|
||||
p_ccb->in_use = TRUE;
|
||||
|
||||
/* Get a CID for the connection */
|
||||
p_ccb->local_cid = L2CAP_BASE_APPL_CID + (list_length(l2cb.p_ccb_pool) - 1);
|
||||
for (tmp_cid = L2CAP_BASE_APPL_CID; tmp_cid < MAX_L2CAP_CHANNELS + L2CAP_BASE_APPL_CID; tmp_cid++) {
|
||||
if (list_foreach(l2cb.p_ccb_pool, l2cu_find_ccb_in_list, &tmp_cid) == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(tmp_cid != MAX_L2CAP_CHANNELS + L2CAP_BASE_APPL_CID);
|
||||
p_ccb->local_cid = tmp_cid;
|
||||
p_ccb->p_lcb = p_lcb;
|
||||
p_ccb->p_rcb = NULL;
|
||||
p_ccb->should_free_rcb = false;
|
||||
|
Submodule components/bt/host/nimble/nimble updated: c6f69c1261...1b808fcb80
@ -488,6 +488,7 @@ esp_err_t esp_bt_sleep_disable(void);
|
||||
* Note that scan duplicate list will be automatically cleared when the maximum amount of device in the filter is reached
|
||||
* the amount of device in the filter can be configured in menuconfig.
|
||||
*
|
||||
* @note This function name is incorrectly spelled, it will be fixed in release 5.x version.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
|
@ -26,7 +26,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_BT_CTRL_CONFIG_MAGIC_VAL 0x5A5AA5A5
|
||||
#define ESP_BT_CTRL_CONFIG_VERSION 0x02101290
|
||||
#define ESP_BT_CTRL_CONFIG_VERSION 0x02103080
|
||||
|
||||
#define ESP_BT_HCI_TL_MAGIC_VALUE 0xfadebead
|
||||
#define ESP_BT_HCI_TL_VERSION 0x00010000
|
||||
@ -133,6 +133,8 @@ enum {
|
||||
|
||||
#define CFG_NASK CFG_MASK_BIT_SCAN_DUPLICATE_OPTION
|
||||
|
||||
#define BLE_HW_TARGET_CODE_ESP32C3_CHIP_ECO0 (0x01010000)
|
||||
|
||||
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \
|
||||
.magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL, \
|
||||
.version = ESP_BT_CTRL_CONFIG_VERSION, \
|
||||
@ -158,6 +160,7 @@ enum {
|
||||
.normal_adv_size = NORMAL_SCAN_DUPLICATE_CACHE_SIZE, \
|
||||
.mesh_adv_size = MESH_DUPLICATE_SCAN_CACHE_SIZE, \
|
||||
.coex_phy_coded_tx_rx_time_limit = CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF, \
|
||||
.hw_target_code = BLE_HW_TARGET_CODE_ESP32C3_CHIP_ECO0, \
|
||||
};
|
||||
|
||||
#else
|
||||
@ -221,6 +224,7 @@ typedef struct {
|
||||
uint16_t normal_adv_size; /*!< Normal adv size for scan duplicate */
|
||||
uint16_t mesh_adv_size; /*!< Mesh adv size for scan duplicate */
|
||||
uint8_t coex_phy_coded_tx_rx_time_limit; /*!< limit on max tx/rx time in case of connection using CODED-PHY with Wi-Fi coexistence */
|
||||
uint32_t hw_target_code; /*!< hardware target */
|
||||
} esp_bt_controller_config_t;
|
||||
|
||||
/**
|
||||
@ -263,22 +267,23 @@ typedef enum {
|
||||
* @brief Bluetooth TX power level(index), it's just a index corresponding to power(dbm).
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_PWR_LVL_N12 = 0, /*!< Corresponding to -12dbm */
|
||||
ESP_PWR_LVL_N9 = 1, /*!< Corresponding to -9dbm */
|
||||
ESP_PWR_LVL_N6 = 2, /*!< Corresponding to -6dbm */
|
||||
ESP_PWR_LVL_N3 = 3, /*!< Corresponding to -3dbm */
|
||||
ESP_PWR_LVL_N0 = 4, /*!< Corresponding to 0dbm */
|
||||
ESP_PWR_LVL_P3 = 5, /*!< Corresponding to +3dbm */
|
||||
ESP_PWR_LVL_P6 = 6, /*!< Corresponding to +6dbm */
|
||||
ESP_PWR_LVL_P9 = 7, /*!< Corresponding to +9dbm */
|
||||
ESP_PWR_LVL_N14 = ESP_PWR_LVL_N12, /*!< Backward compatibility! Setting to -14dbm will actually result to -12dbm */
|
||||
ESP_PWR_LVL_N11 = ESP_PWR_LVL_N9, /*!< Backward compatibility! Setting to -11dbm will actually result to -9dbm */
|
||||
ESP_PWR_LVL_N8 = ESP_PWR_LVL_N6, /*!< Backward compatibility! Setting to -8dbm will actually result to -6dbm */
|
||||
ESP_PWR_LVL_N5 = ESP_PWR_LVL_N3, /*!< Backward compatibility! Setting to -5dbm will actually result to -3dbm */
|
||||
ESP_PWR_LVL_N2 = ESP_PWR_LVL_N0, /*!< Backward compatibility! Setting to -2dbm will actually result to 0dbm */
|
||||
ESP_PWR_LVL_P1 = ESP_PWR_LVL_P3, /*!< Backward compatibility! Setting to +1dbm will actually result to +3dbm */
|
||||
ESP_PWR_LVL_P4 = ESP_PWR_LVL_P6, /*!< Backward compatibility! Setting to +4dbm will actually result to +6dbm */
|
||||
ESP_PWR_LVL_P7 = ESP_PWR_LVL_P9, /*!< Backward compatibility! Setting to +7dbm will actually result to +9dbm */
|
||||
ESP_PWR_LVL_N27 = 0, /*!< Corresponding to -27dbm */
|
||||
ESP_PWR_LVL_N24 = 1, /*!< Corresponding to -24dbm */
|
||||
ESP_PWR_LVL_N21 = 2, /*!< Corresponding to -21dbm */
|
||||
ESP_PWR_LVL_N18 = 3, /*!< Corresponding to -18dbm */
|
||||
ESP_PWR_LVL_N15 = 4, /*!< Corresponding to -15dbm */
|
||||
ESP_PWR_LVL_N12 = 5, /*!< Corresponding to -12dbm */
|
||||
ESP_PWR_LVL_N9 = 6, /*!< Corresponding to -9dbm */
|
||||
ESP_PWR_LVL_N6 = 7, /*!< Corresponding to -6dbm */
|
||||
ESP_PWR_LVL_N3 = 8, /*!< Corresponding to -3dbm */
|
||||
ESP_PWR_LVL_N0 = 9, /*!< Corresponding to 0dbm */
|
||||
ESP_PWR_LVL_P3 = 10, /*!< Corresponding to +3dbm */
|
||||
ESP_PWR_LVL_P6 = 11, /*!< Corresponding to +6dbm */
|
||||
ESP_PWR_LVL_P9 = 12, /*!< Corresponding to +9dbm */
|
||||
ESP_PWR_LVL_P12 = 13, /*!< Corresponding to +12dbm */
|
||||
ESP_PWR_LVL_P15 = 14, /*!< Corresponding to +15dbm */
|
||||
ESP_PWR_LVL_P18 = 15, /*!< Corresponding to +18dbm */
|
||||
ESP_PWR_LVL_INVALID = 0xFF, /*!< Indicates an invalid value */
|
||||
} esp_power_level_t;
|
||||
|
||||
/**
|
||||
|
@ -160,17 +160,12 @@ static void adc_power_on_internal(void)
|
||||
|
||||
void adc_power_acquire(void)
|
||||
{
|
||||
bool powered_on = false;
|
||||
ADC_POWER_ENTER();
|
||||
s_adc_power_on_cnt++;
|
||||
if (s_adc_power_on_cnt == 1) {
|
||||
adc_power_on_internal();
|
||||
powered_on = true;
|
||||
}
|
||||
ADC_POWER_EXIT();
|
||||
if (powered_on) {
|
||||
ESP_LOGV(ADC_TAG, "%s: ADC powered on", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void adc_power_on(void)
|
||||
@ -182,12 +177,15 @@ void adc_power_on(void)
|
||||
|
||||
static void adc_power_off_internal(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
adc_hal_set_power_manage(ADC_POWER_SW_OFF);
|
||||
#else
|
||||
adc_hal_set_power_manage(ADC_POWER_BY_FSM);
|
||||
#endif
|
||||
}
|
||||
|
||||
void adc_power_release(void)
|
||||
{
|
||||
bool powered_off = false;
|
||||
ADC_POWER_ENTER();
|
||||
s_adc_power_on_cnt--;
|
||||
/* Sanity check */
|
||||
@ -197,12 +195,8 @@ void adc_power_release(void)
|
||||
abort();
|
||||
} else if (s_adc_power_on_cnt == 0) {
|
||||
adc_power_off_internal();
|
||||
powered_off = true;
|
||||
}
|
||||
ADC_POWER_EXIT();
|
||||
if (powered_off) {
|
||||
ESP_LOGV(ADC_TAG, "%s: ADC powered off", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void adc_power_off(void)
|
||||
@ -212,6 +206,33 @@ void adc_power_off(void)
|
||||
ADC_POWER_EXIT();
|
||||
}
|
||||
|
||||
esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num)
|
||||
{
|
||||
ADC_CHANNEL_CHECK(ADC_NUM_1, channel);
|
||||
|
||||
int io = ADC_GET_IO_NUM(ADC_NUM_1, channel);
|
||||
if (io < 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
} else {
|
||||
*gpio_num = (gpio_num_t)io;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num)
|
||||
{
|
||||
ADC_CHANNEL_CHECK(ADC_NUM_2, channel);
|
||||
|
||||
int io = ADC_GET_IO_NUM(ADC_NUM_2, channel);
|
||||
if (io < 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
} else {
|
||||
*gpio_num = (gpio_num_t)io;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
esp_err_t adc_set_clk_div(uint8_t clk_div)
|
||||
@ -323,20 +344,6 @@ esp_err_t adc_rtc_reset(void)
|
||||
/*-------------------------------------------------------------------------------------
|
||||
* ADC1
|
||||
*------------------------------------------------------------------------------------*/
|
||||
esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num)
|
||||
{
|
||||
ADC_CHANNEL_CHECK(ADC_NUM_1, channel);
|
||||
|
||||
int io = ADC_GET_IO_NUM(ADC_NUM_1, channel);
|
||||
if (io < 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
} else {
|
||||
*gpio_num = (gpio_num_t)io;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
ADC_CHANNEL_CHECK(ADC_NUM_1, channel);
|
||||
@ -466,20 +473,6 @@ void adc1_ulp_enable(void)
|
||||
/*---------------------------------------------------------------
|
||||
ADC2
|
||||
---------------------------------------------------------------*/
|
||||
esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num)
|
||||
{
|
||||
ADC_CHANNEL_CHECK(ADC_NUM_2, channel);
|
||||
|
||||
int io = ADC_GET_IO_NUM(ADC_NUM_2, channel);
|
||||
if (io < 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
} else {
|
||||
*gpio_num = (gpio_num_t)io;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/** For ESP32S2 the ADC2 The right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/
|
||||
esp_err_t adc2_wifi_acquire(void)
|
||||
{
|
||||
@ -562,6 +555,7 @@ static inline void adc2_dac_disable( adc2_channel_t channel)
|
||||
*/
|
||||
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
int adc_value = 0;
|
||||
|
||||
ADC_CHECK(raw_out != NULL, "ADC out value err", ESP_ERR_INVALID_ARG);
|
||||
@ -601,7 +595,8 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
#endif //CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
if (adc_hal_convert(ADC_NUM_2, channel, &adc_value)) {
|
||||
ret = adc_hal_convert(ADC_NUM_2, channel, &adc_value);
|
||||
if (ret != ESP_OK) {
|
||||
adc_value = -1;
|
||||
}
|
||||
|
||||
@ -618,13 +613,8 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
adc_power_release();
|
||||
SARADC2_RELEASE();
|
||||
|
||||
if (adc_value < 0) {
|
||||
ESP_LOGD( ADC_TAG, "ADC2 ARB: Return data is invalid." );
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
*raw_out = adc_value;
|
||||
return ESP_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "hal/cpu_hal.h"
|
||||
#include "hal/cpu_ll.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
@ -267,13 +268,13 @@ esp_err_t dedic_gpio_new_bundle(const dedic_gpio_bundle_config_t *config, dedic_
|
||||
// route dedicated GPIO channel signals to GPIO matrix
|
||||
if (config->flags.in_en) {
|
||||
for (size_t i = 0; i < config->array_size; i++) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->gpio_array[i]], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->gpio_array[i]], PIN_FUNC_GPIO);
|
||||
esp_rom_gpio_connect_in_signal(config->gpio_array[i], dedic_gpio_periph_signals.cores[core_id].in_sig_per_channel[in_offset + i], config->flags.in_invert);
|
||||
}
|
||||
}
|
||||
if (config->flags.out_en) {
|
||||
for (size_t i = 0; i < config->array_size; i++) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->gpio_array[i]], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->gpio_array[i]], PIN_FUNC_GPIO);
|
||||
esp_rom_gpio_connect_out_signal(config->gpio_array[i], dedic_gpio_periph_signals.cores[core_id].out_sig_per_channel[out_offset + i], config->flags.out_invert, false);
|
||||
}
|
||||
}
|
||||
|
@ -135,6 +135,7 @@ esp_err_t adc_digi_init(void)
|
||||
|
||||
esp_err_t adc_digi_deinit(void)
|
||||
{
|
||||
adc_power_release();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_deinit();
|
||||
ADC_EXIT_CRITICAL();
|
||||
@ -143,6 +144,8 @@ esp_err_t adc_digi_deinit(void)
|
||||
|
||||
esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
|
||||
{
|
||||
/* If enable digital controller, adc xpd should always on. */
|
||||
adc_power_acquire();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_controller_config(config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_pm.h"
|
||||
#include "sys/lock.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
@ -32,6 +33,7 @@
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/dma_types.h"
|
||||
#include "esp32c3/esp_efuse_rtc_calib.h"
|
||||
#include "esp_private/gdma.h"
|
||||
|
||||
#define ADC_CHECK_RET(fun_ret) ({ \
|
||||
if (fun_ret != ESP_OK) { \
|
||||
@ -57,37 +59,34 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi
|
||||
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
|
||||
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital Controller Context
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* 1. adc_digi_mutex: this mutex lock is used for ADC digital controller. On ESP32-C3, the ADC single read APIs (unit1 & unit2)
|
||||
* and ADC DMA continuous read APIs share the ``apb_saradc_struct.h`` regs.
|
||||
*
|
||||
* 2. sar_adc_mutex: this mutex lock is used for SARADC2 module. On ESP32C-C3, the ADC single read APIs (unit2), ADC DMA
|
||||
* continuous read APIs and WIFI share the SARADC2 analog IP.
|
||||
*
|
||||
* Sequence:
|
||||
* Acquire: 1. sar_adc_mutex; 2. adc_digi_mutex;
|
||||
* Release: 1. adc_digi_mutex; 2. sar_adc_mutex;
|
||||
* 1. sar_adc1_lock: this mutex lock is to protect the SARADC1 module.
|
||||
* 2. sar_adc2_lock: this mutex lock is to protect the SARADC2 module. On C3, it is controlled by the digital controller
|
||||
* and PWDET controller.
|
||||
* 3. adc_reg_lock: this spin lock is to protect the shared registers used by ADC1 / ADC2 single read mode.
|
||||
*/
|
||||
static _lock_t adc_digi_mutex;
|
||||
#define ADC_DIGI_LOCK_ACQUIRE() _lock_acquire(&adc_digi_mutex)
|
||||
#define ADC_DIGI_LOCK_RELEASE() _lock_release(&adc_digi_mutex)
|
||||
static _lock_t sar_adc2_mutex;
|
||||
#define SAC_ADC2_LOCK_ACQUIRE() _lock_acquire(&sar_adc2_mutex)
|
||||
#define SAC_ADC2_LOCK_RELEASE() _lock_release(&sar_adc2_mutex)
|
||||
static _lock_t sar_adc1_lock;
|
||||
#define SAR_ADC1_LOCK_ACQUIRE() _lock_acquire(&sar_adc1_lock)
|
||||
#define SAR_ADC1_LOCK_RELEASE() _lock_release(&sar_adc1_lock)
|
||||
static _lock_t sar_adc2_lock;
|
||||
#define SAR_ADC2_LOCK_ACQUIRE() _lock_acquire(&sar_adc2_lock)
|
||||
#define SAR_ADC2_LOCK_RELEASE() _lock_release(&sar_adc2_lock)
|
||||
portMUX_TYPE adc_reg_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#define ADC_REG_LOCK_ENTER() portENTER_CRITICAL(&adc_reg_lock)
|
||||
#define ADC_REG_LOCK_EXIT() portEXIT_CRITICAL(&adc_reg_lock)
|
||||
|
||||
#define INTERNAL_BUF_NUM 5
|
||||
#define IN_SUC_EOF_BIT GDMA_LL_EVENT_RX_SUC_EOF
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital Controller Context
|
||||
---------------------------------------------------------------*/
|
||||
typedef struct adc_digi_context_t {
|
||||
intr_handle_t dma_intr_hdl; //MD interrupt handle
|
||||
uint32_t bytes_between_intr; //bytes between in suc eof intr
|
||||
uint8_t *rx_dma_buf; //dma buffer
|
||||
adc_dma_hal_context_t hal_dma; //dma context (hal)
|
||||
adc_dma_hal_config_t hal_dma_config; //dma config (hal)
|
||||
adc_hal_context_t hal; //hal context
|
||||
gdma_channel_handle_t rx_dma_channel; //dma rx channel handle
|
||||
RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler
|
||||
intptr_t rx_eof_desc_addr; //eof descriptor address of RX channel
|
||||
bool ringbuf_overflow_flag; //1: ringbuffer overflow
|
||||
bool driver_start_flag; //1: driver is started; 0: driver is stoped
|
||||
bool use_adc1; //1: ADC unit1 will be used; 0: ADC unit1 won't be used.
|
||||
@ -95,6 +94,7 @@ typedef struct adc_digi_context_t {
|
||||
adc_atten_t adc1_atten; //Attenuation for ADC1. On this chip each ADC can only support one attenuation.
|
||||
adc_atten_t adc2_atten; //Attenuation for ADC2. On this chip each ADC can only support one attenuation.
|
||||
adc_digi_config_t digi_controller_config; //Digital Controller Configuration
|
||||
esp_pm_lock_handle_t pm_lock; //For power management
|
||||
} adc_digi_context_t;
|
||||
|
||||
static adc_digi_context_t *s_adc_digi_ctx = NULL;
|
||||
@ -104,7 +104,7 @@ static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t cha
|
||||
/*---------------------------------------------------------------
|
||||
ADC Continuous Read Mode (via DMA)
|
||||
---------------------------------------------------------------*/
|
||||
static void adc_dma_intr(void* arg);
|
||||
static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
|
||||
|
||||
static int8_t adc_digi_get_io_num(uint8_t adc_unit, uint8_t adc_channel)
|
||||
{
|
||||
@ -149,11 +149,6 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = esp_intr_alloc(SOC_GDMA_ADC_INTR_SOURCE, 0, adc_dma_intr, (void *)s_adc_digi_ctx, &s_adc_digi_ctx->dma_intr_hdl);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//ringbuffer
|
||||
s_adc_digi_ctx->ringbuf_hdl = xRingbufferCreate(init_config->max_store_buf_size, RINGBUF_TYPE_BYTEBUF);
|
||||
if (!s_adc_digi_ctx->ringbuf_hdl) {
|
||||
@ -161,22 +156,19 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//malloc internal buffer
|
||||
s_adc_digi_ctx->bytes_between_intr = init_config->conv_num_each_intr;
|
||||
s_adc_digi_ctx->rx_dma_buf = heap_caps_calloc(1, s_adc_digi_ctx->bytes_between_intr * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL);
|
||||
//malloc internal buffer used by DMA
|
||||
s_adc_digi_ctx->rx_dma_buf = heap_caps_calloc(1, init_config->conv_num_each_intr * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL);
|
||||
if (!s_adc_digi_ctx->rx_dma_buf) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
//malloc dma descriptor
|
||||
s_adc_digi_ctx->hal_dma_config.rx_desc = heap_caps_calloc(1, (sizeof(dma_descriptor_t)) * INTERNAL_BUF_NUM, MALLOC_CAP_DMA);
|
||||
if (!s_adc_digi_ctx->hal_dma_config.rx_desc) {
|
||||
s_adc_digi_ctx->hal.rx_desc = heap_caps_calloc(1, (sizeof(dma_descriptor_t)) * INTERNAL_BUF_NUM, MALLOC_CAP_DMA);
|
||||
if (!s_adc_digi_ctx->hal.rx_desc) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
s_adc_digi_ctx->hal_dma_config.desc_max_num = INTERNAL_BUF_NUM;
|
||||
s_adc_digi_ctx->hal_dma_config.dma_chan = init_config->dma_chan;
|
||||
|
||||
//malloc pattern table
|
||||
s_adc_digi_ctx->digi_controller_config.adc_pattern = calloc(1, SOC_ADC_PATT_LEN_MAX * sizeof(adc_digi_pattern_table_t));
|
||||
@ -185,6 +177,14 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc_dma", &s_adc_digi_ctx->pm_lock);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
//init gpio pins
|
||||
if (init_config->adc1_chan_mask) {
|
||||
ret = adc_digi_gpio_init(ADC_NUM_1, init_config->adc1_chan_mask);
|
||||
if (ret != ESP_OK) {
|
||||
@ -198,8 +198,39 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
|
||||
}
|
||||
}
|
||||
|
||||
//alloc rx gdma channel
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
};
|
||||
ret = gdma_new_channel(&rx_alloc_config, &s_adc_digi_ctx->rx_dma_channel);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
gdma_connect(s_adc_digi_ctx->rx_dma_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_ADC, 0));
|
||||
|
||||
gdma_strategy_config_t strategy_config = {
|
||||
.auto_update_desc = true,
|
||||
.owner_check = true
|
||||
};
|
||||
gdma_apply_strategy(s_adc_digi_ctx->rx_dma_channel, &strategy_config);
|
||||
|
||||
gdma_rx_event_callbacks_t cbs = {
|
||||
.on_recv_eof = adc_dma_in_suc_eof_callback
|
||||
};
|
||||
gdma_register_rx_event_callbacks(s_adc_digi_ctx->rx_dma_channel, &cbs, s_adc_digi_ctx);
|
||||
|
||||
int dma_chan;
|
||||
gdma_get_channel_id(s_adc_digi_ctx->rx_dma_channel, &dma_chan);
|
||||
|
||||
adc_hal_config_t config = {
|
||||
.desc_max_num = INTERNAL_BUF_NUM,
|
||||
.dma_chan = dma_chan,
|
||||
.eof_num = init_config->conv_num_each_intr / ADC_HAL_DATA_LEN_PER_CONV
|
||||
};
|
||||
adc_hal_context_config(&s_adc_digi_ctx->hal, &config);
|
||||
|
||||
//enable SARADC module clock
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
periph_module_enable(PERIPH_GDMA_MODULE);
|
||||
|
||||
adc_hal_calibration_init(ADC_NUM_1);
|
||||
adc_hal_calibration_init(ADC_NUM_2);
|
||||
@ -212,46 +243,42 @@ cleanup:
|
||||
|
||||
}
|
||||
|
||||
static IRAM_ATTR void adc_dma_intr(void *arg)
|
||||
static IRAM_ATTR bool adc_dma_intr(adc_digi_context_t *adc_digi_ctx);
|
||||
|
||||
static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
|
||||
{
|
||||
assert(event_data);
|
||||
adc_digi_context_t *adc_digi_ctx = (adc_digi_context_t *)user_data;
|
||||
adc_digi_ctx->rx_eof_desc_addr = event_data->rx_eof_desc_addr;
|
||||
return adc_dma_intr(adc_digi_ctx);
|
||||
}
|
||||
|
||||
static IRAM_ATTR bool adc_dma_intr(adc_digi_context_t *adc_digi_ctx)
|
||||
{
|
||||
portBASE_TYPE taskAwoken = 0;
|
||||
BaseType_t ret;
|
||||
adc_hal_dma_desc_status_t status = false;
|
||||
dma_descriptor_t *current_desc = NULL;
|
||||
|
||||
//clear the in suc eof interrupt
|
||||
adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config, IN_SUC_EOF_BIT);
|
||||
|
||||
while (s_adc_digi_ctx->hal_dma_config.cur_desc_ptr->dw0.owner == 0) {
|
||||
|
||||
dma_descriptor_t *current_desc = s_adc_digi_ctx->hal_dma_config.cur_desc_ptr;
|
||||
ret = xRingbufferSendFromISR(s_adc_digi_ctx->ringbuf_hdl, current_desc->buffer, current_desc->dw0.length, &taskAwoken);
|
||||
if (ret == pdFALSE) {
|
||||
//ringbuffer overflow
|
||||
s_adc_digi_ctx->ringbuf_overflow_flag = 1;
|
||||
}
|
||||
|
||||
s_adc_digi_ctx->hal_dma_config.desc_cnt += 1;
|
||||
//cycle the dma descriptor and buffers
|
||||
s_adc_digi_ctx->hal_dma_config.cur_desc_ptr = s_adc_digi_ctx->hal_dma_config.cur_desc_ptr->next;
|
||||
if (!s_adc_digi_ctx->hal_dma_config.cur_desc_ptr) {
|
||||
while (1) {
|
||||
status = adc_hal_get_reading_result(&adc_digi_ctx->hal, adc_digi_ctx->rx_eof_desc_addr, ¤t_desc);
|
||||
if (status != ADC_HAL_DMA_DESC_VALID) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, current_desc->buffer, current_desc->dw0.length, &taskAwoken);
|
||||
if (ret == pdFALSE) {
|
||||
//ringbuffer overflow
|
||||
adc_digi_ctx->ringbuf_overflow_flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_adc_digi_ctx->hal_dma_config.cur_desc_ptr) {
|
||||
|
||||
assert(s_adc_digi_ctx->hal_dma_config.desc_cnt == s_adc_digi_ctx->hal_dma_config.desc_max_num);
|
||||
//reset the current descriptor status
|
||||
s_adc_digi_ctx->hal_dma_config.cur_desc_ptr = s_adc_digi_ctx->hal_dma_config.rx_desc;
|
||||
s_adc_digi_ctx->hal_dma_config.desc_cnt = 0;
|
||||
|
||||
if (status == ADC_HAL_DMA_DESC_NULL) {
|
||||
//start next turns of dma operation
|
||||
adc_hal_digi_dma_multi_descriptor(&s_adc_digi_ctx->hal_dma_config, s_adc_digi_ctx->rx_dma_buf, s_adc_digi_ctx->bytes_between_intr, s_adc_digi_ctx->hal_dma_config.desc_max_num);
|
||||
adc_hal_digi_rxdma_start(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config);
|
||||
adc_hal_digi_rxdma_start(&adc_digi_ctx->hal, adc_digi_ctx->rx_dma_buf);
|
||||
}
|
||||
|
||||
if(taskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
return (taskAwoken == pdTRUE);
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_start(void)
|
||||
@ -260,15 +287,21 @@ esp_err_t adc_digi_start(void)
|
||||
ESP_LOGE(ADC_TAG, "The driver is already started");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
adc_power_acquire();
|
||||
//reset flags
|
||||
s_adc_digi_ctx->ringbuf_overflow_flag = 0;
|
||||
s_adc_digi_ctx->driver_start_flag = 1;
|
||||
|
||||
//When using SARADC2 module, this task needs to be protected from WIFI
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
SAC_ADC2_LOCK_ACQUIRE();
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
SAR_ADC1_LOCK_ACQUIRE();
|
||||
}
|
||||
ADC_DIGI_LOCK_ACQUIRE();
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
SAR_ADC2_LOCK_ACQUIRE();
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
// Lock APB frequency while ADC driver is in use
|
||||
esp_pm_lock_acquire(s_adc_digi_ctx->pm_lock);
|
||||
#endif
|
||||
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
@ -281,26 +314,16 @@ esp_err_t adc_digi_start(void)
|
||||
}
|
||||
|
||||
adc_hal_init();
|
||||
|
||||
adc_hal_arbiter_config(&config);
|
||||
adc_hal_digi_init(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config);
|
||||
adc_hal_digi_init(&s_adc_digi_ctx->hal);
|
||||
adc_hal_digi_controller_config(&s_adc_digi_ctx->digi_controller_config);
|
||||
|
||||
//create dma descriptors
|
||||
adc_hal_digi_dma_multi_descriptor(&s_adc_digi_ctx->hal_dma_config, s_adc_digi_ctx->rx_dma_buf, s_adc_digi_ctx->bytes_between_intr, s_adc_digi_ctx->hal_dma_config.desc_max_num);
|
||||
adc_hal_digi_set_eof_num(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config, (s_adc_digi_ctx->bytes_between_intr)/4);
|
||||
//set the current descriptor pointer
|
||||
s_adc_digi_ctx->hal_dma_config.cur_desc_ptr = s_adc_digi_ctx->hal_dma_config.rx_desc;
|
||||
s_adc_digi_ctx->hal_dma_config.desc_cnt = 0;
|
||||
|
||||
//enable in suc eof intr
|
||||
adc_hal_digi_ena_intr(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config, IN_SUC_EOF_BIT);
|
||||
|
||||
//start ADC
|
||||
adc_hal_digi_start(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config);
|
||||
|
||||
//reset ADC and DMA
|
||||
adc_hal_fifo_reset(&s_adc_digi_ctx->hal);
|
||||
//start DMA
|
||||
adc_hal_digi_rxdma_start(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config);
|
||||
adc_hal_digi_rxdma_start(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf);
|
||||
//start ADC
|
||||
adc_hal_digi_start(&s_adc_digi_ctx->hal);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -314,20 +337,27 @@ esp_err_t adc_digi_stop(void)
|
||||
s_adc_digi_ctx->driver_start_flag = 0;
|
||||
|
||||
//disable the in suc eof intrrupt
|
||||
adc_hal_digi_dis_intr(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config, IN_SUC_EOF_BIT);
|
||||
adc_hal_digi_dis_intr(&s_adc_digi_ctx->hal, IN_SUC_EOF_BIT);
|
||||
//clear the in suc eof interrupt
|
||||
adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config, IN_SUC_EOF_BIT);
|
||||
//stop DMA
|
||||
adc_hal_digi_rxdma_stop(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config);
|
||||
adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal, IN_SUC_EOF_BIT);
|
||||
//stop ADC
|
||||
adc_hal_digi_stop(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config);
|
||||
adc_hal_digi_stop(&s_adc_digi_ctx->hal);
|
||||
//stop DMA
|
||||
adc_hal_digi_rxdma_stop(&s_adc_digi_ctx->hal);
|
||||
adc_hal_digi_deinit();
|
||||
|
||||
ADC_DIGI_LOCK_RELEASE();
|
||||
//When using SARADC2 module, this task needs to be protected from WIFI
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
SAC_ADC2_LOCK_RELEASE();
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (s_adc_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_release(s_adc_digi_ctx->pm_lock);
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
SAR_ADC1_LOCK_RELEASE();
|
||||
}
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
SAR_ADC2_LOCK_RELEASE();
|
||||
}
|
||||
adc_power_release();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -375,23 +405,27 @@ esp_err_t adc_digi_deinitialize(void)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (s_adc_digi_ctx->dma_intr_hdl) {
|
||||
esp_intr_free(s_adc_digi_ctx->dma_intr_hdl);
|
||||
}
|
||||
|
||||
if(s_adc_digi_ctx->ringbuf_hdl) {
|
||||
if (s_adc_digi_ctx->ringbuf_hdl) {
|
||||
vRingbufferDelete(s_adc_digi_ctx->ringbuf_hdl);
|
||||
s_adc_digi_ctx->ringbuf_hdl = NULL;
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (s_adc_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_delete(s_adc_digi_ctx->pm_lock);
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
free(s_adc_digi_ctx->rx_dma_buf);
|
||||
free(s_adc_digi_ctx->hal_dma_config.rx_desc);
|
||||
free(s_adc_digi_ctx->hal.rx_desc);
|
||||
free(s_adc_digi_ctx->digi_controller_config.adc_pattern);
|
||||
gdma_disconnect(s_adc_digi_ctx->rx_dma_channel);
|
||||
gdma_del_channel(s_adc_digi_ctx->rx_dma_channel);
|
||||
|
||||
free(s_adc_digi_ctx);
|
||||
s_adc_digi_ctx = NULL;
|
||||
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
periph_module_disable(PERIPH_GDMA_MODULE);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -402,6 +436,38 @@ esp_err_t adc_digi_deinitialize(void)
|
||||
static adc_atten_t s_atten1_single[ADC1_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC1, used by single read API
|
||||
static adc_atten_t s_atten2_single[ADC2_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC2, used by single read API
|
||||
|
||||
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint32_t channel = ADC2_CHANNEL_MAX;
|
||||
if (adc_unit == ADC_UNIT_2) {
|
||||
for (int i = 0; i < ADC2_CHANNEL_MAX; i++) {
|
||||
if (gpio == ADC_GET_IO_NUM(ADC_NUM_2, i)) {
|
||||
channel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (channel == ADC2_CHANNEL_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
adc_power_acquire();
|
||||
if (adc_unit & ADC_UNIT_1) {
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_vref_output(ADC_NUM_1, channel, true);
|
||||
ADC_EXIT_CRITICAL()
|
||||
} else if (adc_unit & ADC_UNIT_2) {
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_vref_output(ADC_NUM_2, channel, true);
|
||||
ADC_EXIT_CRITICAL()
|
||||
}
|
||||
|
||||
ret = adc_digi_gpio_init(ADC_NUM_2, BIT(channel));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc1_config_width(adc_bits_width_t width_bit)
|
||||
{
|
||||
//On ESP32C3, the data width is always 12-bits.
|
||||
@ -429,41 +495,26 @@ esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
|
||||
int adc1_get_raw(adc1_channel_t channel)
|
||||
{
|
||||
int raw_out = 0;
|
||||
adc_digi_config_t dig_cfg = {
|
||||
.conv_limit_en = 0,
|
||||
.conv_limit_num = 250,
|
||||
.sample_freq_hz = SOC_ADC_SAMPLE_FREQ_THRES_HIGH,
|
||||
};
|
||||
|
||||
ADC_DIGI_LOCK_ACQUIRE();
|
||||
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
adc_power_acquire();
|
||||
|
||||
SAR_ADC1_LOCK_ACQUIRE();
|
||||
|
||||
adc_atten_t atten = s_atten1_single[channel];
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_1, channel, atten);
|
||||
adc_hal_set_calibration_param(ADC_NUM_1, cal_val);
|
||||
|
||||
adc_hal_digi_controller_config(&dig_cfg);
|
||||
ADC_REG_LOCK_ENTER();
|
||||
adc_hal_set_atten(ADC_NUM_2, channel, atten);
|
||||
adc_hal_convert(ADC_NUM_1, channel, &raw_out);
|
||||
ADC_REG_LOCK_EXIT();
|
||||
|
||||
adc_hal_intr_clear(ADC_EVENT_ADC1_DONE);
|
||||
SAR_ADC1_LOCK_RELEASE();
|
||||
|
||||
adc_hal_adc1_onetime_sample_enable(true);
|
||||
adc_hal_onetime_channel(ADC_NUM_1, channel);
|
||||
adc_hal_set_onetime_atten(atten);
|
||||
|
||||
//Trigger single read.
|
||||
adc_hal_onetime_start(&dig_cfg);
|
||||
while (!adc_hal_intr_get_raw(ADC_EVENT_ADC1_DONE));
|
||||
adc_hal_single_read(ADC_NUM_1, &raw_out);
|
||||
|
||||
adc_hal_intr_clear(ADC_EVENT_ADC1_DONE);
|
||||
adc_hal_adc1_onetime_sample_enable(false);
|
||||
|
||||
adc_hal_digi_deinit();
|
||||
adc_power_release();
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
|
||||
ADC_DIGI_LOCK_RELEASE();
|
||||
|
||||
return raw_out;
|
||||
}
|
||||
|
||||
@ -489,42 +540,26 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
adc_digi_config_t dig_cfg = {
|
||||
.conv_limit_en = 0,
|
||||
.conv_limit_num = 250,
|
||||
.sample_freq_hz = SOC_ADC_SAMPLE_FREQ_THRES_HIGH,
|
||||
};
|
||||
|
||||
SAC_ADC2_LOCK_ACQUIRE();
|
||||
ADC_DIGI_LOCK_ACQUIRE();
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
adc_power_acquire();
|
||||
|
||||
SAR_ADC2_LOCK_ACQUIRE();
|
||||
|
||||
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);
|
||||
|
||||
adc_hal_digi_controller_config(&dig_cfg);
|
||||
ADC_REG_LOCK_ENTER();
|
||||
adc_hal_set_atten(ADC_NUM_2, channel, atten);
|
||||
ret = adc_hal_convert(ADC_NUM_2, channel, raw_out);
|
||||
ADC_REG_LOCK_EXIT();
|
||||
|
||||
adc_hal_intr_clear(ADC_EVENT_ADC2_DONE);
|
||||
SAR_ADC2_LOCK_RELEASE();
|
||||
|
||||
adc_hal_adc2_onetime_sample_enable(true);
|
||||
adc_hal_onetime_channel(ADC_NUM_2, channel);
|
||||
adc_hal_set_onetime_atten(atten);
|
||||
|
||||
//Trigger single read.
|
||||
adc_hal_onetime_start(&dig_cfg);
|
||||
while (!adc_hal_intr_get_raw(ADC_EVENT_ADC2_DONE));
|
||||
ret = adc_hal_single_read(ADC_NUM_2, raw_out);
|
||||
|
||||
adc_hal_intr_clear(ADC_EVENT_ADC2_DONE);
|
||||
adc_hal_adc2_onetime_sample_enable(false);
|
||||
|
||||
adc_hal_digi_deinit();
|
||||
adc_power_release();
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
|
||||
ADC_DIGI_LOCK_RELEASE();
|
||||
SAC_ADC2_LOCK_RELEASE();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -551,7 +586,7 @@ esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
|
||||
s_adc_digi_ctx->use_adc1 = 0;
|
||||
s_adc_digi_ctx->use_adc2 = 0;
|
||||
for (int i = 0; i < config->adc_pattern_len; i++) {
|
||||
const adc_digi_pattern_table_t* pat = &config->adc_pattern[i];
|
||||
const adc_digi_pattern_table_t *pat = &config->adc_pattern[i];
|
||||
if (pat->unit == ADC_NUM_1) {
|
||||
s_adc_digi_ctx->use_adc1 = 1;
|
||||
|
||||
@ -575,86 +610,6 @@ esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_arbiter_config(adc_unit_t adc_unit, adc_arbiter_t *config)
|
||||
{
|
||||
if (adc_unit & ADC_UNIT_1) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_arbiter_config(config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set ADC module controller.
|
||||
* There are five SAR ADC controllers:
|
||||
* Two digital controller: Continuous conversion mode (DMA). High performance with multiple channel scan modes;
|
||||
* Two RTC controller: Single conversion modes (Polling). For low power purpose working during deep sleep;
|
||||
* the other is dedicated for Power detect (PWDET / PKDET), Only support ADC2.
|
||||
*
|
||||
* @note Only ADC2 support arbiter to switch controllers automatically. Access to the ADC is based on the priority of the controller.
|
||||
* @note For ADC1, Controller access is mutually exclusive.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param ctrl ADC controller, Refer to `adc_controller_t`.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_set_controller(adc_unit_t adc_unit, adc_controller_t ctrl)
|
||||
{
|
||||
adc_arbiter_t config = {0};
|
||||
adc_arbiter_t cfg = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
|
||||
if (adc_unit & ADC_UNIT_1) {
|
||||
adc_hal_set_controller(ADC_NUM_1, ctrl);
|
||||
}
|
||||
if (adc_unit & ADC_UNIT_2) {
|
||||
adc_hal_set_controller(ADC_NUM_2, ctrl);
|
||||
switch (ctrl) {
|
||||
case ADC2_CTRL_FORCE_PWDET:
|
||||
config.pwdet_pri = 2;
|
||||
config.mode = ADC_ARB_MODE_SHIELD;
|
||||
adc_hal_arbiter_config(&config);
|
||||
adc_hal_set_controller(ADC_NUM_2, ADC2_CTRL_PWDET);
|
||||
break;
|
||||
case ADC2_CTRL_FORCE_RTC:
|
||||
config.rtc_pri = 2;
|
||||
config.mode = ADC_ARB_MODE_SHIELD;
|
||||
adc_hal_arbiter_config(&config);
|
||||
adc_hal_set_controller(ADC_NUM_2, ADC_CTRL_RTC);
|
||||
break;
|
||||
case ADC2_CTRL_FORCE_DIG:
|
||||
config.dig_pri = 2;
|
||||
config.mode = ADC_ARB_MODE_SHIELD;
|
||||
adc_hal_arbiter_config(&config);
|
||||
adc_hal_set_controller(ADC_NUM_2, ADC_CTRL_DIG);
|
||||
break;
|
||||
default:
|
||||
adc_hal_arbiter_config(&cfg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset FSM of adc digital controller.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_reset(void)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_reset();
|
||||
adc_hal_digi_clear_pattern_table(ADC_NUM_1);
|
||||
adc_hal_digi_clear_pattern_table(ADC_NUM_2);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/* Digital controller filter setting */
|
||||
/*************************************/
|
||||
@ -712,90 +667,6 @@ esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
/* Digital controller intr setting */
|
||||
/**************************************/
|
||||
|
||||
esp_err_t adc_digi_intr_enable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (adc_unit & ADC_UNIT_1) {
|
||||
adc_hal_digi_intr_enable(ADC_NUM_1, intr_mask);
|
||||
}
|
||||
if (adc_unit & ADC_UNIT_2) {
|
||||
adc_hal_digi_intr_enable(ADC_NUM_2, intr_mask);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_intr_disable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (adc_unit & ADC_UNIT_1) {
|
||||
adc_hal_digi_intr_disable(ADC_NUM_1, intr_mask);
|
||||
}
|
||||
if (adc_unit & ADC_UNIT_2) {
|
||||
adc_hal_digi_intr_disable(ADC_NUM_2, intr_mask);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_intr_clear(adc_unit_t adc_unit, adc_digi_intr_t intr_mask)
|
||||
{
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (adc_unit & ADC_UNIT_1) {
|
||||
adc_hal_digi_intr_clear(ADC_NUM_1, intr_mask);
|
||||
}
|
||||
if (adc_unit & ADC_UNIT_2) {
|
||||
adc_hal_digi_intr_clear(ADC_NUM_2, intr_mask);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t adc_digi_intr_get_status(adc_unit_t adc_unit)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
ADC_ENTER_CRITICAL();
|
||||
if (adc_unit & ADC_UNIT_1) {
|
||||
ret = adc_hal_digi_get_intr_status(ADC_NUM_1);
|
||||
}
|
||||
if (adc_unit & ADC_UNIT_2) {
|
||||
ret = adc_hal_digi_get_intr_status(ADC_NUM_2);
|
||||
}
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool s_isr_registered = 0;
|
||||
static intr_handle_t s_adc_isr_handle = NULL;
|
||||
|
||||
esp_err_t adc_digi_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags)
|
||||
{
|
||||
ADC_CHECK((fn != NULL), "Parameter error", ESP_ERR_INVALID_ARG);
|
||||
ADC_CHECK(s_isr_registered == 0, "ADC ISR have installed, can not install again", ESP_FAIL);
|
||||
|
||||
esp_err_t ret = esp_intr_alloc(ETS_APB_ADC_INTR_SOURCE, intr_alloc_flags, fn, arg, &s_adc_isr_handle);
|
||||
if (ret == ESP_OK) {
|
||||
s_isr_registered = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t adc_digi_isr_deregister(void)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
if (s_isr_registered) {
|
||||
ret = esp_intr_free(s_adc_isr_handle);
|
||||
if (ret == ESP_OK) {
|
||||
s_isr_registered = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
RTC controller setting
|
||||
---------------------------------------------------------------*/
|
||||
|
@ -22,25 +22,6 @@ extern "C" {
|
||||
/*---------------------------------------------------------------
|
||||
Common setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Config ADC module arbiter.
|
||||
* The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority,
|
||||
* the low priority controller will read the invalid ADC2 data, and the validity of the data can be judged by the flag bit in the data.
|
||||
*
|
||||
* @note Only ADC2 support arbiter.
|
||||
* @note Default priority: Wi-Fi > RTC > Digital;
|
||||
* @note In normal use, there is no need to call this interface to config arbiter.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param config Refer to `adc_arbiter_t`.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_NOT_SUPPORTED ADC unit not support arbiter.
|
||||
*/
|
||||
esp_err_t adc_arbiter_config(adc_unit_t adc_unit, adc_arbiter_t *config);
|
||||
|
||||
/*************************************/
|
||||
/* Digital controller filter setting */
|
||||
/*************************************/
|
||||
@ -114,78 +95,6 @@ esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monit
|
||||
*/
|
||||
esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable);
|
||||
|
||||
/**************************************/
|
||||
/* Digital controller intr setting */
|
||||
/**************************************/
|
||||
|
||||
/**
|
||||
* @brief Enable interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_intr_enable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask);
|
||||
|
||||
/**
|
||||
* @brief Disable interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_intr_disable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask);
|
||||
|
||||
/**
|
||||
* @brief Clear interrupt of adc digital controller by bitmask.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t adc_digi_intr_clear(adc_unit_t adc_unit, adc_digi_intr_t intr_mask);
|
||||
|
||||
/**
|
||||
* @brief Get interrupt status mask of adc digital controller.
|
||||
*
|
||||
* @param adc_unit ADC unit.
|
||||
* @return
|
||||
* - intr Interrupt bitmask, See ``adc_digi_intr_t``.
|
||||
*/
|
||||
uint32_t adc_digi_intr_get_status(adc_unit_t adc_unit);
|
||||
|
||||
/**
|
||||
* @brief Register ADC interrupt handler, the handler is an ISR.
|
||||
* The handler will be attached to the same CPU core that this function is running on.
|
||||
*
|
||||
* @param fn Interrupt handler function.
|
||||
* @param arg Parameter for handler function
|
||||
* @param 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.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
|
||||
* - ESP_ERR_INVALID_ARG Function pointer error.
|
||||
*/
|
||||
esp_err_t adc_digi_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags);
|
||||
|
||||
/**
|
||||
* @brief Deregister ADC interrupt handler, the handler is an ISR.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG hander error.
|
||||
* - ESP_FAIL ISR not be registered.
|
||||
*/
|
||||
esp_err_t adc_digi_isr_deregister(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <esp_types.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
@ -26,6 +27,7 @@
|
||||
#include "driver/temp_sensor.h"
|
||||
#include "regi2c_ctrl.h"
|
||||
#include "esp32c3/rom/ets_sys.h"
|
||||
#include "esp32c3/esp_efuse_rtc_calib.h"
|
||||
|
||||
static const char *TAG = "tsens";
|
||||
|
||||
@ -58,6 +60,8 @@ static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = {
|
||||
{TSENS_DAC_L4, 2, 10, -40, 20, 3},
|
||||
};
|
||||
|
||||
static float s_deltaT = NAN; // unused number
|
||||
|
||||
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
{
|
||||
REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_TSENS_CLK_EN);
|
||||
@ -112,6 +116,28 @@ esp_err_t temp_sensor_read_raw(uint32_t *tsens_out)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void read_delta_t_from_efuse(void)
|
||||
{
|
||||
uint32_t version = esp_efuse_rtc_calib_get_ver();
|
||||
if (version == 1) {
|
||||
// fetch calibration value for temp sensor from eFuse
|
||||
s_deltaT = esp_efuse_rtc_calib_get_cal_temp(version);
|
||||
} else {
|
||||
// no value to fetch, use 0.
|
||||
s_deltaT = 0;
|
||||
}
|
||||
ESP_LOGD(TAG, "s_deltaT = %f", s_deltaT);
|
||||
}
|
||||
|
||||
static float parse_temp_sensor_raw_value(uint32_t tsens_raw, const int dac_offset)
|
||||
{
|
||||
if (isnan(s_deltaT)) { //suggests that the value is not initialized
|
||||
read_delta_t_from_efuse();
|
||||
}
|
||||
float result = (TSENS_ADC_FACTOR * (float)tsens_raw - TSENS_DAC_FACTOR * dac_offset - TSENS_SYS_OFFSET) - s_deltaT / 10.0;
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_read_celsius(float *celsius)
|
||||
{
|
||||
TSENS_CHECK(celsius != NULL, ESP_ERR_INVALID_ARG);
|
||||
@ -123,7 +149,7 @@ esp_err_t temp_sensor_read_celsius(float *celsius)
|
||||
printf("tsens_out %d\r\n", tsens_out);
|
||||
TSENS_CHECK(ret == ESP_OK, ret);
|
||||
const tsens_dac_offset_t *dac = &dac_offset[tsens.dac_offset];
|
||||
*celsius = (TSENS_ADC_FACTOR * (float)tsens_out - TSENS_DAC_FACTOR * dac->offset - TSENS_SYS_OFFSET);
|
||||
*celsius = parse_temp_sensor_raw_value(tsens_out, dac->offset);
|
||||
if (*celsius < dac->range_min || *celsius > dac->range_max) {
|
||||
ESP_LOGW(TAG, "Exceeding the temperature range!");
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
|
@ -89,6 +89,7 @@ esp_err_t adc_digi_deinit(void)
|
||||
s_adc_digi_arbiter_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
adc_power_release();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_deinit();
|
||||
ADC_EXIT_CRITICAL();
|
||||
@ -124,6 +125,8 @@ esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
|
||||
}
|
||||
}
|
||||
|
||||
/* If enable digtal controller, adc xpd should always on. */
|
||||
adc_power_acquire();
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_digi_controller_config(config);
|
||||
ADC_EXIT_CRITICAL();
|
||||
|
@ -13,12 +13,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "driver/touch_sensor_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "driver/touch_sensor_common.h"
|
||||
|
||||
/**
|
||||
* @brief Set touch sensor FSM start
|
||||
* @note Start FSM after the touch sensor FSM mode is set.
|
||||
@ -579,6 +579,22 @@ esp_err_t touch_pad_sleep_channel_reset_benchmark(void);
|
||||
*/
|
||||
esp_err_t touch_pad_sleep_channel_read_proximity_cnt(touch_pad_t pad_num, uint32_t *proximity_cnt);
|
||||
|
||||
/**
|
||||
* @brief Change the operating frequency of touch pad in deep sleep state. Reducing the operating frequency can effectively reduce power consumption.
|
||||
* If this function is not called, the working frequency of touch in the deep sleep state is the same as that in the wake-up state.
|
||||
*
|
||||
* @param sleep_cycle The touch sensor will sleep after each measurement.
|
||||
* sleep_cycle decide the interval between each measurement.
|
||||
* t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency).
|
||||
* The approximate frequency value of RTC_SLOW_CLK can be obtained using rtc_clk_slow_freq_get_hz function.
|
||||
* @param meas_times The times of charge and discharge in each measure process of touch channels.
|
||||
* The timer frequency is 8Mhz. Range: 0 ~ 0xffff.
|
||||
* Recommended typical value: Modify this value to make the measurement time around 1ms.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t touch_pad_sleep_channel_set_work_time(uint16_t sleep_cycle, uint16_t meas_times);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include "esp_types.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
@ -61,7 +62,7 @@ static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = {
|
||||
|
||||
static SemaphoreHandle_t rtc_tsens_mux = NULL;
|
||||
|
||||
static float deltaT = 1000; // greater than range
|
||||
static float s_deltaT = NAN; // Unused number
|
||||
|
||||
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
{
|
||||
@ -142,20 +143,20 @@ static void read_delta_t_from_efuse(void)
|
||||
uint32_t version = esp_efuse_rtc_table_read_calib_version();
|
||||
if (version == 1 || version == 2) {
|
||||
// fetch calibration value for temp sensor from eFuse
|
||||
deltaT = esp_efuse_rtc_table_get_parsed_efuse_value(RTCCALIB_IDX_TMPSENSOR, false) / 10.0;
|
||||
s_deltaT = esp_efuse_rtc_table_get_parsed_efuse_value(RTCCALIB_IDX_TMPSENSOR, false) / 10.0;
|
||||
} else {
|
||||
// no value to fetch, use 0.
|
||||
deltaT = 0;
|
||||
s_deltaT = 0;
|
||||
}
|
||||
ESP_LOGD(TAG, "deltaT = %f\n", deltaT);
|
||||
ESP_LOGD(TAG, "s_deltaT = %f\n", s_deltaT);
|
||||
}
|
||||
|
||||
static float parse_temp_sensor_raw_value(uint32_t tsens_raw, const tsens_dac_offset_t *dac)
|
||||
static float parse_temp_sensor_raw_value(uint32_t tsens_raw, const int dac_offset)
|
||||
{
|
||||
if (deltaT > 512) { //suggests that the value is not initialized
|
||||
if (isnan(s_deltaT)) { //suggests that the value is not initialized
|
||||
read_delta_t_from_efuse();
|
||||
}
|
||||
float result = (TSENS_ADC_FACTOR * (float)tsens_raw - TSENS_DAC_FACTOR * dac->offset - TSENS_SYS_OFFSET) - deltaT;
|
||||
float result = (TSENS_ADC_FACTOR * (float)tsens_raw - TSENS_DAC_FACTOR * dac_offset - TSENS_SYS_OFFSET) - s_deltaT;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -169,7 +170,7 @@ esp_err_t temp_sensor_read_celsius(float *celsius)
|
||||
ret = temp_sensor_read_raw(&tsens_out);
|
||||
TSENS_CHECK(ret == ESP_OK, ret);
|
||||
const tsens_dac_offset_t *dac = &dac_offset[tsens.dac_offset];
|
||||
*celsius = parse_temp_sensor_raw_value(tsens_out, dac);
|
||||
*celsius = parse_temp_sensor_raw_value(tsens_out, dac->offset);
|
||||
if (*celsius < dac->range_min || *celsius > dac->range_max) {
|
||||
ESP_LOGW(TAG, "Exceeding the temperature range!");
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
|
@ -629,3 +629,9 @@ esp_err_t touch_pad_sleep_channel_read_proximity_cnt(touch_pad_t pad_num, uint32
|
||||
touch_hal_sleep_read_proximity_cnt(approach_cnt);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t touch_pad_sleep_channel_set_work_time(uint16_t sleep_cycle, uint16_t meas_times)
|
||||
{
|
||||
touch_hal_sleep_channel_set_work_time(sleep_cycle, meas_times);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -577,6 +577,22 @@ esp_err_t touch_pad_sleep_channel_reset_benchmark(void);
|
||||
*/
|
||||
esp_err_t touch_pad_sleep_channel_read_proximity_cnt(touch_pad_t pad_num, uint32_t *proximity_cnt);
|
||||
|
||||
/**
|
||||
* @brief Change the operating frequency of touch pad in deep sleep state. Reducing the operating frequency can effectively reduce power consumption.
|
||||
* If this function is not called, the working frequency of touch in the deep sleep state is the same as that in the wake-up state.
|
||||
*
|
||||
* @param sleep_cycle The touch sensor will sleep after each measurement.
|
||||
* sleep_cycle decide the interval between each measurement.
|
||||
* t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency).
|
||||
* The approximate frequency value of RTC_SLOW_CLK can be obtained using rtc_clk_slow_freq_get_hz function.
|
||||
* @param meas_times The times of charge and discharge in each measure process of touch channels.
|
||||
* The timer frequency is 8Mhz. Range: 0 ~ 0xffff.
|
||||
* Recommended typical value: Modify this value to make the measurement time around 1ms.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t touch_pad_sleep_channel_set_work_time(uint16_t sleep_cycle, uint16_t meas_times);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -50,17 +50,30 @@ typedef struct gdma_channel_t gdma_channel_t;
|
||||
typedef struct gdma_tx_channel_t gdma_tx_channel_t;
|
||||
typedef struct gdma_rx_channel_t gdma_rx_channel_t;
|
||||
|
||||
/**
|
||||
* GDMA driver consists of there object class, namely: Group, Pair and Channel.
|
||||
* Channel is allocated when user calls `gdma_new_channel`, its lifecycle is maintained by user.
|
||||
* Pair and Group are all lazy allocated, their life cycles are maintained by this driver.
|
||||
* We use reference count to track their life cycles, i.e. the driver will free their memory only when their reference count reached to 0.
|
||||
*
|
||||
* We don't use an all-in-one spin lock in this driver, instead, we created different spin locks at different level.
|
||||
* For platform, it has a spinlock, which is used to protect the group handle slots and reference count of each group.
|
||||
* For group, it has a spinlock, which is used to protect group level stuffs, e.g. hal object, pair handle slots and reference count of each pair.
|
||||
* For pair, it has a sinlock, which is used to protect pair level stuffs, e.g. interrupt handle, channel handle slots, occupy code.
|
||||
*/
|
||||
|
||||
struct gdma_platform_t {
|
||||
portMUX_TYPE spinlock; // platform level spinlock
|
||||
gdma_group_t *groups[SOC_GDMA_GROUPS]; // array of GDMA group instances
|
||||
int group_ref_counts[SOC_GDMA_GROUPS]; // reference count used to protect group install/uninstall
|
||||
};
|
||||
|
||||
struct gdma_group_t {
|
||||
int group_id; // Group ID, index from 0
|
||||
gdma_hal_context_t hal; // HAL instance is at group level
|
||||
portMUX_TYPE spinlock; // group level spinlock
|
||||
int ref_count; // reference count
|
||||
gdma_pair_t *pairs[SOC_GDMA_PAIRS_PER_GROUP]; // handles of GDMA pairs
|
||||
gdma_pair_t *pairs[SOC_GDMA_PAIRS_PER_GROUP]; // handles of GDMA pairs
|
||||
int pair_ref_counts[SOC_GDMA_PAIRS_PER_GROUP]; // reference count used to protect pair install/uninstall
|
||||
};
|
||||
|
||||
struct gdma_pair_t {
|
||||
@ -71,7 +84,6 @@ struct gdma_pair_t {
|
||||
int occupy_code; // each bit indicates which channel has been occupied (an occupied channel will be skipped during channel search)
|
||||
intr_handle_t intr; // Interrupt is at pair level
|
||||
portMUX_TYPE spinlock; // pair level spinlock
|
||||
int ref_count; // reference count
|
||||
};
|
||||
|
||||
struct gdma_channel_t {
|
||||
@ -138,9 +150,9 @@ esp_err_t gdma_new_channel(const gdma_channel_alloc_config_t *config, gdma_chann
|
||||
DMA_CHECK(config->sibling_chan->direction != config->direction,
|
||||
"sibling channel should have a different direction", err, ESP_ERR_INVALID_ARG);
|
||||
group = pair->group;
|
||||
portENTER_CRITICAL(&pair->spinlock);
|
||||
pair->ref_count++; // channel obtains a reference to pair
|
||||
portEXIT_CRITICAL(&pair->spinlock);
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
group->pair_ref_counts[pair->pair_id]++; // channel obtains a reference to pair
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
goto search_done; // skip the search path below if user has specify a sibling channel
|
||||
}
|
||||
|
||||
@ -152,10 +164,14 @@ esp_err_t gdma_new_channel(const gdma_channel_alloc_config_t *config, gdma_chann
|
||||
portENTER_CRITICAL(&pair->spinlock);
|
||||
if (!(search_code & pair->occupy_code)) { // pair has suitable position for acquired channel(s)
|
||||
pair->occupy_code |= search_code;
|
||||
pair->ref_count++; // channel obtains a reference to pair
|
||||
search_code = 0; // exit search loop
|
||||
}
|
||||
portEXIT_CRITICAL(&pair->spinlock);
|
||||
if (!search_code) {
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
group->pair_ref_counts[j]++; // channel obtains a reference to pair
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
}
|
||||
}
|
||||
gdma_release_pair_handle(pair);
|
||||
} // loop used to search pair
|
||||
@ -404,26 +420,21 @@ err:
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
static inline bool gdma_is_group_busy(gdma_group_t *group)
|
||||
{
|
||||
return group->ref_count;
|
||||
}
|
||||
|
||||
static void gdma_uninstall_group(gdma_group_t *group)
|
||||
{
|
||||
int group_id = group->group_id;
|
||||
bool do_deinitialize = false;
|
||||
|
||||
if (s_platform.groups[group_id] && !gdma_is_group_busy(group)) {
|
||||
portENTER_CRITICAL(&s_platform.spinlock);
|
||||
if (s_platform.groups[group_id] && !gdma_is_group_busy(group)) {
|
||||
do_deinitialize = true;
|
||||
s_platform.groups[group_id] = NULL; // deregister from platfrom
|
||||
gdma_ll_enable_clock(group->hal.dev, false);
|
||||
periph_module_disable(gdma_periph_signals.groups[group_id].module);
|
||||
}
|
||||
portEXIT_CRITICAL(&s_platform.spinlock);
|
||||
portENTER_CRITICAL(&s_platform.spinlock);
|
||||
s_platform.group_ref_counts[group_id]--;
|
||||
if (s_platform.group_ref_counts[group_id] == 0) {
|
||||
assert(s_platform.groups[group_id]);
|
||||
do_deinitialize = true;
|
||||
s_platform.groups[group_id] = NULL; // deregister from platfrom
|
||||
gdma_ll_enable_clock(group->hal.dev, false);
|
||||
periph_module_disable(gdma_periph_signals.groups[group_id].module);
|
||||
}
|
||||
portEXIT_CRITICAL(&s_platform.spinlock);
|
||||
|
||||
if (do_deinitialize) {
|
||||
free(group);
|
||||
@ -453,7 +464,7 @@ static gdma_group_t *gdma_acquire_group_handle(int group_id)
|
||||
group = s_platform.groups[group_id];
|
||||
}
|
||||
// someone acquired the group handle means we have a new object that refer to this group
|
||||
group->ref_count++;
|
||||
s_platform.group_ref_counts[group_id]++;
|
||||
portEXIT_CRITICAL(&s_platform.spinlock);
|
||||
|
||||
if (new_group) {
|
||||
@ -468,39 +479,31 @@ out:
|
||||
static void gdma_release_group_handle(gdma_group_t *group)
|
||||
{
|
||||
if (group) {
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
group->ref_count--;
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
gdma_uninstall_group(group);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool gdma_is_pair_busy(gdma_pair_t *pair)
|
||||
{
|
||||
return pair->ref_count;
|
||||
}
|
||||
|
||||
static void gdma_uninstall_pair(gdma_pair_t *pair)
|
||||
{
|
||||
gdma_group_t *group = pair->group;
|
||||
int pair_id = pair->pair_id;
|
||||
bool do_deinitialize = false;
|
||||
|
||||
if (group->pairs[pair_id] && !gdma_is_pair_busy(pair)) {
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
if (group->pairs[pair_id] && !gdma_is_pair_busy(pair)) {
|
||||
do_deinitialize = true;
|
||||
group->pairs[pair_id] = NULL; // deregister from pair
|
||||
group->ref_count--; // decrease reference count, because this pair won't refer to the group
|
||||
if (pair->intr) {
|
||||
// disable interrupt handler (but not freed, esp_intr_free is a blocking API, we can't use it in a critical section)
|
||||
esp_intr_disable(pair->intr);
|
||||
gdma_ll_enable_interrupt(group->hal.dev, pair->pair_id, UINT32_MAX, false); // disable all interupt events
|
||||
gdma_ll_clear_interrupt_status(group->hal.dev, pair->pair_id, UINT32_MAX); // clear all pending events
|
||||
}
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
group->pair_ref_counts[pair_id]--;
|
||||
if (group->pair_ref_counts[pair_id] == 0) {
|
||||
assert(group->pairs[pair_id]);
|
||||
do_deinitialize = true;
|
||||
group->pairs[pair_id] = NULL; // deregister from pair
|
||||
if (pair->intr) {
|
||||
// disable interrupt handler (but not freed, esp_intr_free is a blocking API, we can't use it in a critical section)
|
||||
esp_intr_disable(pair->intr);
|
||||
gdma_ll_enable_interrupt(group->hal.dev, pair->pair_id, UINT32_MAX, false); // disable all interupt events
|
||||
gdma_ll_clear_interrupt_status(group->hal.dev, pair->pair_id, UINT32_MAX); // clear all pending events
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
|
||||
if (do_deinitialize) {
|
||||
if (pair->intr) {
|
||||
esp_intr_free(pair->intr); // free interrupt resource
|
||||
@ -508,6 +511,7 @@ static void gdma_uninstall_pair(gdma_pair_t *pair)
|
||||
}
|
||||
free(pair);
|
||||
ESP_LOGD(TAG, "del pair (%d,%d)", group->group_id, pair_id);
|
||||
|
||||
gdma_uninstall_group(group);
|
||||
}
|
||||
}
|
||||
@ -525,7 +529,6 @@ static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id)
|
||||
new_pair = true;
|
||||
pair = pre_alloc_pair;
|
||||
group->pairs[pair_id] = pair; // register to group
|
||||
group->ref_count++; // pair obtains a reference to group
|
||||
pair->group = group;
|
||||
pair->pair_id = pair_id;
|
||||
pair->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
@ -533,10 +536,13 @@ static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id)
|
||||
pair = group->pairs[pair_id];
|
||||
}
|
||||
// someone acquired the pair handle means we have a new object that refer to this pair
|
||||
pair->ref_count++;
|
||||
group->pair_ref_counts[pair_id]++;
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
|
||||
if (new_pair) {
|
||||
portENTER_CRITICAL(&s_platform.spinlock);
|
||||
s_platform.group_ref_counts[group->group_id]++; // pair obtains a reference to group
|
||||
portEXIT_CRITICAL(&s_platform.spinlock);
|
||||
ESP_LOGD(TAG, "new pair (%d,%d) at %p", group->group_id, pair->pair_id, pair);
|
||||
} else {
|
||||
free(pre_alloc_pair);
|
||||
@ -548,9 +554,6 @@ out:
|
||||
static void gdma_release_pair_handle(gdma_pair_t *pair)
|
||||
{
|
||||
if (pair) {
|
||||
portENTER_CRITICAL(&pair->spinlock);
|
||||
pair->ref_count--;
|
||||
portEXIT_CRITICAL(&pair->spinlock);
|
||||
gdma_uninstall_pair(pair);
|
||||
}
|
||||
}
|
||||
@ -558,16 +561,15 @@ static void gdma_release_pair_handle(gdma_pair_t *pair)
|
||||
static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel)
|
||||
{
|
||||
gdma_pair_t *pair = dma_channel->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_tx_channel_t *tx_chan = __containerof(dma_channel, gdma_tx_channel_t, base);
|
||||
portENTER_CRITICAL(&pair->spinlock);
|
||||
pair->tx_chan = NULL;
|
||||
pair->ref_count--; // decrease reference count, because this channel won't refer to the pair
|
||||
pair->occupy_code &= ~SEARCH_REQUEST_TX_CHANNEL;
|
||||
portEXIT_CRITICAL(&pair->spinlock);
|
||||
|
||||
ESP_LOGD(TAG, "del tx channel (%d,%d)", pair->group->group_id, pair->pair_id);
|
||||
ESP_LOGD(TAG, "del tx channel (%d,%d)", group->group_id, pair->pair_id);
|
||||
free(tx_chan);
|
||||
|
||||
gdma_uninstall_pair(pair);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -575,16 +577,15 @@ static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel)
|
||||
static esp_err_t gdma_del_rx_channel(gdma_channel_t *dma_channel)
|
||||
{
|
||||
gdma_pair_t *pair = dma_channel->pair;
|
||||
gdma_group_t *group = pair->group;
|
||||
gdma_rx_channel_t *rx_chan = __containerof(dma_channel, gdma_rx_channel_t, base);
|
||||
portENTER_CRITICAL(&pair->spinlock);
|
||||
pair->rx_chan = NULL;
|
||||
pair->ref_count--; // decrease reference count, because this channel won't refer to the pair
|
||||
pair->occupy_code &= ~SEARCH_REQUEST_RX_CHANNEL;
|
||||
portEXIT_CRITICAL(&pair->spinlock);
|
||||
|
||||
ESP_LOGD(TAG, "del rx channel (%d,%d)", pair->group->group_id, pair->pair_id);
|
||||
ESP_LOGD(TAG, "del rx channel (%d,%d)", group->group_id, pair->pair_id);
|
||||
free(rx_chan);
|
||||
|
||||
gdma_uninstall_pair(pair);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -391,7 +391,8 @@ esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)
|
||||
gpio_intr_disable(io_num);
|
||||
}
|
||||
|
||||
PIN_FUNC_SELECT(io_reg, PIN_FUNC_GPIO); /*function number 2 is GPIO_FUNC for each pin */
|
||||
/* By default, all the pins have to be configured as GPIO pins. */
|
||||
gpio_hal_iomux_func_sel(io_reg, PIN_FUNC_GPIO);
|
||||
}
|
||||
|
||||
io_num++;
|
||||
@ -554,11 +555,16 @@ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if ((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) {
|
||||
#if SOC_RTCIO_WAKE_SUPPORTED
|
||||
if (rtc_gpio_is_valid_gpio(gpio_num)) {
|
||||
ret = rtc_gpio_wakeup_enable(gpio_num, intr_type);
|
||||
}
|
||||
#endif
|
||||
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
gpio_hal_wakeup_enable(gpio_context.gpio_hal, gpio_num, intr_type);
|
||||
#if SOC_GPIO_SUPPORT_SLP_SWITCH && CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND
|
||||
gpio_hal_sleep_sel_dis(gpio_context.gpio_hal, gpio_num);
|
||||
#endif
|
||||
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
} else {
|
||||
ESP_LOGE(GPIO_TAG, "GPIO wakeup only supports level mode, but edge mode set. gpio_num:%u", gpio_num);
|
||||
@ -572,12 +578,16 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
#if SOC_RTCIO_WAKE_SUPPORTED
|
||||
if (rtc_gpio_is_valid_gpio(gpio_num)) {
|
||||
ret = rtc_gpio_wakeup_disable(gpio_num);
|
||||
}
|
||||
#endif
|
||||
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
gpio_hal_wakeup_disable(gpio_context.gpio_hal, gpio_num);
|
||||
#if SOC_GPIO_SUPPORT_SLP_SWITCH && CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND
|
||||
gpio_hal_sleep_sel_en(gpio_context.gpio_hal, gpio_num);
|
||||
#endif
|
||||
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
return ret;
|
||||
}
|
||||
@ -630,7 +640,9 @@ esp_err_t gpio_hold_en(gpio_num_t gpio_num)
|
||||
int ret = ESP_OK;
|
||||
|
||||
if (rtc_gpio_is_valid_gpio(gpio_num)) {
|
||||
#if SOC_RTCIO_HOLD_SUPPORTED
|
||||
ret = rtc_gpio_hold_en(gpio_num);
|
||||
#endif
|
||||
} else if (GPIO_HOLD_MASK[gpio_num]) {
|
||||
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
gpio_hal_hold_en(gpio_context.gpio_hal, gpio_num);
|
||||
@ -648,7 +660,9 @@ esp_err_t gpio_hold_dis(gpio_num_t gpio_num)
|
||||
int ret = ESP_OK;
|
||||
|
||||
if (rtc_gpio_is_valid_gpio(gpio_num)) {
|
||||
#if SOC_RTCIO_HOLD_SUPPORTED
|
||||
ret = rtc_gpio_hold_dis(gpio_num);
|
||||
#endif
|
||||
}else if (GPIO_HOLD_MASK[gpio_num]) {
|
||||
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
gpio_hal_hold_dis(gpio_context.gpio_hal, gpio_num);
|
||||
@ -678,7 +692,9 @@ void gpio_deep_sleep_hold_dis(void)
|
||||
|
||||
esp_err_t gpio_force_hold_all()
|
||||
{
|
||||
#if SOC_RTCIO_HOLD_SUPPORTED
|
||||
rtc_gpio_force_hold_all();
|
||||
#endif
|
||||
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
gpio_hal_force_hold_all(gpio_context.gpio_hal);
|
||||
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
@ -687,9 +703,11 @@ esp_err_t gpio_force_hold_all()
|
||||
|
||||
esp_err_t gpio_force_unhold_all()
|
||||
{
|
||||
#if SOC_RTCIO_HOLD_SUPPORTED
|
||||
rtc_gpio_force_hold_dis_all();
|
||||
#endif
|
||||
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
gpio_hal_force_unhold_all(gpio_context.gpio_hal);
|
||||
gpio_hal_force_unhold_all();
|
||||
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -876,5 +894,41 @@ esp_err_t gpio_sleep_pupd_config_unapply(gpio_num_t gpio_num)
|
||||
gpio_hal_sleep_pupd_config_unapply(gpio_context.gpio_hal, gpio_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
|
||||
#endif // SOC_GPIO_SUPPORT_SLP_SWITCH
|
||||
|
||||
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
|
||||
esp_err_t gpio_deep_sleep_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||
{
|
||||
if (!gpio_hal_is_valid_deepsleep_wakeup_gpio(gpio_num)) {
|
||||
ESP_LOGE(GPIO_TAG, "GPIO %d does not support deep sleep wakeup", gpio_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if ((intr_type != GPIO_INTR_LOW_LEVEL) && (intr_type != GPIO_INTR_HIGH_LEVEL)) {
|
||||
ESP_LOGE(GPIO_TAG, "GPIO wakeup only supports level mode, but edge mode set. gpio_num:%u", gpio_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
gpio_hal_deepsleep_wakeup_enable(gpio_context.gpio_hal, gpio_num, intr_type);
|
||||
#if SOC_GPIO_SUPPORT_SLP_SWITCH && CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND
|
||||
gpio_hal_sleep_sel_dis(gpio_context.gpio_hal, gpio_num);
|
||||
#endif
|
||||
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gpio_deep_sleep_wakeup_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
if (!gpio_hal_is_valid_deepsleep_wakeup_gpio(gpio_num)) {
|
||||
ESP_LOGE(GPIO_TAG, "GPIO %d does not support deep sleep wakeup", gpio_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
gpio_hal_deepsleep_wakeup_disable(gpio_context.gpio_hal, gpio_num);
|
||||
#if SOC_GPIO_SUPPORT_SLP_SWITCH && CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND
|
||||
gpio_hal_sleep_sel_en(gpio_context.gpio_hal, gpio_num);
|
||||
#endif
|
||||
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "esp_pm.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "hal/i2c_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "soc/i2c_periph.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
@ -831,7 +832,7 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, bool s
|
||||
scl_in_sig = i2c_periph_signal[i2c_num].scl_in_sig;
|
||||
if (sda_io_num >= 0) {
|
||||
gpio_set_level(sda_io_num, I2C_IO_INIT_LEVEL);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(sda_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
|
||||
if (sda_pullup_en == GPIO_PULLUP_ENABLE) {
|
||||
@ -844,7 +845,7 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, bool s
|
||||
}
|
||||
if (scl_io_num >= 0) {
|
||||
gpio_set_level(scl_io_num, I2C_IO_INIT_LEVEL);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[scl_io_num], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[scl_io_num], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(scl_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
esp_rom_gpio_connect_out_signal(scl_io_num, scl_out_sig, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(scl_io_num, scl_in_sig, 0);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "soc/lldesc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#if SOC_I2S_SUPPORTS_ADC_DAC
|
||||
#include "driver/dac.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
@ -118,7 +119,7 @@ static inline void gpio_matrix_out_check(int gpio, uint32_t signal_idx, bool out
|
||||
{
|
||||
//if pin = -1, do not need to configure
|
||||
if (gpio != -1) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(gpio, signal_idx, out_inv, oen_inv);
|
||||
}
|
||||
@ -127,7 +128,7 @@ static inline void gpio_matrix_out_check(int gpio, uint32_t signal_idx, bool out
|
||||
static inline void gpio_matrix_in_check(int gpio, uint32_t signal_idx, bool inv)
|
||||
{
|
||||
if (gpio != -1) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
//Set direction, for some GPIOs, the input function are not enabled as default.
|
||||
gpio_set_direction(gpio, GPIO_MODE_INPUT);
|
||||
esp_rom_gpio_connect_in_signal(gpio, signal_idx, inv);
|
||||
|
@ -60,7 +60,7 @@ typedef enum {
|
||||
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO1 */
|
||||
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO2 */
|
||||
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO3 */
|
||||
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO34 */
|
||||
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO4 */
|
||||
ADC1_CHANNEL_MAX,
|
||||
} adc1_channel_t;
|
||||
#endif // CONFIG_IDF_TARGET_*
|
||||
@ -137,9 +137,8 @@ typedef enum {
|
||||
typedef struct adc_digi_init_config_s {
|
||||
uint32_t max_store_buf_size; ///< Max length of the converted data that driver can store before they are processed. When this length is reached, driver will dump out all the old data and start to store them again.
|
||||
uint32_t conv_num_each_intr; ///< Bytes of data that can be converted in 1 interrupt.
|
||||
uint32_t dma_chan; ///< DMA channel.
|
||||
uint16_t adc1_chan_mask; ///< Channel list of ADC1 to be initialized.
|
||||
uint16_t adc2_chan_mask; ///< Channel list of ADC2 to be initialized.
|
||||
uint32_t adc1_chan_mask; ///< Channel list of ADC1 to be initialized.
|
||||
uint32_t adc2_chan_mask; ///< Channel list of ADC2 to be initialized.
|
||||
} adc_digi_init_config_t;
|
||||
#endif
|
||||
|
||||
@ -176,6 +175,7 @@ void adc_power_acquire(void);
|
||||
*/
|
||||
void adc_power_release(void);
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32C3
|
||||
/**
|
||||
* @brief Initialize ADC pad
|
||||
* @param adc_unit ADC unit index
|
||||
@ -185,11 +185,11 @@ void adc_power_release(void);
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel);
|
||||
#endif //#if !CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
RTC controller setting
|
||||
ADC Single Read Setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Get the GPIO number of a specific ADC1 channel.
|
||||
*
|
||||
@ -284,6 +284,7 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit);
|
||||
*/
|
||||
int adc1_get_raw(adc1_channel_t channel);
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32C3
|
||||
/**
|
||||
* @brief Set ADC data invert
|
||||
* @param adc_unit ADC unit index
|
||||
@ -324,6 +325,7 @@ esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit);
|
||||
* to be called to configure ADC1 channels, before ADC1 is used by the ULP.
|
||||
*/
|
||||
void adc1_ulp_enable(void);
|
||||
#endif //#if !CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
/**
|
||||
* @brief Get the GPIO number of a specific ADC2 channel.
|
||||
@ -450,6 +452,7 @@ esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio);
|
||||
* - ESP_ERR_INVALID_ARG: Unsupported GPIO
|
||||
*/
|
||||
esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) __attribute__((deprecated));
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital controller setting
|
||||
---------------------------------------------------------------*/
|
||||
@ -490,7 +493,7 @@ esp_err_t adc_digi_controller_config(const adc_digi_config_t *config);
|
||||
/**
|
||||
* @brief Initialize the Digital ADC.
|
||||
*
|
||||
* @param init_config Pointer to Digital ADC initilisation config. Refer to ``adc_digi_init_config_t``.
|
||||
* @param init_config Pointer to Digital ADC initilization config. Refer to ``adc_digi_init_config_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
|
||||
|
@ -516,6 +516,38 @@ esp_err_t gpio_sleep_pupd_config_unapply(gpio_num_t gpio_num);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
|
||||
|
||||
#define GPIO_IS_DEEP_SLEEP_WAKEUP_VALID_GPIO(gpio_num) ((gpio_num & ~SOC_GPIO_DEEP_SLEEP_WAKEUP_VALID_GPIO_MASK) == 0)
|
||||
|
||||
/**
|
||||
* @brief Enable GPIO deep-sleep wake-up function.
|
||||
*
|
||||
* @param gpio_num GPIO number.
|
||||
*
|
||||
* @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used.
|
||||
*
|
||||
* @note Called by the SDK. User shouldn't call this directly in the APP.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t gpio_deep_sleep_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
|
||||
|
||||
/**
|
||||
* @brief Disable GPIO deep-sleep wake-up function.
|
||||
*
|
||||
* @param gpio_num GPIO number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t gpio_deep_sleep_wakeup_disable(gpio_num_t gpio_num);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -28,6 +28,12 @@ extern "C" {
|
||||
/// Handle representing an SD SPI device
|
||||
typedef int sdspi_dev_handle_t;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#define SDSPI_DEFAULT_HOST HSPI_HOST
|
||||
#else
|
||||
#define SDSPI_DEFAULT_HOST SPI2_HOST
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default sdmmc_host_t structure initializer for SD over SPI driver
|
||||
*
|
||||
@ -37,7 +43,7 @@ typedef int sdspi_dev_handle_t;
|
||||
*/
|
||||
#define SDSPI_HOST_DEFAULT() {\
|
||||
.flags = SDMMC_HOST_FLAG_SPI | SDMMC_HOST_FLAG_DEINIT_ARG, \
|
||||
.slot = HSPI_HOST, \
|
||||
.slot = SDSPI_DEFAULT_HOST, \
|
||||
.max_freq_khz = SDMMC_FREQ_DEFAULT, \
|
||||
.io_voltage = 3.3f, \
|
||||
.init = &sdspi_host_init, \
|
||||
@ -71,7 +77,7 @@ typedef struct {
|
||||
* Macro defining default configuration of SD SPI device.
|
||||
*/
|
||||
#define SDSPI_DEVICE_CONFIG_DEFAULT() {\
|
||||
.host_id = HSPI_HOST, \
|
||||
.host_id = SDSPI_DEFAULT_HOST, \
|
||||
.gpio_cs = GPIO_NUM_13, \
|
||||
.gpio_cd = SDSPI_SLOT_NO_CD, \
|
||||
.gpio_wp = SDSPI_SLOT_NO_WP, \
|
||||
@ -228,7 +234,7 @@ typedef struct {
|
||||
*
|
||||
* @note The SDIO over sdspi needs an extra interrupt line. Call ``gpio_install_isr_service()`` before this function.
|
||||
*
|
||||
* @param slot SPI controller to use (HSPI_HOST or VSPI_HOST)
|
||||
* @param slot SPI controller to use (SPI2_HOST or SPI3_HOST)
|
||||
* @param slot_config pointer to slot configuration structure
|
||||
|
||||
* @deprecated Use `sdspi_host_init_device` instead.
|
||||
|
@ -72,6 +72,24 @@ extern "C"
|
||||
|
||||
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
|
||||
|
||||
/**
|
||||
* @brief SPI DMA channels
|
||||
*/
|
||||
typedef enum {
|
||||
SPI_DMA_DISABLED = 0, ///< Do not enable DMA for SPI
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
SPI_DMA_CH1 = 1, ///< Enable DMA, select DMA Channel 1
|
||||
SPI_DMA_CH2 = 2, ///< Enable DMA, select DMA Channel 2
|
||||
#endif
|
||||
SPI_DMA_CH_AUTO = 3, ///< Enable DMA, channel is automatically selected by driver
|
||||
} spi_common_dma_t;
|
||||
|
||||
#if __cplusplus
|
||||
/* Needed for C++ backwards compatibility with earlier ESP-IDF where this argument is a bare 'int'. Can be removed in ESP-IDF 5 */
|
||||
typedef int spi_dma_chan_t;
|
||||
#else
|
||||
typedef spi_common_dma_t spi_dma_chan_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This is a configuration structure for a SPI bus.
|
||||
@ -101,15 +119,14 @@ typedef struct {
|
||||
/**
|
||||
* @brief Initialize a SPI bus
|
||||
*
|
||||
* @warning For now, only supports HSPI and VSPI.
|
||||
* @warning SPI0/1 is not supported
|
||||
*
|
||||
* @param host_id SPI peripheral that controls this bus
|
||||
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
|
||||
* @param dma_chan Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel
|
||||
* for a SPI bus allows transfers on the bus to have sizes only limited by the amount of
|
||||
* internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of
|
||||
* bytes transfered to a maximum of 64. Set to 0 if only the SPI flash uses
|
||||
* this bus.
|
||||
* @param host_id SPI peripheral that controls this bus
|
||||
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
|
||||
* @param dma_chan - Selecting a DMA channel for an SPI bus allows transactions on the bus with size only limited by the amount of internal memory.
|
||||
* - Selecting SPI_DMA_DISABLED limits the size of transactions.
|
||||
* - Set to SPI_DMA_DISABLED if only the SPI flash uses this bus.
|
||||
* - Set to SPI_DMA_CH_AUTO to let the driver to allocate the DMA channel.
|
||||
*
|
||||
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
|
||||
* DMA-capable memory.
|
||||
@ -121,10 +138,11 @@ typedef struct {
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if configuration is invalid
|
||||
* - ESP_ERR_INVALID_STATE if host already is in use
|
||||
* - ESP_ERR_NOT_FOUND if there is no available DMA channel
|
||||
* - ESP_ERR_NO_MEM if out of memory
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, int dma_chan);
|
||||
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Free a SPI bus
|
||||
|
@ -65,7 +65,9 @@ typedef struct {
|
||||
spi_bus_config_t bus_cfg; ///< Config used to initialize the bus
|
||||
uint32_t flags; ///< Flags (attributes) of the bus
|
||||
int max_transfer_sz; ///< Maximum length of bytes available to send
|
||||
int dma_chan; ///< DMA channel used
|
||||
bool dma_enabled; ///< To enable DMA or not
|
||||
int tx_dma_chan; ///< TX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same
|
||||
int rx_dma_chan; ///< RX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same
|
||||
int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx.
|
||||
lldesc_t *dmadesc_tx; ///< DMA descriptor array for TX
|
||||
lldesc_t *dmadesc_rx; ///< DMA descriptor array for RX
|
||||
@ -116,47 +118,29 @@ bool spicommon_periph_in_use(spi_host_device_t host);
|
||||
bool spicommon_periph_free(spi_host_device_t host);
|
||||
|
||||
/**
|
||||
* @brief Try to claim a SPI DMA channel
|
||||
* @brief Alloc DMA for SPI Slave
|
||||
*
|
||||
* Call this if your driver wants to use SPI with a DMA channnel.
|
||||
* @param host_id SPI host ID
|
||||
* @param dma_chan DMA channel to be used
|
||||
* @param[out] out_actual_tx_dma_chan Actual TX DMA channel (if you choose to assign a specific DMA channel, this will be the channel you assigned before)
|
||||
* @param[out] out_actual_rx_dma_chan Actual RX DMA channel (if you choose to assign a specific DMA channel, this will be the channel you assigned before)
|
||||
*
|
||||
* @param dma_chan channel to claim
|
||||
*
|
||||
* @note This public API is deprecated.
|
||||
*
|
||||
* @return True if success; false otherwise.
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
* - ESP_ERR_NO_MEM: No enough memory
|
||||
* - ESP_ERR_NOT_FOUND: There is no available DMA channel
|
||||
*/
|
||||
bool spicommon_dma_chan_claim(int dma_chan);
|
||||
esp_err_t spicommon_slave_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Check whether the spi DMA channel is in use.
|
||||
* @brief Free DMA for SPI Slave
|
||||
*
|
||||
* @param dma_chan DMA channel to check.
|
||||
* @param host_id SPI host ID
|
||||
*
|
||||
* @note This public API is deprecated.
|
||||
*
|
||||
* @return True if in use, otherwise false.
|
||||
* @return
|
||||
* - ESP_OK: On success
|
||||
*/
|
||||
bool spicommon_dma_chan_in_use(int dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA.
|
||||
*
|
||||
* @param dma_chan channel to return
|
||||
*
|
||||
* @note This public API is deprecated.
|
||||
*
|
||||
* @return True if success; false otherwise.
|
||||
*/
|
||||
bool spicommon_dma_chan_free(int dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Connect SPI and DMA peripherals
|
||||
*
|
||||
* @param host SPI peripheral
|
||||
* @param dma_chan DMA channel
|
||||
*/
|
||||
void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan);
|
||||
esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id);
|
||||
|
||||
/**
|
||||
* @brief Connect a SPI peripheral to GPIO pins
|
||||
@ -170,7 +154,6 @@ void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan);
|
||||
*
|
||||
* @param host SPI peripheral to be routed
|
||||
* @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins
|
||||
* @param dma_chan DMA-channel (1 or 2) to use, or 0 for no DMA.
|
||||
* @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions:
|
||||
* - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode
|
||||
* - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode
|
||||
@ -192,7 +175,7 @@ void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan);
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, uint32_t flags, uint32_t *flags_o);
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Free the IO used by a SPI peripheral
|
||||
|
@ -88,14 +88,15 @@ struct spi_slave_transaction_t {
|
||||
/**
|
||||
* @brief Initialize a SPI bus as a slave interface
|
||||
*
|
||||
* @warning For now, only supports HSPI and VSPI.
|
||||
* @warning SPI0/1 is not supported
|
||||
*
|
||||
* @param host SPI peripheral to use as a SPI slave interface
|
||||
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
|
||||
* @param slave_config Pointer to a spi_slave_interface_config_t struct specifying the details for the slave interface
|
||||
* @param dma_chan Either 1 or 2. A SPI bus used by this driver must have a DMA channel associated with
|
||||
* it. The SPI hardware has two DMA channels to share. This parameter indicates which
|
||||
* one to use.
|
||||
* @param host SPI peripheral to use as a SPI slave interface
|
||||
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
|
||||
* @param slave_config Pointer to a spi_slave_interface_config_t struct specifying the details for the slave interface
|
||||
* @param dma_chan - Selecting a DMA channel for an SPI bus allows transactions on the bus with size only limited by the amount of internal memory.
|
||||
* - Selecting SPI_DMA_DISABLED limits the size of transactions.
|
||||
* - Set to SPI_DMA_DISABLED if only the SPI flash uses this bus.
|
||||
* - Set to SPI_DMA_CH_AUTO to let the driver to allocate the DMA channel.
|
||||
*
|
||||
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
|
||||
* DMA-capable memory.
|
||||
@ -107,10 +108,11 @@ struct spi_slave_transaction_t {
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if configuration is invalid
|
||||
* - ESP_ERR_INVALID_STATE if host already is in use
|
||||
* - ESP_ERR_NOT_FOUND if there is no available DMA channel
|
||||
* - ESP_ERR_NO_MEM if out of memory
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, int dma_chan);
|
||||
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, spi_dma_chan_t dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Free a SPI bus claimed as a SPI slave interface
|
||||
|
@ -86,7 +86,7 @@ typedef struct {
|
||||
uint32_t address_bits; ///< address field bits, multiples of 8 and at least 8.
|
||||
uint32_t dummy_bits; ///< dummy field bits, multiples of 8 and at least 8.
|
||||
uint32_t queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_slave_hd_queue_trans but not yet finished using spi_slave_hd_get_trans_result) at the same time
|
||||
uint32_t dma_chan; ///< DMA channel used
|
||||
spi_dma_chan_t dma_chan; ///< DMA channel to used.
|
||||
spi_slave_hd_callback_config_t cb_config; ///< Callback configuration
|
||||
} spi_slave_hd_slot_config_t;
|
||||
|
||||
@ -97,10 +97,11 @@ typedef struct {
|
||||
* @param bus_config Bus configuration for the bus used
|
||||
* @param config Configuration for the SPI Slave HD driver
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_INVALID_ARG: invalid argument given
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_INVALID_ARG: invalid argument given
|
||||
* - ESP_ERR_INVALID_STATE: function called in invalid state, may be some resources are already in use
|
||||
* - ESP_ERR_NO_MEM: memory allocation failed
|
||||
* - ESP_ERR_NOT_FOUND if there is no available DMA channel
|
||||
* - ESP_ERR_NO_MEM: memory allocation failed
|
||||
* - or other return value from `esp_intr_alloc`
|
||||
*/
|
||||
esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config,
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/ledc_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_sys.h"
|
||||
@ -355,7 +356,7 @@ esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc
|
||||
LEDC_ARG_CHECK(ledc_channel < LEDC_CHANNEL_MAX, "ledc_channel");
|
||||
LEDC_ARG_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "gpio_num");
|
||||
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(gpio_num, ledc_periph_signal[speed_mode].sig_out0_idx + ledc_channel, 0, 0);
|
||||
return ESP_OK;
|
||||
@ -402,7 +403,7 @@ esp_err_t ledc_channel_config(const ledc_channel_config_t* ledc_conf)
|
||||
ledc_channel, gpio_num, duty, timer_select
|
||||
);
|
||||
/*set LEDC signal in gpio matrix*/
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(gpio_num, ledc_periph_signal[speed_mode].sig_out0_idx + ledc_channel, 0, 0);
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/mcpwm_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
typedef struct {
|
||||
@ -109,7 +110,7 @@ esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal,
|
||||
MCPWM_CHECK((GPIO_IS_VALID_GPIO(gpio_num)), MCPWM_GPIO_ERROR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
periph_module_enable(PERIPH_PWM0_MODULE + mcpwm_num);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
bool mcpwm_gpio_sig = (io_signal <= MCPWM2B);
|
||||
if (mcpwm_num == MCPWM_UNIT_0) {
|
||||
if (mcpwm_gpio_sig) {
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "driver/pcnt.h"
|
||||
#include "hal/pcnt_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
#define PCNT_CHANNEL_ERR_STR "PCNT CHANNEL ERROR"
|
||||
@ -85,14 +86,14 @@ static inline esp_err_t _pcnt_set_pin(pcnt_port_t pcnt_port, pcnt_unit_t unit, p
|
||||
PCNT_CHECK(GPIO_IS_VALID_GPIO(ctrl_io) || ctrl_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
if (pulse_io >= 0) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pulse_io], PIN_FUNC_GPIO);
|
||||
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);
|
||||
}
|
||||
|
||||
if (ctrl_io >= 0) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[ctrl_io], PIN_FUNC_GPIO);
|
||||
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);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/rmt_hal.h"
|
||||
#include "hal/rmt_ll.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
#define RMT_CHANNEL_ERROR_STR "RMT CHANNEL ERR"
|
||||
@ -534,7 +535,7 @@ esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_nu
|
||||
(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) && (mode == RMT_MODE_TX))),
|
||||
RMT_GPIO_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
if (mode == RMT_MODE_TX) {
|
||||
RMT_CHECK(RMT_IS_TX_CHANNEL(channel), RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "driver/rtc_io.h"
|
||||
#include "hal/rtc_io_hal.h"
|
||||
|
||||
static const char *RTCIO_TAG = "RTCIO";
|
||||
static const char __attribute__((__unused__)) *RTCIO_TAG = "RTCIO";
|
||||
|
||||
#define RTCIO_CHECK(a, str, ret_val) ({ \
|
||||
if (!(a)) { \
|
||||
@ -164,29 +164,19 @@ esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num)
|
||||
|
||||
esp_err_t rtc_gpio_hold_en(gpio_num_t gpio_num)
|
||||
{
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3 // should use HAL here, TODO ESP32-C3 IDF-2511
|
||||
RTCIO_CHECK(gpio_num <= GPIO_NUM_5, "RTCIO number error", ESP_ERR_INVALID_ARG);
|
||||
REG_SET_BIT(RTC_CNTL_PAD_HOLD_REG, BIT(gpio_num));
|
||||
#else
|
||||
RTCIO_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTCIO number error", ESP_ERR_INVALID_ARG);
|
||||
RTCIO_ENTER_CRITICAL();
|
||||
rtcio_hal_hold_enable(rtc_io_number_get(gpio_num));
|
||||
RTCIO_EXIT_CRITICAL();
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rtc_gpio_hold_dis(gpio_num_t gpio_num)
|
||||
{
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3 // should use HAL here, TODO ESP32-C3 IDF-2511
|
||||
RTCIO_CHECK(gpio_num <= GPIO_NUM_5, "RTCIO number error", ESP_ERR_INVALID_ARG);
|
||||
REG_CLR_BIT(RTC_CNTL_PAD_HOLD_REG, BIT(gpio_num));
|
||||
#else
|
||||
RTCIO_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTCIO number error", ESP_ERR_INVALID_ARG);
|
||||
RTCIO_ENTER_CRITICAL();
|
||||
rtcio_hal_hold_disable(rtc_io_number_get(gpio_num));
|
||||
RTCIO_EXIT_CRITICAL();
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -224,16 +214,6 @@ esp_err_t rtc_gpio_force_hold_dis_all(void)
|
||||
|
||||
esp_err_t rtc_gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||
{
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3 // should use HAL here, TODO ESP32-C3 IDF-2511
|
||||
RTCIO_CHECK(gpio_num <= GPIO_NUM_5, "RTCIO number error", ESP_ERR_INVALID_ARG);
|
||||
REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_PIN0_WAKEUP_ENABLE_M >> gpio_num);
|
||||
|
||||
uint32_t reg = REG_READ(RTC_CNTL_GPIO_WAKEUP_REG);
|
||||
reg &= (~(RTC_CNTL_GPIO_PIN0_INT_TYPE_V << (RTC_CNTL_GPIO_PIN0_INT_TYPE_S - gpio_num * 3)));
|
||||
reg |= (intr_type << (RTC_CNTL_GPIO_PIN0_INT_TYPE_S - gpio_num * 3));
|
||||
REG_WRITE(RTC_CNTL_GPIO_WAKEUP_REG, reg);
|
||||
ESP_LOGD(RTCIO_TAG, "gpio wake up 0x%08x", REG_READ(RTC_CNTL_GPIO_WAKEUP_REG));
|
||||
#else
|
||||
RTCIO_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTCIO number error", ESP_ERR_INVALID_ARG);
|
||||
if (intr_type == GPIO_INTR_POSEDGE || intr_type == GPIO_INTR_NEGEDGE || intr_type == GPIO_INTR_ANYEDGE) {
|
||||
return ESP_ERR_INVALID_ARG; // Dont support this mode.
|
||||
@ -241,21 +221,15 @@ esp_err_t rtc_gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||
RTCIO_ENTER_CRITICAL();
|
||||
rtcio_hal_wakeup_enable(rtc_io_number_get(gpio_num), intr_type);
|
||||
RTCIO_EXIT_CRITICAL();
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rtc_gpio_wakeup_disable(gpio_num_t gpio_num)
|
||||
{
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3 // should use HAL here, TODO ESP32-C3 IDF-2511
|
||||
RTCIO_CHECK(gpio_num <= GPIO_NUM_5, "RTCIO number error", ESP_ERR_INVALID_ARG);
|
||||
REG_CLR_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_PIN0_WAKEUP_ENABLE_M >> gpio_num);
|
||||
#else
|
||||
RTCIO_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTCIO number error", ESP_ERR_INVALID_ARG);
|
||||
RTCIO_ENTER_CRITICAL();
|
||||
rtcio_hal_wakeup_disable(rtc_io_number_get(gpio_num));
|
||||
RTCIO_EXIT_CRITICAL();
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,7 @@ The driver of FIFOs works as below:
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/sdio_slave_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
|
||||
|
||||
#define SDIO_SLAVE_CHECK(res, str, ret_val) do { if(!(res)){\
|
||||
@ -280,7 +281,7 @@ static void configure_pin(int pin, uint32_t func, bool pullup)
|
||||
assert(reg != UINT32_MAX);
|
||||
|
||||
PIN_INPUT_ENABLE(reg);
|
||||
PIN_FUNC_SELECT(reg, sdmmc_func);
|
||||
gpio_hal_iomux_func_sel(reg, sdmmc_func);
|
||||
PIN_SET_DRV(reg, drive_strength);
|
||||
gpio_pulldown_dis(pin);
|
||||
if (pullup) {
|
||||
@ -322,7 +323,7 @@ static void recover_pin(int pin, int sdio_func)
|
||||
int func = REG_GET_FIELD(reg, MCU_SEL);
|
||||
if (func == sdio_func) {
|
||||
gpio_set_direction(pin, GPIO_MODE_INPUT);
|
||||
PIN_FUNC_SELECT(reg, PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(reg, PIN_FUNC_GPIO);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "soc/sdmmc_periph.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
|
||||
#define SDMMC_EVENT_QUEUE_LENGTH 32
|
||||
|
||||
@ -303,7 +304,7 @@ static void configure_pin(int pin)
|
||||
uint32_t reg = GPIO_PIN_MUX_REG[pin];
|
||||
assert(reg != UINT32_MAX);
|
||||
PIN_INPUT_ENABLE(reg);
|
||||
PIN_FUNC_SELECT(reg, sdmmc_func);
|
||||
gpio_hal_iomux_func_sel(reg, sdmmc_func);
|
||||
PIN_SET_DRV(reg, drive_strength);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "driver/sigmadelta.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "hal/sigmadelta_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
static const char *TAG = "sigma-delta";
|
||||
@ -57,7 +58,7 @@ static inline esp_err_t _sigmadelta_set_pin(sigmadelta_port_t sigmadelta_port, s
|
||||
{
|
||||
SIGMADELTA_OBJ_CHECK(sigmadelta_port);
|
||||
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(gpio_num, sigma_delta_periph_signals.channels[channel].sd_sig, 0, 0);
|
||||
return ESP_OK;
|
||||
|
@ -30,22 +30,13 @@
|
||||
#include "driver/spi_common_internal.h"
|
||||
#include "stdatomic.h"
|
||||
#include "hal/spi_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "soc/dport_reg.h"
|
||||
#endif
|
||||
|
||||
//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
#include "hal/gdma_ll.h"
|
||||
#include "soc/gdma_channel.h"
|
||||
#include "soc/spi_caps.h"
|
||||
|
||||
#define spi_dma_set_rx_channel_priority(gdma_chan, priority) gdma_ll_rx_set_priority(&GDMA, gdma_chan, priority);
|
||||
#define spi_dma_set_tx_channel_priority(gdma_chan, priority) gdma_ll_tx_set_priority(&GDMA, gdma_chan, priority);
|
||||
#define spi_dma_connect_rx_channel_to_periph(gdma_chan, periph_id) gdma_ll_rx_connect_to_periph(&GDMA, gdma_chan, periph_id);
|
||||
#define spi_dma_connect_tx_channel_to_periph(gdma_chan, periph_id) gdma_ll_tx_connect_to_periph(&GDMA, gdma_chan, periph_id);
|
||||
#include "esp_private/gdma.h"
|
||||
#endif
|
||||
|
||||
static const char *SPI_TAG = "spi";
|
||||
@ -63,44 +54,61 @@ static const char *SPI_TAG = "spi";
|
||||
SPI_CHECK(GPIO_IS_VALID_GPIO(pin_num), pin_name" not valid", ESP_ERR_INVALID_ARG); \
|
||||
}
|
||||
|
||||
|
||||
typedef struct spi_device_t spi_device_t;
|
||||
#define SPI_MAIN_BUS_DEFAULT() { \
|
||||
.host_id = 0, \
|
||||
.bus_attr = { \
|
||||
.tx_dma_chan = 0, \
|
||||
.rx_dma_chan = 0, \
|
||||
.max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, \
|
||||
.dma_desc_num= 0, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define FUNC_GPIO PIN_FUNC_GPIO
|
||||
|
||||
#define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1))
|
||||
|
||||
|
||||
typedef struct {
|
||||
int host_id;
|
||||
spi_destroy_func_t destroy_func;
|
||||
void* destroy_arg;
|
||||
spi_bus_attr_t bus_attr;
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
gdma_channel_handle_t tx_channel;
|
||||
gdma_channel_handle_t rx_channel;
|
||||
#endif
|
||||
} spicommon_bus_context_t;
|
||||
|
||||
#define MAIN_BUS_DEFAULT() { \
|
||||
.host_id = 0, \
|
||||
.bus_attr = { \
|
||||
.dma_chan = 0, \
|
||||
.max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, \
|
||||
.dma_desc_num= 0, \
|
||||
}, \
|
||||
}
|
||||
|
||||
//Periph 1 is 'claimed' by SPI flash code.
|
||||
static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), ATOMIC_VAR_INIT(false),
|
||||
#if SOC_SPI_PERIPH_NUM >= 4
|
||||
ATOMIC_VAR_INIT(false),
|
||||
static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false),
|
||||
#if (SOC_SPI_PERIPH_NUM >= 3)
|
||||
ATOMIC_VAR_INIT(false),
|
||||
#endif
|
||||
#if (SOC_SPI_PERIPH_NUM >= 4)
|
||||
ATOMIC_VAR_INIT(false),
|
||||
#endif
|
||||
};
|
||||
static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
|
||||
static uint8_t spi_dma_chan_enabled = 0;
|
||||
static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static spicommon_bus_context_t s_mainbus = MAIN_BUS_DEFAULT();
|
||||
static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
|
||||
static spicommon_bus_context_t s_mainbus = SPI_MAIN_BUS_DEFAULT();
|
||||
static spicommon_bus_context_t* bus_ctx[SOC_SPI_PERIPH_NUM] = {&s_mainbus};
|
||||
|
||||
#if !SOC_GDMA_SUPPORTED
|
||||
//Each bit stands for 1 dma channel, BIT(0) should be used for SPI1
|
||||
static uint8_t spi_dma_chan_enabled = 0;
|
||||
static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#endif //#if !SOC_GDMA_SUPPORTED
|
||||
|
||||
|
||||
static inline bool is_valid_host(spi_host_device_t host)
|
||||
{
|
||||
#if (SOC_SPI_PERIPH_NUM == 2)
|
||||
return host >= SPI1_HOST && host <= SPI2_HOST;
|
||||
#elif (SOC_SPI_PERIPH_NUM == 3)
|
||||
return host >= SPI1_HOST && host <= SPI3_HOST;
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------alloc spi periph-------------------------------------------------------//
|
||||
//Returns true if this peripheral is successfully claimed, false if otherwise.
|
||||
bool spicommon_periph_claim(spi_host_device_t host, const char* source)
|
||||
{
|
||||
@ -139,90 +147,217 @@ int spicommon_irqdma_source_for_host(spi_host_device_t host)
|
||||
return spi_periph_signal[host].irq_dma;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------alloc dma periph-------------------------------------------------------//
|
||||
#if !SOC_GDMA_SUPPORTED
|
||||
static inline periph_module_t get_dma_periph(int dma_chan)
|
||||
{
|
||||
assert(dma_chan >= 1 && dma_chan <= SOC_SPI_DMA_CHAN_NUM);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if (dma_chan == 1) {
|
||||
return PERIPH_SPI2_DMA_MODULE;
|
||||
} else if (dma_chan==2) {
|
||||
} else if (dma_chan == 2) {
|
||||
return PERIPH_SPI3_DMA_MODULE;
|
||||
} else {
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
return PERIPH_SPI_DMA_MODULE;
|
||||
#elif SOC_GDMA_SUPPORTED
|
||||
return PERIPH_GDMA_MODULE;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool spicommon_dma_chan_claim(int dma_chan)
|
||||
static bool spicommon_dma_chan_claim(int dma_chan, uint32_t *out_actual_dma_chan)
|
||||
{
|
||||
bool ret = false;
|
||||
assert(dma_chan >= 1 && dma_chan <= SOC_SPI_DMA_CHAN_NUM);
|
||||
|
||||
portENTER_CRITICAL(&spi_dma_spinlock);
|
||||
if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) {
|
||||
// get the channel only when it's not claimed yet.
|
||||
spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan);
|
||||
bool is_used = (BIT(dma_chan) & spi_dma_chan_enabled);
|
||||
if (!is_used) {
|
||||
spi_dma_chan_enabled |= BIT(dma_chan);
|
||||
periph_module_enable(get_dma_periph(dma_chan));
|
||||
*out_actual_dma_chan = dma_chan;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
periph_module_enable(get_dma_periph(dma_chan));
|
||||
portEXIT_CRITICAL(&spi_dma_spinlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool spicommon_dma_chan_in_use(int dma_chan)
|
||||
{
|
||||
assert(dma_chan ==1 || dma_chan == 2);
|
||||
return spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan);
|
||||
}
|
||||
|
||||
bool spicommon_dma_chan_free(int dma_chan)
|
||||
{
|
||||
assert( dma_chan == 1 || dma_chan == 2 );
|
||||
assert( spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan) );
|
||||
|
||||
portENTER_CRITICAL(&spi_dma_spinlock);
|
||||
spi_dma_chan_enabled &= ~DMA_CHANNEL_ENABLED(dma_chan);
|
||||
periph_module_disable(get_dma_periph(dma_chan));
|
||||
portEXIT_CRITICAL(&spi_dma_spinlock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan)
|
||||
static void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
//On ESP32S2, each SPI controller has its own DMA channel. So there is no need to connect them.
|
||||
#elif SOC_GDMA_SUPPORTED
|
||||
int gdma_chan, periph_id;
|
||||
if (dma_chan == 1) {
|
||||
gdma_chan = SOC_GDMA_SPI2_DMA_CHANNEL;
|
||||
periph_id = SOC_GDMA_TRIG_PERIPH_SPI2;
|
||||
#ifdef SOC_GDMA_TRIG_PERIPH_SPI3
|
||||
} else if (dma_chan == 2) {
|
||||
gdma_chan = SOC_GDMA_SPI3_DMA_CHANNEL;
|
||||
periph_id = SOC_GDMA_TRIG_PERIPH_SPI3;
|
||||
#endif
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
spi_dma_connect_rx_channel_to_periph(gdma_chan, periph_id);
|
||||
spi_dma_connect_tx_channel_to_periph(gdma_chan, periph_id);
|
||||
spi_dma_set_rx_channel_priority(gdma_chan, 1);
|
||||
spi_dma_set_tx_channel_priority(gdma_chan, 1);
|
||||
#endif //#elif SOC_GDMA_SUPPORTED
|
||||
}
|
||||
|
||||
static esp_err_t spicommon_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
|
||||
{
|
||||
assert(is_valid_host(host_id));
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
assert(dma_chan > SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
assert(dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO);
|
||||
#endif
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
bool success = false;
|
||||
uint32_t actual_dma_chan = 0;
|
||||
|
||||
if (dma_chan == SPI_DMA_CH_AUTO) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
for (int i = 1; i < SOC_SPI_DMA_CHAN_NUM+1; i++) {
|
||||
success = spicommon_dma_chan_claim(i, &actual_dma_chan);
|
||||
if (success) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
//On ESP32S2, each SPI controller has its own DMA channel
|
||||
success = spicommon_dma_chan_claim(host_id, &actual_dma_chan);
|
||||
#endif //#if CONFIG_IDF_TARGET_XXX
|
||||
} else {
|
||||
success = spicommon_dma_chan_claim((int)dma_chan, &actual_dma_chan);
|
||||
}
|
||||
|
||||
//On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
||||
*out_actual_tx_dma_chan = actual_dma_chan;
|
||||
*out_actual_rx_dma_chan = actual_dma_chan;
|
||||
|
||||
if (!success) {
|
||||
SPI_CHECK(false, "no available dma channel", ESP_ERR_NOT_FOUND);
|
||||
}
|
||||
|
||||
spicommon_connect_spi_and_dma(host_id, *out_actual_tx_dma_chan);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else //SOC_GDMA_SUPPORTED
|
||||
static esp_err_t spicommon_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
|
||||
{
|
||||
assert(is_valid_host(host_id));
|
||||
assert(dma_chan == SPI_DMA_CH_AUTO);
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
spicommon_bus_context_t *ctx = bus_ctx[host_id];
|
||||
|
||||
if (dma_chan == SPI_DMA_CH_AUTO) {
|
||||
gdma_channel_alloc_config_t tx_alloc_config = {
|
||||
.flags.reserve_sibling = 1,
|
||||
.direction = GDMA_CHANNEL_DIRECTION_TX,
|
||||
};
|
||||
ret = gdma_new_channel(&tx_alloc_config, &ctx->tx_channel);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
gdma_channel_alloc_config_t rx_alloc_config = {
|
||||
.direction = GDMA_CHANNEL_DIRECTION_RX,
|
||||
.sibling_chan = ctx->tx_channel,
|
||||
};
|
||||
ret = gdma_new_channel(&rx_alloc_config, &ctx->rx_channel);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (host_id == SPI2_HOST) {
|
||||
gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2));
|
||||
gdma_connect(ctx->tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2));
|
||||
}
|
||||
#if (SOC_SPI_PERIPH_NUM >= 3)
|
||||
else if (host_id == SPI3_HOST) {
|
||||
gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3));
|
||||
gdma_connect(ctx->tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3));
|
||||
}
|
||||
#endif
|
||||
gdma_get_channel_id(ctx->tx_channel, (int *)out_actual_tx_dma_chan);
|
||||
gdma_get_channel_id(ctx->rx_channel, (int *)out_actual_rx_dma_chan);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif //#if !SOC_GDMA_SUPPORTED
|
||||
|
||||
esp_err_t spicommon_slave_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
|
||||
{
|
||||
assert(is_valid_host(host_id));
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
assert(dma_chan > SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
assert(dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO);
|
||||
#endif
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t actual_tx_dma_chan = 0;
|
||||
uint32_t actual_rx_dma_chan = 0;
|
||||
spicommon_bus_context_t *ctx = (spicommon_bus_context_t *)calloc(1, sizeof(spicommon_bus_context_t));
|
||||
if (!ctx) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
bus_ctx[host_id] = ctx;
|
||||
ctx->host_id = host_id;
|
||||
|
||||
ret = spicommon_dma_chan_alloc(host_id, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
ctx->bus_attr.tx_dma_chan = actual_tx_dma_chan;
|
||||
ctx->bus_attr.rx_dma_chan = actual_rx_dma_chan;
|
||||
*out_actual_tx_dma_chan = actual_tx_dma_chan;
|
||||
*out_actual_rx_dma_chan = actual_rx_dma_chan;
|
||||
|
||||
return ret;
|
||||
|
||||
cleanup:
|
||||
free(ctx);
|
||||
ctx = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------free dma periph-------------------------------------------------------//
|
||||
static esp_err_t spicommon_dma_chan_free(spi_host_device_t host_id)
|
||||
{
|
||||
assert(is_valid_host(host_id));
|
||||
|
||||
spicommon_bus_context_t *ctx = bus_ctx[host_id];
|
||||
#if !SOC_GDMA_SUPPORTED
|
||||
//On ESP32S2, each SPI controller has its own DMA channel
|
||||
int dma_chan = ctx->bus_attr.tx_dma_chan;
|
||||
assert(spi_dma_chan_enabled & BIT(dma_chan));
|
||||
|
||||
portENTER_CRITICAL(&spi_dma_spinlock);
|
||||
spi_dma_chan_enabled &= ~BIT(dma_chan);
|
||||
periph_module_disable(get_dma_periph(dma_chan));
|
||||
portEXIT_CRITICAL(&spi_dma_spinlock);
|
||||
|
||||
#else //SOC_GDMA_SUPPORTED
|
||||
if (ctx->rx_channel) {
|
||||
gdma_disconnect(ctx->rx_channel);
|
||||
gdma_del_channel(ctx->rx_channel);
|
||||
}
|
||||
if (ctx->tx_channel) {
|
||||
gdma_disconnect(ctx->tx_channel);
|
||||
gdma_del_channel(ctx->tx_channel);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id)
|
||||
{
|
||||
assert(is_valid_host(host_id));
|
||||
|
||||
esp_err_t ret = spicommon_dma_chan_free(host_id);
|
||||
free(bus_ctx[host_id]);
|
||||
bus_ctx[host_id] = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------IO general-------------------------------------------------------//
|
||||
static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
if (bus_config->sclk_io_num>=0 &&
|
||||
@ -254,7 +389,7 @@ Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pi
|
||||
bus config struct and it'll set up the GPIO matrix and enable the device. If a pin is set to non-negative value,
|
||||
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, int dma_chan, uint32_t flags, uint32_t* flags_o)
|
||||
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)
|
||||
{
|
||||
uint32_t temp_flag = 0;
|
||||
|
||||
@ -364,7 +499,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->mosi_io_num]);
|
||||
#endif
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], FUNC_GPIO);
|
||||
}
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
if (miso_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
|
||||
@ -377,7 +512,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->miso_io_num]);
|
||||
#endif
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->miso_io_num], FUNC_GPIO);
|
||||
}
|
||||
if (bus_config->quadwp_io_num >= 0) {
|
||||
gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
@ -386,7 +521,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num]);
|
||||
#endif
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], FUNC_GPIO);
|
||||
}
|
||||
if (bus_config->quadhd_io_num >= 0) {
|
||||
gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
@ -395,7 +530,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num]);
|
||||
#endif
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], FUNC_GPIO);
|
||||
}
|
||||
if (bus_config->sclk_io_num >= 0) {
|
||||
if (sclk_need_output) {
|
||||
@ -408,7 +543,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->sclk_io_num]);
|
||||
#endif
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,7 +583,7 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
|
||||
}
|
||||
if (cs_num == 0) esp_rom_gpio_connect_in_signal(cs_io_num, spi_periph_signal[host].spics_in, false);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[cs_io_num]);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[cs_io_num], FUNC_GPIO);
|
||||
}
|
||||
}
|
||||
|
||||
@ -480,22 +615,23 @@ spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id)
|
||||
return bus_ctx[host_id]->bus_attr.lock;
|
||||
}
|
||||
|
||||
static inline bool is_valid_host(spi_host_device_t host)
|
||||
{
|
||||
return host >= SPI1_HOST && host <= SPI3_HOST;
|
||||
}
|
||||
|
||||
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, int dma_chan)
|
||||
//----------------------------------------------------------master bus init-------------------------------------------------------//
|
||||
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
spicommon_bus_context_t *ctx = NULL;
|
||||
spi_bus_attr_t *bus_attr = NULL;
|
||||
uint32_t actual_tx_dma_chan = 0;
|
||||
uint32_t actual_rx_dma_chan = 0;
|
||||
|
||||
SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(bus_ctx[host_id] == NULL, "SPI bus already initialized.", ESP_ERR_INVALID_STATE);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
SPI_CHECK(dma_chan >= SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
SPI_CHECK( dma_chan == 0 || dma_chan == host_id, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
#elif SOC_GDMA_SUPPORTED
|
||||
SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG );
|
||||
#endif
|
||||
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
||||
#ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
|
||||
@ -505,36 +641,27 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
|
||||
bool spi_chan_claimed = spicommon_periph_claim(host_id, "spi master");
|
||||
SPI_CHECK(spi_chan_claimed, "host_id already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
if (dma_chan != 0) {
|
||||
bool dma_chan_claimed = spicommon_dma_chan_claim(dma_chan);
|
||||
if (!dma_chan_claimed) {
|
||||
spicommon_periph_free(host_id);
|
||||
SPI_CHECK(false, "dma channel already in use", ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
|
||||
spicommon_connect_spi_and_dma(host_id, dma_chan);
|
||||
}
|
||||
|
||||
//clean and initialize the context
|
||||
ctx = (spicommon_bus_context_t*)malloc(sizeof(spicommon_bus_context_t));
|
||||
ctx = (spicommon_bus_context_t *)calloc(1, sizeof(spicommon_bus_context_t));
|
||||
if (!ctx) {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
*ctx = (spicommon_bus_context_t) {
|
||||
.host_id = host_id,
|
||||
.bus_attr = {
|
||||
.bus_cfg = *bus_config,
|
||||
.dma_chan = dma_chan,
|
||||
},
|
||||
};
|
||||
|
||||
bus_ctx[host_id] = ctx;
|
||||
ctx->host_id = host_id;
|
||||
bus_attr = &ctx->bus_attr;
|
||||
if (dma_chan == 0) {
|
||||
bus_attr->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
|
||||
bus_attr->dma_desc_num = 0;
|
||||
} else {
|
||||
//See how many dma descriptors we need and allocate them
|
||||
bus_attr->bus_cfg = *bus_config;
|
||||
|
||||
if (dma_chan != SPI_DMA_DISABLED) {
|
||||
bus_attr->dma_enabled = 1;
|
||||
|
||||
err = spicommon_dma_chan_alloc(host_id, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
|
||||
if (err != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
bus_attr->tx_dma_chan = actual_tx_dma_chan;
|
||||
bus_attr->rx_dma_chan = actual_rx_dma_chan;
|
||||
|
||||
int dma_desc_ct = lldesc_get_required_num(bus_config->max_transfer_sz);
|
||||
if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
|
||||
|
||||
@ -546,6 +673,10 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
|
||||
goto cleanup;
|
||||
}
|
||||
bus_attr->dma_desc_num = dma_desc_ct;
|
||||
} else {
|
||||
bus_attr->dma_enabled = 0;
|
||||
bus_attr->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
|
||||
bus_attr->dma_desc_num = 0;
|
||||
}
|
||||
|
||||
spi_bus_lock_config_t lock_config = {
|
||||
@ -565,12 +696,11 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
err = spicommon_bus_initialize_io(host_id, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags);
|
||||
err = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags);
|
||||
if (err != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bus_ctx[host_id] = ctx;
|
||||
return ESP_OK;
|
||||
|
||||
cleanup:
|
||||
@ -583,12 +713,15 @@ cleanup:
|
||||
}
|
||||
free(bus_attr->dmadesc_tx);
|
||||
free(bus_attr->dmadesc_rx);
|
||||
}
|
||||
free(ctx);
|
||||
if (dma_chan) {
|
||||
spicommon_dma_chan_free(dma_chan);
|
||||
bus_attr->dmadesc_tx = NULL;
|
||||
bus_attr->dmadesc_rx = NULL;
|
||||
if (bus_attr->dma_enabled) {
|
||||
spicommon_dma_chan_free(host_id);
|
||||
}
|
||||
}
|
||||
spicommon_periph_free(host_id);
|
||||
free(bus_ctx[host_id]);
|
||||
bus_ctx[host_id] = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -615,15 +748,14 @@ esp_err_t spi_bus_free(spi_host_device_t host_id)
|
||||
esp_pm_lock_delete(bus_attr->pm_lock);
|
||||
#endif
|
||||
spi_bus_deinit_lock(bus_attr->lock);
|
||||
|
||||
free(bus_attr->dmadesc_rx);
|
||||
free(bus_attr->dmadesc_tx);
|
||||
|
||||
if (bus_attr->dma_chan > 0) {
|
||||
spicommon_dma_chan_free (bus_attr->dma_chan);
|
||||
bus_attr->dmadesc_tx = NULL;
|
||||
bus_attr->dmadesc_rx = NULL;
|
||||
if (bus_attr->dma_enabled > 0) {
|
||||
spicommon_dma_chan_free(host_id);
|
||||
}
|
||||
spicommon_periph_free(host_id);
|
||||
|
||||
free(ctx);
|
||||
bus_ctx[host_id] = NULL;
|
||||
return err;
|
||||
|
@ -188,10 +188,12 @@ static esp_err_t spi_master_deinit_driver(void* arg);
|
||||
|
||||
static inline bool is_valid_host(spi_host_device_t host)
|
||||
{
|
||||
//SPI1 can be used as GPSPI only on ESP32
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
return host >= SPI1_HOST && host <= SPI3_HOST;
|
||||
#else
|
||||
// SPI_HOST (SPI1_HOST) is not supported by the SPI Master driver on ESP32-S2 and later
|
||||
#elif (SOC_SPI_PERIPH_NUM == 2)
|
||||
return host == SPI2_HOST;
|
||||
#elif (SOC_SPI_PERIPH_NUM == 3)
|
||||
return host >= SPI2_HOST && host <= SPI3_HOST;
|
||||
#endif
|
||||
}
|
||||
@ -231,17 +233,18 @@ static esp_err_t spi_master_init_driver(spi_host_device_t host_id)
|
||||
}
|
||||
|
||||
//assign the SPI, RX DMA and TX DMA peripheral registers beginning address
|
||||
spi_hal_dma_config_t hal_dma_config = {
|
||||
spi_hal_config_t hal_config = {
|
||||
//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. Pass the registers of SPI peripheral to control it.
|
||||
.dma_in = SPI_LL_GET_HW(host_id),
|
||||
.dma_out = SPI_LL_GET_HW(host_id),
|
||||
.dma_enabled = bus_attr->dma_enabled,
|
||||
.dmadesc_tx = bus_attr->dmadesc_tx,
|
||||
.dmadesc_rx = bus_attr->dmadesc_rx,
|
||||
.dmadesc_n = bus_attr->dma_desc_num
|
||||
.tx_dma_chan = bus_attr->tx_dma_chan,
|
||||
.rx_dma_chan = bus_attr->rx_dma_chan,
|
||||
.dmadesc_n = bus_attr->dma_desc_num,
|
||||
};
|
||||
|
||||
spi_hal_init(&host->hal, host_id, &hal_dma_config);
|
||||
host->hal.dma_enabled = (bus_attr->dma_chan != 0);
|
||||
spi_hal_init(&host->hal, host_id, &hal_config);
|
||||
|
||||
if (host_id != SPI1_HOST) {
|
||||
//SPI1 attributes are already initialized at start up.
|
||||
@ -606,8 +609,9 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
||||
//Okay, transaction is done.
|
||||
const int cs = host->cur_cs;
|
||||
//Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
|
||||
if (bus_attr->dma_chan) {
|
||||
spicommon_dmaworkaround_idle(bus_attr->dma_chan);
|
||||
if (bus_attr->dma_enabled) {
|
||||
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
||||
spicommon_dmaworkaround_idle(bus_attr->tx_dma_chan);
|
||||
}
|
||||
|
||||
//cur_cs is changed to DEV_NUM_MAX here
|
||||
@ -658,9 +662,10 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
||||
|
||||
if (trans_found) {
|
||||
spi_trans_priv_t *const cur_trans_buf = &host->cur_trans_buf;
|
||||
if (bus_attr->dma_chan != 0 && (cur_trans_buf->buffer_to_rcv || cur_trans_buf->buffer_to_send)) {
|
||||
if (bus_attr->dma_enabled && (cur_trans_buf->buffer_to_rcv || cur_trans_buf->buffer_to_send)) {
|
||||
//mark channel as active, so that the DMA will not be reset by the slave
|
||||
spicommon_dmaworkaround_transfer_active(bus_attr->dma_chan);
|
||||
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
||||
spicommon_dmaworkaround_transfer_active(bus_attr->tx_dma_chan);
|
||||
}
|
||||
spi_new_trans(device_to_send, cur_trans_buf);
|
||||
}
|
||||
@ -693,7 +698,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
||||
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);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
SPI_CHECK(!is_half_duplex || bus_attr->dma_chan == 0 || !rx_enabled || !tx_enabled, "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG );
|
||||
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
|
||||
SPI_CHECK(!is_half_duplex || !tx_enabled || !rx_enabled, "SPI half duplex mode is not supported when both MOSI and MISO phases are enabled.", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
@ -788,7 +793,7 @@ 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 );
|
||||
|
||||
spi_trans_priv_t trans_buf;
|
||||
ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_chan!=0));
|
||||
ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled));
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
@ -877,8 +882,9 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_acquire_bus(spi_device_t *device, TickT
|
||||
//configure the device ahead so that we don't need to do it again in the following transactions
|
||||
spi_setup_device(host->device[device->id]);
|
||||
//the DMA is also occupied by the device, all the slave devices that using DMA should wait until bus released.
|
||||
if (host->bus_attr->dma_chan != 0) {
|
||||
spicommon_dmaworkaround_transfer_active(host->bus_attr->dma_chan);
|
||||
if (host->bus_attr->dma_enabled) {
|
||||
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
||||
spicommon_dmaworkaround_transfer_active(host->bus_attr->tx_dma_chan);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -893,8 +899,9 @@ void SPI_MASTER_ISR_ATTR spi_device_release_bus(spi_device_t *dev)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (host->bus_attr->dma_chan != 0) {
|
||||
spicommon_dmaworkaround_idle(host->bus_attr->dma_chan);
|
||||
if (host->bus_attr->dma_enabled) {
|
||||
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
||||
spicommon_dmaworkaround_idle(host->bus_attr->tx_dma_chan);
|
||||
}
|
||||
//Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
|
||||
|
||||
@ -928,7 +935,7 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl
|
||||
}
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
||||
ret = setup_priv_desc(trans_desc, &host->cur_trans_buf, (host->bus_attr->dma_chan!=0));
|
||||
ret = setup_priv_desc(trans_desc, &host->cur_trans_buf, (host->bus_attr->dma_enabled));
|
||||
if (ret!=ESP_OK) return ret;
|
||||
|
||||
//Polling, no interrupt is used.
|
||||
|
@ -67,7 +67,9 @@ typedef struct {
|
||||
int max_transfer_sz;
|
||||
QueueHandle_t trans_queue;
|
||||
QueueHandle_t ret_queue;
|
||||
int dma_chan;
|
||||
bool dma_enabled;
|
||||
uint32_t tx_dma_chan;
|
||||
uint32_t rx_dma_chan;
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_handle_t pm_lock;
|
||||
#endif
|
||||
@ -79,10 +81,12 @@ static void IRAM_ATTR spi_intr(void *arg);
|
||||
|
||||
static inline bool is_valid_host(spi_host_device_t host)
|
||||
{
|
||||
//SPI1 can be used as GPSPI only on ESP32
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
return host >= SPI1_HOST && host <= SPI3_HOST;
|
||||
#else
|
||||
// SPI_HOST (SPI1_HOST) is not supported by the SPI Slave driver on ESP32-S2 & later
|
||||
#elif (SOC_SPI_PERIPH_NUM == 2)
|
||||
return host == SPI2_HOST;
|
||||
#elif (SOC_SPI_PERIPH_NUM == 3)
|
||||
return host >= SPI2_HOST && host <= SPI3_HOST;
|
||||
#endif
|
||||
}
|
||||
@ -108,17 +112,20 @@ static inline void restore_cs(spi_slave_t *host)
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, int dma_chan)
|
||||
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, spi_dma_chan_t dma_chan)
|
||||
{
|
||||
bool spi_chan_claimed, dma_chan_claimed;
|
||||
bool spi_chan_claimed;
|
||||
uint32_t actual_tx_dma_chan = 0;
|
||||
uint32_t actual_rx_dma_chan = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_err_t err;
|
||||
//We only support HSPI/VSPI, period.
|
||||
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
SPI_CHECK( dma_chan == 0 || dma_chan == host, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
SPI_CHECK(dma_chan >= SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == (int)host || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
#elif SOC_GDMA_SUPPORTED
|
||||
SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG );
|
||||
#endif
|
||||
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
||||
#ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM
|
||||
@ -129,17 +136,6 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
spi_chan_claimed=spicommon_periph_claim(host, "spi slave");
|
||||
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
bool use_dma = dma_chan != 0;
|
||||
if (use_dma) {
|
||||
dma_chan_claimed=spicommon_dma_chan_claim(dma_chan);
|
||||
if ( !dma_chan_claimed ) {
|
||||
spicommon_periph_free( host );
|
||||
SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
|
||||
spicommon_connect_spi_and_dma(host, dma_chan);
|
||||
}
|
||||
|
||||
spihost[host] = malloc(sizeof(spi_slave_t));
|
||||
if (spihost[host] == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
@ -149,7 +145,16 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
|
||||
spihost[host]->id = host;
|
||||
|
||||
err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE|bus_config->flags, &spihost[host]->flags);
|
||||
bool use_dma = (dma_chan != SPI_DMA_DISABLED);
|
||||
spihost[host]->dma_enabled = use_dma;
|
||||
if (use_dma) {
|
||||
ret = spicommon_slave_dma_chan_alloc(host, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
err = spicommon_bus_initialize_io(host, bus_config, SPICOMMON_BUSFLAG_SLAVE|bus_config->flags, &spihost[host]->flags);
|
||||
if (err!=ESP_OK) {
|
||||
ret = err;
|
||||
goto cleanup;
|
||||
@ -162,7 +167,8 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
if (use_dma) freeze_cs(spihost[host]);
|
||||
|
||||
int dma_desc_ct = 0;
|
||||
spihost[host]->dma_chan = dma_chan;
|
||||
spihost[host]->tx_dma_chan = actual_tx_dma_chan;
|
||||
spihost[host]->rx_dma_chan = actual_rx_dma_chan;
|
||||
if (use_dma) {
|
||||
//See how many dma descriptors we need and allocate them
|
||||
dma_desc_ct = (bus_config->max_transfer_sz + SPI_MAX_DMA_LEN - 1) / SPI_MAX_DMA_LEN;
|
||||
@ -220,6 +226,8 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
hal->tx_lsbfirst = (slave_config->flags & SPI_SLAVE_TXBIT_LSBFIRST) ? 1 : 0;
|
||||
hal->mode = slave_config->mode;
|
||||
hal->use_dma = use_dma;
|
||||
hal->tx_dma_chan = actual_tx_dma_chan;
|
||||
hal->rx_dma_chan = actual_rx_dma_chan;
|
||||
|
||||
spi_slave_hal_setup_device(hal);
|
||||
|
||||
@ -239,10 +247,14 @@ cleanup:
|
||||
#endif
|
||||
}
|
||||
spi_slave_hal_deinit(&spihost[host]->hal);
|
||||
if (spihost[host]->dma_enabled) {
|
||||
spicommon_slave_free_dma(host);
|
||||
}
|
||||
|
||||
free(spihost[host]);
|
||||
spihost[host] = NULL;
|
||||
spicommon_periph_free(host);
|
||||
if (dma_chan != 0) spicommon_dma_chan_free(dma_chan);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -252,8 +264,8 @@ esp_err_t spi_slave_free(spi_host_device_t host)
|
||||
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
|
||||
if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue);
|
||||
if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
|
||||
if ( spihost[host]->dma_chan > 0 ) {
|
||||
spicommon_dma_chan_free ( spihost[host]->dma_chan );
|
||||
if (spihost[host]->dma_enabled) {
|
||||
spicommon_slave_free_dma(host);
|
||||
}
|
||||
free(spihost[host]->hal.dmadesc_tx);
|
||||
free(spihost[host]->hal.dmadesc_rx);
|
||||
@ -274,9 +286,9 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi
|
||||
BaseType_t r;
|
||||
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
|
||||
SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
|
||||
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL ||
|
||||
SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->rx_buffer==NULL ||
|
||||
(esp_ptr_dma_capable(trans_desc->rx_buffer) && esp_ptr_word_aligned(trans_desc->rx_buffer) &&
|
||||
(trans_desc->length%4==0)),
|
||||
"rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG);
|
||||
@ -332,7 +344,7 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
||||
|
||||
assert(spi_slave_hal_usr_is_done(hal));
|
||||
|
||||
bool use_dma = host->dma_chan != 0;
|
||||
bool use_dma = host->dma_enabled;
|
||||
if (host->cur_trans) {
|
||||
// When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready.
|
||||
if (use_dma) freeze_cs(host);
|
||||
@ -341,7 +353,8 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
||||
host->cur_trans->trans_len = spi_slave_hal_get_rcv_bitlen(hal);
|
||||
|
||||
if (spi_slave_hal_dma_need_reset(hal)) {
|
||||
spicommon_dmaworkaround_req_reset(host->dma_chan, spi_slave_restart_after_dmareset, host);
|
||||
//On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
||||
spicommon_dmaworkaround_req_reset(host->tx_dma_chan, spi_slave_restart_after_dmareset, host);
|
||||
}
|
||||
if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans);
|
||||
//Okay, transaction is done.
|
||||
@ -350,7 +363,8 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
||||
host->cur_trans = NULL;
|
||||
}
|
||||
if (use_dma) {
|
||||
spicommon_dmaworkaround_idle(host->dma_chan);
|
||||
//On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
||||
spicommon_dmaworkaround_idle(host->tx_dma_chan);
|
||||
if (spicommon_dmaworkaround_reset_in_progress()) {
|
||||
//We need to wait for the reset to complete. Disable int (will be re-enabled on reset callback) and exit isr.
|
||||
esp_intr_disable(host->intr);
|
||||
@ -375,7 +389,8 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
||||
hal->tx_buffer = trans->tx_buffer;
|
||||
|
||||
if (use_dma) {
|
||||
spicommon_dmaworkaround_transfer_active(host->dma_chan);
|
||||
//On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
||||
spicommon_dmaworkaround_transfer_active(host->tx_dma_chan);
|
||||
}
|
||||
|
||||
spi_slave_hal_prepare_data(hal);
|
||||
|
@ -23,12 +23,15 @@
|
||||
#include "hal/spi_slave_hd_hal.h"
|
||||
|
||||
|
||||
//SPI1 can never be used as the slave
|
||||
#define VALID_HOST(x) (x>SPI_HOST && x<=HSPI_HOST)
|
||||
#if (SOC_SPI_PERIPH_NUM == 2)
|
||||
#define VALID_HOST(x) ((x) == SPI2_HOST)
|
||||
#elif (SOC_SPI_PERIPH_NUM == 3)
|
||||
#define VALID_HOST(x) ((x) >= SPI2_HOST && (x) <= SPI3_HOST)
|
||||
#endif
|
||||
#define SPIHD_CHECK(cond,warn,ret) do{if(!(cond)){ESP_LOGE(TAG, warn); return ret;}} while(0)
|
||||
|
||||
typedef struct {
|
||||
int dma_chan;
|
||||
bool dma_enabled;
|
||||
int max_transfer_sz;
|
||||
uint32_t flags;
|
||||
portMUX_TYPE int_spinlock;
|
||||
@ -64,12 +67,18 @@ static void spi_slave_hd_intr_append(void *arg);
|
||||
esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config,
|
||||
const spi_slave_hd_slot_config_t *config)
|
||||
{
|
||||
bool spi_chan_claimed, dma_chan_claimed;
|
||||
bool spi_chan_claimed;
|
||||
bool append_mode = (config->flags & SPI_SLAVE_HD_APPEND_MODE);
|
||||
uint32_t actual_tx_dma_chan = 0;
|
||||
uint32_t actual_rx_dma_chan = 0;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
SPIHD_CHECK(VALID_HOST(host_id), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPIHD_CHECK(config->dma_chan == 0 || config->dma_chan == host_id, "invalid dma channel", ESP_ERR_INVALID_ARG);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
SPIHD_CHECK(config->dma_chan == SPI_DMA_DISABLED || config->dma_chan == (int)host_id || config->dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG);
|
||||
#elif SOC_GDMA_SUPPORTED
|
||||
SPIHD_CHECK(config->dma_chan == SPI_DMA_DISABLED || config->dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
#if !CONFIG_IDF_TARGET_ESP32S2
|
||||
//Append mode is only supported on ESP32S2 now
|
||||
SPIHD_CHECK(append_mode == 0, "Append mode is only supported on ESP32S2 now", ESP_ERR_INVALID_ARG);
|
||||
@ -78,29 +87,23 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
||||
spi_chan_claimed = spicommon_periph_claim(host_id, "slave_hd");
|
||||
SPIHD_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
if ( config->dma_chan != 0 ) {
|
||||
dma_chan_claimed = spicommon_dma_chan_claim(config->dma_chan);
|
||||
if (!dma_chan_claimed) {
|
||||
spicommon_periph_free(host_id);
|
||||
SPIHD_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
|
||||
spicommon_connect_spi_and_dma(host_id, config->dma_chan);
|
||||
}
|
||||
|
||||
spi_slave_hd_slot_t* host = malloc(sizeof(spi_slave_hd_slot_t));
|
||||
spi_slave_hd_slot_t* host = calloc(1, sizeof(spi_slave_hd_slot_t));
|
||||
if (host == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
spihost[host_id] = host;
|
||||
memset(host, 0, sizeof(spi_slave_hd_slot_t));
|
||||
|
||||
host->dma_chan = config->dma_chan;
|
||||
host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
host->dma_enabled = (config->dma_chan != SPI_DMA_DISABLED);
|
||||
|
||||
ret = spicommon_bus_initialize_io(host_id, bus_config, config->dma_chan,
|
||||
SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags);
|
||||
if (host->dma_enabled) {
|
||||
ret = spicommon_slave_dma_chan_alloc(host_id, config->dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
@ -113,14 +116,16 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
||||
.host_id = host_id,
|
||||
.dma_in = SPI_LL_GET_HW(host_id),
|
||||
.dma_out = SPI_LL_GET_HW(host_id),
|
||||
.dma_chan = config->dma_chan,
|
||||
.dma_enabled = host->dma_enabled,
|
||||
.tx_dma_chan = actual_tx_dma_chan,
|
||||
.rx_dma_chan = actual_rx_dma_chan,
|
||||
.append_mode = append_mode,
|
||||
.mode = config->mode,
|
||||
.tx_lsbfirst = (config->flags & SPI_SLAVE_HD_RXBIT_LSBFIRST),
|
||||
.rx_lsbfirst = (config->flags & SPI_SLAVE_HD_TXBIT_LSBFIRST),
|
||||
};
|
||||
|
||||
if (config->dma_chan != 0) {
|
||||
if (host->dma_enabled) {
|
||||
//Malloc for all the DMA descriptors
|
||||
uint32_t total_desc_size = spi_slave_hd_hal_get_total_desc_size(&host->hal, bus_config->max_transfer_sz);
|
||||
host->hal.dmadesc_tx = heap_caps_malloc(total_desc_size, MALLOC_CAP_DMA);
|
||||
@ -243,8 +248,8 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
|
||||
}
|
||||
|
||||
spicommon_periph_free(host_id);
|
||||
if (host->dma_chan) {
|
||||
spicommon_dma_chan_free(host->dma_chan);
|
||||
if (host->dma_enabled) {
|
||||
spicommon_slave_free_dma(host_id);
|
||||
}
|
||||
free(host);
|
||||
spihost[host_id] = NULL;
|
||||
@ -392,9 +397,7 @@ static IRAM_ATTR void spi_slave_hd_intr_append(void *arg)
|
||||
spi_slave_hd_data_t *trans_desc;
|
||||
while (1) {
|
||||
bool trans_finish = false;
|
||||
portENTER_CRITICAL_ISR(&host->int_spinlock);
|
||||
trans_finish = spi_slave_hd_hal_get_tx_finished_trans(hal, (void **)&trans_desc);
|
||||
portEXIT_CRITICAL_ISR(&host->int_spinlock);
|
||||
if (!trans_finish) {
|
||||
break;
|
||||
}
|
||||
@ -425,9 +428,7 @@ static IRAM_ATTR void spi_slave_hd_intr_append(void *arg)
|
||||
size_t trans_len;
|
||||
while (1) {
|
||||
bool trans_finish = false;
|
||||
portENTER_CRITICAL_ISR(&host->int_spinlock);
|
||||
trans_finish = spi_slave_hd_hal_get_rx_finished_trans(hal, (void **)&trans_desc, &trans_len);
|
||||
portEXIT_CRITICAL_ISR(&host->int_spinlock);
|
||||
if (!trans_finish) {
|
||||
break;
|
||||
}
|
||||
@ -546,17 +547,13 @@ esp_err_t spi_slave_hd_append_trans(spi_host_device_t host_id, spi_slave_chan_t
|
||||
if (ret == pdFALSE) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
portENTER_CRITICAL(&host->int_spinlock);
|
||||
err = spi_slave_hd_hal_txdma_append(hal, trans->data, trans->len, trans);
|
||||
portEXIT_CRITICAL(&host->int_spinlock);
|
||||
} else {
|
||||
BaseType_t ret = xSemaphoreTake(host->rx_cnting_sem, timeout);
|
||||
if (ret == pdFALSE) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
portENTER_CRITICAL(&host->int_spinlock);
|
||||
err = spi_slave_hd_hal_rxdma_append(hal, trans->data, trans->len, trans);
|
||||
portEXIT_CRITICAL(&host->int_spinlock);
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Wait until the DMA finishes its transaction");
|
||||
|
@ -16,32 +16,29 @@
|
||||
// All the tests using the header should use this definition as much as possible,
|
||||
// so that the working host can be changed easily in the future.
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define TEST_SPI_HOST HSPI_HOST
|
||||
#define TEST_SLAVE_HOST VSPI_HOST
|
||||
#define TEST_SPI_HOST SPI2_HOST
|
||||
#define TEST_SLAVE_HOST SPI3_HOST
|
||||
|
||||
#define PIN_NUM_MISO HSPI_IOMUX_PIN_NUM_MISO
|
||||
#define PIN_NUM_MOSI HSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define PIN_NUM_CLK HSPI_IOMUX_PIN_NUM_CLK
|
||||
#define PIN_NUM_CS HSPI_IOMUX_PIN_NUM_CS
|
||||
#define PIN_NUM_WP HSPI_IOMUX_PIN_NUM_WP
|
||||
#define PIN_NUM_HD HSPI_IOMUX_PIN_NUM_HD
|
||||
#define PIN_NUM_MISO SPI2_IOMUX_PIN_NUM_MISO
|
||||
#define PIN_NUM_MOSI SPI2_IOMUX_PIN_NUM_MOSI
|
||||
#define PIN_NUM_CLK SPI2_IOMUX_PIN_NUM_CLK
|
||||
#define PIN_NUM_CS SPI2_IOMUX_PIN_NUM_CS
|
||||
#define PIN_NUM_WP SPI2_IOMUX_PIN_NUM_WP
|
||||
#define PIN_NUM_HD SPI2_IOMUX_PIN_NUM_HD
|
||||
|
||||
#define SLAVE_PIN_NUM_MISO VSPI_IOMUX_PIN_NUM_MISO
|
||||
#define SLAVE_PIN_NUM_MOSI VSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define SLAVE_PIN_NUM_CLK VSPI_IOMUX_PIN_NUM_CLK
|
||||
#define SLAVE_PIN_NUM_CS VSPI_IOMUX_PIN_NUM_CS
|
||||
#define SLAVE_PIN_NUM_WP VSPI_IOMUX_PIN_NUM_WP
|
||||
#define SLAVE_PIN_NUM_HD VSPI_IOMUX_PIN_NUM_HD
|
||||
#define MASTER_IOMUX_PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
|
||||
#define MASTER_IOMUX_PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
|
||||
#define MASTER_IOMUX_PIN_SCLK SPI2_IOMUX_PIN_NUM_CLK
|
||||
#define MASTER_IOMUX_PIN_CS SPI2_IOMUX_PIN_NUM_CS
|
||||
#define MASTER_IOMUX_PIN_WP SPI2_IOMUX_PIN_NUM_WP
|
||||
#define MASTER_IOMUX_PIN_HD SPI2_IOMUX_PIN_NUM_HD
|
||||
|
||||
#define SLAVE_IOMUX_PIN_MISO VSPI_IOMUX_PIN_NUM_MISO
|
||||
#define SLAVE_IOMUX_PIN_MOSI VSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define SLAVE_IOMUX_PIN_SCLK VSPI_IOMUX_PIN_NUM_CLK
|
||||
#define SLAVE_IOMUX_PIN_CS VSPI_IOMUX_PIN_NUM_CS
|
||||
|
||||
#define MASTER_IOMUX_PIN_MISO HSPI_IOMUX_PIN_NUM_MISO
|
||||
#define MASTER_IOMUX_PIN_MOSI HSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define MASTER_IOMUX_PIN_SCLK HSPI_IOMUX_PIN_NUM_CLK
|
||||
#define MASTER_IOMUX_PIN_CS HSPI_IOMUX_PIN_NUM_CS
|
||||
#define SLAVE_IOMUX_PIN_MISO SPI3_IOMUX_PIN_NUM_MISO
|
||||
#define SLAVE_IOMUX_PIN_MOSI SPI3_IOMUX_PIN_NUM_MOSI
|
||||
#define SLAVE_IOMUX_PIN_SCLK SPI3_IOMUX_PIN_NUM_CLK
|
||||
#define SLAVE_IOMUX_PIN_CS SPI3_IOMUX_PIN_NUM_CS
|
||||
#define SLAVE_IOMUX_PIN_WP SPI3_IOMUX_PIN_NUM_WP
|
||||
#define SLAVE_IOMUX_PIN_HD SPI3_IOMUX_PIN_NUM_HD
|
||||
|
||||
#define UNCONNECTED_PIN 27
|
||||
#define INPUT_ONLY_PIN 34
|
||||
@ -50,34 +47,29 @@
|
||||
#define WIRE_DELAY 12.5
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#define TEST_SPI_HOST SPI2_HOST
|
||||
#define TEST_SLAVE_HOST SPI3_HOST
|
||||
|
||||
#define TEST_SPI_HOST FSPI_HOST
|
||||
#define TEST_SLAVE_HOST HSPI_HOST
|
||||
#define PIN_NUM_MISO SPI2_IOMUX_PIN_NUM_MISO
|
||||
#define PIN_NUM_MOSI SPI2_IOMUX_PIN_NUM_MOSI
|
||||
#define PIN_NUM_CLK SPI2_IOMUX_PIN_NUM_CLK
|
||||
#define PIN_NUM_CS SPI2_IOMUX_PIN_NUM_CS
|
||||
#define PIN_NUM_WP SPI2_IOMUX_PIN_NUM_WP
|
||||
#define PIN_NUM_HD SPI2_IOMUX_PIN_NUM_HD
|
||||
|
||||
#define PIN_NUM_MISO FSPI_IOMUX_PIN_NUM_MISO
|
||||
#define PIN_NUM_MOSI FSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define PIN_NUM_CLK FSPI_IOMUX_PIN_NUM_CLK
|
||||
#define PIN_NUM_CS FSPI_IOMUX_PIN_NUM_CS
|
||||
|
||||
#define PIN_NUM_WP FSPI_IOMUX_PIN_NUM_WP
|
||||
#define PIN_NUM_HD FSPI_IOMUX_PIN_NUM_HD
|
||||
|
||||
#define SLAVE_PIN_NUM_MISO HSPI_IOMUX_PIN_NUM_MISO
|
||||
#define SLAVE_PIN_NUM_MOSI HSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define SLAVE_PIN_NUM_CLK HSPI_IOMUX_PIN_NUM_CLK
|
||||
#define SLAVE_PIN_NUM_CS HSPI_IOMUX_PIN_NUM_CS
|
||||
#define SLAVE_PIN_NUM_WP -1
|
||||
#define SLAVE_PIN_NUM_HD -1
|
||||
#define MASTER_IOMUX_PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
|
||||
#define MASTER_IOMUX_PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
|
||||
#define MASTER_IOMUX_PIN_SCLK SPI2_IOMUX_PIN_NUM_CLK
|
||||
#define MASTER_IOMUX_PIN_CS SPI2_IOMUX_PIN_NUM_CS
|
||||
#define MASTER_IOMUX_PIN_WP SPI2_IOMUX_PIN_NUM_WP
|
||||
#define MASTER_IOMUX_PIN_HD SPI2_IOMUX_PIN_NUM_HD
|
||||
|
||||
#define SLAVE_IOMUX_PIN_MISO -1
|
||||
#define SLAVE_IOMUX_PIN_MOSI -1
|
||||
#define SLAVE_IOMUX_PIN_SCLK -1
|
||||
#define SLAVE_IOMUX_PIN_CS -1
|
||||
|
||||
#define MASTER_IOMUX_PIN_MISO FSPI_IOMUX_PIN_NUM_MISO
|
||||
#define MASTER_IOMUX_PIN_MOSI FSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define MASTER_IOMUX_PIN_SCLK FSPI_IOMUX_PIN_NUM_CLK
|
||||
#define MASTER_IOMUX_PIN_CS FSPI_IOMUX_PIN_NUM_CS
|
||||
#define SLAVE_IOMUX_PIN_NUM_WP -1
|
||||
#define SLAVE_IOMUX_PIN_NUM_HD -1
|
||||
|
||||
#define UNCONNECTED_PIN 41
|
||||
#define INPUT_ONLY_PIN 46
|
||||
@ -86,40 +78,30 @@
|
||||
#define WIRE_DELAY 12.5
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
#define TEST_SPI_HOST FSPI_HOST
|
||||
#define TEST_SLAVE_HOST FSPI_HOST
|
||||
|
||||
#define PIN_NUM_MISO FSPI_IOMUX_PIN_NUM_MISO
|
||||
#define PIN_NUM_MOSI FSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define PIN_NUM_CLK FSPI_IOMUX_PIN_NUM_CLK
|
||||
#define PIN_NUM_CS FSPI_IOMUX_PIN_NUM_CS
|
||||
|
||||
#define PIN_NUM_WP FSPI_IOMUX_PIN_NUM_WP
|
||||
#define PIN_NUM_HD FSPI_IOMUX_PIN_NUM_HD
|
||||
|
||||
#define SLAVE_PIN_NUM_MISO -1
|
||||
#define SLAVE_PIN_NUM_MOSI -1
|
||||
#define SLAVE_PIN_NUM_CLK -1
|
||||
#define SLAVE_PIN_NUM_CS -1
|
||||
#define SLAVE_PIN_NUM_WP -1
|
||||
#define SLAVE_PIN_NUM_HD -1
|
||||
|
||||
//NOTE: On esp32c3, there is only 1 GPSPI controller, so master-slave test on single board should be disabled
|
||||
#define SLAVE_IOMUX_PIN_MISO FSPI_IOMUX_PIN_NUM_MISO
|
||||
#define SLAVE_IOMUX_PIN_MOSI FSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define SLAVE_IOMUX_PIN_SCLK FSPI_IOMUX_PIN_NUM_CLK
|
||||
#define SLAVE_IOMUX_PIN_CS FSPI_IOMUX_PIN_NUM_CS
|
||||
#define TEST_SPI_HOST SPI2_HOST
|
||||
#define TEST_SLAVE_HOST SPI2_HOST
|
||||
|
||||
#define MASTER_IOMUX_PIN_MISO FSPI_IOMUX_PIN_NUM_MISO
|
||||
#define MASTER_IOMUX_PIN_MOSI FSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define MASTER_IOMUX_PIN_SCLK FSPI_IOMUX_PIN_NUM_CLK
|
||||
#define MASTER_IOMUX_PIN_CS FSPI_IOMUX_PIN_NUM_CS
|
||||
#define PIN_NUM_MISO SPI2_IOMUX_PIN_NUM_MISO
|
||||
#define PIN_NUM_MOSI SPI2_IOMUX_PIN_NUM_MOSI
|
||||
#define PIN_NUM_CLK SPI2_IOMUX_PIN_NUM_CLK
|
||||
#define PIN_NUM_CS SPI2_IOMUX_PIN_NUM_CS
|
||||
#define PIN_NUM_WP SPI2_IOMUX_PIN_NUM_WP
|
||||
#define PIN_NUM_HD SPI2_IOMUX_PIN_NUM_HD
|
||||
|
||||
#define SLAVE_IOMUX_PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
|
||||
#define SLAVE_IOMUX_PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
|
||||
#define SLAVE_IOMUX_PIN_SCLK SPI2_IOMUX_PIN_NUM_CLK
|
||||
#define SLAVE_IOMUX_PIN_CS SPI2_IOMUX_PIN_NUM_CS
|
||||
|
||||
#define MASTER_IOMUX_PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
|
||||
#define MASTER_IOMUX_PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
|
||||
#define MASTER_IOMUX_PIN_SCLK SPI2_IOMUX_PIN_NUM_CLK
|
||||
#define MASTER_IOMUX_PIN_CS SPI2_IOMUX_PIN_NUM_CS
|
||||
|
||||
#define GPIO_DELAY 0
|
||||
#define ESP_SPI_SLAVE_TV 0
|
||||
#define WIRE_DELAY 12.5
|
||||
|
||||
#endif
|
||||
|
||||
#define GET_DMA_CHAN(HOST) (HOST)
|
||||
|
@ -122,7 +122,6 @@ static void continuous_adc_init(uint16_t adc1_chan_mask, uint16_t adc2_chan_mask
|
||||
adc_digi_init_config_t adc_dma_config = {
|
||||
.max_store_buf_size = TEST_COUNT*2,
|
||||
.conv_num_each_intr = 128,
|
||||
.dma_chan = SOC_GDMA_ADC_DMA_CHANNEL,
|
||||
.adc1_chan_mask = adc1_chan_mask,
|
||||
.adc2_chan_mask = adc2_chan_mask,
|
||||
};
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "driver/spi_slave.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
|
||||
int test_freq_default[]=TEST_FREQ_DEFAULT();
|
||||
|
||||
@ -202,13 +203,13 @@ void master_free_device_bus(spi_device_handle_t spi)
|
||||
|
||||
void spitest_gpio_output_sel(uint32_t gpio_num, int func, uint32_t signal_idx)
|
||||
{
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], func);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], func);
|
||||
GPIO.func_out_sel_cfg[gpio_num].func_sel = signal_idx;
|
||||
}
|
||||
|
||||
void spitest_gpio_input_sel(uint32_t gpio_num, int func, uint32_t signal_idx)
|
||||
{
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], func);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], func);
|
||||
GPIO.func_in_sel_cfg[signal_idx].func_sel = gpio_num;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "soc/uart_struct.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
|
||||
|
||||
#define DATA_LENGTH 512 /*!<Data buffer length for test buffer*/
|
||||
@ -651,7 +652,7 @@ TEST_CASE("I2C general API test", "[i2c]")
|
||||
//Init uart baud rate detection
|
||||
static void uart_aut_baud_det_init(int rxd_io_num)
|
||||
{
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rxd_io_num], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxd_io_num], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(rxd_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(rxd_io_num, I2CEXT1_SCL_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(rxd_io_num, U1RXD_IN_IDX, 0);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "unity.h"
|
||||
#include "math.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
@ -44,9 +45,9 @@
|
||||
static void i2s_test_io_config(int mode)
|
||||
{
|
||||
// Connect internal signals using IO matrix.
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[MASTER_BCK_IO], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[MASTER_WS_IO], PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[DATA_OUT_IO], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_BCK_IO], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_WS_IO], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[DATA_OUT_IO], PIN_FUNC_GPIO);
|
||||
|
||||
gpio_set_direction(MASTER_BCK_IO, GPIO_MODE_INPUT_OUTPUT);
|
||||
gpio_set_direction(MASTER_WS_IO, GPIO_MODE_INPUT_OUTPUT);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/cpu_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
@ -63,7 +64,7 @@ static void rmt_setup_testbench(int tx_channel, int rx_channel, uint32_t flags)
|
||||
}
|
||||
|
||||
// Routing internal signals by IO Matrix (bind rmt tx and rx signal on the same GPIO)
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[RMT_DATA_IO], PIN_FUNC_GPIO);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[RMT_DATA_IO], PIN_FUNC_GPIO);
|
||||
TEST_ESP_OK(gpio_set_direction(RMT_DATA_IO, GPIO_MODE_INPUT_OUTPUT));
|
||||
esp_rom_gpio_connect_out_signal(RMT_DATA_IO, RMT_SIG_OUT0_IDX + tx_channel, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(RMT_DATA_IO, RMT_SIG_IN0_IDX + rx_channel, 0);
|
||||
|
@ -39,7 +39,7 @@
|
||||
//TEST_CNT > 512
|
||||
#define TEST_CNT 10000
|
||||
|
||||
#define TEST_SDSPI_HOST HSPI_HOST
|
||||
#define TEST_SDSPI_HOST SPI2_HOST
|
||||
#define TEST_SDSPI_DMACHAN 1
|
||||
|
||||
#define TEST_RESET_DATA_LEN 10
|
||||
|
@ -74,7 +74,7 @@ TEST_CASE("SPI Master clockdiv calculation routines", "[spi]")
|
||||
.quadhd_io_num=-1
|
||||
};
|
||||
esp_err_t ret;
|
||||
ret=spi_bus_initialize(TEST_SPI_HOST, &buscfg, 1);
|
||||
ret = spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
|
||||
check_spi_pre_n_for(26000000, 1, 3);
|
||||
@ -110,13 +110,10 @@ static spi_device_handle_t setup_spi_bus_loopback(int clkspeed, bool dma) {
|
||||
.spics_io_num=PIN_NUM_CS,
|
||||
.queue_size=3,
|
||||
};
|
||||
esp_err_t ret;
|
||||
spi_device_handle_t handle;
|
||||
|
||||
ret=spi_bus_initialize(TEST_SPI_HOST, &buscfg, dma?1:0);
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
ret=spi_bus_add_device(TEST_SPI_HOST, &devcfg, &handle);
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, dma ? SPI_DMA_CH_AUTO : 0));
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &handle));
|
||||
//connect MOSI to two devices breaks the output, fix it.
|
||||
spitest_gpio_output_sel(PIN_NUM_MOSI, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out);
|
||||
printf("Bus/dev inited.\n");
|
||||
@ -276,8 +273,10 @@ static esp_err_t test_master_pins(int mosi, int miso, int sclk, int cs)
|
||||
spi_device_interface_config_t master_cfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
master_cfg.spics_io_num = cs;
|
||||
|
||||
ret = spi_bus_initialize(TEST_SPI_HOST, &cfg, 1);
|
||||
if (ret != ESP_OK) return ret;
|
||||
ret = spi_bus_initialize(TEST_SPI_HOST, &cfg, SPI_DMA_CH_AUTO);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_device_handle_t spi;
|
||||
ret = spi_bus_add_device(TEST_SPI_HOST, &master_cfg, &spi);
|
||||
@ -301,8 +300,10 @@ static esp_err_t test_slave_pins(int mosi, int miso, int sclk, int cs)
|
||||
spi_slave_interface_config_t slave_cfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
|
||||
slave_cfg.spics_io_num = cs;
|
||||
|
||||
ret = spi_slave_initialize(TEST_SLAVE_HOST, &cfg, &slave_cfg, TEST_DMA_CHAN_SLAVE);
|
||||
if (ret != ESP_OK) return ret;
|
||||
ret = spi_slave_initialize(TEST_SLAVE_HOST, &cfg, &slave_cfg, SPI_DMA_CH_AUTO);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_slave_free(TEST_SLAVE_HOST);
|
||||
return ESP_OK;
|
||||
@ -315,7 +316,6 @@ TEST_CASE("spi placed on input-only pins", "[spi]")
|
||||
TEST_ESP_OK(test_master_pins(PIN_NUM_MOSI, INPUT_ONLY_PIN, PIN_NUM_CLK, PIN_NUM_CS));
|
||||
TEST_ASSERT(test_master_pins(PIN_NUM_MOSI, PIN_NUM_MISO, INPUT_ONLY_PIN, PIN_NUM_CS) != ESP_OK);
|
||||
TEST_ASSERT(test_master_pins(PIN_NUM_MOSI, PIN_NUM_MISO, PIN_NUM_CLK, INPUT_ONLY_PIN) != ESP_OK);
|
||||
|
||||
TEST_ESP_OK(test_slave_pins(PIN_NUM_MOSI, PIN_NUM_MISO, PIN_NUM_CLK, PIN_NUM_CS));
|
||||
TEST_ESP_OK(test_slave_pins(INPUT_ONLY_PIN, PIN_NUM_MISO, PIN_NUM_CLK, PIN_NUM_CS));
|
||||
TEST_ASSERT(test_slave_pins(PIN_NUM_MOSI, INPUT_ONLY_PIN, PIN_NUM_CLK, PIN_NUM_CS) != ESP_OK);
|
||||
@ -336,18 +336,18 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
||||
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_IOMUX_PINS | SPICOMMON_BUSFLAG_QUAD;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
|
||||
ESP_LOGI(TAG, "test 4 iomux output pins...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_IOMUX_PINS | SPICOMMON_BUSFLAG_DUAL;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
|
||||
ESP_LOGI(TAG, "test 6 output pins...");
|
||||
@ -355,9 +355,9 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
||||
//swap MOSI and MISO
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
|
||||
ESP_LOGI(TAG, "test 4 output pins...");
|
||||
@ -365,9 +365,9 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
||||
//swap MOSI and MISO
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
|
||||
#if !DISABLED_FOR_TARGETS(ESP32C3) //There is no input-only pin on esp32c3, so this test could be ignored.
|
||||
@ -375,14 +375,14 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
||||
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_WPHD | SPICOMMON_BUSFLAG_GPIO_PINS;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = INPUT_ONLY_PIN, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
|
||||
ESP_LOGI(TAG, "test slave 5 output pins and MISO on input-only pin...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_WPHD | SPICOMMON_BUSFLAG_GPIO_PINS;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = INPUT_ONLY_PIN, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
|
||||
ESP_LOGI(TAG, "test master 3 output pins and MOSI on input-only pin...");
|
||||
@ -390,14 +390,14 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
||||
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = INPUT_ONLY_PIN, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
|
||||
ESP_LOGI(TAG, "test slave 3 output pins and MISO on input-only pin...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_GPIO_PINS;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = INPUT_ONLY_PIN, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||
#endif
|
||||
|
||||
@ -406,75 +406,75 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
||||
//swap MOSI and MISO
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
|
||||
ESP_LOGI(TAG, "check native flag for 4 output pins...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_IOMUX_PINS;
|
||||
//swap MOSI and MISO
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
|
||||
#if !DISABLED_FOR_TARGETS(ESP32C3) //There is no input-only pin on esp32c3, so this test could be ignored.
|
||||
ESP_LOGI(TAG, "check dual flag for master 5 output pins and MISO/MOSI on input-only pin...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_DUAL | SPICOMMON_BUSFLAG_GPIO_PINS;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = INPUT_ONLY_PIN, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = INPUT_ONLY_PIN, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
|
||||
ESP_LOGI(TAG, "check dual flag for master 3 output pins and MISO/MOSI on input-only pin...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_DUAL | SPICOMMON_BUSFLAG_GPIO_PINS;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = INPUT_ONLY_PIN, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = INPUT_ONLY_PIN, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "check sclk flag...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_SCLK;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = -1, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
|
||||
ESP_LOGI(TAG, "check mosi flag...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_MOSI;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = -1, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
|
||||
ESP_LOGI(TAG, "check miso flag...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_MISO;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = -1, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
|
||||
ESP_LOGI(TAG, "check quad flag...");
|
||||
flags_expected = SPICOMMON_BUSFLAG_QUAD;
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = -1, .quadwp_io_num = spi_periph_signal[TEST_SPI_HOST].spiwp_iomux_pin,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
cfg = (spi_bus_config_t){.mosi_io_num = spi_periph_signal[TEST_SPI_HOST].spid_iomux_pin, .miso_io_num = spi_periph_signal[TEST_SPI_HOST].spiq_iomux_pin, .sclk_io_num = spi_periph_signal[TEST_SPI_HOST].spiclk_iomux_pin, .quadhd_io_num = spi_periph_signal[TEST_SPI_HOST].spihd_iomux_pin, .quadwp_io_num = -1,
|
||||
.max_transfer_sz = 8, .flags = flags_expected};
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||
}
|
||||
|
||||
TEST_CASE("SPI Master no response when switch from host1 (HSPI) to host2 (VSPI)", "[spi]")
|
||||
TEST_CASE("SPI Master no response when switch from host1 (SPI2) to host2 (SPI3)", "[spi]")
|
||||
{
|
||||
//spi config
|
||||
spi_bus_config_t bus_config;
|
||||
@ -507,30 +507,29 @@ TEST_CASE("SPI Master no response when switch from host1 (HSPI) to host2 (VSPI)"
|
||||
//initialize for first host
|
||||
host = TEST_SPI_HOST;
|
||||
|
||||
TEST_ASSERT(spi_bus_initialize(host, &bus_config, GET_DMA_CHAN(host)) == ESP_OK);
|
||||
TEST_ASSERT(spi_bus_add_device(host, &device_config, &spi) == ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_initialize(host, &bus_config, SPI_DMA_CH_AUTO));
|
||||
TEST_ESP_OK(spi_bus_add_device(host, &device_config, &spi));
|
||||
|
||||
printf("before first xmit\n");
|
||||
TEST_ASSERT(spi_device_transmit(spi, &transaction) == ESP_OK);
|
||||
TEST_ESP_OK(spi_device_transmit(spi, &transaction));
|
||||
printf("after first xmit\n");
|
||||
|
||||
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
|
||||
TEST_ASSERT(spi_bus_free(host) == ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_remove_device(spi));
|
||||
TEST_ESP_OK(spi_bus_free(host));
|
||||
|
||||
//for second host and failed before
|
||||
host = TEST_SLAVE_HOST;
|
||||
|
||||
TEST_ASSERT(spi_bus_initialize(host, &bus_config, GET_DMA_CHAN(host)) == ESP_OK);
|
||||
TEST_ASSERT(spi_bus_add_device(host, &device_config, &spi) == ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_initialize(host, &bus_config, SPI_DMA_CH_AUTO));
|
||||
TEST_ESP_OK(spi_bus_add_device(host, &device_config, &spi));
|
||||
|
||||
printf("before second xmit\n");
|
||||
// the original version (bit mis-written) stucks here.
|
||||
TEST_ASSERT(spi_device_transmit(spi, &transaction) == ESP_OK);
|
||||
TEST_ESP_OK(spi_device_transmit(spi, &transaction));
|
||||
// test case success when see this.
|
||||
printf("after second xmit\n");
|
||||
|
||||
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
|
||||
TEST_ASSERT(spi_bus_free(host) == ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_remove_device(spi));
|
||||
TEST_ESP_OK(spi_bus_free(host));
|
||||
}
|
||||
|
||||
DRAM_ATTR static uint32_t data_dram[80]={0};
|
||||
@ -588,11 +587,9 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]")
|
||||
spi_device_interface_config_t devcfg=SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
|
||||
//Initialize the SPI bus
|
||||
ret=spi_bus_initialize(TEST_SPI_HOST, &buscfg, 1);
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
//Attach the LCD to the SPI bus
|
||||
ret=spi_bus_add_device(TEST_SPI_HOST, &devcfg, &spi);
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &spi));
|
||||
//connect MOSI to two devices breaks the output, fix it.
|
||||
spitest_gpio_output_sel(buscfg.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out);
|
||||
|
||||
@ -658,7 +655,6 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
uint8_t tx_buf[320]={0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43};
|
||||
uint8_t rx_buf[320];
|
||||
|
||||
esp_err_t ret;
|
||||
spi_device_handle_t spi;
|
||||
spi_bus_config_t buscfg={
|
||||
.miso_io_num=PIN_NUM_MOSI,
|
||||
@ -675,11 +671,9 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||
.pre_cb=NULL,
|
||||
};
|
||||
//Initialize the SPI bus
|
||||
ret=spi_bus_initialize(TEST_SPI_HOST, &buscfg, 1);
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
//Attach the LCD to the SPI bus
|
||||
ret=spi_bus_add_device(TEST_SPI_HOST, &devcfg, &spi);
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &spi));
|
||||
|
||||
//connect MOSI to two devices breaks the output, fix it.
|
||||
spitest_gpio_output_sel(buscfg.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out);
|
||||
@ -746,7 +740,7 @@ void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first)
|
||||
//initial master, mode 0, 1MHz
|
||||
spi_bus_config_t buscfg=SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
buscfg.quadhd_io_num = UNCONNECTED_PIN;
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, 1));
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
spi_device_interface_config_t devcfg=SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
devcfg.clock_speed_hz = 1*1000*1000;
|
||||
if (lsb_first) devcfg.flags |= SPI_DEVICE_BIT_LSBFIRST;
|
||||
@ -984,6 +978,8 @@ TEST_CASE("SPI master hd dma TX without RX test", "[spi]")
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &dev_cfg, &spi));
|
||||
|
||||
spi_slave_interface_config_t slave_cfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
|
||||
|
||||
printf("TEST_SLAVE_HOST is %d\n", TEST_SLAVE_HOST);
|
||||
TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &bus_cfg, &slave_cfg, TEST_SLAVE_HOST));
|
||||
|
||||
same_pin_func_sel(bus_cfg, dev_cfg, 0);
|
||||
@ -1076,16 +1072,13 @@ TEST_CASE("SPI master hd dma TX without RX test", "[spi]")
|
||||
|
||||
static void speed_setup(spi_device_handle_t* spi, bool use_dma)
|
||||
{
|
||||
esp_err_t ret;
|
||||
spi_bus_config_t buscfg=SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
spi_device_interface_config_t devcfg=SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
devcfg.queue_size=8; //We want to be able to queue 7 transactions at a time
|
||||
|
||||
//Initialize the SPI bus and the device to test
|
||||
ret=spi_bus_initialize(TEST_SPI_HOST, &buscfg, (use_dma? GET_DMA_CHAN(TEST_SPI_HOST): 0));
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
ret=spi_bus_add_device(TEST_SPI_HOST, &devcfg, spi);
|
||||
TEST_ASSERT(ret==ESP_OK);
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, (use_dma ? SPI_DMA_CH_AUTO : 0)));
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, spi));
|
||||
}
|
||||
|
||||
static void sorted_array_insert(uint32_t* array, int* size, uint32_t item)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user