Merge branch 'master' of ssh://gitlab.espressif.cn:27227/idf/esp-idf

This commit is contained in:
Liu Zhi Fu 2017-02-21 15:03:34 +08:00
commit adfb289e81
68 changed files with 1415 additions and 579 deletions

View file

@ -24,6 +24,16 @@ Once you've found the project you want to work with, change to its directory and
`make menuconfig`
* Opens a text-based configuration menu for the project.
* Use up & down arrow keys to navigate the menu.
* Use Enter key to go into a submenu, Escape key to go out or to exit.
* Type `?` to see a help screen. Enter key exits the help screen.
* Use Space key, or `Y` and `N` keys to enable (Yes) and disable (No) configuration items with checkboxes "`[*]`"
* Pressing `?` while highlighting a configuration item displays help about that item.
* Type `/` to search the configuration items.
Once done configuring, press Escape multiple times to exit and say "Yes" to save the new configuration when prompted.
## Compiling the Project
`make all`
@ -59,7 +69,7 @@ After the initial flash, you may just want to build and flash just your app, not
`make app-flash` will automatically rebuild the app if it needs it.
(There's no downside to reflashing the bootloader and partition table each time, if they haven't changed.)
(In normal development there's no downside to reflashing the bootloader and partition table each time, if they haven't changed.)
## Parallel Builds

View file

@ -9,7 +9,7 @@
if [ -z ${IDF_PATH} ]; then
echo "IDF_PATH must be set before including this script."
else
IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool:${IDF_PATH}/components/partition_table/"
IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool:${IDF_PATH}/components/espcoredump:${IDF_PATH}/components/partition_table/"
export PATH="${PATH}:${IDF_ADD_PATHS_EXTRAS}"
echo "Added to PATH: ${IDF_ADD_PATHS_EXTRAS}"
fi

View file

@ -27,6 +27,7 @@
#include "esp_spi_flash.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "esp_flash_encrypt.h"
#include "sdkconfig.h"
#include "esp_ota_ops.h"
@ -44,6 +45,10 @@ typedef struct ota_ops_entry_ {
esp_partition_t part;
uint32_t erased_size;
uint32_t wrote_size;
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
uint8_t partial_bytes;
uint8_t partial_data[16];
#endif
LIST_ENTRY(ota_ops_entry_) entries;
} ota_ops_entry_t;
@ -106,6 +111,7 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
{
const uint8_t *data_bytes = (const uint8_t *)data;
esp_err_t ret;
ota_ops_entry_t *it;
@ -119,7 +125,47 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
if (it->handle == handle) {
// must erase the partition before writing to it
assert(it->erased_size > 0 && "must erase the partition before writing to it");
ret = esp_partition_write(&it->part, it->wrote_size, data, size);
if(it->wrote_size == 0 && size > 0 && data_bytes[0] != 0xE9) {
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x", data_bytes[0]);
return ESP_ERR_OTA_VALIDATE_FAILED;
}
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
if (esp_flash_encryption_enabled()) {
/* Can only write 16 byte blocks to flash, so need to cache anything else */
size_t copy_len;
/* check if we have partially written data from earlier */
if (it->partial_bytes != 0) {
copy_len = OTA_MIN(16 - it->partial_bytes, size);
memcpy(it->partial_data + it->partial_bytes, data_bytes, copy_len);
it->partial_bytes += copy_len;
if (it->partial_bytes != 16) {
return ESP_OK; /* nothing to write yet, just filling buffer */
}
/* write 16 byte to partition */
ret = esp_partition_write(&it->part, it->wrote_size, it->partial_data, 16);
if (ret != ESP_OK) {
return ret;
}
it->partial_bytes = 0;
memset(it->partial_data, 0xFF, 16);
it->wrote_size += 16;
data_bytes += copy_len;
size -= copy_len;
}
/* check if we need to save trailing data that we're about to write */
it->partial_bytes = size % 16;
if (it->partial_bytes != 0) {
size -= it->partial_bytes;
memcpy(it->partial_data, data_bytes + size, it->partial_bytes);
}
}
#endif
ret = esp_partition_write(&it->part, it->wrote_size, data_bytes, size);
if(ret == ESP_OK){
it->wrote_size += size;
}
@ -135,26 +181,11 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
esp_err_t esp_ota_end(esp_ota_handle_t handle)
{
ota_ops_entry_t *it;
size_t image_size;
esp_err_t ret = ESP_OK;
for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) {
if (it->handle == handle) {
// an ota handle need to be ended after erased and wrote data in it
if ((it->erased_size == 0) || (it->wrote_size == 0)) {
return ESP_ERR_INVALID_ARG;
}
#ifdef CONFIG_SECUREBOOTLOADER
esp_err_t ret;
size_t image_size;
if (esp_image_basic_verify(it->part.address, &image_size) != ESP_OK) {
return ESP_ERR_OTA_VALIDATE_FAILED;
}
ret = esp_secure_boot_verify_signature(it->part.address, image_size);
if (ret != ESP_OK) {
return ESP_ERR_OTA_VALIDATE_FAILED;
}
#endif
LIST_REMOVE(it, entries);
break;
}
}
@ -163,8 +194,44 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
return ESP_ERR_NOT_FOUND;
}
/* 'it' holds the ota_ops_entry_t for 'handle' */
// esp_ota_end() is only valid if some data was written to this handle
if ((it->erased_size == 0) || (it->wrote_size == 0)) {
ret = ESP_ERR_INVALID_ARG;
goto cleanup;
}
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
if (it->partial_bytes > 0 && esp_flash_encryption_enabled()) {
/* Write out last 16 bytes, if necessary */
ret = esp_partition_write(&it->part, it->wrote_size, it->partial_data, 16);
if (ret != ESP_OK) {
ret = ESP_ERR_INVALID_STATE;
goto cleanup;
}
it->wrote_size += 16;
it->partial_bytes = 0;
}
#endif
if (esp_image_basic_verify(it->part.address, true, &image_size) != ESP_OK) {
ret = ESP_ERR_OTA_VALIDATE_FAILED;
goto cleanup;
}
#ifdef CONFIG_SECURE_BOOT_ENABLED
ret = esp_secure_boot_verify_signature(it->part.address, image_size);
if (ret != ESP_OK) {
ret = ESP_ERR_OTA_VALIDATE_FAILED;
goto cleanup;
}
#endif
cleanup:
LIST_REMOVE(it, entries);
free(it);
return ESP_OK;
return ret;
}
static uint32_t ota_select_crc(const ota_select *s)
@ -271,11 +338,9 @@ static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype)
}
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition);
} else if (s_ota_select[0].ota_seq == 0xFFFFFFFF && s_ota_select[1].ota_seq == 0xFFFFFFFF) {
return rewrite_ota_seq(SUB_TYPE_ID(subtype) + 1, 0, find_partition);
} else {
return ESP_ERR_OTA_SELECT_INFO_INVALID;
/* Both OTA slots are invalid, probably because unformatted... */
return rewrite_ota_seq(SUB_TYPE_ID(subtype) + 1, 0, find_partition);
}
} else {
@ -285,17 +350,18 @@ static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype)
esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)
{
size_t image_size;
const esp_partition_t *find_partition = NULL;
if (partition == NULL) {
return ESP_ERR_INVALID_ARG;
}
#ifdef CONFIG_SECUREBOOTLOADER
size_t image_size;
if (esp_image_basic_verify(partition->address, &image_size) != ESP_OK) {
if (esp_image_basic_verify(partition->address, true, &image_size) != ESP_OK) {
return ESP_ERR_OTA_VALIDATE_FAILED;
}
ret = esp_secure_boot_verify_signature(partition->address, image_size);
#ifdef CONFIG_SECURE_BOOT_ENABLED
esp_err_t ret = esp_secure_boot_verify_signature(partition->address, image_size);
if (ret != ESP_OK) {
return ESP_ERR_OTA_VALIDATE_FAILED;
}
@ -349,33 +415,34 @@ const esp_partition_t *esp_ota_get_boot_partition(void)
}
ota_app_count = get_ota_partition_count();
ESP_LOGD(TAG, "found ota bin max = %d", ota_app_count);
ESP_LOGD(TAG, "found ota app max = %d", ota_app_count);
if (s_ota_select[0].ota_seq == 0xFFFFFFFF && s_ota_select[1].ota_seq == 0xFFFFFFFF) {
ESP_LOGD(TAG, "finding factory bin......");
ESP_LOGD(TAG, "finding factory app......");
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
} else if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) {
ESP_LOGD(TAG, "finding ota_%d bin......", \
ESP_LOGD(TAG, "finding ota_%d app......", \
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count));
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count), NULL);
} else if (ota_select_valid(&s_ota_select[0])) {
ESP_LOGD(TAG, "finding ota_%d bin......", \
ESP_LOGD(TAG, "finding ota_%d app......", \
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count);
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count, NULL);
} else if (ota_select_valid(&s_ota_select[1])) {
ESP_LOGD(TAG, "finding ota_%d bin......", \
ESP_LOGD(TAG, "finding ota_%d app......", \
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count);
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count, NULL);
} else {
ESP_LOGE(TAG, "not found current bin");
return NULL;
ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory");
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
}
}

View file

@ -73,11 +73,16 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void* data, size_t size);
/**
* @brief Finish the update and validate written data
*
* @param handle Handle obtained from esp_ota_begin
* @param handle Handle obtained from esp_ota_begin.
*
* @return:
* - ESP_OK: if validate ota image pass
* - ESP_ERR_OTA_VALIDATE_FAILED: validate the ota image is invalid
* @note After calling esp_ota_end(), the handle is no longer valid and any memory associated with it is freed (regardless of result).
*
* @return:
* - ESP_OK: Newly written OTA app image is valid.
* - ESP_ERR_NOT_FOUND: OTA handle was not found.
* - ESP_ERR_INVALID_ARG: Handle was never written to.
* - ESP_ERR_OTA_VALIDATE_FAILED: OTA image is invalid (either not a valid app image, or - if secure boot is enabled - signature failed to verify.)
* - ESP_ERR_INVALID_STATE: If flash encryption is enabled, this result indicates an internal error writing the final encrypted bytes to flash.
*/
esp_err_t esp_ota_end(esp_ota_handle_t handle);

View file

@ -35,16 +35,16 @@ endmenu
menu "Security features"
config SECURE_BOOT_ENABLED
bool "Enable secure boot in bootloader"
bool "Enable secure boot in bootloader (READ DOCS FIRST)"
default N
help
Build a bootloader which enables secure boot on first boot.
Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition table or boot an app if the data has a verified digital signature.
Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition table or boot an app if the data has a verified digital signature. There are implications for reflashing updated apps once secure boot is enabled.
When enabling secure boot, JTAG and ROM BASIC Interpreter are permanently disabled by default.
See docs/security/secure-boot.rst for details.
Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling.
choice SECURE_BOOTLOADER_MODE
bool "Secure bootloader mode"
@ -108,7 +108,7 @@ config SECURE_BOOT_VERIFICATION_KEY
PEM formatted private key using the espsecure.py
extract_public_key command.
See docs/security/secure-boot.rst for details.
Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling.
config SECURE_BOOT_INSECURE
bool "Allow potentially insecure options"
@ -119,16 +119,18 @@ config SECURE_BOOT_INSECURE
Only enable these options if you are very sure.
Refer to docs/security/secure-boot.rst and docs/security/flash-encryption.rst for details.
Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling.
config FLASH_ENCRYPTION_ENABLED
bool "Enable flash encryption on boot"
bool "Enable flash encryption on boot (READ DOCS FIRST)"
default N
help
If this option is set, flash contents will be encrypted by the bootloader on first boot.
Note: After first boot, the system will be permanently encrypted.
See docs/securityflash-encryption.rst for details.
Note: After first boot, the system will be permanently encrypted. Re-flashing an encrypted
system is complicated and not always possible.
Read http://esp-idf.readthedocs.io/en/latest/security/flash-encryption.html before enabling.
config FLASH_ENCRYPTION_INSECURE
bool "Allow potentially insecure options"

View file

@ -323,12 +323,15 @@ void bootloader_main()
} else {
if(ota_select_valid(&sa) && ota_select_valid(&sb)) {
load_part_pos = bs.ota[(((sa.ota_seq > sb.ota_seq)?sa.ota_seq:sb.ota_seq) - 1)%bs.app_count];
}else if(ota_select_valid(&sa)) {
} else if(ota_select_valid(&sa)) {
load_part_pos = bs.ota[(sa.ota_seq - 1) % bs.app_count];
}else if(ota_select_valid(&sb)) {
} else if(ota_select_valid(&sb)) {
load_part_pos = bs.ota[(sb.ota_seq - 1) % bs.app_count];
}else {
ESP_LOGE(TAG, "ota data partition info error");
} else if (bs.factory.offset != 0) {
ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
load_part_pos = bs.factory;
} else {
ESP_LOGE(TAG, "ota data partition invalid and no factory, can't boot");
return;
}
}

View file

@ -18,6 +18,6 @@ ifdef IS_BOOTLOADER_BUILD
# following lines are a workaround to link librtc into the
# bootloader, until clock setting code is in a source-based esp-idf
# component. See also rtc_printf() in bootloader_start.c
COMPONENT_ADD_LDFLAGS += -L $(IDF_PATH)/components/esp32/lib/ -lrtc
COMPONENT_ADD_LDFLAGS += -L $(IDF_PATH)/components/esp32/lib/ -lrtc_clk -lrtc
COMPONENT_EXTRA_INCLUDES += $(IDF_PATH)/components/esp32/
endif

View file

@ -15,14 +15,17 @@
#define __ESP32_FLASH_ENCRYPT_H
#include <stdbool.h>
#include <esp_err.h>
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_spi_flash.h"
#include "soc/efuse_reg.h"
/* Support functions for flash encryption features.
Can be compiled as part of app or bootloader code.
*/
/**
* @file esp_partition.h
* @brief Support functions for flash encryption features
*
* Can be compiled as part of app or bootloader code.
*/
/** @brief Is flash encryption currently enabled in hardware?
*
@ -30,9 +33,17 @@
*
* @return true if flash encryption is enabled.
*/
static inline bool esp_flash_encryption_enabled(void) {
static inline IRAM_ATTR bool esp_flash_encryption_enabled(void) {
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_RD_FLASH_CRYPT_CNT);
return __builtin_parity(flash_crypt_cnt) == 1;
/* __builtin_parity is in flash, so we calculate parity inline */
bool enabled = false;
while(flash_crypt_cnt) {
if (flash_crypt_cnt & 1) {
enabled = !enabled;
}
flash_crypt_cnt >>= 1;
}
return enabled;
}
/* @brief Update on-device flash encryption

View file

@ -16,6 +16,7 @@
#include <bootloader_flash.h>
#include <esp_log.h>
#include <esp_spi_flash.h> /* including in bootloader for error values */
#include <esp_flash_encrypt.h>
#ifndef BOOTLOADER_BUILD
/* Normal app version maps to esp_spi_flash.h operations...
@ -48,7 +49,11 @@ void bootloader_munmap(const void *mapping)
esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size, bool allow_decrypt)
{
return spi_flash_read(src, dest, size);
if (allow_decrypt && esp_flash_encryption_enabled()) {
return spi_flash_read_encrypted(src, dest, size);
} else {
return spi_flash_read(src, dest, size);
}
}
esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)

View file

@ -285,6 +285,9 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit
} else {
should_encrypt = false;
}
} else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) {
/* check if we have ota data partition and the partition should be encrypted unconditionally */
should_encrypt = true;
}
if (!should_encrypt) {

View file

@ -16,6 +16,7 @@
#include "esp_bt_main.h"
#include "btc_task.h"
#include "btc_main.h"
#include "bt.h"
#include "future.h"
static bool esp_already_enable = false;
@ -103,6 +104,11 @@ esp_err_t esp_bluedroid_init(void)
btc_msg_t msg;
future_t **future_p;
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
LOG_ERROR("%s conroller not init\n", __func__);
return ESP_ERR_INVALID_STATE;
}
if (esp_already_init) {
LOG_ERROR("%s already init\n", __func__);
return ESP_ERR_INVALID_STATE;

View file

@ -221,6 +221,10 @@ static void start_up(void)
}
if (HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array)) {
/* set default tx data length to MAX 251 */
response = AWAIT_COMMAND(packet_factory->make_ble_write_suggested_default_data_length(BTM_BLE_DATA_SIZE_MAX, BTM_BLE_DATA_TX_TIME_MAX));
packet_parser->parse_generic_command_complete(response);
response = AWAIT_COMMAND(packet_factory->make_ble_read_suggested_default_data_length());
packet_parser->parse_ble_read_suggested_default_data_length_response(
response,

View file

@ -154,6 +154,17 @@ static BT_HDR *make_ble_read_suggested_default_data_length(void)
return make_command_no_params(HCI_BLE_READ_DEFAULT_DATA_LENGTH);
}
static BT_HDR *make_ble_write_suggested_default_data_length(uint16_t SuggestedMaxTxOctets, uint16_t SuggestedMaxTxTime)
{
uint8_t *stream;
uint8_t parameter_size = sizeof(uint16_t) + sizeof(uint16_t);
BT_HDR *packet = make_command(HCI_BLE_WRITE_DEFAULT_DATA_LENGTH, parameter_size, &stream);
UINT16_TO_STREAM(stream, SuggestedMaxTxOctets);
UINT16_TO_STREAM(stream, SuggestedMaxTxTime);
return packet;
}
static BT_HDR *make_ble_set_event_mask(const bt_event_mask_t *event_mask)
{
uint8_t *stream;
@ -215,6 +226,7 @@ static const hci_packet_factory_t interface = {
make_ble_read_local_supported_features,
make_ble_read_resolving_list_size,
make_ble_read_suggested_default_data_length,
make_ble_write_suggested_default_data_length,
make_ble_set_event_mask
};

View file

@ -40,6 +40,7 @@ typedef struct {
BT_HDR *(*make_ble_read_local_supported_features)(void);
BT_HDR *(*make_ble_read_resolving_list_size)(void);
BT_HDR *(*make_ble_read_suggested_default_data_length)(void);
BT_HDR *(*make_ble_write_suggested_default_data_length)(uint16_t SuggestedMaxTxOctets, uint16_t SuggestedMaxTxTime);
BT_HDR *(*make_ble_set_event_mask)(const bt_event_mask_t *event_mask);
} hci_packet_factory_t;

View file

@ -1073,9 +1073,11 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
GATTS_REQ_TYPE_WRITE,
&sr_data);
if(status == GATT_SUCCESS){
if (status == GATT_SUCCESS) {
attp_send_sr_msg(p_tcb, p_msg);
gatt_dequeue_sr_cmd(p_tcb);
} else {
GKI_freebuf(p_msg);
}
} else {

View file

@ -27,6 +27,7 @@
#include "esp_task.h"
#include "esp_intr.h"
#include "esp_attr.h"
#include "esp_phy_init.h"
#include "bt.h"
#if CONFIG_BT_ENABLED
@ -34,6 +35,11 @@
/* not for user call, so don't put to include file */
extern void btdm_osi_funcs_register(void *osi_funcs);
extern void btdm_controller_init(void);
extern void btdm_controller_schedule(void);
extern void btdm_controller_deinit(void);
extern int btdm_controller_enable(esp_bt_mode_t mode);
extern int btdm_controller_disable(esp_bt_mode_t mode);
extern void btdm_rf_bb_init(void);
/* VHCI function interface */
typedef struct vhci_host_callback {
@ -70,6 +76,12 @@ struct osi_funcs_t {
esp_err_t (* _read_efuse_mac)(uint8_t mac[6]);
};
/* Static variable declare */
static bool btdm_bb_init_flag = false;
static esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
static xTaskHandle btControllerTaskHandle;
static portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED;
static void IRAM_ATTR interrupt_disable(void)
@ -145,14 +157,87 @@ void esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)
static void bt_controller_task(void *pvParam)
{
btdm_osi_funcs_register(&osi_funcs);
btdm_controller_init();
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
/* Loop */
btdm_controller_schedule();
}
void esp_bt_controller_init()
{
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) {
return;
}
xTaskCreatePinnedToCore(bt_controller_task, "btController",
ESP_TASK_BT_CONTROLLER_STACK, NULL,
ESP_TASK_BT_CONTROLLER_PRIO, NULL, 0);
ESP_TASK_BT_CONTROLLER_PRIO, &btControllerTaskHandle, 0);
}
void esp_bt_controller_deinit(void)
{
vTaskDelete(btControllerTaskHandle);
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
}
esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
{
int ret;
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) {
return ESP_ERR_INVALID_STATE;
}
if (mode != ESP_BT_MODE_BTDM) {
return ESP_ERR_INVALID_ARG;
}
esp_phy_load_cal_and_init();
if (btdm_bb_init_flag == false) {
btdm_bb_init_flag = true;
btdm_rf_bb_init(); /* only initialise once */
}
ret = btdm_controller_enable(mode);
if (ret) {
return ESP_ERR_INVALID_STATE;
}
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED;
return ESP_OK;
}
esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode)
{
int ret;
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
if (mode != ESP_BT_MODE_BTDM) {
return ESP_ERR_INVALID_ARG;
}
ret = btdm_controller_disable(mode);
if (ret) {
return ESP_ERR_INVALID_STATE;
}
esp_phy_rf_deinit();
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
return ESP_OK;
}
esp_bt_controller_status_t esp_bt_controller_get_status(void)
{
return btdm_controller_status;
}
#endif

View file

@ -23,14 +23,63 @@
extern "C" {
#endif
/**
* @brief Bluetooth mode for controller enable/disable
*/
typedef enum {
ESP_BT_MODE_ILDE = 0x00, /*!< Bluetooth is not run */
ESP_BT_MODE_BLE = 0x01, /*!< Run BLE mode */
ESP_BT_MODE_CLASSIC_BT = 0x02, /*!< Run Classic BT mode */
ESP_BT_MODE_BTDM = 0x03, /*!< Run dual mode */
} esp_bt_mode_t;
/**
* @brief Initialize BT controller
* @brief Bluetooth controller enable/disable/initialised/de-initialised status
*/
typedef enum {
ESP_BT_CONTROLLER_STATUS_IDLE = 0,
ESP_BT_CONTROLLER_STATUS_INITED,
ESP_BT_CONTROLLER_STATUS_ENABLED,
ESP_BT_CONTROLLER_STATUS_NUM,
} esp_bt_controller_status_t;
/**
* @brief Initialize BT controller to allocate task and other resource.
*
* This function should be called only once, before any other BT functions are called.
*/
void esp_bt_controller_init(void);
/**
* @brief De-initialize BT controller to free resource and delete task.
*
* This function should be called only once, after any other BT functions are called.
* This function is not whole completed, esp_bt_controller_init cannot called after this function.
*/
void esp_bt_controller_deinit(void);
/**
* @brief Enable BT controller
* @param mode : the mode(BLE/BT/BTDM) to enable.
* Now only support BTDM.
* @return ESP_OK - success, other - failed
*/
esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode);
/**
* @brief Disable BT controller
* @param mode : the mode(BLE/BT/BTDM) to disable.
* Now only support BTDM.
* @return ESP_OK - success, other - failed
*/
esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode);
/**
* @brief Get BT controller is initialised/de-initialised/enabled/disabled
* @return status value
*/
esp_bt_controller_status_t esp_bt_controller_get_status(void);
/** @brief esp_vhci_host_callback
* used for vhci call host function to notify what host need to do
*/

@ -1 +1 @@
Subproject commit 9c1eea6bb03adc3b3847fff79c3f017652840a46
Subproject commit dbac82b5c2694f2639161b0a2b3c0bd8c7d3efc5

View file

@ -49,11 +49,11 @@ typedef enum {
} adc1_channel_t;
/**
* @brief Configuration ADC1 capture width.
* @brief Configure ADC1 capture width.
*
* The configuration is in effect for all channels of ADC1
* The configuration is for all channels of ADC1
*
* @param width_bit ADC1
* @param width_bit Bit capture width for ADC1
*
* @return
* - ESP_OK success
@ -62,10 +62,29 @@ typedef enum {
esp_err_t adc1_config_width(adc_bits_width_t width_bit);
/**
* @brief Configuration ADC1 capture attenuation of channels.
* @brief Configure the ADC1 channel, including setting attenuation.
*
* @param channel the ADC1 channel
* @param atten attenuation
* @note This function also configures the input GPIO pin mux to
* connect it to the ADC1 channel. It must be called before calling
* adc1_get_voltage() for this channel.
*
* The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage,
* usually 3.3V) requires setting >0dB signal attenuation for that ADC channel.
*
* When VDD_A is 3.3V:
*
* - 0dB attenuaton (ADC_ATTEN_0db) gives full-scale voltage 1.1V
* - 2.5dB attenuation (ADC_ATTEN_2_5db) gives full-scale voltage 1.5V
* - 6dB attenuation (ADC_ATTEN_6db) gives full-scale voltage 2.2V
* - 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V (see note below)
*
* @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured
* bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.)
*
* @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage.
*
* @param channel ADC1 channel to configure
* @param atten Attenuation level
*
* @return
* - ESP_OK success
@ -74,46 +93,38 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit);
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten);
/**
* @brief ADC1 get the value of the voltage.
* @brief Take an ADC1 reading on a single channel
*
* @param channel the ADC1 channel
* @note Call adc1_config_width() before the first time this
* function is called.
*
* @note For a given channel, adc1_config_channel_atten(channel)
* must be called before the first time this function is called.
*
* @param channel ADC1 channel to read
*
* @return
* - -1 Parameter error
* - Other the value of ADC1 channel
* - -1: Parameter error
* - Other: ADC1 channel reading.
*/
int adc1_get_voltage(adc1_channel_t channel);
/**
* @brief Hall Sensor output value.
* @note
* The Hall Sensor uses Channel_0 and Channel_3 of ADC1.
* So, firstly: please configure ADC1 module by calling adc1_config_width before calling hall_sensor_read.
We recommend that the WIDTH ADC1 be configured as 12Bit, because the values of hall_sensor_read are small and almost the same if WIDTH ADC1 is configured as 9Bit, 10Bit or 11Bit.
* secondly: when you use the hall sensor, please do not use Channel_0 and Channel_3 of ADC1 as
* ADC channels.
* @brief Read Hall Sensor
*
* @return the value of hall sensor
* @note The Hall Sensor uses channels 0 and 3 of ADC1. Do not configure
* these channels for use as ADC channels.
*
* @note The ADC1 module must be enabled by calling
* adc1_config_width() before calling hall_sensor_read(). ADC1
* should be configured for 12 bit readings, as the hall sensor
* readings are low values and do not cover the full range of the
* ADC.
*
* @return The hall sensor reading.
*/
int hall_sensor_read();
/**
*----------EXAMPLE TO USE ADC1------------ *
* @code{c}
* adc1_config_width(ADC_WIDTH_12Bit);//config adc1 width
* adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_0db);//config channel0 attenuation
* int val=adc1_get_voltage(ADC1_CHANNEL_0);//get the val of channel0
* @endcode
**/
/**
*----------EXAMPLE TO USE HALL SENSOR------------ *
* @code{c}
* adc1_config_width(ADC_WIDTH_12Bit);//config adc1 width
* int val=hall_sensor_read();
* @endcode
**/
#ifdef __cplusplus
}
#endif

View file

@ -29,12 +29,15 @@ typedef enum {
} dac_channel_t;
/**
* @brief Set Dac output voltage.
* @brief Set DAC output voltage.
*
* Dac width is 8bit ,and the voltage max is vdd
* DAC output is 8-bit. Maximum (255) corresponds to VDD.
*
* @param channel dac channel
* @param dac_value dac output value
* @note When this function is called, function for the DAC
* channel's GPIO pin is reconfigured for RTC DAC function.
*
* @param channel DAC channel
* @param dac_value DAC output value
*
* @return
* - ESP_OK success
@ -42,13 +45,6 @@ typedef enum {
*/
esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value);
/**
*----------EXAMPLE TO USE DAC------------ *
* @code{c}
* dac_out_voltage(DAC_CHANNEL_1,200);//the dac out voltage ≈ 200*vdd/255
* @endcode
**/
#ifdef __cplusplus
}
#endif

View file

@ -302,9 +302,9 @@ int gpio_get_level(gpio_num_t gpio_num);
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
/**
* @brief GPIO set pull
* @brief Configure GPIO pull-up/pull-down resistors
*
* User this Function,configure GPIO pull mode,such as pull-up,pull-down
* Only pins that support both input & output have integrated pull-up and pull-down resistors. Input-only GPIOs 34-39 do not.
*
* @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param pull GPIO pull up/down mode.
@ -317,7 +317,7 @@ esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
/**
* @brief enable GPIO wake-up function.
* @brief Enable GPIO wake-up function.
*
* @param gpio_num GPIO number.
*
@ -341,15 +341,23 @@ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
/**
* @brief register GPIO interrupt handler, the handler is an ISR.
* @brief Register GPIO interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
*
* This ISR function is called whenever any GPIO interrupt occurs. See
* the alternative gpio_install_isr_service() and
* gpio_isr_handler_add() API in order to have the driver support
* per-GPIO ISRs.
*
* @param fn Interrupt 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.
* @param arg Parameter for handler function
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will be returned here.
*
* \verbatim embed:rst:leading-asterisk
* To disable or remove the ISR, pass the returned handle to the :doc:`interrupt allocation functions </api/system/intr_alloc>`.
* \endverbatim
*
* @return
* - ESP_OK Success ;
@ -402,7 +410,9 @@ esp_err_t gpio_pulldown_en(gpio_num_t gpio_num);
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
/**
* @brief Install a GPIO ISR service, so we can assign different ISR handler for different pins
* @brief Install the driver's GPIO ISR handler service, which allows per-pin GPIO interrupt handlers.
*
* This function is incompatible with gpio_isr_register() - if that function is used, a single global ISR is registered for all GPIO interrupts. If this function is used, the ISR service provides a global GPIO ISR and individual pin handlers are registered via the gpio_isr_register() 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.
@ -415,17 +425,24 @@ esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
esp_err_t gpio_install_isr_service(int intr_alloc_flags);
/**
* @brief Un-install GPIO ISR service, free the resources.
* @brief Uninstall the driver's GPIO ISR service, freeing related resources.
*/
void gpio_uninstall_isr_service();
/**
* @brief Add ISR handler for the corresponding GPIO.
* @brief Add ISR handler for the corresponding GPIO pin.
*
* Interrupt handlers no longer need to be declared with IRAM_ATTR, unless you pass the ESP_INTR_FLAG_IRAM flag
* when allocating the ISR in gpio_install_isr_service().
* This ISR handler will be called from an ISR. So there probably is some stack size limit, and this limit
* is smaller compared to a "raw" interrupt handler due to another level of indirection.
* Call this function after using gpio_install_isr_service() to
* install the driver's GPIO ISR handler service.
*
* The pin ISR handlers no longer need to be declared with IRAM_ATTR,
* unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the
* ISR in gpio_install_isr_service().
*
* This ISR handler will be called from an ISR. So there is a stack
* size limit (configurable as "ISR stack size" in menuconfig). This
* limit is smaller compared to a global GPIO interrupt handler due
* to the additional level of indirection.
*
* @param gpio_num GPIO number
* @param isr_handler ISR handler function for the corresponding GPIO number.
@ -439,7 +456,7 @@ void gpio_uninstall_isr_service();
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void* args);
/**
* @brief Remove ISR handler for the corresponding GPIO.
* @brief Remove ISR handler for the corresponding GPIO pin.
*
* @param gpio_num GPIO number
*

View file

@ -32,9 +32,6 @@
extern "C" {
#endif
#define I2S_PIN_NO_CHANGE (-1)
/**
* @brief I2S bit width per sample.
*
@ -147,6 +144,8 @@ typedef struct {
size_t size; /*!< I2S data size for I2S_DATA event*/
} i2s_event_t;
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
/**
* @brief I2S pin number for i2s_set_pin
*
@ -160,15 +159,18 @@ typedef struct {
typedef intr_handle_t i2s_isr_handle_t;
/**
* @brief Set I2S pin number
* @brief Set I2S pin number
*
* @note
* Internal signal can be output to multiple GPIO pads
* Only one GPIO pad can connect with input signal
* @note
* The I2S peripheral output signals can be connected to multiple GPIO pads.
* However, the I2S peripheral input signal can only be connected to one GPIO pad.
*
* @param i2s_num I2S_NUM_0 or I2S_NUM_1
*
* @param pin I2S Pin struct, or NULL for 2-channels, 8-bits DAC pin configuration (GPIO25 & GPIO26)
* @param pin I2S Pin structure, or NULL to set 2-channel 8-bit internal DAC pin configuration (GPIO25 & GPIO26)
*
* Inside the pin configuration structure, set I2S_PIN_NO_CHANGE for any pin where
* the current configuration should not be changed.
*
* @return
* - ESP_OK Success
@ -177,15 +179,17 @@ typedef intr_handle_t i2s_isr_handle_t;
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
/**
* @brief i2s install and start driver
* @brief Install and start I2S driver.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param i2s_config I2S configurations - see i2s_config_t struct
* @param i2s_config I2S configurations - see i2s_config_t struct
*
* @param queue_size I2S event queue size/depth.
* @param queue_size I2S event queue size/depth.
*
* @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue.
* @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue.
*
* This function must be called before any I2S driver read/write operations.
*
* @return
* - ESP_OK Success
@ -205,68 +209,88 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
/**
* @brief i2s read data buffer to i2s dma buffer
* @brief Write data to I2S DMA transmit buffer.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src source address to write
* @param src Source address to write from
*
* @param size size of data (size in bytes)
* @param size Size of data in bytes
*
* @param ticks_to_wait Write timeout
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
* many ticks pass without space becoming available in the DMA
* transmit buffer, then the function will return (note that if the
* data is written to the DMA buffer in pieces, the overall operation
* may still take longer than this timeout.) Pass portMAX_DELAY for no
* timeout.
*
* @return number of written bytes
* Format of the data in source buffer is determined by the I2S
* configuration (see i2s_config_t).
*
* @return Number of bytes written, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes written will be less than total size.
*/
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait);
/**
* @brief i2s write data buffer to i2s dma buffer
* @brief Read data from I2S DMA receive buffer
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param dest destination address to read
* @param dest Destination address to read into
*
* @param size size of data (size in bytes)
* @param size Size of data in bytes
*
* @param ticks_to_wait Read timeout
* @param ticks_to_wait RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.
*
* @return number of read bytes
* Format of the data in source buffer is determined by the I2S
* configuration (see i2s_config_t).
*
* @return Number of bytes read, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes read will be less than total size.
*/
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait);
/**
* @brief i2s push 1 sample to i2s dma buffer, with the size parameter equal to one sample's size in bytes = bits_per_sample/8.
* @brief Push (write) a single sample to the I2S DMA TX buffer.
*
* Size of the sample is determined by the channel_format (mono or stereo)) & bits_per_sample configuration (see i2s_config_t).
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param sample destination address to write (depend on bits_per_sample, size of sample (in bytes) = 2*bits_per_sample/8)
* @param sample Pointer to buffer containing sample to write. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8.
*
* @param ticks_to_wait Push timeout
* @param ticks_to_wait Push timeout in RTOS ticks. If space is not available in the DMA TX buffer within this period, no data is written and function returns 0.
*
* @return number of push bytes
* @return Number of bytes successfully pushed to DMA buffer, or ESP_FAIL (-1) for parameter error. Will be either zero or the size of configured sample buffer.
*/
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait);
/**
* @brief Pop 1 sample to i2s dma buffer, with the size parameter equal to one sample's size in bytes = bits_per_sample/8.
* @brief Pop (read) a single sample from the I2S DMA RX buffer.
*
* Size of the sample is determined by the channel_format (mono or stereo)) & bits_per_sample configuration (see i2s_config_t).
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param sample destination address to write (depend on bits_per_sample, size of sample (in bytes) = 2*bits_per_sample/8)
* @param sample Buffer sample data will be read into. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8.
*
* @param ticks_to_wait Pop timeout
* @param ticks_to_wait Pop timeout in RTOS ticks. If a sample is not available in the DMA buffer within this period, no data is read and function returns zero.
*
* @return number of pop bytes
* @return Number of bytes successfully read from DMA buffer, or ESP_FAIL (-1) for parameter error. Byte count will be either zero or the size of the configured sample buffer.
*/
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait);
/**
* @brief Set clock rate used for I2S RX and TX
* @brief Set sample rate used for I2S RX and TX.
*
* The bit clock rate is determined by the sample rate and i2s_config_t configuration parameters (number of channels, bits_per_sample).
*
* `bit_clock = rate * (number of channels) * bits_per_sample`
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S clock (ex: 8000, 44100...)
* @param rate I2S sample rate (ex: 8000, 44100...)
*
* @return
* - ESP_OK Success
@ -275,18 +299,9 @@ int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait);
esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
/**
* @brief Start driver
* @brief Stop I2S driver
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_start(i2s_port_t i2s_num);
/**
* @brief Stop driver
* Disables I2S TX/RX, until i2s_start() is called.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
@ -297,7 +312,23 @@ esp_err_t i2s_start(i2s_port_t i2s_num);
esp_err_t i2s_stop(i2s_port_t i2s_num);
/**
* @brief Set the TX DMA buffer contents to all zeroes
* @brief Start I2S driver
*
* It is not necessary to call this function after i2s_driver_install() (it is started automatically), however it is necessary to call it after i2s_stop().
*
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_start(i2s_port_t i2s_num);
/**
* @brief Zero the contents of the TX DMA buffer.
*
* Pushes zero-byte samples into the TX DMA buffer, until it is full.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
@ -307,72 +338,6 @@ esp_err_t i2s_stop(i2s_port_t i2s_num);
*/
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
/***************************EXAMPLE**********************************
*
*
* ----------------EXAMPLE OF I2S SETTING ---------------------
* @code{c}
*
* #include "freertos/queue.h"
* #define I2S_INTR_NUM 17 //choose one interrupt number from soc.h
* int i2s_num = 0; //i2s port number
* i2s_config_t i2s_config = {
* .mode = I2S_MODE_MASTER | I2S_MODE_TX,
* .sample_rate = 44100,
* .bits_per_sample = 16, //16, 32
* .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //format LEFT_RIGHT
* .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
* .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
* .dma_buf_count = 8,
* .dma_buf_len = 64
* };
*
* i2s_pin_config_t pin_config = {
* .bck_io_num = 26,
* .ws_io_num = 25,
* .data_out_num = 22,
* .data_in_num = I2S_PIN_NO_CHANGE
* };
*
* i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
*
* i2s_set_pin(i2s_num, &pin_config);
*
* i2s_set_sample_rates(i2s_num, 22050); //set sample rates
*
*
* i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
*@endcode
*
* ----------------EXAMPLE USING I2S WITH DAC ---------------------
* @code{c}
*
* #include "freertos/queue.h"
* #define I2S_INTR_NUM 17 //choose one interrupt number from soc.h
* int i2s_num = 0; //i2s port number
* i2s_config_t i2s_config = {
* .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
* .sample_rate = 44100,
* .bits_per_sample = 8, // Only 8-bit DAC support
* .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //
* .communication_format = I2S_COMM_FORMAT_I2S_MSB,
* .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
* .dma_buf_count = 8,
* .dma_buf_len = 64
* };
*
*
* i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
*
* i2s_set_pin(i2s_num, NULL); //for internal DAC
*
* i2s_set_sample_rates(i2s_num, 22050); //set sample rates
*
* i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
*@endcode
*-----------------------------------------------------------------------------*
***************************END OF EXAMPLE**********************************/
#ifdef __cplusplus
}
#endif

View file

@ -24,7 +24,10 @@ extern "C" {
#endif
/**
* @brief Pullup/pulldown information for a single GPIO pad
* @brief Pin function information for a single GPIO pad's RTC functions.
*
* This is an internal function of the driver, and is not usually useful
* for external use.
*/
typedef struct {
uint32_t reg; /*!< Register of RTC pad, or 0 if not an RTC GPIO */
@ -46,10 +49,29 @@ typedef enum {
RTC_GPIO_MODE_DISABLED, /*!< Pad (output + input) disable */
} rtc_gpio_mode_t;
#define RTC_GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num < GPIO_PIN_COUNT && rtc_gpio_desc[gpio_num].reg != 0)) //to decide whether it is a valid GPIO number
/**
* @brief Provides access to a constant table of RTC I/O pin
* function information.
*
* This is an internal function of the driver, and is not usually useful
* for external use.
*/
extern const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT];
/**
* @brief Determine if the specified GPIO is a valid RTC GPIO.
*
* @param gpio_num GPIO number
* @return true if GPIO is valid for RTC GPIO use. talse otherwise.
*/
inline static bool rtc_gpio_is_valid_gpio(gpio_num_t gpio_num)
{
return gpio_num < GPIO_PIN_COUNT
&& rtc_gpio_desc[gpio_num].reg != 0;
}
#define RTC_GPIO_IS_VALID_GPIO(gpio_num) rtc_gpio_is_valid_gpio(gpio_num) // Deprecated, use rtc_gpio_is_valid_gpio()
/**
* @brief Init a GPIO as RTC GPIO
*

View file

@ -469,8 +469,6 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
* @brief Install UART driver.
*
* UART ISR handler will be attached to the same CPU core that this function is running on.
* Users should know that which CPU is running and then pick a INUM that is not used by system.
* We can find the information of INUM and interrupt level in soc.h.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param rx_buffer_size UART RX ring buffer size, rx_buffer_size should be greater than UART_FIFO_LEN.
@ -644,7 +642,6 @@ esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, u
* @code{c}
* //1. Setup UART
* #include "freertos/queue.h"
* #define UART_INTR_NUM 17 //choose one interrupt number from soc.h
* //a. Set UART parameter
* int uart_num = 0; //uart port number
* uart_config_t uart_config = {

View file

@ -87,7 +87,7 @@ const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
---------------------------------------------------------------*/
esp_err_t rtc_gpio_init(gpio_num_t gpio_num)
{
RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
// 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module.
SET_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, (rtc_gpio_desc[gpio_num].mux));
@ -100,7 +100,7 @@ esp_err_t rtc_gpio_init(gpio_num_t gpio_num)
esp_err_t rtc_gpio_deinit(gpio_num_t gpio_num)
{
RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
//Select Gpio as Digital Gpio
CLEAR_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, (rtc_gpio_desc[gpio_num].mux));
@ -131,7 +131,7 @@ static esp_err_t rtc_gpio_output_disable(gpio_num_t gpio_num)
static esp_err_t rtc_gpio_input_enable(gpio_num_t gpio_num)
{
RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
SET_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, rtc_gpio_desc[gpio_num].ie);
portEXIT_CRITICAL(&rtc_spinlock);
@ -141,7 +141,7 @@ static esp_err_t rtc_gpio_input_enable(gpio_num_t gpio_num)
static esp_err_t rtc_gpio_input_disable(gpio_num_t gpio_num)
{
RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
CLEAR_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, rtc_gpio_desc[gpio_num].ie);
portEXIT_CRITICAL(&rtc_spinlock);
@ -152,7 +152,7 @@ static esp_err_t rtc_gpio_input_disable(gpio_num_t gpio_num)
esp_err_t rtc_gpio_set_level(gpio_num_t gpio_num, uint32_t level)
{
int rtc_gpio_num = rtc_gpio_num = rtc_gpio_desc[gpio_num].rtc_num;;
RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
if (level) {
WRITE_PERI_REG(RTC_GPIO_OUT_W1TS_REG, (1 << (rtc_gpio_num + RTC_GPIO_OUT_DATA_W1TS_S)));
@ -167,7 +167,7 @@ uint32_t rtc_gpio_get_level(gpio_num_t gpio_num)
{
uint32_t level = 0;
int rtc_gpio_num = rtc_gpio_desc[gpio_num].rtc_num;
RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
level = READ_PERI_REG(RTC_GPIO_IN_REG);
@ -177,7 +177,7 @@ uint32_t rtc_gpio_get_level(gpio_num_t gpio_num)
esp_err_t rtc_gpio_set_direction(gpio_num_t gpio_num, rtc_gpio_mode_t mode)
{
RTC_MODULE_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_gpio_is_valid_gpio(gpio_num), "RTC_GPIO number error", ESP_ERR_INVALID_ARG);
switch (mode) {
case RTC_GPIO_MODE_INPUT_ONLY:

View file

@ -495,7 +495,7 @@ config ESP32_WIFI_RX_BUFFER_NUM
int "Max number of WiFi RX buffers"
depends on WIFI_ENABLED
range 2 25
default 25
default 10
help
Set the number of WiFi rx buffers. Each buffer takes approximately 1.6KB of RAM.
Larger number for higher throughput but more memory. Smaller number for lower
@ -507,19 +507,15 @@ config PHY_ENABLED
menu PHY
visible if PHY_ENABLED
config ESP32_PHY_AUTO_INIT
bool "Initialize PHY in startup code"
config ESP32_PHY_CALIBRATION_AND_DATA_STORAGE
bool "Do phy calibration and store calibration data in NVS"
depends on PHY_ENABLED
default y
help
If enabled, PHY will be initialized in startup code, before
app_main function runs.
If this is undesired, disable this option and call esp_phy_init
from the application before enabling WiFi or BT.
If this option is enabled, startup code will also initialize
NVS prior to initializing PHY.
If this option is enabled, NVS will be initialized and calibration data will be loaded from there.
PHY calibration will be skipped on deep sleep wakeup. If calibration data is not found, full calibration
will be performed and stored in NVS. In all other cases, only partial calibration will be performed.
If unsure, choose 'y'.

View file

@ -3,7 +3,7 @@
#
COMPONENT_SRCDIRS := . hwcrypto
LIBS := core rtc
LIBS := core rtc rtc_clk
ifdef CONFIG_PHY_ENABLED # BT || WIFI
LIBS += phy coexist
endif

View file

@ -73,9 +73,6 @@ static bool app_cpu_started = false;
static void do_global_ctors(void);
static void main_task(void* args);
extern void app_main(void);
#if CONFIG_ESP32_PHY_AUTO_INIT
static void do_phy_init();
#endif
extern int _bss_start;
extern int _bss_end;
@ -214,17 +211,6 @@ void start_cpu0_default(void)
esp_core_dump_init();
#endif
#if CONFIG_ESP32_PHY_AUTO_INIT
nvs_flash_init();
do_phy_init();
#endif
#if CONFIG_SW_COEXIST_ENABLE
if (coex_init() == ESP_OK) {
coexist_set_enable(true);
}
#endif
xTaskCreatePinnedToCore(&main_task, "main",
ESP_TASK_MAIN_STACK, NULL,
ESP_TASK_MAIN_PRIO, NULL, 0);
@ -268,39 +254,3 @@ static void main_task(void* args)
vTaskDelete(NULL);
}
#if CONFIG_ESP32_PHY_AUTO_INIT
static void do_phy_init()
{
esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL;
if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
calibration_mode = PHY_RF_CAL_NONE;
}
const esp_phy_init_data_t* init_data = esp_phy_get_init_data();
if (init_data == NULL) {
ESP_LOGE(TAG, "failed to obtain PHY init data");
abort();
}
esp_phy_calibration_data_t* cal_data =
(esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1);
if (cal_data == NULL) {
ESP_LOGE(TAG, "failed to allocate memory for RF calibration data");
abort();
}
esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data);
if (err != ESP_OK) {
ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration");
calibration_mode = PHY_RF_CAL_FULL;
}
esp_phy_init(init_data, calibration_mode, cal_data);
if (calibration_mode != PHY_RF_CAL_NONE) {
err = esp_phy_store_cal_data_to_nvs(cal_data);
} else {
err = ESP_OK;
}
esp_phy_release_init_data(init_data);
free(cal_data); // PHY maintains a copy of calibration data, so we can free this
}
#endif //CONFIG_ESP32_PHY_AUTO_INIT

View file

@ -82,7 +82,7 @@ void esp_crosscore_int_init() {
assert(err == ESP_OK);
}
void esp_crosscore_int_send_yield(int coreId) {
void IRAM_ATTR esp_crosscore_int_send_yield(int coreId) {
assert(coreId<portNUM_PROCESSORS);
//Mark the reason we interrupt the other CPU
portENTER_CRITICAL(&reasonSpinlock);

View file

@ -25,6 +25,11 @@ extern "C" {
*/
esp_err_t coex_init(void);
/**
* @brief De-init software coexist
*/
void coex_deinit(void);
/**
* @brief Get software coexist enable or not
*

View file

@ -14,6 +14,7 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
@ -192,7 +193,7 @@ void esp_phy_release_init_data(const esp_phy_init_data_t* data);
* mechanism for loading calibration data, disable
* "Initialize PHY in startup code" option in menuconfig and call esp_phy_init
* function from the application. For an example usage of esp_phy_init and
* this function, see do_phy_init function in cpu_start.c
* this function, see esp_phy_store_cal_data_to_nvs function in cpu_start.c
*
* @param out_cal_data pointer to calibration data structure to be filled with
* loaded data.
@ -220,28 +221,39 @@ esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_dat
esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data);
/**
* @brief Initialize PHY module
* @brief Initialize PHY and RF module
*
* PHY module should be initialized in order to use WiFi or BT.
* If "Initialize PHY in startup code" option is set in menuconfig,
* this function will be called automatically before app_main is called,
* using parameters obtained from esp_phy_get_init_data.
*
* Applications which don't need to enable PHY on every start up should
* disable this menuconfig option and call esp_phy_init before calling
* esp_wifi_init or esp_bt_controller_init. See do_phy_init function in
* cpu_start.c for an example of using this function.
* PHY and RF module should be initialized in order to use WiFi or BT.
* Now PHY and RF initializing job is done automatically when start WiFi or BT. Users should not
* call this API in their application.
*
* @param init_data PHY parameters. Default set of parameters can
* be obtained by calling esp_phy_get_default_init_data
* function.
* @param mode Calibration mode (Full, partial, or no calibration)
* @param[inout] calibration_data
* @param is_sleep WiFi wakes up from sleep or not
* @return ESP_OK on success.
* @return ESP_FAIL on fail.
*/
esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data,
esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data, bool is_sleep);
/**
* @brief De-initialize PHY and RF module
*
* PHY module should be de-initialized in order to shutdown WiFi or BT.
* Now PHY and RF de-initializing job is done automatically when stop WiFi or BT. Users should not
* call this API in their application.
*
* @return ESP_OK on success.
*/
esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data,
esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data);
esp_err_t esp_phy_rf_deinit(void);
/**
* @brief Load calibration data from NVS and initialize PHY and RF module
*/
void esp_phy_load_cal_and_init(void);
#ifdef __cplusplus
}

View file

@ -130,6 +130,7 @@ esp_err_t esp_wifi_init(wifi_init_config_t *config);
* Free all resource allocated in esp_wifi_init and stop WiFi task
*
* @attention 1. This API should be called if you want to remove WiFi driver from the system
* @attention 2. This API can not be called yet and will be done in the future.
*
* @return ESP_OK: succeed
*/

View file

@ -268,10 +268,10 @@
* 2 1 extern level
* 3 1 extern level
* 4 1 extern level WBB
* 5 1 extern level BT Controller
* 5 1 extern level BT/BLE Controller
* 6 1 timer FreeRTOS Tick(L1) FreeRTOS Tick(L1)
* 7 1 software Reserved Reserved
* 8 1 extern level BLE Controller
* 8 1 extern level BT/BLE BB(RX/TX)
* 9 1 extern level
* 10 1 extern edge Internal Timer
* 11 3 profiling

View file

@ -83,7 +83,11 @@ SECTIONS
*libesp32.a:core_dump.o(.literal .text .literal.* .text.*)
*libphy.a:(.literal .text .literal.* .text.*)
*librtc.a:(.literal .text .literal.* .text.*)
*libpp.a:(.literal .text .literal.* .text.*)
*librtc_clk.a:(.literal .text .literal.* .text.*)
*libpp.a:lmac.o(.literal .text .literal.* .text.*)
*libpp.a:wdev.o(.literal .text .literal.* .text.*)
*libcore.a:ets_timer.o(.literal .text .literal.* .text.*)
*libnet80211.a:ieee80211_misc.o(.literal .text .literal.* .text.*)
*libhal.a:(.literal .text .literal.* .text.*)
*libcoexist.a:(.literal .text .literal.* .text.*)
_iram_text_end = ABSOLUTE(.);

@ -1 +1 @@
Subproject commit d0b97976010528cbb469d5bb12f2c20449ca6c5b
Subproject commit ed85cf9156f2ef358c29d07fb849a73c5758eecb

View file

@ -17,7 +17,10 @@
#include <string.h>
#include <stdbool.h>
#include <sys/lock.h>
#include "rom/ets_sys.h"
#include "rom/rtc.h"
#include "soc/dport_reg.h"
#include "esp_err.h"
@ -25,30 +28,71 @@
#include "esp_system.h"
#include "esp_log.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#ifdef CONFIG_PHY_ENABLED
#include "phy.h"
#include "phy_init_data.h"
#include "rtc.h"
#include "esp_coexist.h"
static const char* TAG = "phy_init";
/* Count value to indicate if there is peripheral that has initialized PHY and RF */
static int s_phy_rf_init_count = 0;
static bool s_mac_rst_flag = false;
esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data,
esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data)
static _lock_t s_phy_rf_init_lock;
esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data,
esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data, bool is_sleep)
{
assert(init_data);
assert(calibration_data);
assert((s_phy_rf_init_count <= 1) && (s_phy_rf_init_count >= 0));
REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST);
REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST);
// Enable WiFi peripheral clock
SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf);
ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d",
init_data, calibration_data, mode);
phy_set_wifi_mode_only(0);
register_chipv7_phy(init_data, calibration_data, mode);
coex_bt_high_prio();
_lock_acquire(&s_phy_rf_init_lock);
if (s_phy_rf_init_count == 0) {
if (is_sleep == false) {
if (s_mac_rst_flag == false) {
s_mac_rst_flag = true;
REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST);
REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST);
}
}
// Enable WiFi peripheral clock
SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf);
ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d",
init_data, calibration_data, mode);
phy_set_wifi_mode_only(0);
register_chipv7_phy(init_data, calibration_data, mode);
coex_bt_high_prio();
} else {
#if CONFIG_SW_COEXIST_ENABLE
coex_init();
#endif
}
s_phy_rf_init_count++;
_lock_release(&s_phy_rf_init_lock);
return ESP_OK;
}
esp_err_t esp_phy_rf_deinit(void)
{
assert((s_phy_rf_init_count <= 2) && (s_phy_rf_init_count >= 1));
_lock_acquire(&s_phy_rf_init_lock);
if (s_phy_rf_init_count == 1) {
// Disable PHY and RF. TODO: convert this function to another one.
pm_close_rf();
// Disable WiFi peripheral clock
CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf);
} else {
#if CONFIG_SW_COEXIST_ENABLE
coex_deinit();
#endif
}
s_phy_rf_init_count--;
_lock_release(&s_phy_rf_init_lock);
return ESP_OK;
}
@ -220,4 +264,43 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle,
return err;
}
void esp_phy_load_cal_and_init(void)
{
#ifdef CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE
nvs_flash_init();
esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL;
if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
calibration_mode = PHY_RF_CAL_NONE;
}
const esp_phy_init_data_t* init_data = esp_phy_get_init_data();
if (init_data == NULL) {
ESP_LOGE(TAG, "failed to obtain PHY init data");
abort();
}
esp_phy_calibration_data_t* cal_data =
(esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1);
if (cal_data == NULL) {
ESP_LOGE(TAG, "failed to allocate memory for RF calibration data");
abort();
}
esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data);
if (err != ESP_OK) {
ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration");
calibration_mode = PHY_RF_CAL_FULL;
}
esp_phy_rf_init(init_data, calibration_mode, cal_data, false);
if (calibration_mode != PHY_RF_CAL_NONE && err != ESP_OK) {
err = esp_phy_store_cal_data_to_nvs(cal_data);
} else {
err = ESP_OK;
}
esp_phy_release_init_data(init_data);
free(cal_data); // PHY maintains a copy of calibration data, so we can free this
#else
esp_phy_rf_init(NULL, PHY_RF_CAL_NONE, NULL, false);
#endif
}
#endif // CONFIG_PHY_ENABLED

View file

@ -135,6 +135,10 @@ void rtc_slp_prep_lite(uint32_t deep_slp, uint32_t cpu_lp_mode);
*/
uint32_t rtc_sleep(uint32_t cycles_h, uint32_t cycles_l, uint32_t wakeup_opt, uint32_t reject_opt);
/**
* @brief Shutdown PHY and RF. TODO: convert this function to another one.
*/
void pm_close_rf(void);
#ifdef __cplusplus
}

View file

@ -75,6 +75,7 @@ struct emac_config_data {
bool emac_flow_ctrl_enable;
bool emac_flow_ctrl_partner_support;
eth_phy_get_partner_pause_enable_func emac_phy_get_partner_pause_enable;
eth_phy_power_enable_func emac_phy_power_enable;
};
enum emac_post_type {

View file

@ -225,6 +225,7 @@ static void emac_set_user_config_data(eth_config_t *config )
emac_config.emac_flow_ctrl_enable = false;
#endif
emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable;
emac_config.emac_phy_power_enable = config->phy_power_enable;
}
static void emac_enable_intr()
@ -291,6 +292,11 @@ static esp_err_t emac_verify_args(void)
ret = ESP_FAIL;
}
if(emac_config.emac_phy_power_enable == NULL) {
ESP_LOGE(TAG, "phy power enable func is null");
ret = ESP_FAIL;
}
return ret;
}
@ -943,6 +949,8 @@ esp_err_t esp_eth_init(eth_config_t *config)
emac_set_user_config_data(config);
}
emac_config.emac_phy_power_enable(true);
ret = emac_verify_args();
if (ret != ESP_OK) {

View file

@ -80,7 +80,7 @@ typedef void (*eth_phy_func)(void);
typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb);
typedef void (*eth_gpio_config_func)(void);
typedef bool (*eth_phy_get_partner_pause_enable_func)(void);
typedef void (*eth_phy_power_enable_func)(bool enable);
/**
* @brief ethernet configuration
@ -98,6 +98,7 @@ typedef struct {
eth_gpio_config_func gpio_config; /*!< gpio config func */
bool flow_ctrl_enable; /*!< flag of flow ctrl enable */
eth_phy_get_partner_pause_enable_func phy_get_partner_pause_enable; /*!< get partner pause enable */
eth_phy_power_enable_func phy_power_enable; /*!< enable or disable phy power */
} eth_config_t;

View file

@ -152,7 +152,7 @@ static int fat_mode_conv(int m)
}
if ((m & O_CREAT) && (m & O_EXCL)) {
res |= FA_CREATE_NEW;
} else if (m & O_CREAT) {
} else if ((m & O_CREAT) && (m & O_TRUNC)) {
res |= FA_CREATE_ALWAYS;
} else if (m & O_APPEND) {
res |= FA_OPEN_ALWAYS;

View file

@ -69,6 +69,55 @@ TEST_CASE("can create and write file on sd card", "[fatfs][ignore]")
HEAP_SIZE_CHECK(0);
}
TEST_CASE("overwrite and append file on sd card", "[fatfs][ignore]")
{
HEAP_SIZE_CAPTURE();
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 5
};
TEST_ESP_OK(esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, NULL));
/* Create new file with 'aaaa' */
const char *NAME = "/sdcard/hello.txt";
create_file_with_text(NAME, "aaaa");
/* Append 'bbbb' to file */
FILE *f_a = fopen(NAME, "a");
TEST_ASSERT_NOT_NULL(f_a);
TEST_ASSERT_NOT_EQUAL(EOF, fputs("bbbb", f_a));
TEST_ASSERT_EQUAL(0, fclose(f_a));
/* Read back 8 bytes from file, verify it's 'aaaabbbb' */
char buf[10] = { 0 };
FILE *f_r = fopen(NAME, "r");
TEST_ASSERT_NOT_NULL(f_r);
TEST_ASSERT_EQUAL(8, fread(buf, 1, 8, f_r));
TEST_ASSERT_EQUAL_STRING_LEN("aaaabbbb", buf, 8);
/* Be sure we're at end of file */
TEST_ASSERT_EQUAL(0, fread(buf, 1, 8, f_r));
TEST_ASSERT_EQUAL(0, fclose(f_r));
/* Overwrite file with 'cccc' */
create_file_with_text(NAME, "cccc");
/* Verify file now only contains 'cccc' */
f_r = fopen(NAME, "r");
TEST_ASSERT_NOT_NULL(f_r);
bzero(buf, sizeof(buf));
TEST_ASSERT_EQUAL(4, fread(buf, 1, 8, f_r)); // trying to read 8 bytes, only expecting 4
TEST_ASSERT_EQUAL_STRING_LEN("cccc", buf, 4);
TEST_ASSERT_EQUAL(0, fclose(f_r));
TEST_ESP_OK(esp_vfs_fat_sdmmc_unmount());
HEAP_SIZE_CHECK(0);
}
TEST_CASE("can read file on sd card", "[fatfs][ignore]")
{
HEAP_SIZE_CAPTURE();

View file

@ -216,6 +216,9 @@ static inline uint32_t xPortGetCoreID() {
return id;
}
/* Get tick rate per second */
uint32_t xPortGetTickRateHz(void);
#ifdef __cplusplus
}
#endif

View file

@ -406,7 +406,9 @@ void vPortSetStackWatchpoint( void* pxStackStart ) {
esp_set_watchpoint(1, (char*)addr, 32, ESP_WATCHPOINT_STORE);
}
uint32_t xPortGetTickRateHz(void) {
return (uint32_t)configTICK_RATE_HZ;
}

View file

@ -3012,9 +3012,14 @@ BaseType_t xReturn;
This function assumes that a check has already been made to ensure that
pxEventList is not empty. */
pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
configASSERT( pxUnblockedTCB );
( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
if ( ( listLIST_IS_EMPTY( pxEventList ) ) == pdFALSE ) {
pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
configASSERT( pxUnblockedTCB );
( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
} else {
taskEXIT_CRITICAL_ISR(&xTaskQueueMutex);
return pdFALSE;
}
if( uxSchedulerSuspended[ xPortGetCoreID() ] == ( UBaseType_t ) pdFALSE )
{
@ -3025,9 +3030,7 @@ BaseType_t xReturn;
{
/* The delayed and ready lists cannot be accessed, so hold this task
pending until the scheduler is resumed. */
taskENTER_CRITICAL(&xTaskQueueMutex);
vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxUnblockedTCB->xEventListItem ) );
taskEXIT_CRITICAL(&xTaskQueueMutex);
}
if ( tskCAN_RUN_HERE(pxUnblockedTCB->xCoreID) && pxUnblockedTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )

View file

@ -28,6 +28,7 @@
#include "esp_ipc.h"
#include "esp_attr.h"
#include "esp_spi_flash.h"
#include "esp_flash_encrypt.h"
#include "esp_log.h"
#include "cache_utils.h"
@ -52,8 +53,10 @@
This ensures stale cache entries are never read after fresh calls
to spi_flash_mmap(), while keeping the number of cache flushes to a
minimum.
Returns true if cache was flushed.
*/
static void spi_flash_ensure_unmodified_region(size_t start_addr, size_t length);
static bool spi_flash_ensure_unmodified_region(size_t start_addr, size_t length);
typedef struct mmap_entry_{
uint32_t handle;
@ -89,6 +92,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_
const void** out_ptr, spi_flash_mmap_handle_t* out_handle)
{
esp_err_t ret;
bool did_flush, need_flush = false;
mmap_entry_t* new_entry = (mmap_entry_t*) malloc(sizeof(mmap_entry_t));
if (new_entry == 0) {
return ESP_ERR_NO_MEM;
@ -102,7 +106,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_
spi_flash_disable_interrupts_caches_and_other_cpu();
spi_flash_ensure_unmodified_region(src_addr, size);
did_flush = spi_flash_ensure_unmodified_region(src_addr, size);
if (s_mmap_page_refcnt[0] == 0) {
spi_flash_mmap_init();
@ -159,8 +163,11 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_
(DPORT_PRO_FLASH_MMU_TABLE[i] == entry_val &&
DPORT_APP_FLASH_MMU_TABLE[i] == entry_val));
if (s_mmap_page_refcnt[i] == 0) {
DPORT_PRO_FLASH_MMU_TABLE[i] = entry_val;
DPORT_APP_FLASH_MMU_TABLE[i] = entry_val;
if (DPORT_PRO_FLASH_MMU_TABLE[i] != entry_val || DPORT_APP_FLASH_MMU_TABLE[i] != entry_val) {
DPORT_PRO_FLASH_MMU_TABLE[i] = entry_val;
DPORT_APP_FLASH_MMU_TABLE[i] = entry_val;
need_flush = true;
}
}
++s_mmap_page_refcnt[i];
}
@ -173,6 +180,18 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_
*out_ptr = (void*) (region_addr + start * SPI_FLASH_MMU_PAGE_SIZE);
ret = ESP_OK;
}
/* This is a temporary fix for an issue where some
encrypted cache reads may see stale data.
Working on a long term fix that doesn't require invalidating
entire cache.
*/
if (esp_flash_encryption_enabled() && !did_flush && need_flush) {
Cache_Flush(0);
Cache_Flush(1);
}
spi_flash_enable_interrupts_caches_and_other_cpu();
if (*out_ptr == NULL) {
free(new_entry);
@ -240,25 +259,29 @@ void spi_flash_mmap_dump()
*/
static uint32_t written_pages[256/32];
static void update_written_pages(size_t start_addr, size_t length, bool mark);
static bool update_written_pages(size_t start_addr, size_t length, bool mark);
void IRAM_ATTR spi_flash_mark_modified_region(size_t start_addr, size_t length)
{
update_written_pages(start_addr, length, true);
}
static void IRAM_ATTR spi_flash_ensure_unmodified_region(size_t start_addr, size_t length)
static IRAM_ATTR bool spi_flash_ensure_unmodified_region(size_t start_addr, size_t length)
{
update_written_pages(start_addr, length, false);
return update_written_pages(start_addr, length, false);
}
/* generic implementation for the previous two functions */
static inline IRAM_ATTR void update_written_pages(size_t start_addr, size_t length, bool mark)
static inline IRAM_ATTR bool update_written_pages(size_t start_addr, size_t length, bool mark)
{
for (uint32_t addr = start_addr; addr < start_addr + length; addr += SPI_FLASH_MMU_PAGE_SIZE) {
/* align start_addr & length to full MMU pages */
uint32_t page_start_addr = start_addr & ~(SPI_FLASH_MMU_PAGE_SIZE-1);
length += (start_addr - page_start_addr);
length = (length + SPI_FLASH_MMU_PAGE_SIZE - 1) & ~(SPI_FLASH_MMU_PAGE_SIZE-1);
for (uint32_t addr = page_start_addr; addr < page_start_addr + length; addr += SPI_FLASH_MMU_PAGE_SIZE) {
int page = addr / SPI_FLASH_MMU_PAGE_SIZE;
if (page >= 256) {
return; /* invalid address */
return false; /* invalid address */
}
int idx = page / 32;
@ -277,6 +300,8 @@ static inline IRAM_ATTR void update_written_pages(size_t start_addr, size_t leng
Cache_Flush(1);
#endif
bzero(written_pages, sizeof(written_pages));
return true;
}
}
return false;
}

View file

@ -166,10 +166,14 @@ static esp_err_t load_partitions()
item->info.type = it->type;
item->info.subtype = it->subtype;
item->info.encrypted = it->flags & PART_FLAG_ENCRYPTED;
if (esp_flash_encryption_enabled() && it->type == PART_TYPE_APP) {
/* All app partitions are encrypted if encryption is turned on */
if (esp_flash_encryption_enabled() && (
it->type == PART_TYPE_APP
|| (it->type == PART_TYPE_DATA && it->subtype == PART_SUBTYPE_DATA_OTA))) {
/* If encryption is turned on, all app partitions and OTA data
are always encrypted */
item->info.encrypted = true;
}
// it->label may not be zero-terminated
strncpy(item->info.label, (const char*) it->label, sizeof(it->label));
item->info.label[sizeof(it->label)] = 0;

View file

@ -37,7 +37,8 @@ INPUT = ../components/esp32/include/esp_wifi.h \
../components/fatfs/src/esp_vfs_fat.h \
../components/fatfs/src/diskio.h \
../components/esp32/include/esp_core_dump.h \
../components/mdns/include/mdns.h
../components/mdns/include/mdns.h \
../components/bootloader_support/include/esp_flash_encrypt.h
## Get warnings for functions that have no documentation for their parameters or return value
##

View file

@ -33,6 +33,7 @@ Type Definitions
Enumerations
^^^^^^^^^^^^
.. doxygenenum:: esp_bt_mode_t
Structures
^^^^^^^^^^
@ -45,6 +46,10 @@ Functions
^^^^^^^^^
.. doxygenfunction:: esp_bt_controller_init
.. doxygenfunction:: esp_bt_controller_deinit
.. doxygenfunction:: esp_bt_controller_enable
.. doxygenfunction:: esp_bt_controller_disable
.. doxygenfunction:: esp_bt_controller_get_status
.. doxygenfunction:: esp_vhci_host_check_send_available
.. doxygenfunction:: esp_vhci_host_send_packet
.. doxygenfunction:: esp_vhci_host_register_callback

View file

@ -0,0 +1,62 @@
Analog to Digital Converter
===========================
Overview
--------
ESP32 integrates two 12-bit SAR ("Successive Approximation Register") ADCs (Analog to Digital Converters) and supports measurements on 18 channels (analog enabled pins). Some of these pins can be used to build a programmable gain amplifier which is used for the measurement of small
analog signals.
The ADC driver API currently only supports ADC1 (9 channels, attached to GPIOs 32-39).
Taking an ADC reading involves configuring the ADC with the desired precision and attentuation settings, and then calling adc1_get_voltage() to read the channel.
It is also possible to read the internal hall effect sensor via ADC1.
Application Example
-------------------
Reading voltage on ADC1 channel 0 (GPIO 36)::
#include <driver/adc.h>
...
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_0db);
int val = adc1_get_voltage(ADC1_CHANNEL_0);
Reading the internal hall effect sensor::
#include <driver/adc.h>
...
adc1_config_width(ADC_WIDTH_12Bit);
int val = hall_sensor_read();
The value read in both these examples is 12 bits wide (range 0-4095).
API Reference
-------------
Header Files
^^^^^^^^^^^^
* `components/driver/include/driver/adc.h`
Enumerations
^^^^^^^^^^^^
.. doxygenenum:: adc1_channel_t
.. doxygenenum:: adc_atten_t
.. doxygenenum:: adc_bits_width_t
Functions
^^^^^^^^^
.. doxygenfunction:: adc1_config_width
.. doxygenfunction:: adc1_config_channel_atten
.. doxygenfunction:: adc1_get_voltage
.. doxygenfunction:: hall_sensor_read

View file

@ -0,0 +1,45 @@
Digital To Analog Converter
===========================
Overview
--------
ESP32 has two 8-bit DAC (digital to analog converter) channels, connected to GPIO25 (Channel 1) and GPIO26 (Channel 2).
The DAC driver allows these channels to be set to arbitrary voltages.
The DAC channels can also be driven with DMA-style written sample data, via the :doc:`I2S driver <i2s>` when using the "built-in DAC mode".
For other analog output options, see the :doc:`Sigma-delta Modulation module <sigmadelta>` and the :doc:`LED Control module <ledc>`. Both these modules produce high frequency PWM output, which can be hardware low-pass filtered in order to generate a lower frequency analog output.
Application Example
-------------------
Setting DAC channel 1 (GPIO 25) voltage to approx 0.78 of VDD_A voltage (VDD * 200 / 255). For VDD_A 3.3V, this is 2.59V::
#include <driver/dac.h>
...
dac_out_voltage(DAC_CHANNEL_1, 200);
API Reference
-------------
Header Files
^^^^^^^^^^^^
* `components/driver/include/driver/dac.h`
Enumerations
^^^^^^^^^^^^
.. doxygenenum:: dac_channel_t
Functions
^^^^^^^^^
.. doxygenfunction:: dac_out_voltage

View file

@ -1,11 +1,15 @@
GPIO
====
GPIO & RTC GPIO
===============
Overview
--------
The ESP32 chip features 40 physical GPIO pads. Some GPIO pads cannot be used or do not have the corresponding pin on the chip package(refer to technical reference manual ). Each pad can be used as a general purpose I/O or can be connected to an internal peripheral signal.
Note that GPIO6-11 are usually used for SPI flash. GPIO34-39 can only be set as input mode.
- Note that GPIO6-11 are usually used for SPI flash.
- GPIO34-39 can only be set as input mode and do not have software pullup or pulldown functions.
There is also separate "RTC GPIO" support, which functions when GPIOs are routed to the "RTC" low-power and analog subsystem. These pin functions can be used when in deep sleep, when the :doc:`Ultra Low Power co-processor </ulp>` is running, or when analog functions such as ADC/DAC/etc are in use.
Application Example
-------------------
@ -19,10 +23,14 @@ Header Files
^^^^^^^^^^^^
* :component_file:`driver/include/driver/gpio.h`
* :component_file:`driver/include/driver/rtc_io.h`
Macros
^^^^^^
Normal GPIO
~~~~~~~~~~~
.. doxygendefine:: GPIO_SEL_0
.. doxygendefine:: GPIO_SEL_1
.. doxygendefine:: GPIO_SEL_2
@ -107,12 +115,18 @@ Macros
Type Definitions
^^^^^^^^^^^^^^^^
Normal GPIO
~~~~~~~~~~~
.. doxygentypedef:: gpio_isr_t
.. doxygentypedef:: gpio_isr_handle_t
Enumerations
^^^^^^^^^^^^
Normal GPIO
~~~~~~~~~~~
.. doxygenenum:: gpio_num_t
.. doxygenenum:: gpio_int_type_t
.. doxygenenum:: gpio_mode_t
@ -120,16 +134,26 @@ Enumerations
.. doxygenenum:: gpio_pulldown_t
.. doxygenenum:: gpio_pull_mode_t
RTC GPIO
~~~~~~~~
.. doxygenenum:: rtc_gpio_mode_t
Structures
^^^^^^^^^^
Normal GPIO
~~~~~~~~~~~
.. doxygenstruct:: gpio_config_t
:members:
Functions
^^^^^^^^^
Normal GPIO
~~~~~~~~~~~
.. doxygenfunction:: gpio_config
.. doxygenfunction:: gpio_set_intr_type
.. doxygenfunction:: gpio_intr_enable
@ -150,3 +174,18 @@ Functions
.. doxygenfunction:: gpio_isr_handler_add
.. doxygenfunction:: gpio_isr_handler_remove
RTC GPIO
~~~~~~~~
.. doxygenfunction:: rtc_gpio_is_valid_gpio
.. doxygenfunction:: rtc_gpio_init
.. doxygenfunction:: rtc_gpio_deinit
.. doxygenfunction:: rtc_gpio_get_level
.. doxygenfunction:: rtc_gpio_set_level
.. doxygenfunction:: rtc_gpio_set_direction
.. doxygenfunction:: rtc_gpio_pullup_en
.. doxygenfunction:: rtc_gpio_pulldown_en
.. doxygenfunction:: rtc_gpio_pullup_dis
.. doxygenfunction:: rtc_gpio_pulldown_dis
.. doxygenfunction:: rtc_gpio_unhold_all

View file

@ -0,0 +1,131 @@
I2S
===
Overview
--------
ESP32 contains two I2S peripherals. These peripherals can be configured to input and output sample data via the I2S driver.
The I2S peripheral supports DMA meaning it can stream sample data without requiring each sample to be read or written by the CPU.
I2S output can also be routed directly to the Digital/Analog Converter output channels (GPIO 25 & GPIO 26) to produce analog output directly, rather than via an external I2S codec.
Application Example
-------------------
A full I2S example is available in esp-idf: :example:`peripherals/i2s`.
Short example of I2S configuration::
#include "driver/i2s.h"
#include "freertos/queue.h"
static const int i2s_num = 0; // i2s port number
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 26,
.ws_io_num = 25,
.data_out_num = 22,
.data_in_num = I2S_PIN_NO_CHANGE
};
...
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, &pin_config);
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
Short example configuring I2S to use internal DAC for analog output::
#include "driver/i2s.h"
#include "freertos/queue.h"
static const int i2s_num = 0; // i2s port number
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.sample_rate = 44100,
.bits_per_sample = 8, /* must be 8 for built-in DAC */
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64
};
...
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, NULL); //for internal DAC
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
API Reference
-------------
Header Files
^^^^^^^^^^^^
* `components/driver/include/driver/i2s.h`
Data Structures
^^^^^^^^^^^^^^^
.. doxygenstruct:: i2s_config_t
:members:
.. doxygenstruct:: i2s_event_t
:members:
.. doxygenstruct:: i2s_pin_config_t
:members:
Macros
^^^^^^
.. doxygendefine:: I2S_PIN_NO_CHANGE
Enumerations
^^^^^^^^^^^^
.. doxygenenum:: i2s_bits_per_sample_t
.. doxygenenum:: i2s_comm_format_t
.. doxygenenum:: i2s_channel_fmt_t
.. doxygenenum:: pdm_sample_rate_ratio_t
.. doxygenenum:: pdm_pcm_conv_t
.. doxygenenum:: i2s_port_t
.. doxygenenum:: i2s_mode_t
.. doxygenenum:: i2s_event_type_t
Functions
^^^^^^^^^
.. doxygenfunction:: i2s_set_pin
.. doxygenfunction:: i2s_driver_install
.. doxygenfunction:: i2s_driver_uninstall
.. doxygenfunction:: i2s_write_bytes
.. doxygenfunction:: i2s_read_bytes
.. doxygenfunction:: i2s_push_sample
.. doxygenfunction:: i2s_pop_sample
.. doxygenfunction:: i2s_set_sample_rates
.. doxygenfunction:: i2s_start
.. doxygenfunction:: i2s_stop
.. doxygenfunction:: i2s_zero_dma_buffer

View file

@ -4,15 +4,18 @@ Peripherals API
.. toctree::
:maxdepth: 1
GPIO <gpio>
UART <uart>
ADC <adc>
DAC <dac>
GPIO (including RTC low power I/O) <gpio>
I2C <i2c>
SPI Master <spi_master>
Timer <timer>
Pulse Counter <pcnt>
Sigma-delta Modulation <sigmadelta>
I2S <i2s>
LED Control <ledc>
Pulse Counter <pcnt>
SD/MMC Card Host <../storage/sdmmc>
Sigma-delta Modulation <sigmadelta>
SPI Master <spi_master>
Remote Control <rmt>
Timer <timer>
UART <uart>
Example code for this API section is provided in :example:`peripherals` directory of ESP-IDF examples.

View file

@ -4,7 +4,7 @@ Sigma-delta Modulation
Overview
--------
ESP32 has a second-order sigma-delta modulation module.
ESP32 has a second-order sigma-delta modulation module.
This driver configures the channels of the sigma-delta module.
Application Example

View file

@ -8,7 +8,7 @@ Header Files
* :component_file:`spi_flash/include/esp_spi_flash.h`
* :component_file:`spi_flash/include/esp_partition.h`
* :component_file:`esp32/include/esp_flash_encrypt.h`
* :component_file:`bootloader_support/include/esp_flash_encrypt.h`
Macros
^^^^^^

View file

@ -53,10 +53,10 @@ Contents:
.. toctree::
:caption: Hardware Reference
Technical Reference Manual <http://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>
Pin List and Functions <http://espressif.com/sites/default/files/documentation/esp32_chip_pin_list_en.pdf>
Chip Pinout <http://espressif.com/sites/default/files/documentation/esp32_pinout_v1_0.pdf>
Silicon Errata <http://espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_en.pdf>
Technical Reference Manual (PDF) <http://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>
Pin List and Functions (PDF) <http://espressif.com/sites/default/files/documentation/esp32_chip_pin_list_en.pdf>
Chip Pinout (PDF) <http://espressif.com/sites/default/files/documentation/esp32_pinout_v1_0.pdf>
Silicon Errata (PDF) <http://espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_en.pdf>
.. toctree::
:caption: Contribute
@ -78,4 +78,4 @@ Contents:
Indices
=======
* :ref:`genindex`
* :ref:`genindex`

View file

@ -3,9 +3,9 @@ Flash Encryption
Flash Encryption is a feature for encrypting the contents of the ESP32's attached SPI flash. When flash encryption is enabled, physical readout of the SPI flash is not sufficient to recover most flash contents.
Flash Encryption is separate from the `Secure Boot` feature, and you can use flash encryption without enabling secure boot. However we recommend using both features together for a secure environment.
Flash Encryption is separate from the :doc:`Secure Boot <secure-boot>` feature, and you can use flash encryption without enabling secure boot. However we recommend using both features together for a secure environment.
**IMPORTANT: Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including `Limitations of Flash Encryption` and understand the implications of enabling flash encryption.**
**IMPORTANT: Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including :ref:`flash-encryption-limitations`) and understand the implications of enabling flash encryption.**
Background
----------
@ -17,6 +17,7 @@ Background
- Encryption is applied by flashing the ESP32 with plaintext data, and (if encryption is enabled) the bootloader encrypts the data in place on first boot.
- Not all of the flash is encrypted. The following kinds of flash data are encrypted:
- Bootloader
- Secure boot bootloader digest (if secure boot is enabled)
- Partition Table
@ -29,58 +30,75 @@ Background
- The `flash encryption algorithm` is AES-256, where the key is "tweaked" with the offset address of each 32 byte block of flash. This means every 32 byte block (two consecutive 16 byte AES blocks) is encrypted with a unique key derived from the flash encryption key.
- Although software running on the chip can transparently decrypt flash contents, by default it is made possible for the UART bootloader to decrypt (or encrypt) data when flash encryption is enabled.
- Although software running on the chip can transparently decrypt flash contents, by default it is made impossible for the UART bootloader to decrypt (or encrypt) data when flash encryption is enabled.
- If flash encrption may be enabled, the programmer must take certain precautions when writing code that :ref:`uses encrypted flash <using-encrypted-flash>`.
.. _flash-encryption-initialisation:
Flash Encryption Initialisation
-------------------------------
This is the default (and recommended) flash encryption initialisation process. It is possible to customise this process for development or other purposes, see `Flash Encryption Advanced Features` for details.
This is the default (and recommended) flash encryption initialisation process. It is possible to customise this process for development or other purposes, see :ref:`flash-encryption-advanced-features` for details.
**IMPORTANT: Once flash encryption is enabled on first boot, the hardware allows a maximum of 3 subsequent flash updates via physical re-flashing. If secure boot is enabled, no physical re-flashes are possible. OTA updates can be used to update flash content without counting towards this limit. When enabling flash encryption in development, use a `precalculated flash encryption key` to allow physically re-flashing an unlimited number of times with pre-encrypted data.**
**IMPORTANT: Once flash encryption is enabled on first boot, the hardware allows a maximum of 3 subsequent flash updates via serial re-flashing.** A special procedure (documented in :ref:`updating-encrypted-flash-serial`) must be followed to perform these updates.
- The bootloader must be compiled with flash encryption support enabled. In ``make menuconfig``, navigate to "Security Features" and select "Yes" for "Enable flash nencryption on boot".
- If secure boot is enabled, no physical re-flashes are possible.
- OTA updates can be used to update flash content without counting towards this limit.
- When enabling flash encryption in development, use a `pregenerated flash encryption key` to allow physically re-flashing an unlimited number of times with pre-encrypted data.**
- If enabling Secure Boot at the same time, you can simultaneously select those options now. See the `Secure Boot` documentation for details.
Process to enable flash encryption:
- The bootloader must be compiled with flash encryption support enabled. In ``make menuconfig``, navigate to "Security Features" and select "Yes" for "Enable flash encryption on boot".
- If enabling Secure Boot at the same time, it is best to simultaneously select those options now. Read the :doc:`Secure Boot <secure-boot>` documentation first.
- Build and flash the bootloader, partition table and factory app image as normal. These partitions are initially written to the flash unencrypted.
- On first boot, the bootloader sees ``FLASH_CRYPT_CNT`` efuse is set to 0 so it generates a flash encryption key using the hardware random number generator. This key is stored in efuse. The key is read and write protected against further software access.
- On first boot, the bootloader sees :ref:`FLASH_CRYPT_CNT` is set to 0 (factory default) so it generates a flash encryption key using the hardware random number generator. This key is stored in efuse. The key is read and write protected against further software access.
- All of the encrypted partitions are then encrypted in-place by the bootloader. Encrypting in-place can take some time (up to a minute for large partitions.)
**IMPORTANT: Do not interrupt power to the ESP32 while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and require flashing with unencrypted data again. This re-flash will not count towards the flashing limit, as ``FLASH_CRYPT_CNT`` is only updated after this process finishes.**
**IMPORTANT: Do not interrupt power to the ESP32 while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and require flashing with unencrypted data again. A reflash like this will not count towards the flashing limit.**
- Once flashing is complete. efuses are blown (by default) to disable encrypted flash access while the UART bootloader is running.
- Once flashing is complete. efuses are blown (by default) to disable encrypted flash access while the UART bootloader is running. See :ref:`uart-bootloader-encryption` for advanced details.
- If not already write-protected, the ``FLASH_CRYPT_CONFIG`` efuse is also burned to the maximum value (``0xF``) to maximise the number of key bits which are tweaked in the flash algorithm. See `Setting FLASH_CRYPT_CONFIG` for details of this efuse.
- The ``FLASH_CRYPT_CONFIG`` efuse is also burned to the maximum value (``0xF``) to maximise the number of key bits which are tweaked in the flash algorithm. See :ref:`setting-flash-crypt-config` for advanced details.
- Finally, the ``FLASH_CRYPT_CNT`` efuse is burned with the initial value 1. It is this efuse which activates the transparent flash encryption layer, and limits the number of subsequent reflashes. See the `Updating Encrypted Flash` section for details about ``FLASH_CRYPT_CNT``.
- Finally, the :ref:`FLASH_CRYPT_CNT` is burned with the initial value 1. It is this efuse which activates the transparent flash encryption layer, and limits the number of subsequent reflashes. See the :ref:`updating-encrypted-flash` section for details about :ref:`FLASH_CRYPT_CNT`.
- The bootloader resets itself to reboot from the newly encrypted flash.
.. _using-encrypted-flash:
Encrypted Flash Access
----------------------
Using Encrypted Flash
---------------------
Reading Encrypted Flash
^^^^^^^^^^^^^^^^^^^^^^^
ESP32 app code can check if flash encryption is currently enabled by calling :func:`esp_flash_encryption_enabled`.
Whenever the ``FLASH_CRYPT_CNT`` efuse is set to a value with an odd number of bits set, all flash content which is accessed via the MMU's flash cache is transparently decrypted. This includes:
Once flash encryption is enabled, some care needs to be taken when accessing flash contents from code.
Scope of Flash Encryption
^^^^^^^^^^^^^^^^^^^^^^^^^
Whenever the :ref:`FLASH_CRYPT_CNT` is set to a value with an odd number of bits set, all flash content which is accessed via the MMU's flash cache is transparently decrypted. This includes:
- Executable application code in flash (IROM).
- All read-only data stored in flash (DROM).
- Any data accessed via ``esp_spi_flash_mmap``.
- Any data accessed via :func:`esp_spi_flash_mmap`.
- The software bootloader image when it is read by the ROM bootloader.
**IMPORTANT: The MMU flash cache unconditionally decrypts all data. Data which is stored unencrypted in the flash will be "transparently decrypted" via the flash cache and appear to software like random garbage.**
To read data without using a flash cache MMU mapping, we recommend using the partition read function ``esp_partition_read``. When using this function, data will only be decrypted when it is read from an encrypted partition. Other partitions will be read unencrypted. In this way, software can access encrypted and non-encrypted flash in the same way.
Reading Encrypted Flash
^^^^^^^^^^^^^^^^^^^^^^^
To read data without using a flash cache MMU mapping, we recommend using the partition read function :func:`esp_partition_read`. When using this function, data will only be decrypted when it is read from an encrypted partition. Other partitions will be read unencrypted. In this way, software can access encrypted and non-encrypted flash in the same way.
Data which is read via other SPI read APIs are not decrypted:
- Data read via ``esp_spi_flash_read`` is not decrypted
- Data read via ROM function ``SPIRead`` is not decrypted (this function is not supported in esp-idf apps).
- Data stored using the Non-Volatile Storage (NVS) API is always stored decrypted.
- Data read via :func:`esp_spi_flash_read` is not decrypted
- Data read via ROM function :func:`SPIRead` is not decrypted (this function is not supported in esp-idf apps).
- Data stored using the Non-Volatile Storage (NVS) API is always stored and read decrypted.
Writing Encrypted Flash
@ -92,92 +110,179 @@ The ``esp_spi_flash_write`` function will write data when the write_encrypted pa
The ROM function ``SPI_Encrypt_Write`` will write encrypted data to flash, the ROM function ``SPIWrite`` will write unencrypted to flash. (these function are not supported in esp-idf apps).
The minimum write size for unencrypted data is 4 bytes (and the alignment is 4 bytes). Because data is encrypted in blocks, the minimum write size for encrypted data is 32 bytes (and the alignment is 32 bytes.)
The minimum write size for unencrypted data is 4 bytes (and the alignment is 4 bytes). Because data is encrypted in blocks, the minimum write size for encrypted data is 16 bytes (and the alignment is 16 bytes.)
.. _updating-encrypted-flash:
Updating Encrypted Flash
------------------------
.. _updating-encrypted-flash-ota:
OTA Updates
^^^^^^^^^^^
OTA updates to encrypted partitions will automatically write encrypted, as long as the ``esp_partition_write`` function is used.
.. _updating-encrypted-flash-serial:
Serial Flashing
^^^^^^^^^^^^^^^
Provided secure boot is not used, the ``FLASH_CRYPT_CNT`` registers allow the flash to be updated with new plaintext data via serial flashing (or other physical methods), up to 3 additional times. ``FLASH_CRYPT_CNT`` efuse is an 8-bit value, and the flash encryption enables or disables based on the number of bits which are set to "1":
Provided secure boot is not used, the :ref:`FLASH_CRYPT_CNT` allows the flash to be updated with new plaintext data via serial flashing (or other physical methods), up to 3 additional times.
- Even number (0-6) bits are set: Transparent reading of encrypted flash is disabled, any encrypted data cannot be decrypted. If the bootloader was built with "Enable flash encryption on boot" then it will see this situation and immediately re-encrypt the flash wherever it finds unencrypted data. Once done, it sets another bit in the efuse to '1' meaning an odd number of bits are now set.
- Odd number (1-7) bits are set: Transparent reading of encrypted flash is enabled.
- All 8 bits are set (valuye 0: Transparent reading of encrypted flash is disabled, any encrypted data is inaccessible. Bootloader will normally detect this condition and halt. To avoid use of this state to load unauthorised code, secure boot must be used or ``FLASH_CRYPT_CNT`` must be write-protected.
The espefuse.py tool can be used to manually change the number of bits set in ``FLASH_CRYPT_CNT``, via serial bootloader.
The process involves flashing plaintext data, and then bumping the value of :ref:`FLASH_CRYPT_CNT` which causes the bootloader to re-encrypt this data.
Limited Updates
^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~
Only 4 physical flash updates (writing plaintext data which is then encrypted) are possible:
Only 4 serial flash update cycles of this kind are possible, including the initial encrypted flash.
1. On first plaintext boot, bit count has brand new value 0 and bootloader changes to 1 (0x01) following encryption.
2. On next plaintext flash update, bit count is manually updated to 2 (0x03) and bootloader changes to 4 (0x07) following encryption.
3. Then bit count is manually updated to 4 (0x0F) and the bootloader changes efuse bit count to 5 (0x1F).
4. Finally bootloader is manually updated to 6 (0x3F) and bootloader changes efuse bit count to 7 (0x7F).
After the fourth time encryption is disabled, :ref:`FLASH_CRYPT_CNT` has the maximum value `0xFF` and encryption is permanently disabled.
Cautions With Re-Flashing
^^^^^^^^^^^^^^^^^^^^^^^^^^
Using :ref:`updating-encrypted-flash-ota` or :ref:`pregenerated-flash-encryption-key` allows you to exceed this limit.
- When reflashing via serial, reflash every partition that was previously written with plaintext (including bootloader). It is possible to skip app partitions which are not the "currently selected" OTA partition (these will not be re-encrypted unless a plaintext app image is found there.) However any partition marked with the "encrypt" flag will be unconditionally re-encrypted, meaning that any already encrypted data will be encrypted twice and corrupted.
Cautions With Serial Flashing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- If secure boot is enabled, you can't reflash via serial at all unless you used chosen the "Reflashable" option for Secure Boot, pre-generated a key and burned it to the ESP32. In this case you can re-flash a plaintext secure boot digest and bootloader image at offset 0 (see `Secure Boot` documentation.) In production secure boot configuration, the secure boot digest is stored encrypted - so if ``FLASH_CRYPT_CNT`` is set to an even value then the ROM bootloader will read the encrypted digest as-is and therefore will fail to verify any bootloader image as valid.
- When reflashing via serial, reflash every partition that was initially written with plaintext data (including bootloader). It is possible to skip app partitions which are not the "currently selected" OTA partition (these will not be re-encrypted unless a plaintext app image is found there.) However any partition marked with the "encrypt" flag will be unconditionally re-encrypted, meaning that any already encrypted data will be encrypted twice and corrupted.
Re-Flashing Procedure
^^^^^^^^^^^^^^^^^^^^^
- Using ``make flash`` should flash all partitions which need to be flashed.
The steps to update a device with plaintext via UART bootloader, when flash encryption is enabled are:
- If secure boot is enabled, you can't reflash via serial at all unless you used the "Reflashable" option for Secure Boot, pre-generated a key and burned it to the ESP32 (refer to :doc:`Secure Boot <secure-boot>` docs.). In this case you can re-flash a plaintext secure boot digest and bootloader image at offset 0x0. It is necessary to re-flash this digest before flashing other plaintext data.
Serial Re-Flashing Procedure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Build the application as usual.
- Burn the ``FLASH_CRYPT_CNT`` efuse by running the command ``espefuse.py burn_efuse FLASH_CRYPT_CNT``. espefuse.py will automatically increment the bit count by 1.
- Flash the device with plaintext data as usual (``make flash`` or ``esptool.py`` commands.) Flash all previously encrypted partitions, including the bootloader (see previous section).
- Flash the device with plaintext data as usual (``make flash`` or ``esptool.py`` commands.) Flash all previously encrypted partitions, including the bootloader. If secure boot is enabled, it must be enabled in "Reflashable" mode and a pre-generated key burned to the ESP32 - flash the bootloader-reflash-digest.bin file at offset 0x0.
- At this point, the device will fail to boot (message is ``flash read err, 1000``) because it expects to see an encrypted bootloader, but the bootloader is plaintext.
- Reset the device and it will re-encrypt plaintext partitions, burn the ``FLASH_CRYPT_CNT`` flag to re-enable encryption.
- Burn the :ref:`FLASH_CRYPT_CNT` by running the command ``espefuse.py burn_efuse FLASH_CRYPT_CNT``. espefuse.py will automatically increment the bit count by 1, which disables encryption.
- Reset the device and it will re-encrypt plaintext partitions, then burn the :ref:`FLASH_CRYPT_CNT` again to re-enable encryption.
Disabling Updates
^^^^^^^^^^^^^^^^^
Disabling Serial Updates
~~~~~~~~~~~~~~~~~~~~~~~~
To prevent further plaintext updates via physical access, use espefuse.py to write protect the ``FLASH_CRYPT_CNT`` efuse after flash encryption has been enabled (ie after first boot is complete)::
To prevent further plaintext updates via serial, use espefuse.py to write protect the :ref:`FLASH_CRYPT_CNT` after flash encryption has been enabled (ie after first boot is complete)::
espefuse.py write_protect_efuse FLASH_CRYPT_CNT
espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT
This prevents any further modifications to disable or re-enable flash encryption.
.. _pregenerated-flash-encryption-key:
Reflashing via Pregenerated Flash Encryption Key
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It is possible to pregenerate a flash encryption key on the host computer and burn it into the ESP32's efuse key block. This allows data to be pre-encrypted on the host and flashed to the ESP32 without needing a plaintext flash update.
This is useful for development, because it removes the 4 time reflashing limit. It also allows reflashing with secure boot enabled, because the bootloader doesn't need to be reflashed each time.
**IMPORTANT This method is intended to assist with development only, not for production devices. If pre-generating flash encryption for production, ensure the keys are generated from a high quality random number source and do not share the same flash encryption key across multiple devices.**
Pregenerating a Flash Encryption Key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Flash encryption keys are 32 bytes of random data. You can generate a random key with espsecure.py::
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
(The randomness of this data is only as good as the OS and it's Python installation's random data source.)
Alternatively, if you're using :doc:`secure boot <secure-boot>` and have a secure boot signing key then you can generate a deterministic SHA-256 digest of the secure boot private signing key and use this as the flash encryption key::
espsecure.py digest_private-key --keyfile secure_boot_signing_key.pem my_flash_encryption_key.bin
(The same 32 bytes is used as the secure boot digest key if you enable :ref:`reflashable mode<secure-boot-reflashable>` for secure boot.)
Generating the flash encryption key from the secure boot signing key in this way means that you only need to store one key file. However this method is **not at all suitable** for production devices.
Burning Flash Encryption Key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once you have generated a flash encryption key, you need to burn it to the ESP32's efuse key block. **This must be done before first encrypted boot**, otherwise the ESP32 will generate a random key that software can't access or modify.
To burn a key to the device (one time only)::
espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin
First Flash with pregenerated key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After flashing the key, follow the same steps as for default :ref:`flash-encryption-initialisation` and flash a plaintext image for the first boot. The bootloader will enable flash encryption using the pre-burned key and encrypt all partitions.
Reflashing with pregenerated key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After encryption is enabled on first boot, reflashing an encrypted image requires an additional manual step. This is where we pre-encrypt the data that we wish to update in flash.
Suppose that this is the normal command used to flash plaintext data::
esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash 0x10000 build/my-app.bin
Binary app image ``build/my-app.bin`` is written to offset ``0x10000``. This file name and offset need to be used to encrypt the data, as follows::
espsecure.py encrypt_flash_data --keyfile my_flash_encryption_key.bin --address 0x10000 -o build/my-app-encrypted.bin build/my-app.bin
This example command will encrypts ``my-app.bin`` using the supplied key, and produce an encrypted file ``my-app-encrypted.bin``. Be sure that the address argument matches the address where you plan to flash the binary.
Then, flash the encrypted binary with esptool.py::
esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash 0x10000 build/my-app-encrypted.bin
No further steps or efuse manipulation is necessary, because the data is already encrypted when we flash it.
Disabling Flash Encryption
--------------------------
If you've accidentally enabled flash encryption for some reason, the next flash of plaintext data will soft-brick the ESP32 (the device will reboot continously, printing the error ``flash read err, 1000``).
You can disable flash encryption again by writing :ref:`FLASH_CRYPT_CNT`:
- First, run ``make menuconfig`` and uncheck "Enable flash encryption boot" under "Security Features".
- Exit menuconfig and save the new configuration.
- Run ``make menuconfig`` again and double-check you really disabled this option! *If this option is left enabled, the bootloader will immediately re-enable encryption when it boots*.
- Run ``make flash`` to build and flash a new bootloader and app, without flash encryption enabled.
- Run ``espefuse.py`` (in ``components/esptool_py/esptool``) to disable the :ref:`FLASH_CRYPT_CNT`)::
espefuse.py burn_efuse FLASH_CRYPT_CNT
Reset the ESP32 and flash encryption should be disabled, the bootloader will boot as normal.
.. _flash-encryption-limitations:
Limitations of Flash Encryption
-------------------------------
Flash Encryption prevents plaintext readout of the encrypted flash, to protect firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption system:
- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device to burn with ``esp_efuse.py burn_key``, ensure they are generated from a quality random number source, kept secure, and never shared between devices.
- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device (see :ref:`pregenerated-flash-encryption-key`), ensure proper procedure is followed.
- Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption.
- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every two 16 byte AES blocks. When both adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (ie to tell if two devices are probably running the same firmware version).
- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every pair of adjacent 16 byte AES blocks. When these adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (ie to tell if two devices are probably running the same firmware version).
- For the same reason, an attacker can always guess when two adjacent 16 byte blocks (32 byte aligned) contain identical content. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient).
- For the same reason, an attacker can always tell when a pair of adjacent 16 byte blocks (32 byte aligned) contain identical content. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient).
- Flash encryption alone may not prevent an attacker from modifying the firmware of the device. Always use flash encryption in combination with Secure Boot.
- Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from runningon the device, use flash encryption in combination with :doc:`Secure Boot <secure-boot>`.
.. _flash-encryption-advanced-features:
Flash Encryption Advanced Features
----------------------------------
The following information is useful for advanced use of flash encryption:
Encrypted Partition Flag
^^^^^^^^^^^^^^^^^^^^^^^^
In the `partition table` description CSV files, there is a field for flags.
Some partitions are encrypted by default. Otherwise, it is possible to mark any partition as requiring encryption:
In the :doc:`partition table </partition-tables>` description CSV files, there is a field for flags.
Usually left blank, if you write "encrypted" in this field then the partition will be marked as encrypted in the partition table, and data written here will be treated as encrypted (same as an app partition)::
@ -187,7 +292,7 @@ Usually left blank, if you write "encrypted" in this field then the partition wi
factory, app, factory, 0x10000, 1M
secret_data, 0x40, 0x01, 0x20000, 256K, encrypted
- None of the default partition formats have any encrypted data partitions.
- None of the default partition tables include any encrypted data partitions.
- It is not necessary to mark "app" partitions as encrypted, they are always treated as encrypted.
@ -197,88 +302,70 @@ Usually left blank, if you write "encrypted" in this field then the partition wi
- It is not possible to mark the ``nvs`` partition as encrypted.
Precalculated Flash Encryption Key
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It is possible to pre-generate a flash encryption key on the host computer and burn it into the ESP32 efuse. This allows data to be per-encrypted on the host and flashed to the ESP32 without needing a plaintext flash update.
This is useful for development, because it removes the 4 flash limit and allows reflashing with secure boot enabled.
**IMPORTANT** This method is intended to assist with development only, not for production devices. If pre-generating flash encryption for production, ensure the keys are generated from a high quality random number source and do not share the same flash encryption key across multiple devices.
Obtaining Flash Encryption Key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Flash encryption keys are 32 bytes of random data. You can generate a random key with espsecure.py::
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
(The randomness of this data is only as good as the OS and it's Python installation's random data source.)
Alternatively, if you're using `secure boot` and have a secure boot signing key then you can generate a deterministic SHA-256 digest of the secure boot private key to use::
espsecure.py digest_private-key --keyfile secure_boot_signing_key.pem my_flash_encryption_key.bin
The same key is used as the secure boot digest key if you enabled "Reflashable" mode for secure boot.
This means you can always re-calculate the flash encryption key from the secure boot private signing key. This method is **not at all suitable** for production devices.
Burning Flash Encryption Key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once you have generated a flash encryption key, you need to burn it to efuse on the device. This **must be done before first boot**, otherwise the ESP32 will generate a random key that software can't access.
To burn a key to the device (possible one time only)::
espefuse.py burn_key flash_encryption my_flash_encryption_key.bin
First Flash
~~~~~~~~~~~
For the first flash, follow the same steps as for default `Flash Encryption Initialisation` and flash a plaintext image. The bootloader will enable flash encryption using the pre-burned key and encrypt all partitions.
Reflashing
~~~~~~~~~~
To reflash an encrypted image requires an additional manual update step, to encrypt the data you wish to flash.
Suppose that this is the normal flashing non-encrypted flashing step::
esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash -z 0x10000 build/my-app.bin
The data needs to be pre-encrypted with knowledge of the address (0x10000) and the binary file name::
espsecure.py encrypt_flash_data --keyfile my_flash_encryption_key.bin --address 0x10000 -o build/my-app-encrypted.bin build/my-app.bin
This step will encrypt ``my-app.bin`` using the supplied key, and produce an encrypted file ``my-app-encrypted.bin``. Be sure that the address argument matches the address where you plan to flash the binary.
Then, flash the encrypted binary with esptool.py::
esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash -z 0x10000 build/my-app-encrypted.bin
.. _uart-bootloader-encryption:
Enabling UART Bootloader Encryption/Decryption
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
By default, on first boot the flash encryption process will burn efuses ``DISABLE_DL_ENCRYPT``, ``DISABLE_DL_DECRYPT`` and ``DISABLE_DL_CACHE``.
By default, on first boot the flash encryption process will burn efuses ``DISABLE_DL_ENCRYPT``, ``DISABLE_DL_DECRYPT`` and ``DISABLE_DL_CACHE``:
- ``DISABLE_DL_ENCRYPT`` disables the flash encryption operations when running in UART bootloader boot mode.
- ``DISABLE_DL_DECRYPT`` disables transparent flash decryption when running in UART bootloader mode, even if ``FLASH_CRYPT_CNT`` is set to enable it in normal operation.
- ``DISABLE_DL_DECRYPT`` disables transparent flash decryption when running in UART bootloader mode, even if :ref:`FLASH_CRYPT_CNT` is set to enable it in normal operation.
- ``DISABLE_DL_CACHE`` disables the entire MMU flash cache when running in UART bootloader mode.
It is possible to burn only some of these efuses, and write-protect the rest (with unset value 0) before the first boot, in order to preserve them::
It is possible to burn only some of these efuses, and write-protect the rest (with unset value 0) before the first boot, in order to preserve them. For example::
espefuse.py burn_efuse DISABLE_DL_DECRYPT
espefuse.py write_protect_efuse DISABLE_DL_ENCRYPT
espefuse.py --port PORT burn_efuse DISABLE_DL_DECRYPT
espefuse.py --port PORT write_protect_efuse DISABLE_DL_ENCRYPT
(Note that all 3 of these efuses are disabled via one write protect bit, so write protecting one will write protect all of them.)
(Note that all 3 of these efuses are disabled via one write protect bit, so write protecting one will write protect all of them. For this reason, it's necessary to set any bits before write-protecting.)
Write protecting these efuses when they are unset (0) is not currently useful, as ``esptool.py`` does not support flash encryption functions.
**IMPORTANT**: Write protecting these efuses to keep them unset is not currently very useful, as ``esptool.py`` does not support writing or reading encrypted flash.
**IMPORTANT**: If ``DISABLE_DL_DECRYPT`` is left unset (0) this effectively makes flash encryption useless, as an attacker with physical access can use UART bootloader mode (with custom stub code) to read out the flash contents.
.. _setting-flash-crypt-config:
Setting FLASH_CRYPT_CONFIG
^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``FLASH_CRYPT_CONFIG`` efuse determines the number of bits in the flash encryption key which are "tweaked" with the block offset. See :ref:`flash-encryption-algorithm` for details.
First boot of the bootloader always sets this value to the maximum `0xF`.
It is possible to write these efuse manually, and write protect it before first boot in order to select different tweak values. This is not recommended.
It is strongly recommended to never write protect ``FLASH_CRYPT_CONFIG`` when it the value is zero. If this efuse is set to zero, no bits in the flash encryption key are tweaked and the flash encryption algorithm is equivalent to AES ECB mode.
However, note that write protecting ``DISABLE_DL_DECRYPT`` when it is unset (0) effectively makes flash encryption useless, as an attacker with physical access can use UART bootloader mode to read out the flash.
Technical Details
-----------------
The following sections provide some reference information about the operation of flash encryption.
.. _FLASH_CRYPT_CNT:
FLASH_CRYPT_CNT efuse
^^^^^^^^^^^^^^^^^^^^^
``FLASH_CRYPT_CNT`` is an 8-bit efuse field which controls flash encryption. Flash encryption enables or disables based on the number of bits in this efuse which are set to "1":
- When an even number of bits (0,2,4,6,8) are set: Flash encryption is disabled, any encrypted data cannot be decrypted.
- If the bootloader was built with "Enable flash encryption on boot" then it will see this situation and immediately re-encrypt the flash wherever it finds unencrypted data. Once done, it sets another bit in the efuse to '1' meaning an odd number of bits are now set.
1. On first plaintext boot, bit count has brand new value 0 and bootloader changes it to bit count 1 (value 0x01) following encryption.
2. After next plaintext flash update, bit count is manually updated to 2 (value 0x03). After re-encrypting the bootloader changes efuse bit count to 3 (value 0x07).
3. After next plaintext flash, bit count is manually updated to 4 (value 0x0F). After re-encrypting the bootloader changes efuse bit count to 5 (value 0x1F).
4. After final plaintext flash, bit count is manually updated to 6 (value 0x3F). After re-encrypting the bootloader changes efuse bit count to 7 (value 0x7F).
- When an odd number of bits (1,3,5,7) are set: Transparent reading of encrypted flash is enabled.
- After all 8 bits are set (efuse value 0xFF): Transparent reading of encrypted flash is disabled, any encrypted data is permanently inaccessible. Bootloader will normally detect this condition and halt. To avoid use of this state to load unauthorised code, secure boot must be used or :ref:`FLASH_CRYPT_CNT` must be write-protected.
.. _flash-encryption-algorithm:
Flash Encryption Algorithm
^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -288,7 +375,7 @@ Flash Encryption Algorithm
- The main flash encryption key is stored in efuse (BLK2) and by default is protected from further writes or software readout.
- Each 32 byte block is encrypted with a unique key which is derived from this main flash encryption key XORed with the offset of this block in the flash (a "key tweak").
- Each 32 byte block (two adjacent 16 byte AES blocks) is encrypted with a unique key. The key is derived from the main flash encryption key in efuse, XORed with the offset of this block in the flash (a "key tweak").
- The specific tweak depends on the setting of ``FLASH_CRYPT_CONFIG`` efuse. This is a 4 bit efuse, where each bit enables XORing of a particular range of the key bits:
@ -297,24 +384,11 @@ Flash Encryption Algorithm
- Bit 3, bits 132-194 of the key are XORed.
- Bit 4, bits 195-256 of the key are XORed.
It is recommended that ``FLASH_CRYPT_CONFIG`` is always left to set the default value `0xF`, so that all key bits are XORed with the block offset. See `Setting FLASH_CRYPT_CONFIG` for details.
It is recommended that ``FLASH_CRYPT_CONFIG`` is always left to set the default value `0xF`, so that all key bits are XORed with the block offset. See :ref:`setting-flash-crypt-config` for details.
- The high 19 bits of the block offset (bit 5 to bit 23) are XORed with the main flash encryption key. This range is chosen for two reasons: the maximum flash size is 16MB (24 bits), and each block is 32 bytes so the least significant 5 bits are always zero.
- There is a particular mapping from each of the 19 block offset bits to the 256 bits of the flash encryption key, to determine which bit is XORed with which. See the variable _FLASH_ENCRYPTION_TWEAK_PATTERN in espsecure.py for a list of these.
- There is a particular mapping from each of the 19 block offset bits to the 256 bits of the flash encryption key, to determine which bit is XORed with which. See the variable ``_FLASH_ENCRYPTION_TWEAK_PATTERN`` in the espsecure.py source code for the complete mapping.
- For the full algorithm implemented in Python, see `_flash_encryption_operation()` in the espsecure.py source code.
- To see the full flash encryption algorithm implemented in Python, refer to the `_flash_encryption_operation()` function in the espsecure.py source code.
Setting FLASH_CRYPT_CONFIG
^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``FLASH_CRYPT_CONFIG`` efuse determines the number of bits in the flash encryption key which are "tweaked" with the block offset. See `Flash Encryption Algorithm` for details.
First boot of the bootloader always sets this value to the maximum `0xF`.
It is possible to write these efuse manually, and write protect it before first boot in order to select different tweak values. This is not recommended.
It is strongly recommended to never write protect ``FLASH_CRYPT_CONFIG`` when it the value is zero. If this efuse is set to zero, no bits in the flash encryption key are tweaked and the flash encryption algorithm is equivalent to AES ECB mode.
.. _Secure Boot: secure-boot.rst
.. _partition table: ../partition-tables.rst

View file

@ -3,7 +3,9 @@ Secure Boot
Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset.
Secure Boot is separate from the `Flash Encryption` feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment.
Secure Boot is separate from the :doc:`Flash Encryption <flash-encryption>` feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment.
**IMPORTANT: Enabling secure boot limits your options for further updates of your ESP32. Make sure to read this document throughly and understand the implications of enabling secure boot.**
Background
----------
@ -19,7 +21,7 @@ Background
Secure Boot Process Overview
----------------------------
This is a high level overview of the secure boot process. Step by step instructions are supplied under `How To Enable Secure Boot`. Further in-depth details are supplied under `Technical Details`:
This is a high level overview of the secure boot process. Step by step instructions are supplied under :ref:`secure-boot-howto`. Further in-depth details are supplied under :ref:`secure-boot-technical-details`:
1. The options to enable secure boot are provided in the ``make menuconfig`` hierarchy, under "Secure Boot Configuration".
@ -34,7 +36,7 @@ This is a high level overview of the secure boot process. Step by step instructi
- Depending on Secure Boot Configuration, efuses are burned to disable JTAG and the ROM BASIC interpreter (it is strongly recommended these options are turned on.)
- Bootloader permanently enables secure boot by burning the ABS_DONE_0 efuse. The software bootloader then becomes protected (the chip will only boot a bootloader image if the digest matches.)
5. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see `Hardware Secure Boot Support`.
5. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see :ref:`secure-boot-hardware-support`.
6. When running in secure boot mode, the software bootloader uses the secure boot signing key (the public key of which is embedded in the bootloader itself, and therefore validated as part of the bootloader) to verify the signature appended to all subsequent partition tables and app images before they are booted.
@ -43,19 +45,20 @@ Keys
The following keys are used by the secure boot process:
- "secure bootloader key" is a 256-bit AES key that is stored in Efuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, the user does not need to supply it (it is optionally possible to supply this key, see `Re-Flashable Software Bootloader`). The Efuse holding this key is read & write protected (preventing software access) before secure boot is enabled.
- "secure bootloader key" is a 256-bit AES key that is stored in Efuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, the user does not need to supply it (it is optionally possible to supply this key, see :ref:`secure-boot-reflashable`). The Efuse holding this key is read & write protected (preventing software access) before secure boot is enabled.
- "secure boot signing key" is a standard ECDSA public/private key pair (see `Image Signing Algorithm`) in PEM format.
- "secure boot signing key" is a standard ECDSA public/private key pair (see :ref:`secure-boot-image-signing-algorithm`) in PEM format.
- The public key from this key pair (for signature verificaton but not signature creation) is compiled into the software bootloader and used to verify the second stage of booting (partition table, app image) before booting continues. The public key can be freely distributed, it does not need to be kept secret.
- The private key from this key pair *must be securely kept private*, as anyone who has this key can authenticate to any bootloader that is configured with secure boot and the matching public key.
.. _secure-boot-howto:
How To Enable Secure Boot
-------------------------
1. Run ``make menuconfig``, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see `Re-Flashable Software Bootloader`.)
1. Run ``make menuconfig``, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see :ref:`secure-boot-reflashable`.)
2. Select a name for the secure boot signing key. This option will appear after secure boot is enabled. The file can be anywhere on your system. A relative path will be evaluated from the project directory. The file does not need to exist yet.
@ -65,22 +68,26 @@ How To Enable Secure Boot
**IMPORTANT** A signing key generated this way will use the best random number source available to the OS and its Python installation (`/dev/urandom` on OSX/Linux and `CryptGenRandom()` on Windows). If this random number source is weak, then the private key will be weak.
**IMPORTANT** For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See `Generating Secure Boot Signing Key` for more details.
**IMPORTANT** For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See :ref:`secure-boot-generate-key` for more details.
5. Run ``make bootloader`` to build a secure boot enabled bootloader. The output of `make` will include a prompt for a flashing command, using `esptool.py write_flash`.
5. Run ``make bootloader`` to build a secure boot enabled bootloader. The output of ``make`` will include a prompt for a flashing command, using ``esptool.py write_flash``.
.. _secure-boot-resume-normal-flashing:
6. When you're ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by make) and then wait for flashing to complete. **Remember this is a one time flash, you can't change the bootloader after this!**.
7. Run `make flash` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4.
7. Run ``make flash`` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4.
*NOTE*: `make flash` doesn't flash the bootloader if secure boot is enabled.
*NOTE*: ``make flash`` doesn't flash the bootloader if secure boot is enabled.
8. Reset the ESP32 and it will boot the software bootloader you flashed. The software bootloader will enable secure boot on the chip, and then it verifies the app image signature and boots the app. You should watch the serial console output from the ESP32 to verify that secure boot is enabled and no errors have occured due to the build configuration.
*NOTE* Secure boot won't be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured.
**NOTE** Secure boot won't be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured.
9. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed (using the secure bootloader key) and then the software bootloader will verify the signed partition table and app image (using the public key portion of the secure boot signing key).
.. _secure-boot-reflashable:
Re-Flashable Software Bootloader
--------------------------------
@ -90,7 +97,7 @@ However, an alternative mode "Secure Boot: Reflashable" is also available. This
In the esp-idf build process, this 256-bit key file is derived from the app signing key generated during the generate_signing_key step above. The private key's SHA-256 digest is used as the 256-bit secure bootloader key. This is a convenience so you only need to generate/protect a single private key.
*NOTE*: Although it's possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The "One-Time Flash" option is recommended for production environments.
**NOTE**: Although it's possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The "One-Time Flash" option is recommended for production environments.
To enable a reflashable bootloader:
@ -100,7 +107,9 @@ To enable a reflashable bootloader:
3. Run ``make bootloader``. A 256-bit key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed - the first set of steps includes an ``espefuse.py burn_key`` command which is used to write the bootloader key to efuse. (Flashing this key is a one-time-only process.) The second set of steps can be used to reflash the bootloader with a pre-calculated digest (generated during the build process).
4. Resume from `Step 6<Secure Boot Process Overview>` of the one-time process, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration.
4. Resume from :ref:`Step 6 of the one-time flashing process <secure-boot-resume-normal-flashing>`, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration.
.. _secure-boot-generate-key:
Generating Secure Boot Signing Key
----------------------------------
@ -134,7 +143,7 @@ After the app image and partition table are built, the build system will print s
espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY BINARY_FILE
The above command appends the image signature to the existing binary. You can use the --output argument to place the binary with signature appended into a separate file::
The above command appends the image signature to the existing binary. You can use the `--output` argument to write the signed binary to a separate file::
espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE
@ -145,16 +154,21 @@ Secure Boot Best Practices
* Keep the signing key private at all times. A leak of this key will compromise the secure boot system.
* Do not allow any third party to observe any aspects of the key generation or signing process using espsecure.py. Both processes are vulnerable to timing or other side-channel attacks.
* Enable all secure boot options in the Secure Boot Configuration. These include flash encryption, disabling of JTAG, disabling BASIC ROM interpeter, and disabling the UART bootloader encrypted flash access.
* Use secure boot in combination with :doc:`flash encryption<flash-encryption>` to prevent local readout of the flash contents.
.. _secure-boot-technical-details:
Technical Details
-----------------
The following sections contain low-level descriptions of various technical functions:
The following sections contain low-level reference descriptions of various secure boot elements:
Hardware Secure Boot Support
.. _secure-boot-hardware-support:
Secure Boot Hardware Support
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Secure Boot support hardware can perform three basic operations:
The first stage of secure boot verification (checking the software bootloader) is done via hardware. The ESP32's Secure Boot support hardware can perform three basic operations:
1. Generate a random sequence of bytes from a hardware random number generator.
@ -167,7 +181,7 @@ Secure Bootloader Digest Algorithm
Starting with an "image" of binary data as input, this algorithm generates a digest as output. The digest is sometimes referred to as an "abstract" in hardware documentation.
For a Python version of this algorithm, see the `espsecure.py` tool in the components/esptool_py directory.
For a Python version of this algorithm, see the ``espsecure.py`` tool in the components/esptool_py directory (specifically, the ``digest_secure_bootloader`` command).
Items marked with (^) are to fulfill hardware restrictions, as opposed to cryptographic restrictions.
@ -183,23 +197,27 @@ Items marked with (^) are to fulfill hardware restrictions, as opposed to crypto
Output digest is 192 bytes of data: The 128 byte IV, followed by the 64 byte SHA-512 digest.
.. _secure-boot-image-signing-algorithm:
Image Signing Algorithm
~~~~~~~~~~~~~~~~~~~~~~~
Deterministic ECDSA as specified by `RFC6979`.
Deterministic ECDSA as specified by `RFC 6979 <https://tools.ietf.org/html/rfc6979>`_.
- Curve is NIST256p (openssl calls this curve "prime256v1", it is also sometimes called secp256r1).
- Hash function is SHA256.
- Key format used for storage is PEM.
- In the bootloader, the public key (for signature verification) is flashed as 64 raw bytes.
- Image signature is 68 bytes - a 4 byte version word (currently zero), followed by a 64 bytes of signature data. These 68 bytes are appended to an app image or partition table data.
Manual Commands
~~~~~~~~~~~~~~~
Secure boot is integrated into the esp-idf build system, so `make` will automatically sign an app image if secure boot is enabled. `make bootloader` will produce a bootloader digest if menuconfig is configured for it.
Secure boot is integrated into the esp-idf build system, so ``make`` will automatically sign an app image if secure boot is enabled. ``make bootloader`` will produce a bootloader digest if menuconfig is configured for it.
However, it is possible to use the `espsecure.py` tool to make standalone signatures and digests.
However, it is possible to use the ``espsecure.py`` tool to make standalone signatures and digests.
To sign a binary image::
@ -215,5 +233,3 @@ Keyfile is the 32 byte raw secure boot key for the device. To flash this digest
esptool.py write_flash 0x0 bootloader-digest.bin
.. _RFC6979: https://tools.ietf.org/html/rfc6979
.. _Flash Encryption: flash-encryption.rst

View file

@ -215,6 +215,11 @@ void bleAdvtTask(void *pvParameters)
void app_main()
{
esp_bt_controller_init();
if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) {
return;
}
xTaskCreatePinnedToCore(&bleAdvtTask, "bleAdvtTask", 2048, NULL, 5, NULL, 0);
}

View file

@ -317,6 +317,12 @@ void app_main()
esp_bt_controller_init();
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
if (ret) {
BLUFI_ERROR("%s enable bt controller failed\n", __func__);
return;
}
ret = esp_bluedroid_init();
if (ret) {
BLUFI_ERROR("%s init bluedroid failed\n", __func__);

View file

@ -397,6 +397,8 @@ void gattc_client_test(void)
void app_main()
{
esp_bt_controller_init();
esp_bt_controller_enable(ESP_BT_MODE_BTDM);
gattc_client_test();
}

View file

@ -394,6 +394,11 @@ void app_main()
esp_bt_controller_init();
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
if (ret) {
ESP_LOGE(GATTS_TAG, "%s enable controller failed\n", __func__);
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(GATTS_TAG, "%s init bluetooth failed\n", __func__);

View file

@ -29,6 +29,7 @@
#include "esp_bt_main.h"
#include "gatts_table_creat_demo.h"
#define GATTS_TABLE_TAG "GATTS_TABLE_DEMO"
#define HEART_PROFILE_NUM 1
#define HEART_PROFILE_APP_IDX 0
@ -196,7 +197,7 @@ static const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] =
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
LOG_ERROR("GAP_EVT, event %d\n", event);
ESP_LOGE(GATTS_TABLE_TAG, "GAP_EVT, event %d\n", event);
switch (event) {
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
@ -210,15 +211,15 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
LOG_ERROR("event = %x\n",event);
ESP_LOGE(GATTS_TABLE_TAG, "event = %x\n",event);
switch (event) {
case ESP_GATTS_REG_EVT:
LOG_INFO("%s %d\n", __func__, __LINE__);
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
LOG_INFO("%s %d\n", __func__, __LINE__);
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
esp_ble_gap_config_adv_data(&heart_rate_adv_config);
LOG_INFO("%s %d\n", __func__, __LINE__);
ESP_LOGI(GATTS_TABLE_TAG, "%s %d\n", __func__, __LINE__);
esp_ble_gatts_create_attr_tab(heart_rate_gatt_db, gatts_if,
HRS_IDX_NB, HEART_RATE_SVC_INST_ID);
break;
@ -256,7 +257,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
case ESP_GATTS_CONGEST_EVT:
break;
case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
LOG_ERROR("The number handle =%x\n",param->add_attr_tab.num_handle);
ESP_LOGE(GATTS_TABLE_TAG, "The number handle =%x\n",param->add_attr_tab.num_handle);
if(param->add_attr_tab.num_handle == HRS_IDX_NB){
memcpy(heart_rate_handle_table, param->add_attr_tab.handles,
sizeof(heart_rate_handle_table));
@ -275,14 +276,14 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
esp_ble_gatts_cb_param_t *param)
{
LOG_INFO("EVT %d, gatts if %d\n", event, gatts_if);
ESP_LOGI(GATTS_TABLE_TAG, "EVT %d, gatts if %d\n", event, gatts_if);
/* If event is register event, store the gatts_if for each profile */
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
heart_rate_profile_tab[HEART_PROFILE_APP_IDX].gatts_if = gatts_if;
} else {
LOG_INFO("Reg app failed, app_id %04x, status %d\n",
ESP_LOGI(GATTS_TABLE_TAG, "Reg app failed, app_id %04x, status %d\n",
param->reg.app_id,
param->reg.status);
return;
@ -307,15 +308,22 @@ void app_main()
esp_err_t ret;
esp_bt_controller_init();
LOG_INFO("%s init bluetooth\n", __func__);
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed\n", __func__);
return;
}
ESP_LOGI(GATTS_TABLE_TAG, "%s init bluetooth\n", __func__);
ret = esp_bluedroid_init();
if (ret) {
LOG_ERROR("%s init bluetooth failed\n", __func__);
ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed\n", __func__);
return;
}
ret = esp_bluedroid_enable();
if (ret) {
LOG_ERROR("%s enable bluetooth failed\n", __func__);
ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed\n", __func__);
return;
}

View file

@ -37,6 +37,9 @@
static const char *TAG = "eth_demo";
#define DEFAULT_PHY_CONFIG (AUTO_MDIX_ENABLE|AUTO_NEGOTIATION_ENABLE|AN_1|AN_0|LED_CFG)
#define PIN_PHY_POWER 17
#define PIN_SMI_MDC 23
#define PIN_SMI_MDIO 18
void phy_tlk110_check_phy_init(void)
{
@ -87,6 +90,17 @@ void phy_enable_flow_ctrl(void)
esp_eth_smi_write(AUTO_NEG_ADVERTISEMENT_REG,data|ASM_DIR|PAUSE);
}
void phy_tlk110_power_enable(bool enable)
{
gpio_pad_select_gpio(PIN_PHY_POWER);
gpio_set_direction(PIN_PHY_POWER,GPIO_MODE_OUTPUT);
if(enable == true) {
gpio_set_level(PIN_PHY_POWER, 1);
} else {
gpio_set_level(PIN_PHY_POWER, 0);
}
}
void phy_tlk110_init(void)
{
esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET);
@ -117,11 +131,11 @@ void eth_gpio_config_rmii(void)
//rmii clk ,can not change
gpio_set_direction(0, GPIO_MODE_INPUT);
//mdc to gpio4
gpio_matrix_out(4, EMAC_MDC_O_IDX, 0, 0);
//mdio to gpio2
gpio_matrix_out(2, EMAC_MDO_O_IDX, 0, 0);
gpio_matrix_in(2, EMAC_MDI_I_IDX, 0);
//mdc to gpio23
gpio_matrix_out(PIN_SMI_MDC, EMAC_MDC_O_IDX, 0, 0);
//mdio to gpio18
gpio_matrix_out(PIN_SMI_MDIO, EMAC_MDO_O_IDX, 0, 0);
gpio_matrix_in(PIN_SMI_MDIO, EMAC_MDI_I_IDX, 0);
}
void eth_task(void *pvParameter)
@ -163,6 +177,7 @@ void app_main()
//Only FULLDUPLEX mode support flow ctrl now!
config.flow_ctrl_enable = true;
config.phy_get_partner_pause_enable = phy_tlk110_get_partner_pause_enable;
config.phy_power_enable = phy_tlk110_power_enable;
ret = esp_eth_init(&config);

View file

@ -37,7 +37,7 @@ const static char *TAG = "Openssl_demo";
#define OPENSSL_DEMO_SERVER_ACK "HTTP/1.1 200 OK\r\n" \
"Content-Type: text/html\r\n" \
"Content-Length: 98\r\n" \
"Content-Length: 98\r\n\r\n" \
"<html>\r\n" \
"<head>\r\n" \
"<title>OpenSSL demo</title></head><body>\r\n" \
@ -71,6 +71,10 @@ static void openssl_demo_thread(void *p)
const unsigned int prvtkey_pem_bytes = prvtkey_pem_end - prvtkey_pem_start;
ESP_LOGI(TAG, "SSL server context create ......");
/* For security reasons, it is best if you can use
TLSv1_2_server_method() here instead of TLS_server_method().
However some old browsers may not support TLS v1.2.
*/
ctx = SSL_CTX_new(TLS_server_method());
if (!ctx) {
ESP_LOGI(TAG, "failed");

View file

@ -95,7 +95,7 @@ static void initialise_wifi(void)
}
/*read buffer by byte still delim ,return read bytes counts*/
int read_until(char *buffer, char delim, int len)
static int read_until(char *buffer, char delim, int len)
{
// /*TODO: delim check,buffer check,further: do an buffer length limited*/
int i = 0;
@ -109,7 +109,7 @@ int read_until(char *buffer, char delim, int len)
* return true if packet including \r\n\r\n that means http packet header finished,start to receive packet body
* otherwise return false
* */
bool resolve_pkg(char text[], int total_len, esp_ota_handle_t out_handle)
static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t out_handle)
{
/* i means current position */
int i = 0, i_read_len = 0;
@ -121,17 +121,10 @@ bool resolve_pkg(char text[], int total_len, esp_ota_handle_t out_handle)
memset(ota_write_data, 0, BUFFSIZE);
/*copy first http packet body to write buffer*/
memcpy(ota_write_data, &(text[i + 2]), i_write_len);
/*check write packet header first byte:0xE9 second byte:0x09 */
if (ota_write_data[0] == 0xE9 && i_write_len >= 2 && ota_write_data[1] == 0x09) {
ESP_LOGI(TAG, "OTA Write Header format Check OK. first byte is %02x ,second byte is %02x", ota_write_data[0], ota_write_data[1]);
} else {
ESP_LOGE(TAG, "OTA Write Header format Check Failed! first byte is %02x ,second byte is %02x", ota_write_data[0], ota_write_data[1]);
return false;
}
esp_err_t err = esp_ota_write( out_handle, (const void *)ota_write_data, i_write_len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error: esp_ota_write failed! err=%x", err);
ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err);
return false;
} else {
ESP_LOGI(TAG, "esp_ota_write header OK");
@ -266,7 +259,7 @@ void main_task(void *pvParameter)
task_fatal_error();
}
bool pkg_body_start = false, flag = true;
bool resp_body_start = false, flag = true;
/*deal with all receive packet*/
while (flag) {
memset(text, 0, TEXT_BUFFSIZE);
@ -275,14 +268,14 @@ void main_task(void *pvParameter)
if (buff_len < 0) { /*receive error*/
ESP_LOGE(TAG, "Error: receive data error! errno=%d", errno);
task_fatal_error();
} else if (buff_len > 0 && !pkg_body_start) { /*deal with packet header*/
} else if (buff_len > 0 && !resp_body_start) { /*deal with response header*/
memcpy(ota_write_data, text, buff_len);
pkg_body_start = resolve_pkg(text, buff_len, out_handle);
} else if (buff_len > 0 && pkg_body_start) { /*deal with packet body*/
resp_body_start = read_past_http_header(text, buff_len, out_handle);
} else if (buff_len > 0 && resp_body_start) { /*deal with response body*/
memcpy(ota_write_data, text, buff_len);
err = esp_ota_write( out_handle, (const void *)ota_write_data, buff_len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error: esp_ota_write failed! err=%x", err);
ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err);
task_fatal_error();
}
binary_file_length += buff_len;

View file

@ -9,8 +9,6 @@
struct kconf_id;
static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
%%
mainmenu, T_MAINMENU, TF_COMMAND
menu, T_MENU, TF_COMMAND