Merge branch 'master' into feature/esp32s2beta_update

This commit is contained in:
Angus Gratton 2019-08-16 19:06:34 +10:00 committed by Angus Gratton
commit 6990a7cd54
157 changed files with 4014 additions and 1316 deletions

22
.github/main.workflow vendored
View file

@ -1,22 +0,0 @@
workflow "Sync issues to JIRA" {
on = "issues"
resolves = ["Sync to JIRA"]
}
workflow "Sync issue and PR comments to JIRA" {
on = "issue_comment"
resolves = ["Sync to JIRA"]
}
workflow "Sync PRs to JIRA" {
on = "pull_request"
resolves = ["Sync to JIRA"]
}
action "Sync to JIRA" {
uses = "espressif/github-actions/sync_issues_to_jira@master"
secrets = ["GITHUB_TOKEN", "JIRA_URL", "JIRA_USER", "JIRA_PASS"]
env = {
JIRA_PROJECT = "IDFGH"
}
}

16
.github/workflows/issue_comment.yml vendored Normal file
View file

@ -0,0 +1,16 @@
on: issue_comment
name: Sync issue and PR comments to JIRA
jobs:
syncToJIRA:
name: Sync to JIRA
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Sync to JIRA
uses: espressif/github-actions/sync_issues_to_jira@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JIRA_PASS: ${{ secrets.JIRA_PASS }}
JIRA_PROJECT: IDFGH
JIRA_URL: ${{ secrets.JIRA_URL }}
JIRA_USER: ${{ secrets.JIRA_USER }}

16
.github/workflows/issues.yml vendored Normal file
View file

@ -0,0 +1,16 @@
on: issues
name: Sync issues to JIRA
jobs:
syncToJIRA:
name: Sync to JIRA
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Sync to JIRA
uses: espressif/github-actions/sync_issues_to_jira@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JIRA_PASS: ${{ secrets.JIRA_PASS }}
JIRA_PROJECT: IDFGH
JIRA_URL: ${{ secrets.JIRA_URL }}
JIRA_USER: ${{ secrets.JIRA_USER }}

16
.github/workflows/pull_request.yml vendored Normal file
View file

@ -0,0 +1,16 @@
on: pull_request
name: Sync PRs to JIRA
jobs:
syncToJIRA:
name: Sync to JIRA
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Sync to JIRA
uses: espressif/github-actions/sync_issues_to_jira@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JIRA_PASS: ${{ secrets.JIRA_PASS }}
JIRA_PROJECT: IDFGH
JIRA_URL: ${{ secrets.JIRA_URL }}
JIRA_USER: ${{ secrets.JIRA_USER }}

View file

@ -39,7 +39,7 @@ See the Getting Started guide links above for a detailed setup guide. This is a
* Install host build dependencies mentioned in Getting Started guide.
* Add `tools/` directory to the PATH
* Run `python -m pip install requirements.txt` to install Python dependencies
* Run `python -m pip install -r requirements.txt` to install Python dependencies
## Configuring the Project

View file

@ -21,6 +21,7 @@
#include "soc/timer_periph.h"
#include "esp_app_trace.h"
#include "esp_private/dbg_stubs.h"
#include "hal/timer_ll.h"
#if CONFIG_ESP32_GCOV_ENABLE
@ -124,13 +125,13 @@ void esp_gcov_dump(void)
#endif
while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) {
// to avoid complains that task watchdog got triggered for other tasks
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_feed=1;
TIMERG0.wdt_wprotect=0;
timer_ll_wdt_set_protect(&TIMERG0, false);
timer_ll_wdt_feed(&TIMERG0);
timer_ll_wdt_set_protect(&TIMERG0, true);
// to avoid reboot on INT_WDT
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_feed=1;
TIMERG1.wdt_wprotect=0;
timer_ll_wdt_set_protect(&TIMERG1, false);
timer_ll_wdt_feed(&TIMERG1);
timer_ll_wdt_set_protect(&TIMERG1, true);
}
esp_dbg_stub_gcov_dump_do();

View file

@ -145,56 +145,16 @@ static void esp_apptrace_test_timer_isr(void *arg)
}
tim_arg->data.wr_cnt++;
if (tim_arg->group == 0) {
if (tim_arg->id == 0) {
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[0].update = 1;
TIMERG0.hw_timer[0].config.alarm_en = 1;
} else {
TIMERG0.int_clr_timers.t1 = 1;
TIMERG0.hw_timer[1].update = 1;
TIMERG0.hw_timer[1].config.alarm_en = 1;
}
}
if (tim_arg->group == 1) {
if (tim_arg->id == 0) {
TIMERG1.int_clr_timers.t0 = 1;
TIMERG1.hw_timer[0].update = 1;
TIMERG1.hw_timer[0].config.alarm_en = 1;
} else {
TIMERG1.int_clr_timers.t1 = 1;
TIMERG1.hw_timer[1].update = 1;
TIMERG1.hw_timer[1].config.alarm_en = 1;
}
}
timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id);
timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id);
}
static void esp_apptrace_test_timer_isr_crash(void *arg)
{
esp_apptrace_test_timer_arg_t *tim_arg = (esp_apptrace_test_timer_arg_t *)arg;
if (tim_arg->group == 0) {
if (tim_arg->id == 0) {
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[0].update = 1;
TIMERG0.hw_timer[0].config.alarm_en = 1;
} else {
TIMERG0.int_clr_timers.t1 = 1;
TIMERG0.hw_timer[1].update = 1;
TIMERG0.hw_timer[1].config.alarm_en = 1;
}
}
if (tim_arg->group == 1) {
if (tim_arg->id == 0) {
TIMERG1.int_clr_timers.t0 = 1;
TIMERG1.hw_timer[0].update = 1;
TIMERG1.hw_timer[0].config.alarm_en = 1;
} else {
TIMERG1.int_clr_timers.t1 = 1;
TIMERG1.hw_timer[1].update = 1;
TIMERG1.hw_timer[1].config.alarm_en = 1;
}
}
timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id);
timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id);
if (tim_arg->data.wr_cnt < ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH) {
uint32_t *ts = (uint32_t *)(tim_arg->data.buf + sizeof(uint32_t));
*ts = (uint32_t)esp_apptrace_test_ts_get();//xthal_get_ccount();//xTaskGetTickCount();
@ -850,28 +810,8 @@ static void esp_sysview_test_timer_isr(void *arg)
//ESP_APPTRACE_TEST_LOGI("tim-%d: IRQ %d/%d\n", tim_arg->id, tim_arg->group, tim_arg->timer);
if (tim_arg->group == 0) {
if (tim_arg->timer == 0) {
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[0].update = 1;
TIMERG0.hw_timer[0].config.alarm_en = 1;
} else {
TIMERG0.int_clr_timers.t1 = 1;
TIMERG0.hw_timer[1].update = 1;
TIMERG0.hw_timer[1].config.alarm_en = 1;
}
}
if (tim_arg->group == 1) {
if (tim_arg->timer == 0) {
TIMERG1.int_clr_timers.t0 = 1;
TIMERG1.hw_timer[0].update = 1;
TIMERG1.hw_timer[0].config.alarm_en = 1;
} else {
TIMERG1.int_clr_timers.t1 = 1;
TIMERG1.hw_timer[1].update = 1;
TIMERG1.hw_timer[1].config.alarm_en = 1;
}
}
timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id);
timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id);
}
static void esp_sysviewtrace_test_task(void *p)

View file

@ -73,6 +73,7 @@
#include "bootloader_flash_config.h"
#include "flash_qio_mode.h"
#include "hal/timer_ll.h"
extern int _bss_start;
extern int _bss_end;
@ -202,8 +203,8 @@ static esp_err_t bootloader_main(void)
/* disable watch dog here */
rtc_wdt_disable();
#endif
REG_SET_FIELD(TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY, TIMG_WDT_WKEY_VALUE);
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
timer_ll_wdt_set_protect(&TIMERG0, false);
timer_ll_wdt_flashboot_en(&TIMERG0, false);
#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
const uint32_t spiconfig = ets_efuse_get_spiconfig();

View file

@ -319,3 +319,31 @@ TEST_CASE("can call std::function and bind", "[cxx]")
#endif
/* Tests below are done in the compile time, don't actually get run. */
/* Check whether a enumerator flag can be used in C++ */
template<typename T> __attribute__((unused)) static void test_binary_operators()
{
T flag1 = (T)0;
T flag2 = (T)0;
flag1 = ~flag1;
flag1 = flag1 | flag2;
flag1 = flag1 & flag2;
flag1 = flag1 ^ flag2;
flag1 = flag1 >> 2;
flag1 = flag1 << 2;
flag1 |= flag2;
flag1 &= flag2;
flag1 ^= flag2;
flag1 >>= 2;
flag1 <<= 2;
}
//Add more types here. If any flags cannot pass the build, use FLAG_ATTR in esp_attr.h
#include "hal/timer_types.h"
template void test_binary_operators<timer_intr_t>();

View file

@ -18,6 +18,8 @@ set(srcs
"timer.c"
"uart.c")
set(includes "include")
if(CONFIG_IDF_TARGET_ESP32)
# SDMMC and MCPWM are in ESP32 only.
list(APPEND srcs "mcpwm.c"
@ -27,12 +29,14 @@ if(CONFIG_IDF_TARGET_ESP32)
endif()
if(CONFIG_IDF_TARGET_ESP32S2BETA)
list(APPEND srcs "${CONFIG_IDF_TARGET}/rtc_tempsensor.c"
"${CONFIG_IDF_TARGET}/rtc_touchpad.c")
list(APPEND srcs "esp32s2beta/rtc_tempsensor.c"
"esp32s2beta/rtc_touchpad.c")
# currently only S2 beta has its own target-specific includes
list(APPEND includes "esp32s2beta/include")
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include" "${CONFIG_IDF_TARGET}/include"
INCLUDE_DIRS ${includes}
PRIV_INCLUDE_DIRS "include/driver"
REQUIRES esp_ringbuf soc) #cannot totally hide soc headers, since there are a lot arguments in the driver are chip-dependent

View file

@ -53,6 +53,13 @@ typedef enum {
LEDC_APB_CLK, /*!< LEDC timer clock divided from APB clock (80Mhz) */
} ledc_clk_src_t;
typedef enum {
LEDC_AUTO_CLK, /*!< The driver will automatically select the source clock(REF_TICK or APB) based on the giving resolution and duty parameter when init the timer*/
LEDC_USE_REF_TICK, /*!< LEDC timer select REF_TICK clock as source clock*/
LEDC_USE_APB_CLK, /*!< LEDC timer select APB clock as source clock*/
LEDC_USE_RTC8M_CLK, /*!< LEDC timer select RTC8M_CLK as source clock. Only for low speed channels and this parameter must be the same for all low speed channels*/
} ledc_clk_cfg_t;
typedef enum {
LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */
LEDC_TIMER_1, /*!< LEDC timer 1 */
@ -129,6 +136,9 @@ typedef struct {
};
ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3) */
uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */
ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock.
For low speed channels and high speed channels, you can specify the source clock using LEDC_USE_REF_TICK, LEDC_USE_APB_CLK or LEDC_AUTO_CLK.
For low speed channels, you can also specify the source clock using LEDC_USE_RTC8M_CLK, in this case, all low speed channel's source clock must be RTC8M_CLK*/
} ledc_timer_config_t;
typedef intr_handle_t ledc_isr_handle_t;

View file

@ -19,6 +19,7 @@
#include "soc/soc.h"
#include "soc/timer_periph.h"
#include "esp_intr_alloc.h"
#include "hal/timer_types.h"
#ifdef __cplusplus
extern "C" {
@ -36,15 +37,6 @@ typedef enum {
TIMER_GROUP_MAX,
} timer_group_t;
/**
* @brief Select a hardware timer from timer groups
*/
typedef enum {
TIMER_0 = 0, /*!<Select timer0 of GROUPx*/
TIMER_1 = 1, /*!<Select timer1 of GROUPx*/
TIMER_MAX,
} timer_idx_t;
/**
* @brief Decides the direction of counter
*/
@ -54,14 +46,6 @@ typedef enum {
TIMER_COUNT_MAX
} timer_count_dir_t;
/**
* @brief Decides whether timer is on or paused
*/
typedef enum {
TIMER_PAUSE = 0, /*!<Pause timer counter*/
TIMER_START = 1, /*!<Start timer counter*/
} timer_start_t;
/**
* @brief Decides whether to enable alarm mode
*/
@ -275,9 +259,9 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @note If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set,
* the handler function must be declared with IRAM_ATTR attribute
* and can only call functions in IRAM or ROM. It cannot call other timer APIs.
* @note If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set,
* the handler function must be declared with IRAM_ATTR attribute
* and can only call functions in IRAM or ROM. It cannot call other timer APIs.
* Use direct register access to configure timers from inside the ISR in this case.
*
* @return
@ -287,7 +271,7 @@ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_
esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void*), void * arg, int intr_alloc_flags, timer_isr_handle_t *handle);
/** @brief Initializes and configure the timer.
*
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param config Pointer to timer initialization parameters.
@ -313,28 +297,30 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer
/** @brief Enable timer group interrupt, by enable mask
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param en_mask Timer interrupt enable mask.
* Use TIMG_T0_INT_ENA_M to enable t0 interrupt
* Use TIMG_T1_INT_ENA_M to enable t1 interrupt
* @param intr_mask Timer interrupt enable mask.
* - TIMER_INTR_T0: t0 interrupt
* - TIMER_INTR_T1: t1 interrupt
* - TIMER_INTR_WDT: watchdog interrupt
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask);
esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
/** @brief Disable timer group interrupt, by disable mask
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param disable_mask Timer interrupt disable mask.
* Use TIMG_T0_INT_ENA_M to disable t0 interrupt
* Use TIMG_T1_INT_ENA_M to disable t1 interrupt
* @param intr_mask Timer interrupt disable mask.
* - TIMER_INTR_T0: t0 interrupt
* - TIMER_INTR_T1: t1 interrupt
* - TIMER_INTR_WDT: watchdog interrupt
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask);
esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
/** @brief Enable timer interrupt
*
@ -358,6 +344,52 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num);
*/
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num);
/** @cond */
/* Utilities functions that can be used in the ISR */
/* Preview, don't treat them as stable API. */
/**
* Clear interrupt status bit.
*/
void timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/**
* Enable alarm.
*/
void timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/**
* Get the current counter value.
*/
uint64_t timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/**
* Set the alarm threshold for the timer.
*/
void timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val);
/**
* Enable/disable a counter.
*/
void timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en);
/**
* Get the masked interrupt status.
*/
timer_intr_t timer_group_intr_get_in_isr(timer_group_t group_num);
/**
* Clear interrupt.
*/
void timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask);
/**
* Get auto reload enable status.
*/
bool timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/** @endcond */
#ifdef __cplusplus
}
#endif

View file

@ -368,7 +368,7 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold);
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Touch pad parameter error
* - ESP_ERR_INVALID_STATE This touch pad hardware connection is error, the value of "touch_value" is 0.
p * - ESP_FAIL Touch pad not initialized
* - ESP_FAIL Touch pad not initialized
*/
esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t * touch_value);

View file

@ -866,6 +866,14 @@ esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold);
*/
esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_threshold);
/**
* @brief Wait until UART tx memory empty and the last char send ok (polling mode).
*
* @param uart_num UART number
*
*/
void uart_wait_tx_idle_polling(uart_port_t uart_num);
#ifdef __cplusplus
}
#endif

View file

@ -19,6 +19,7 @@
#include "soc/gpio_periph.h"
#include "driver/ledc.h"
#include "soc/ledc_periph.h"
#include "soc/rtc.h"
#include "esp_log.h"
static const char* LEDC_TAG = "ledc";
@ -56,11 +57,16 @@ static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL;
#define LEDC_DUTY_CYCLE_MAX (LEDC_DUTY_CYCLE_LSCH0_V)
#define LEDC_DUTY_SCALE_MAX (LEDC_DUTY_SCALE_LSCH0_V)
#define LEDC_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH1_V)
#define DELAY_CLK8M_CLK_SWITCH (5)
#define SLOW_CLK_CYC_CALIBRATE (13)
#define LEDC_FADE_TOO_SLOW_STR "LEDC FADE TOO SLOW"
#define LEDC_FADE_TOO_FAST_STR "LEDC FADE TOO FAST"
static const char *LEDC_FADE_SERVICE_ERR_STR = "LEDC fade service not installed";
static const char *LEDC_FADE_INIT_ERROR_STR = "LEDC fade channel init error, not enough memory or service not installed";
//This value will be calibrated when in use.
static uint32_t s_ledc_slow_clk_8M = 0;
static void ledc_ls_timer_update(ledc_mode_t speed_mode, ledc_timer_t timer_sel)
{
if (speed_mode == LEDC_LOW_SPEED_MODE) {
@ -75,6 +81,28 @@ static IRAM_ATTR void ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channe
}
}
//We know that CLK8M is about 8M, but don't know the actual value. So we need to do a calibration.
static bool ledc_slow_clk_calibrate(void)
{
#ifdef CONFIG_IDF_TARGET_ESP32
//Enable CLK8M for LEDC
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
//Waiting for CLK8M to turn on
ets_delay_us(DELAY_CLK8M_CLK_SWITCH);
uint32_t cal_val = rtc_clk_cal(RTC_CAL_8MD256, SLOW_CLK_CYC_CALIBRATE);
if(cal_val == 0) {
ESP_LOGE(LEDC_TAG, "CLK8M_CLK calibration failed");
return false;
}
s_ledc_slow_clk_8M = 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / cal_val;
ESP_LOGD(LEDC_TAG, "Calibrate CLK8M_CLK : %d Hz", s_ledc_slow_clk_8M);
return true;
#else
ESP_LOGE(LEDC_TAG, "CLK8M source currently only supported on ESP32");
return false;
#endif
}
static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type)
{
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
@ -241,6 +269,62 @@ esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags,
return ret;
}
// Setting the LEDC timer divisor with the given source clock, frequency and resolution.
static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_num, ledc_clk_cfg_t clk_cfg, int freq_hz, int duty_resolution)
{
uint32_t div_param = 0;
uint32_t precision = ( 0x1 << duty_resolution );
ledc_clk_src_t timer_clk_src = LEDC_APB_CLK;
// Calculate the divisor
// User specified source clock(RTC8M_CLK) for low speed channel
if ((speed_mode == LEDC_LOW_SPEED_MODE) && (clk_cfg == LEDC_USE_RTC8M_CLK)) {
if(s_ledc_slow_clk_8M == 0) {
if (ledc_slow_clk_calibrate() == false) {
goto error;
}
}
div_param = ( (uint64_t) s_ledc_slow_clk_8M << 8 ) / freq_hz / precision;
} else {
// Automatically select APB or REF_TICK as the source clock.
if (clk_cfg == LEDC_AUTO_CLK) {
// Try calculating divisor based on LEDC_APB_CLK
div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision;
if (div_param > LEDC_TIMER_DIV_NUM_MAX) {
// APB_CLK results in divisor which too high. Try using REF_TICK as clock source.
timer_clk_src = LEDC_REF_TICK;
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
} else if (div_param < 256) {
// divisor is too low
goto error;
}
// User specified source clock(LEDC_APB_CLK_HZ or LEDC_REF_TICK)
} else {
timer_clk_src = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK : LEDC_REF_TICK;
uint32_t sclk_freq = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK_HZ : LEDC_REF_CLK_HZ;
div_param = ( (uint64_t) sclk_freq << 8 ) / freq_hz / precision;
}
}
if (div_param < 256 || div_param > LEDC_TIMER_DIV_NUM_MAX) {
goto error;
}
#ifdef CONFIG_IDF_TARGET_ESP32
// For low speed channels, if RTC_8MCLK is used as the source clock, the `slow_clk_sel` register should be cleared, otherwise it should be set.
if (speed_mode == LEDC_LOW_SPEED_MODE) {
LEDC.conf.slow_clk_sel = (clk_cfg == LEDC_USE_RTC8M_CLK) ? 0 : 1;
}
#endif
//Set the divisor
ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src);
// reset the timer
ledc_timer_rst(speed_mode, timer_num);
return ESP_OK;
error:
ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=%d",
(uint32_t ) div_param);
return ESP_FAIL;
}
esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
{
LEDC_ARG_CHECK(timer_conf != NULL, "timer_conf");
@ -249,6 +333,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
uint32_t timer_num = timer_conf->timer_num;
uint32_t speed_mode = timer_conf->speed_mode;
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
LEDC_ARG_CHECK(!((timer_conf->clk_cfg == LEDC_USE_RTC8M_CLK) && (speed_mode != LEDC_LOW_SPEED_MODE)), "Only low speed channel support RTC8M_CLK");
periph_module_enable(PERIPH_LEDC_MODULE);
if (freq_hz == 0 || duty_resolution == 0 || duty_resolution >= LEDC_TIMER_BIT_MAX) {
ESP_LOGE(LEDC_TAG, "freq_hz=%u duty_resolution=%u", freq_hz, duty_resolution);
@ -258,40 +343,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
ESP_LOGE(LEDC_TAG, "invalid timer #%u", timer_num);
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = ESP_OK;
uint32_t precision = ( 0x1 << duty_resolution ); // 2**depth
// Try calculating divisor based on LEDC_APB_CLK
ledc_clk_src_t timer_clk_src = LEDC_APB_CLK;
// div_param is a Q10.8 fixed point value
uint64_t div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision;
if (div_param < 256) {
// divisor is too low
ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=%d",
(uint32_t ) div_param);
ret = ESP_FAIL;
}
if (div_param > LEDC_TIMER_DIV_NUM_MAX) {
// APB_CLK results in divisor which too high. Try using REF_TICK as clock source.
timer_clk_src = LEDC_REF_TICK;
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
if (div_param < 256 || div_param > LEDC_TIMER_DIV_NUM_MAX) {
ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try increasing freq_hz or duty_resolution. div_param=%d",
(uint32_t ) div_param);
ret = ESP_FAIL;
}
} else {
#ifdef CONFIG_IDF_TARGET_ESP32
if (speed_mode == LEDC_LOW_SPEED_MODE) {
//for now, we only select 80mhz for slow clk of LEDC low speed channels.
LEDC.conf.slow_clk_sel = 1;
}
#endif
}
// set timer parameters
ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src);
// reset timer
ledc_timer_rst(speed_mode, timer_num);
return ret;
return ledc_set_timer_div(timer_num, timer_num, timer_conf->clk_cfg, freq_hz, duty_resolution);
}
esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel)

View file

@ -533,6 +533,7 @@ static inline esp_err_t sdio_slave_hw_init(sdio_slave_config_t *config)
SLC.rx_dscr_conf.slc0_token_no_replace = 1;
HINF.cfg_data1.highspeed_enable = 1;
HINF.cfg_data1.sdio_ver = 0x232;
switch(config->timing) {
case SDIO_SLAVE_TIMING_PSEND_PSAMPLE:

View file

@ -86,6 +86,7 @@ static void timer_frequency_test(ledc_channel_t channel, ledc_timer_bit_t timer_
.bit_num = timer_bit,
.timer_num = timer,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK,
};
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
@ -126,6 +127,7 @@ static void timer_duty_test(ledc_channel_t channel, ledc_timer_bit_t timer_bit,
.bit_num = timer_bit,
.timer_num = timer,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK,
};
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
@ -188,6 +190,7 @@ TEST_CASE("LEDC error log channel and timer config", "[ledc][test_env=UT_T1_LEDC
ledc_time_config.duty_resolution = LEDC_TIMER_13_BIT;
ledc_time_config.timer_num = LEDC_TIMER_0;
ledc_time_config.freq_hz = 5000;
ledc_time_config.clk_cfg = LEDC_AUTO_CLK;
ledc_timer_config_t temp_timer_config = ledc_time_config;
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
@ -228,6 +231,7 @@ TEST_CASE("LEDC normal channel and timer config", "[ledc][test_env=UT_T1_LEDC]")
.bit_num = LEDC_TIMER_13_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config_t temp_time_config = ledc_time_config;
@ -297,6 +301,7 @@ TEST_CASE("LEDC timer set", "[ledc][test_env=UT_T1_LEDC]")
.bit_num = 13,
.timer_num = LEDC_TIMER_0,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK,
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
@ -347,6 +352,7 @@ TEST_CASE("LEDC timer pause and resume", "[ledc][test_env=UT_T1_LEDC]")
.duty_resolution = LEDC_TIMER_13_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK,
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
@ -392,6 +398,7 @@ TEST_CASE("LEDC fade with time(logic analyzer)", "[ledc][ignore]")
.duty_resolution = LEDC_TIMER_13_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK,
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
@ -429,6 +436,7 @@ TEST_CASE("LEDC fade with step(logic analyzer)", "[ledc][ignore]")
.duty_resolution = LEDC_TIMER_13_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK,
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
@ -470,6 +478,7 @@ TEST_CASE("LEDC memory test", "[ledc][test_env=UT_T1_LEDC]")
.duty_resolution = LEDC_TIMER_13_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK,
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));

View file

@ -55,6 +55,7 @@ static void produce_pulse(void)
.timer_num = LEDC_TIMER_1,
.duty_resolution = LEDC_TIMER_10_BIT,
.freq_hz = 1,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config(&ledc_timer);
@ -160,6 +161,7 @@ static void count_mode_test(gpio_num_t ctl_io)
.timer_num = LEDC_TIMER_1,
.duty_resolution = LEDC_TIMER_10_BIT,
.freq_hz = 100,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config(&ledc_timer);

View file

@ -11,68 +11,44 @@
#define TIMER_DELTA 0.001
static bool alarm_flag;
// group0 interruption
static void test_timer_group0_isr(void *para)
{
int timer_idx = (int) para;
uint64_t timer_val;
double time;
uint64_t alarm_value;
alarm_flag = true;
if (TIMERG0.hw_timer[timer_idx].config.autoreload == 1) {
if (timer_idx == 0) {
TIMERG0.int_clr_timers.t0 = 1;
} else {
TIMERG0.int_clr_timers.t1 = 1;
}
ets_printf("This is TG0 timer[%d] reload-timer alarm!\n", timer_idx);
timer_get_counter_value(TIMER_GROUP_0, timer_idx, &timer_val);
timer_get_counter_time_sec(TIMER_GROUP_0, timer_idx, &time);
ets_printf("time: %.8f S\n", time);
} else {
if (timer_idx == 0) {
TIMERG0.int_clr_timers.t0 = 1;
} else {
TIMERG0.int_clr_timers.t1 = 1;
}
ets_printf("This is TG0 timer[%d] count-up-timer alarm!\n", timer_idx);
timer_get_counter_value(TIMER_GROUP_0, timer_idx, &timer_val);
timer_get_counter_time_sec(TIMER_GROUP_0, timer_idx, &time);
timer_get_alarm_value(TIMER_GROUP_0, timer_idx, &alarm_value);
ets_printf("time: %.8f S\n", time);
double alarm_time = (double) alarm_value / TIMER_SCALE;
ets_printf("alarm_time: %.8f S\n", alarm_time);
}
}
typedef struct {
timer_group_t timer_group;
timer_idx_t timer_idx;
} timer_info_t;
// group1 interruption
static void test_timer_group1_isr(void *para)
#define TIMER_INFO_INIT(TG, TID) {.timer_group = (TG), .timer_idx = (TID),}
static timer_info_t timer_info[4] = {
TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_0),
TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_1),
TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_0),
TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_1),
};
#define GET_TIMER_INFO(TG, TID) (&timer_info[(TG)*2+(TID)])
// timer group interruption
static void test_timer_group_isr(void *para)
{
int timer_idx = (int) para;
timer_info_t* info = (timer_info_t*) para;
const timer_group_t timer_group = info->timer_group;
const timer_idx_t timer_idx = info->timer_idx;
uint64_t timer_val;
double time;
uint64_t alarm_value;
alarm_flag = true;
if (TIMERG1.hw_timer[timer_idx].config.autoreload == 1) {
if (timer_idx == 0) {
TIMERG1.int_clr_timers.t0 = 1;
} else {
TIMERG1.int_clr_timers.t1 = 1;
}
ets_printf("This is TG1 timer[%d] reload-timer alarm!\n", timer_idx);
timer_get_counter_value(TIMER_GROUP_1, timer_idx, &timer_val);
timer_get_counter_time_sec(TIMER_GROUP_1, timer_idx, &time);
if (timer_group_get_auto_reload_in_isr(timer_group, timer_idx)) {
timer_group_intr_clr_in_isr(timer_group, timer_idx);
ets_printf("This is TG%d timer[%d] reload-timer alarm!\n", timer_group, timer_idx);
timer_get_counter_value(timer_group, timer_idx, &timer_val);
timer_get_counter_time_sec(timer_group, timer_idx, &time);
ets_printf("time: %.8f S\n", time);
} else {
if (timer_idx == 0) {
TIMERG1.int_clr_timers.t0 = 1;
} else {
TIMERG1.int_clr_timers.t1 = 1;
}
ets_printf("This is TG1 timer[%d] count-up-timer alarm!\n", timer_idx);
timer_get_counter_value(TIMER_GROUP_1, timer_idx, &timer_val);
timer_get_counter_time_sec(TIMER_GROUP_1, timer_idx, &time);
timer_get_alarm_value(TIMER_GROUP_1, timer_idx, &alarm_value);
timer_group_intr_clr_in_isr(timer_group, timer_idx);
ets_printf("This is TG%d timer[%d] count-up-timer alarm!\n", timer_group, timer_idx);
timer_get_counter_value(timer_group, timer_idx, &timer_val);
timer_get_counter_time_sec(timer_group, timer_idx, &time);
timer_get_alarm_value(timer_group, timer_idx, &alarm_value);
ets_printf("time: %.8f S\n", time);
double alarm_time = (double) alarm_value / TIMER_SCALE;
ets_printf("alarm_time: %.8f S\n", alarm_time);
@ -86,13 +62,7 @@ static void tg_timer_init(int timer_group, int timer_idx, double alarm_time)
timer_set_counter_value(timer_group, timer_idx, 0x0);
timer_set_alarm_value(timer_group, timer_idx, alarm_time * TIMER_SCALE);
timer_enable_intr(timer_group, timer_idx);
if (timer_group == 0) {
timer_isr_register(timer_group, timer_idx, test_timer_group0_isr,
(void *) timer_idx, ESP_INTR_FLAG_LOWMED, NULL);
} else {
timer_isr_register(timer_group, timer_idx, test_timer_group1_isr,
(void *) timer_idx, ESP_INTR_FLAG_LOWMED, NULL);
}
timer_isr_register(timer_group, timer_idx, test_timer_group_isr, GET_TIMER_INFO(timer_group, timer_idx), ESP_INTR_FLAG_LOWMED, NULL);
timer_start(timer_group, timer_idx);
}
@ -747,8 +717,8 @@ TEST_CASE("Timer enable timer interrupt", "[hw_timer]")
// enable timer_intr0
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, set_timer_val);
timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1.2 * TIMER_SCALE);
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr,
(void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL);
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr,
GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL);
timer_start(TIMER_GROUP_0, TIMER_0);
vTaskDelay(2000 / portTICK_PERIOD_MS);
TEST_ASSERT(alarm_flag == true)
@ -765,8 +735,8 @@ TEST_CASE("Timer enable timer interrupt", "[hw_timer]")
// enable timer_intr1
timer_set_counter_value(TIMER_GROUP_1, TIMER_1, set_timer_val);
timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, 1.2 * TIMER_SCALE);
timer_isr_register(TIMER_GROUP_1, TIMER_1, test_timer_group1_isr,
(void *) TIMER_1, ESP_INTR_FLAG_LOWMED, NULL);
timer_isr_register(TIMER_GROUP_1, TIMER_1, test_timer_group_isr,
GET_TIMER_INFO(TIMER_GROUP_1, TIMER_1), ESP_INTR_FLAG_LOWMED, NULL);
timer_start(TIMER_GROUP_1, TIMER_1);
vTaskDelay(2000 / portTICK_PERIOD_MS);
TEST_ASSERT(alarm_flag == true)
@ -813,23 +783,21 @@ TEST_CASE("Timer enable timer group interrupt", "[hw_timer][ignore]")
all_timer_set_alarm_value(1.2);
// enable timer group
timer_group_intr_enable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M);
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr,
(void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL);
timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0);
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL);
timer_start(TIMER_GROUP_0, TIMER_0);
vTaskDelay(2000 / portTICK_PERIOD_MS);
TEST_ASSERT(alarm_flag == true);
//test enable auto_reload
alarm_flag = false;
timer_group_intr_disable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M);
timer_group_intr_disable(TIMER_GROUP_0, TIMER_INTR_T0);
timer_start(TIMER_GROUP_0, TIMER_0);
vTaskDelay(2000 / portTICK_PERIOD_MS);
TEST_ASSERT(alarm_flag == false);
timer_group_intr_enable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M);
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr,
(void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL);
timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0);
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL);
timer_start(TIMER_GROUP_0, TIMER_0);
vTaskDelay(2000 / portTICK_PERIOD_MS);
TEST_ASSERT(alarm_flag == true);

View file

@ -19,8 +19,8 @@
#include "freertos/xtensa_api.h"
#include "driver/timer.h"
#include "driver/periph_ctrl.h"
#include "hal/timer_ll.h"
#include "soc/rtc.h"
#include "sdkconfig.h"
static const char* TIMER_TAG = "timer_group";
#define TIMER_CHECK(a, str, ret_val) \
@ -37,7 +37,7 @@ static const char* TIMER_TAG = "timer_group";
#define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR"
#define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR"
#define DIVIDER_RANGE_ERROR "HW TIMER divider outside of [2, 65536] range error"
static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};
DRAM_ATTR static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};
static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
#define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux);
@ -274,7 +274,7 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer
return ESP_OK;
}
esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)
esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t en_mask)
{
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&timer_spinlock[group_num]);
@ -283,7 +283,7 @@ esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)
return ESP_OK;
}
esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask)
esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t disable_mask)
{
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&timer_spinlock[group_num]);
@ -296,12 +296,55 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)
{
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
return timer_group_intr_enable(group_num, BIT(timer_num));
return timer_group_intr_enable(group_num, TIMER_LL_GET_INTR(timer_num));
}
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)
{
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
return timer_group_intr_disable(group_num, BIT(timer_num));
return timer_group_intr_disable(group_num, TIMER_LL_GET_INTR(timer_num));
}
timer_intr_t IRAM_ATTR timer_group_intr_get_in_isr(timer_group_t group_num)
{
return timer_ll_intr_status_get(TG[group_num]);
}
void IRAM_ATTR timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{
timer_ll_intr_status_clear(TG[group_num], TIMER_LL_GET_INTR(timer_num));
}
void IRAM_ATTR timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{
timer_ll_set_alarm_enable(TG[group_num], timer_num, true);
}
uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{
uint64_t val;
timer_ll_get_counter_value(TG[group_num], timer_num, &val);
return val;
}
void IRAM_ATTR timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val)
{
timer_ll_set_alarm_value(TG[group_num], timer_num, alarm_val);
}
void IRAM_ATTR timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en)
{
timer_ll_set_counter_enable(TG[group_num], timer_num, counter_en);
}
void IRAM_ATTR timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask)
{
timer_ll_intr_status_clear(TG[group_num], intr_mask);
}
bool IRAM_ATTR timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{
return timer_ll_get_auto_reload(TG[group_num], timer_num);
}

View file

@ -1663,8 +1663,8 @@ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool *collision_flag)
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG);
UART_CHECK((collision_flag != NULL), "wrong parameter pointer", ESP_ERR_INVALID_ARG);
UART_CHECK((UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)
|| UART_IS_MODE_SET(uart_num, UART_MODE_RS485_COLLISION_DETECT)),
"wrong mode", ESP_ERR_INVALID_ARG);
|| UART_IS_MODE_SET(uart_num, UART_MODE_RS485_COLLISION_DETECT)),
"wrong mode", ESP_ERR_INVALID_ARG);
*collision_flag = p_uart_obj[uart_num]->coll_det_flg;
return ESP_OK;
}
@ -1688,3 +1688,12 @@ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int *out_wakeup_thresh
*out_wakeup_threshold = UART[uart_num]->sleep_conf.active_threshold + UART_MIN_WAKEUP_THRESH;
return ESP_OK;
}
void uart_wait_tx_idle_polling(uart_port_t uart_num)
{
uint32_t status;
do {
status = READ_PERI_REG(UART_STATUS_REG(uart_num));
/* either tx count or state is non-zero */
} while ((status & (UART_ST_UTX_OUT_M | UART_TXFIFO_CNT_M)) != 0);
}

View file

@ -17,7 +17,7 @@
#include <assert.h>
#include "esp_efuse_table.h"
// md5_digest_table 544d434da010ce22f7db1b14d38e1d66
// md5_digest_table 2e23344575b3d07f01ecb695294e9770
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
@ -151,6 +151,10 @@ static const esp_efuse_desc_t CHIP_VER_REV1[] = {
{EFUSE_BLK0, 111, 1}, // EFUSE_RD_CHIP_VER_REV1,
};
static const esp_efuse_desc_t CHIP_VER_REV2[] = {
{EFUSE_BLK0, 180, 1}, // EFUSE_RD_CHIP_VER_REV2,
};
static const esp_efuse_desc_t XPD_SDIO_REG[] = {
{EFUSE_BLK0, 142, 1}, // EFUSE_RD_XPD_SDIO_REG,
};
@ -336,6 +340,11 @@ const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[] = {
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[] = {
&CHIP_VER_REV2[0], // EFUSE_RD_CHIP_VER_REV2
NULL
};
const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[] = {
&XPD_SDIO_REG[0], // EFUSE_RD_XPD_SDIO_REG
NULL

View file

@ -6,7 +6,7 @@
##########################################################################
# *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_MAX_BLK_LEN, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128.
# !!!!!!!!!!! #
# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table"
# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table"
# this will generate new source files, next rebuild all the sources.
# !!!!!!!!!!! #
@ -36,11 +36,11 @@ ABS_DONE_0, EFUSE_BLK0, 196, 1, Secure boot is enabled for
ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, MAX_BLK_LEN, Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128)
ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M
DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT.
DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT.
DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.
DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.
CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT.
DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT.
DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE.
DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG.
CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE.
FLASH_CRYPT_CNT, EFUSE_BLK0, 20, 7, Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT.
# Write protection #
@ -53,7 +53,7 @@ WR_DIS_BLK3, EFUSE_BLK0, 9, 1, Write protection for EFUSE_B
# Read protection #
###################
RD_DIS_BLK1, EFUSE_BLK0, 16, 1, Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1
RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2
RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2
RD_DIS_BLK3, EFUSE_BLK0, 18, 1, Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3
# Chip info #
@ -64,6 +64,7 @@ CHIP_VER_PKG, EFUSE_BLK0, 105, 3, EFUSE_RD_CHIP_VER_PKG
CHIP_CPU_FREQ_LOW, EFUSE_BLK0, 108, 1, EFUSE_RD_CHIP_CPU_FREQ_LOW
CHIP_CPU_FREQ_RATED, EFUSE_BLK0, 109, 1, EFUSE_RD_CHIP_CPU_FREQ_RATED
CHIP_VER_REV1, EFUSE_BLK0, 111, 1, EFUSE_RD_CHIP_VER_REV1
CHIP_VER_REV2, EFUSE_BLK0, 180, 1, EFUSE_RD_CHIP_VER_REV2
XPD_SDIO_REG, EFUSE_BLK0, 142, 1, EFUSE_RD_XPD_SDIO_REG
SDIO_TIEH, EFUSE_BLK0, 143, 1, EFUSE_RD_SDIO_TIEH
SDIO_FORCE, EFUSE_BLK0, 144, 1, EFUSE_RD_SDIO_FORCE

Can't render this file because it contains an unexpected character in line 7 and column 87.

View file

@ -17,7 +17,7 @@ extern "C" {
#endif
// md5_digest_table 544d434da010ce22f7db1b14d38e1d66
// md5_digest_table 2e23344575b3d07f01ecb695294e9770
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
// If you want to change some fields, you need to change esp_efuse_table.csv file
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
@ -52,6 +52,7 @@ extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[];
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[];
extern const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[];
extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[];
extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[];

View file

@ -23,6 +23,7 @@
#include "esp_log.h"
#include "soc/efuse_periph.h"
#include "bootloader_random.h"
#include "soc/apb_ctrl_reg.h"
const static char *TAG = "efuse";
@ -31,8 +32,29 @@ const static char *TAG = "efuse";
// Returns chip version from efuse
uint8_t esp_efuse_get_chip_ver(void)
{
uint8_t chip_ver;
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &chip_ver, 1);
uint8_t eco_bit0, eco_bit1, eco_bit2;
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &eco_bit0, 1);
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV2, &eco_bit1, 1);
eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 80000000) >> 31;
uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
uint8_t chip_ver = 0;
switch (combine_value) {
case 0:
chip_ver = 0;
break;
case 1:
chip_ver = 1;
break;
case 3:
chip_ver = 2;
break;
case 7:
chip_ver = 3;
break;
default:
chip_ver = 0;
break;
}
return chip_ver;
}
@ -111,7 +133,7 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg);
for (int i = 0; i < 8; i++) {
ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]);
REG_WRITE(blk_wdata0_reg + 4*i, buf[i]);
REG_WRITE(blk_wdata0_reg + 4 * i, buf[i]);
}
bzero(buf, sizeof(buf));
bzero(raw, sizeof(raw));

View file

@ -15,6 +15,7 @@
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "esp32/clk.h"
#include "esp_log.h"
#include "assert.h"
#include "sdkconfig.h"
@ -209,6 +210,25 @@ void esp_efuse_utility_burn_efuses(void)
}
}
#else
// Update Efuse timing configuration
uint32_t apb_freq_mhz = esp_clk_apb_freq() / 1000000;
uint32_t clk_sel0, clk_sel1, dac_clk_div;
if (apb_freq_mhz <= 26) {
clk_sel0 = 250;
clk_sel1 = 255;
dac_clk_div = 52;
} else if (apb_freq_mhz <= 40) {
clk_sel0 = 160;
clk_sel1 = 255;
dac_clk_div = 80;
} else {
clk_sel0 = 80;
clk_sel1 = 128;
dac_clk_div = 100;
}
REG_SET_FIELD(EFUSE_DAC_CONF_REG, EFUSE_DAC_CLK_DIV, dac_clk_div);
REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL0, clk_sel0);
REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL1, clk_sel1);
// Permanently update values written to the efuse write registers
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE);
REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM);

View file

@ -1,5 +1,5 @@
idf_component_register(SRCS "esp_tls.c"
INCLUDE_DIRS "."
PRIVATE_INCLUDE_DIRS "private_include"
PRIV_INCLUDE_DIRS "private_include"
REQUIRES mbedtls
PRIV_REQUIRES lwip nghttp)

View file

@ -5,5 +5,16 @@ menu "ESP-TLS"
help
Enable support for creating server side SSL/TLS session
config ESP_TLS_PSK_VERIFICATION
bool "Enable PSK verification"
select MBEDTLS_PSK_MODES
select MBEDTLS_KEY_EXCHANGE_PSK
select MBEDTLS_KEY_EXCHANGE_DHE_PSK
select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK
select MBEDTLS_KEY_EXCHANGE_RSA_PSK
default n
help
Enable support for pre shared key ciphers
endmenu

View file

@ -426,6 +426,23 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls
if (esp_ret != ESP_OK) {
return esp_ret;
}
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
} else if (cfg->psk_hint_key) {
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
//
// PSK encryption mode is configured only if no certificate supplied and psk pointer not null
ESP_LOGD(TAG, "ssl psk authentication");
ret = mbedtls_ssl_conf_psk(&tls->conf, cfg->psk_hint_key->key, cfg->psk_hint_key->key_size,
(const unsigned char *)cfg->psk_hint_key->hint, strlen(cfg->psk_hint_key->hint));
if (ret != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_conf_psk returned -0x%x", -ret);
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
return ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED;
}
#else
ESP_LOGE(TAG, "psk_hint_key configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option");
return ESP_ERR_INVALID_STATE;
#endif
} else {
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
}
@ -443,7 +460,7 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls
};
esp_err_t esp_ret = set_pki_context(tls, &pki);
if (esp_ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set server pki context");
ESP_LOGE(TAG, "Failed to set client pki context");
return esp_ret;
}
} else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) {

View file

@ -48,6 +48,7 @@ extern "C" {
#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */
#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */
#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */
#define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */
typedef struct esp_tls_last_error* esp_tls_error_handle_t;
@ -76,6 +77,15 @@ typedef enum esp_tls_role {
ESP_TLS_SERVER,
} esp_tls_role_t;
/**
* @brief ESP-TLS preshared key and hint structure
*/
typedef struct psk_key_hint {
const uint8_t* key; /*!< key in PSK authentication mode in binary format */
const size_t key_size; /*!< length of the key */
const char* hint; /*!< hint in PSK authentication mode in string format */
} psk_hint_key_t;
/**
* @brief ESP-TLS configuration parameters
*
@ -159,6 +169,11 @@ typedef struct esp_tls_cfg {
If NULL, server certificate CN must match hostname. */
bool skip_common_name; /*!< Skip any validation of server certificate CN field */
const psk_hint_key_t* psk_hint_key; /*!< Pointer to PSK hint and key. if not NULL (and certificates are NULL)
then PSK authentication is enabled with configured setup.
Important note: the pointer must be valid for connection */
} esp_tls_cfg_t;
#ifdef CONFIG_ESP_TLS_SERVER

View file

@ -4,6 +4,34 @@ menu "ESP32-specific"
# not working so we just hide all items here
visible if IDF_TARGET_ESP32
choice ESP32_REV_MIN
prompt "Minimum Supported ESP32 Revision"
default ESP32_REV_MIN_0
help
Minimum revision that ESP-IDF would support.
ESP-IDF performs different strategy on different esp32 revision.
config ESP32_REV_MIN_0
bool "Rev 0"
config ESP32_REV_MIN_1
bool "Rev 1"
config ESP32_REV_MIN_2
bool "Rev 2"
config ESP32_REV_MIN_3
bool "Rev 3"
endchoice
config ESP32_REV_MIN
int
default 0 if ESP32_REV_MIN_0
default 1 if ESP32_REV_MIN_1
default 2 if ESP32_REV_MIN_2
default 3 if ESP32_REV_MIN_3
config ESP32_DPORT_WORKAROUND
bool
default "y" if !FREERTOS_UNICORE && ESP32_REV_MIN < 2
choice ESP32_DEFAULT_CPU_FREQ_MHZ
prompt "CPU frequency"
default ESP32_DEFAULT_CPU_FREQ_160

View file

@ -204,7 +204,7 @@ void IRAM_ATTR call_start_cpu0(void)
abort();
}
ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
esp_flash_enc_mode_t mode;
mode = esp_get_flash_encryption_mode();
if (mode == ESP_FLASH_ENC_MODE_DEVELOPMENT) {
@ -408,6 +408,16 @@ void start_cpu0_default(void)
esp_flash_app_init();
esp_err_t flash_ret = esp_flash_init_default_chip();
assert(flash_ret == ESP_OK);
uint8_t revision = esp_efuse_get_chip_ver();
ESP_LOGI(TAG, "Chip Revision: %d", revision);
if (revision > CONFIG_ESP32_REV_MIN) {
ESP_LOGW(TAG, "Chip revision is higher than the one configured in menuconfig. Suggest to upgrade it.");
} else if(revision != CONFIG_ESP32_REV_MIN) {
ESP_LOGE(TAG, "ESP-IDF can't support this chip revision. Modify minimum supported revision in menuconfig");
abort();
}
#ifdef CONFIG_PM_ENABLE
esp_pm_impl_init();
#ifdef CONFIG_PM_DFS_INIT_AUTO

View file

@ -16,7 +16,7 @@
* DPORT access is used for do protection when dual core access DPORT internal register and APB register via DPORT simultaneously
* This function will be initialize after FreeRTOS startup.
* When cpu0 want to access DPORT register, it should notify cpu1 enter in high-priority interrupt for be mute. When cpu1 already in high-priority interrupt,
* cpu0 can access DPORT register. Currently, cpu1 will wait for cpu0 finish access and exit high-priority interrupt.
* cpu0 can access DPORT register. Currently, cpu1 will wait for cpu0 finish access and exit high-priority interrupt.
*/
#include <stdint.h>
@ -116,7 +116,7 @@ void IRAM_ATTR esp_dport_access_stall_other_cpu_end(void)
{
#ifndef CONFIG_FREERTOS_UNICORE
int cpu_id = xPortGetCoreID();
if (dport_core_state[0] == DPORT_CORE_STATE_IDLE
|| dport_core_state[1] == DPORT_CORE_STATE_IDLE) {
return;
@ -249,7 +249,7 @@ void IRAM_ATTR esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address
*/
uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
uint32_t apb;
@ -295,7 +295,7 @@ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
*/
uint32_t IRAM_ATTR esp_dport_access_sequence_reg_read(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
uint32_t apb;

View file

@ -33,7 +33,7 @@ uint32_t esp_dport_access_sequence_reg_read(uint32_t reg);
//only call in case of panic().
void esp_dport_access_int_abort(void);
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
#define DPORT_STALL_OTHER_CPU_START()
#define DPORT_STALL_OTHER_CPU_END()
#define DPORT_INTERRUPT_DISABLE()

View file

@ -30,10 +30,11 @@
#include "driver/timer.h"
#include "driver/periph_ctrl.h"
#include "esp_int_wdt.h"
#include "hal/timer_ll.h"
#if CONFIG_ESP_INT_WDT
#define TG1_WDT_TICK_US 500
#define WDT_INT_NUM 24
@ -48,11 +49,15 @@ static void IRAM_ATTR tick_hook(void) {
} else {
//Only feed wdt if app cpu also ticked.
if (int_wdt_app_cpu_ticked) {
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
TIMERG1.wdt_feed=1;
TIMERG1.wdt_wprotect=0;
timer_ll_wdt_set_protect(&TIMERG1, false);
//Set timeout before interrupt
timer_ll_wdt_set_timeout(&TIMERG1, 0,
CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US);
//Set timeout before reset
timer_ll_wdt_set_timeout(&TIMERG1, 1,
2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US);
timer_ll_wdt_feed(&TIMERG1);
timer_ll_wdt_set_protect(&TIMERG1, true);
int_wdt_app_cpu_ticked=false;
}
}
@ -60,33 +65,36 @@ static void IRAM_ATTR tick_hook(void) {
#else
static void IRAM_ATTR tick_hook(void) {
if (xPortGetCoreID()!=0) return;
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
TIMERG1.wdt_feed=1;
TIMERG1.wdt_wprotect=0;
timer_ll_wdt_set_protect(&TIMERG1, false);
//Set timeout before interrupt
timer_ll_wdt_set_timeout(&TIMERG1, 0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US);
//Set timeout before reset
timer_ll_wdt_set_timeout(&TIMERG1, 1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US);
timer_ll_wdt_feed(&TIMERG1);
timer_ll_wdt_set_protect(&TIMERG1, true);
}
#endif
void esp_int_wdt_init(void) {
periph_module_enable(PERIPH_TIMG1_MODULE);
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS
TIMERG1.wdt_config0.cpu_reset_length=7; //3.2uS
TIMERG1.wdt_config0.level_int_en=1;
TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt
TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
TIMERG1.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
//The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
//it to their actual value.
TIMERG1.wdt_config2=10000;
TIMERG1.wdt_config3=10000;
TIMERG1.wdt_config0.en=1;
TIMERG1.wdt_feed=1;
TIMERG1.wdt_wprotect=0;
TIMERG1.int_clr_timers.wdt=1;
timer_group_intr_enable(TIMER_GROUP_1, TIMG_WDT_INT_ENA_M);
timer_ll_wdt_set_protect(&TIMERG1, false);
timer_ll_wdt_init(&TIMERG1);
timer_ll_wdt_set_tick(&TIMERG1, TG1_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG1_WDT_TICK_US
//1st stage timeout: interrupt
timer_ll_wdt_set_timeout_behavior(&TIMERG1, 0, TIMER_WDT_INT);
timer_ll_wdt_set_timeout(&TIMERG1, 0, 5*1000*1000/TG1_WDT_TICK_US);
//2nd stage timeout: reset system
timer_ll_wdt_set_timeout_behavior(&TIMERG1, 1, TIMER_WDT_RESET_SYSTEM);
timer_ll_wdt_set_timeout(&TIMERG1, 1, 5*1000*1000/TG1_WDT_TICK_US);
timer_ll_wdt_set_enable(&TIMERG1, true);
timer_ll_wdt_feed(&TIMERG1);
timer_ll_wdt_set_protect(&TIMERG1, true);
timer_ll_intr_status_clear(&TIMERG1, TIMER_INTR_WDT);
timer_group_intr_enable(TIMER_GROUP_1, TIMER_INTR_WDT);
}
void esp_int_wdt_cpu_init(void)

View file

@ -44,6 +44,8 @@
#include "esp_private/system_internal.h"
#include "sdkconfig.h"
#include "esp_ota_ops.h"
#include "driver/timer.h"
#include "hal/timer_ll.h"
#if CONFIG_SYSVIEW_ENABLE
#include "SEGGER_RTT.h"
#endif
@ -311,7 +313,7 @@ void panicHandler(XtExcFrame *frame)
disableAllWdts();
if (frame->exccause == PANIC_RSN_INTWDT_CPU0 ||
frame->exccause == PANIC_RSN_INTWDT_CPU1) {
TIMERG1.int_clr_timers.wdt = 1;
timer_group_clr_intr_sta_in_isr(TIMER_GROUP_1, TIMER_INTR_WDT);
}
#if CONFIG_ESP32_APPTRACE_ENABLE
#if CONFIG_SYSVIEW_ENABLE
@ -401,19 +403,21 @@ static void illegal_instruction_helper(XtExcFrame *frame)
*/
static void reconfigureAllWdts(void)
{
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_feed = 1;
TIMERG0.wdt_config0.sys_reset_length = 7; //3.2uS
TIMERG0.wdt_config0.cpu_reset_length = 7; //3.2uS
TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system
TIMERG0.wdt_config1.clk_prescale = 80 * 500; //Prescaler: wdt counts in ticks of 0.5mS
TIMERG0.wdt_config2 = 2000; //1 second before reset
TIMERG0.wdt_config0.en = 1;
TIMERG0.wdt_wprotect = 0;
timer_ll_wdt_set_protect(&TIMERG0, false);
timer_ll_wdt_feed(&TIMERG0);
timer_ll_wdt_init(&TIMERG0);
timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US
//1st stage timeout: reset system
timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_RESET_SYSTEM);
//1 second before reset
timer_ll_wdt_set_timeout(&TIMERG0, 0, 1000*1000/TG0_WDT_TICK_US);
timer_ll_wdt_set_enable(&TIMERG0, true);
timer_ll_wdt_set_protect(&TIMERG0, true);
//Disable wdt 1
TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config0.en = 0;
TIMERG1.wdt_wprotect = 0;
timer_ll_wdt_set_protect(&TIMERG1, false);
timer_ll_wdt_set_enable(&TIMERG1, false);
timer_ll_wdt_set_protect(&TIMERG1, true);
}
/*
@ -421,14 +425,16 @@ static void reconfigureAllWdts(void)
*/
static inline void disableAllWdts(void)
{
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_config0.en = 0;
TIMERG0.wdt_wprotect = 0;
TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config0.en = 0;
TIMERG1.wdt_wprotect = 0;
timer_ll_wdt_set_protect(&TIMERG0, false);
timer_ll_wdt_set_enable(&TIMERG0, false);
timer_ll_wdt_set_protect(&TIMERG0, true);
timer_ll_wdt_set_protect(&TIMERG1, false);
timer_ll_wdt_set_enable(&TIMERG1, false);
timer_ll_wdt_set_protect(&TIMERG1, true);
}
#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
static void esp_panic_dig_reset(void) __attribute__((noreturn));
static void esp_panic_dig_reset(void)
@ -444,6 +450,7 @@ static void esp_panic_dig_reset(void)
;
}
}
#endif
static void putEntry(uint32_t pc, uint32_t sp)
{

View file

@ -508,6 +508,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t
spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN;
} else if (rd_mode_reg & SPI_FREAD_DIO_M) {
spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S);
} else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) {
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
} else {

View file

@ -38,6 +38,7 @@
#include "esp_private/system_internal.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "hal/timer_ll.h"
static const char* TAG = "system_api";
@ -204,7 +205,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type)
ESP_LOGW(TAG, "incorrect mac type");
break;
}
return ESP_OK;
}
@ -281,12 +282,13 @@ void IRAM_ATTR esp_restart_noos(void)
esp_dport_access_int_abort();
// Disable TG0/TG1 watchdogs
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_config0.en = 0;
TIMERG0.wdt_wprotect=0;
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG1.wdt_config0.en = 0;
TIMERG1.wdt_wprotect=0;
timer_ll_wdt_set_protect(&TIMERG0, false);
timer_ll_wdt_set_enable(&TIMERG0, false);
timer_ll_wdt_set_protect(&TIMERG0, true);
timer_ll_wdt_set_protect(&TIMERG1, false);
timer_ll_wdt_set_enable(&TIMERG1, false);
timer_ll_wdt_set_protect(&TIMERG1, true);
// Flush any data left in UART FIFOs
uart_tx_wait_idle(0);
@ -307,10 +309,10 @@ void IRAM_ATTR esp_restart_noos(void)
WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30);
// Reset wifi/bluetooth/ethernet/sdio (bb/mac)
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG,
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG,
DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST |
DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST |
DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST |
DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST |
DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST);
DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0);
@ -366,35 +368,27 @@ const char* esp_get_idf_version(void)
return IDF_VER;
}
static void get_chip_info_esp32(esp_chip_info_t* out_info)
void esp_chip_info(esp_chip_info_t* out_info)
{
uint32_t reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
uint32_t efuse_rd3 = REG_READ(EFUSE_BLK0_RDATA3_REG);
memset(out_info, 0, sizeof(*out_info));
out_info->model = CHIP_ESP32;
if ((reg & EFUSE_RD_CHIP_VER_REV1_M) != 0) {
out_info->revision = 1;
}
if ((reg & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) {
out_info->revision = esp_efuse_get_chip_ver();
if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) {
out_info->cores = 2;
} else {
out_info->cores = 1;
}
out_info->features = CHIP_FEATURE_WIFI_BGN;
if ((reg & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) {
if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) {
out_info->features |= CHIP_FEATURE_BT | CHIP_FEATURE_BLE;
}
int package = (reg & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S;
int package = (efuse_rd3 & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S;
if (package == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 ||
package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 ||
package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
out_info->features |= CHIP_FEATURE_EMB_FLASH;
}
}
void esp_chip_info(esp_chip_info_t* out_info)
{
// Only ESP32 is supported now, in the future call one of the
// chip-specific functions based on sdkconfig choice
return get_chip_info_esp32(out_info);
}

View file

@ -34,6 +34,8 @@
#include "driver/periph_ctrl.h"
#include "esp_task_wdt.h"
#include "esp_private/system_internal.h"
#include "hal/timer_ll.h"
static const char *TAG = "task_wdt";
@ -107,9 +109,9 @@ static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset)
static void reset_hw_timer(void)
{
//All tasks have reset; time to reset the hardware timer.
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_feed=1;
TIMERG0.wdt_wprotect=0;
timer_ll_wdt_set_protect(&TIMERG0, false);
timer_ll_wdt_feed(&TIMERG0);
timer_ll_wdt_set_protect(&TIMERG0, true);
//Clear all has_reset flags in list
for (twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){
task->has_reset=false;
@ -137,11 +139,11 @@ static void task_wdt_isr(void *arg)
twdt_task_t *twdttask;
const char *cpu;
//Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset)
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_feed=1;
TIMERG0.wdt_wprotect=0;
timer_ll_wdt_set_protect(&TIMERG0, false);
timer_ll_wdt_feed(&TIMERG0);
timer_ll_wdt_set_protect(&TIMERG0, true);
//Acknowledge interrupt
TIMERG0.int_clr_timers.wdt=1;
timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_INTR_WDT);
//We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty
//bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case,
//something bad already happened and reporting this is considered more important
@ -198,32 +200,33 @@ esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic)
//Configure hardware timer
periph_module_enable(PERIPH_TIMG0_MODULE);
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection
TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS
TIMERG0.wdt_config0.level_int_en=1;
TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt
TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt
TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset
TIMERG0.wdt_config0.en=1;
TIMERG0.wdt_feed=1;
TIMERG0.wdt_wprotect=0; //Enable write protection
}else{ //twdt_config previously initialized
timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection
timer_ll_wdt_init(&TIMERG0);
timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US
//1st stage timeout: interrupt
timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_INT);
timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US);
//2nd stage timeout: reset system
timer_ll_wdt_set_timeout_behavior(&TIMERG0, 1, TIMER_WDT_RESET_SYSTEM);
timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US);
timer_ll_wdt_set_enable(&TIMERG0, true);
timer_ll_wdt_feed(&TIMERG0);
timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection
} else { //twdt_config previously initialized
//Reconfigure task wdt
twdt_config->panic = panic;
twdt_config->timeout = timeout;
//Reconfigure hardware timer
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection
TIMERG0.wdt_config0.en=0; //Disable timer
TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt
TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset
TIMERG0.wdt_config0.en=1; //Renable timer
TIMERG0.wdt_feed=1; //Reset timer
TIMERG0.wdt_wprotect=0; //Enable write protection
timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection
timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer
//Set timeout before interrupt
timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US);
//Set timeout before reset
timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US);
timer_ll_wdt_set_enable(&TIMERG0, true); //Renable timer
timer_ll_wdt_feed(&TIMERG0); //Reset timer
timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection
}
portEXIT_CRITICAL(&twdt_spinlock);
return ESP_OK;
@ -238,9 +241,9 @@ esp_err_t esp_task_wdt_deinit(void)
ASSERT_EXIT_CRIT_RETURN((twdt_config->list == NULL), ESP_ERR_INVALID_STATE);
//Disable hardware timer
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection
TIMERG0.wdt_config0.en=0; //Disable timer
TIMERG0.wdt_wprotect=0; //Enable write protection
timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection
timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer
timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection
ESP_ERROR_CHECK(esp_intr_free(twdt_config->intr_handle)); //Unregister interrupt
free(twdt_config); //Free twdt_config

View file

@ -55,24 +55,20 @@ static void timer_isr(void *arg)
int timer_idx = (int)arg;
count[timer_idx]++;
if (timer_idx==0) {
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[0].update=1;
TIMERG0.hw_timer[0].config.alarm_en = 1;
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0);
}
if (timer_idx==1) {
TIMERG0.int_clr_timers.t1 = 1;
TIMERG0.hw_timer[1].update=1;
TIMERG0.hw_timer[1].config.alarm_en = 1;
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1);
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_1);
}
if (timer_idx==2) {
TIMERG1.int_clr_timers.t0 = 1;
TIMERG1.hw_timer[0].update=1;
TIMERG1.hw_timer[0].config.alarm_en = 1;
timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_0);
timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_0);
}
if (timer_idx==3) {
TIMERG1.int_clr_timers.t1 = 1;
TIMERG1.hw_timer[1].update=1;
TIMERG1.hw_timer[1].config.alarm_en = 1;
timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_1);
timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_1);
}
// ets_printf("int %d\n", timer_idx);
}
@ -280,7 +276,7 @@ TEST_CASE("allocate 2 handlers for a same source and remove the later one","[esp
r=esp_intr_alloc(ETS_SPI2_INTR_SOURCE, ESP_INTR_FLAG_SHARED, int_handler2, &ctx, &handle2);
TEST_ESP_OK(r);
SPI2.slave.trans_inten = 1;
printf("trigger first time.\n");
SPI2.slave.trans_done = 1;

View file

@ -280,11 +280,12 @@ static void timer_group_test_first_stage(void)
//Start timer
timer_start(TIMER_GROUP_0, TIMER_0);
//Waiting for timer_group to generate an interrupt
while( !TIMERG0.int_raw.t0 && loop_cnt++ < 100) {
while( !(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0) &&
loop_cnt++ < 100) {
vTaskDelay(200);
}
//TIMERG0.int_raw.t0 == 1 means an interruption has occurred
TEST_ASSERT_EQUAL(1, TIMERG0.int_raw.t0);
TEST_ASSERT(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0);
esp_restart();
}

View file

@ -0,0 +1,113 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "sdkconfig.h"
#if defined(CONFIG_IDF_TARGET_ESP32)
#include "esp32/rom/crc.h"
#endif
/******************* Polynomials Used in the CRC APIs ****************************
* CRC-8 x8+x2+x1+1 0x07
* CRC16-CCITT x16+x12+x5+1 0x1021
* CRC32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x1+1 0x04c11db7
********************************************************************************/
/**
* @brief CRC32 value in little endian.
*
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
* @param buf: Data buffer that used to calculate the CRC value
* @param len: Length of the data buffer
* @return CRC32 value
*/
static inline uint32_t esp_crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len)
{
return crc32_le(crc, buf, len);
}
/**
* @brief CRC32 value in big endian.
*
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
* @param buf: Data buffer that used to calculate the CRC value
* @param len: Length of the data buffer
* @return CRC32 value
*/
static inline uint32_t esp_crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len)
{
return crc32_be(crc, buf, len);
}
/**
* @brief CRC16 value in little endian.
*
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
* @param buf: Data buffer that used to calculate the CRC value
* @param len: Length of the data buffer
* @return CRC16 value
*/
static inline uint16_t esp_crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len)
{
return crc16_le(crc, buf, len);
}
/**
* @brief CRC16 value in big endian.
*
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
* @param buf: Data buffer that used to calculate the CRC value
* @param len: Length of the data buffer
* @return CRC16 value
*/
static inline uint16_t esp_crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len)
{
return crc16_be(crc, buf, len);
}
/**
* @brief CRC8 value in little endian.
*
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
* @param buf: Data buffer that used to calculate the CRC value
* @param len: Length of the data buffer
* @return CRC8 value
*/
static inline uint8_t esp_crc8_le(uint8_t crc, uint8_t const *buf, uint32_t len)
{
return crc8_le(crc, buf, len);
}
/**
* @brief CRC8 value in big endian.
*
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
* @param buf: Data buffer that used to calculate the CRC value
* @param len: Length of the data buffer
* @return CRC8 value
*/
static inline uint8_t esp_crc8_be(uint8_t crc, uint8_t const *buf, uint32_t len)
{
return crc8_be(crc, buf, len);
}
#ifdef __cplusplus
}
#endif

View file

@ -21,7 +21,7 @@ extern "C" {
/** Major version number (X.x.x) */
#define ESP_IDF_VERSION_MAJOR 4
/** Minor version number (x.X.x) */
#define ESP_IDF_VERSION_MINOR 0
#define ESP_IDF_VERSION_MINOR 1
/** Patch version number (x.x.X) */
#define ESP_IDF_VERSION_PATCH 0

View file

@ -20,6 +20,8 @@ extern "C" {
#include "esp_system.h"
#define TG0_WDT_TICK_US 500
/**
* @brief Internal function to restart PRO and APP CPUs.
*

View file

@ -30,14 +30,14 @@ static const char* TAG = "test_event";
#define TEST_CONFIG_WAIT_MULTIPLIER 5
// The initial logging "initializing test" is to ensure mutex allocation is not counted against memory not being freed
// during teardown.
// The initial logging "initializing test" is to ensure mutex allocation is not counted against memory not being freed
// during teardown.
#define TEST_SETUP() \
ESP_LOGI(TAG, "initializing test"); \
size_t free_mem_before = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); \
test_setup(); \
s_test_core_id = xPortGetCoreID(); \
s_test_priority = uxTaskPriorityGet(NULL);
s_test_priority = uxTaskPriorityGet(NULL);
#define TEST_TEARDOWN() \
test_teardown(); \
@ -297,15 +297,11 @@ void IRAM_ATTR test_event_on_timer_alarm(void* para)
{
/* Retrieve the interrupt status and the counter value
from the timer that reported the interrupt */
TIMERG0.hw_timer[TIMER_0].update = 1;
uint64_t timer_counter_value =
((uint64_t) TIMERG0.hw_timer[TIMER_0].cnt_high) << 32
| TIMERG0.hw_timer[TIMER_0].cnt_low;
TIMERG0.int_clr_timers.t0 = 1;
timer_group_get_counter_value_in_isr(TIMER_GROUP_0, TIMER_0);
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
TIMERG0.hw_timer[TIMER_0].alarm_high = (uint32_t) (timer_counter_value >> 32);
TIMERG0.hw_timer[TIMER_0].alarm_low = (uint32_t) timer_counter_value;
timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, TIMER_0, timer_counter_value);
int data = (int) para;
// Posting events with data more than 4 bytes should fail.

View file

@ -205,12 +205,14 @@ static void handle_H_command(const unsigned char* cmd, int len)
} else if (requested_task_index > s_scratch.task_count) {
ret = "E00";
} else {
TaskHandle_t handle;
TaskHandle_t handle = NULL;
get_task_handle(requested_task_index, &handle);
/* FIXME: for the task currently running on the other CPU, extracting the registers from TCB
* isn't valid. Need to use some IPC mechanism to obtain the registers of the other CPU
*/
esp_gdbstub_tcb_to_regfile(handle, &s_scratch.regfile);
if (handle != NULL) {
esp_gdbstub_tcb_to_regfile(handle, &s_scratch.regfile);
}
}
esp_gdbstub_send_str_packet(ret);
} else {

View file

@ -378,6 +378,10 @@ static void httpd_sess_close(void *arg)
{
struct sock_db *sock_db = (struct sock_db *)arg;
if (sock_db) {
if (sock_db->lru_counter == 0) {
ESP_LOGD(TAG, "Skipping session close for %d as it seems to be a race condition", sock_db->fd);
return;
}
int fd = sock_db->fd;
struct httpd_data *hd = (struct httpd_data *) sock_db->handle;
httpd_sess_delete(hd, fd);

View file

@ -110,6 +110,19 @@ esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_
*/
esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle);
/**
* @brief Checks if complete data was received or not
*
* @note This API can be called just before esp_https_ota_finish() to validate if the complete image was indeed received.
*
* @param[in] https_ota_handle pointer to esp_https_ota_handle_t structure
*
* @return
* - false
* - true
*/
bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle);
/**
* @brief Clean-up HTTPS OTA Firmware upgrade and close HTTPS connection
*

View file

@ -85,17 +85,21 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client
static esp_err_t _http_connect(esp_http_client_handle_t http_client)
{
esp_err_t err = ESP_FAIL;
int status_code;
int status_code, header_ret;
do {
err = esp_http_client_open(http_client, 0);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
return err;
}
esp_http_client_fetch_headers(http_client);
header_ret = esp_http_client_fetch_headers(http_client);
if (header_ret < 0) {
return header_ret;
}
status_code = esp_http_client_get_status_code(http_client);
if (_http_handle_response_code(http_client, status_code) != ESP_OK) {
return ESP_FAIL;
err = _http_handle_response_code(http_client, status_code);
if (err != ESP_OK) {
return err;
}
} while (process_again(status_code));
return err;
@ -276,6 +280,12 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
return ESP_OK;
}
bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle)
{
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
return esp_http_client_is_complete_data_received(handle->http_client);
}
esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)
{
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
@ -361,4 +371,4 @@ esp_err_t esp_https_ota(const esp_http_client_config_t *config)
return ota_finish_err;
}
return ESP_OK;
}
}

View file

@ -356,8 +356,8 @@ static int iterations;
static void ringbuffer_isr(void *arg)
{
//Clear timer interrupt
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1;
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID());
//Test sending to buffer from ISR from ISR
if (buf_type < NO_OF_RB_TYPES) {

View file

@ -1,3 +1,3 @@
--encrypt ${ESPTOOLPY_FLASH_PROJECT_OPTIONS}
$<JOIN:$<TARGET_PROPERTY:flash_project_args_target,FLASH_PROJECT_ARGS>,
$<JOIN:${FLASH_PROJECT_ARGS},
>

View file

@ -64,27 +64,15 @@
static const USHORT usTimerIndex = CONFIG_FMB_TIMER_INDEX; // Modbus Timer index used by stack
static const USHORT usTimerGroupIndex = CONFIG_FMB_TIMER_GROUP; // Modbus Timer group index used by stack
static timg_dev_t *MB_TG[2] = {&TIMERG0, &TIMERG1};
/* ----------------------- Start implementation -----------------------------*/
static void IRAM_ATTR vTimerGroupIsr(void *param)
{
// Retrieve the interrupt status and the counter value
// from the timer that reported the interrupt
#if CONFIG_IDF_TARGET_ESP32
uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st_timers.val;
#elif CONFIG_IDF_TARGET_ESP32S2BETA
uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st.val;
#endif
if (intr_status & BIT(usTimerIndex)) {
#if CONFIG_IDF_TARGET_ESP32
MB_TG[usTimerGroupIndex]->int_clr_timers.val |= BIT(usTimerIndex);
#elif CONFIG_IDF_TARGET_ESP32S2BETA
MB_TG[usTimerGroupIndex]->int_clr.val |= BIT(usTimerIndex);
#endif
(void)pxMBPortCBTimerExpired(); // Timer callback function
MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].config.alarm_en = TIMER_ALARM_EN;
}
assert((int)param == usTimerIndex);
// Retrieve the counter value from the timer that reported the interrupt
timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex);
(void)pxMBPortCBTimerExpired(); // Timer callback function
// Enable alarm
timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex);
}
#endif
@ -121,7 +109,7 @@ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
"failure to set alarm failure, timer_set_alarm_value() returned (0x%x).",
(uint32_t)xErr);
// Register ISR for timer
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, NULL, ESP_INTR_FLAG_IRAM, NULL);
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_IRAM, NULL);
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"timer set value failure, timer_isr_register() returned (0x%x).",
(uint32_t)xErr);

View file

@ -62,34 +62,16 @@ static USHORT usT35TimeOut50us;
static const USHORT usTimerIndex = MB_TIMER_INDEX; // Initialize Modbus Timer index used by stack,
static const USHORT usTimerGroupIndex = MB_TIMER_GROUP; // Timer group index used by stack
static timg_dev_t *MB_TG[2] = { &TIMERG0, &TIMERG1 };
/* ----------------------- static functions ---------------------------------*/
static void IRAM_ATTR vTimerGroupIsr(void *param)
{
// Retrieve the interrupt status and the counter value
// from the timer that reported the interrupt
#if CONFIG_IDF_TARGET_ESP32
uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st_timers.val;
#elif CONFIG_IDF_TARGET_ESP32S2BETA
uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st.val;
#endif
if (intr_status & BIT(usTimerIndex)) {
#if CONFIG_IDF_TARGET_ESP32
MB_TG[usTimerGroupIndex]->int_clr_timers.val |= BIT(usTimerIndex);
#elif CONFIG_IDF_TARGET_ESP32S2BETA
MB_TG[usTimerGroupIndex]->int_clr.val |= BIT(usTimerIndex);
#endif
#if CONFIG_IDF_TARGET_ESP32
MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].update = 1;
#elif CONFIG_IDF_TARGET_ESP32S2BETA
MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].update.update = 1;
#endif
(void)pxMBMasterPortCBTimerExpired(); // Timer expired callback function
// Enable alarm
MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].config.alarm_en = TIMER_ALARM_EN;
}
assert((int)param == usTimerIndex);
// Retrieve the the counter value from the timer that reported the interrupt
timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex);
(void)pxMBMasterPortCBTimerExpired(); // Timer expired callback function
// Enable alarm
timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex);
}
/* ----------------------- Start implementation -----------------------------*/
@ -128,7 +110,7 @@ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
(uint32_t)xErr);
// Register ISR for timer
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex,
vTimerGroupIsr, NULL, ESP_INTR_FLAG_IRAM, NULL);
vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_IRAM, NULL);
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"timer set value failure, timer_isr_register() returned (0x%x).",
(uint32_t)xErr);

View file

@ -136,11 +136,15 @@ typedef unsigned portBASE_TYPE UBaseType_t;
/* "mux" data structure (spinlock) */
typedef struct {
/* owner field values:
* 0 - Uninitialized (invalid)
* 0 - Uninitialized (invalid)
* portMUX_FREE_VAL - Mux is free, can be locked by either CPU
* CORE_ID_PRO / CORE_ID_APP - Mux is locked to the particular core
* CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core
*
* Any value other than portMUX_FREE_VAL, CORE_ID_PRO, CORE_ID_APP indicates corruption
* Note that for performance reasons we use the full Xtensa CORE ID values
* (CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP) and not the 0,1 values which are used in most
* other FreeRTOS code.
*
* Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption
*/
uint32_t owner;
/* count field:

View file

@ -185,7 +185,7 @@ typedef struct xTASK_STATUS
StackType_t *pxStackBase; /*!< Points to the lowest address of the task's stack area. */
uint32_t usStackHighWaterMark; /*!< The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */
#if configTASKLIST_INCLUDE_COREID
BaseType_t xCoreID; /*!< Core this task is pinned to. This field is present if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set. */
BaseType_t xCoreID; /*!< Core this task is pinned to (0, 1, or -1 for tskNO_AFFINITY). This field is present if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set. */
#endif
} TaskStatus_t;
@ -324,7 +324,7 @@ is used in assert() statements. */
*
* @param xCoreID If the value is tskNO_AFFINITY, the created task is not
* pinned to any CPU, and the scheduler can run it on any core available.
* Other values indicate the index number of the CPU which the task should
* Values 0 or 1 indicate the index number of the CPU which the task should
* be pinned to. Specifying values larger than (portNUM_PROCESSORS - 1) will
* cause the function to fail.
*
@ -476,7 +476,7 @@ is used in assert() statements. */
*
* @param xCoreID If the value is tskNO_AFFINITY, the created task is not
* pinned to any CPU, and the scheduler can run it on any core available.
* Other values indicate the index number of the CPU which the task should
* Values 0 or 1 indicate the index number of the CPU which the task should
* be pinned to. Specifying values larger than (portNUM_PROCESSORS - 1) will
* cause the function to fail.
*

View file

@ -325,8 +325,17 @@ STRUCT_END(XtSolFrame)
.endm
#endif
#define CORE_ID_PRO 0xCDCD
#define CORE_ID_APP 0xABAB
/* Note: These are different to xCoreID used in ESP-IDF FreeRTOS, most places use
0 and 1 which are determined by checking bit 13 (see previous comment)
*/
#define CORE_ID_REGVAL_PRO 0xCDCD
#define CORE_ID_REGVAL_APP 0xABAB
/* Included for compatibility, recommend using CORE_ID_REGVAL_PRO instead */
#define CORE_ID_PRO CORE_ID_REGVAL_PRO
/* Included for compatibility, recommend using CORE_ID_REGVAL_APP instead */
#define CORE_ID_APP CORE_ID_REGVAL_APP
/*
-------------------------------------------------------------------------------

View file

@ -49,7 +49,7 @@
#include "soc/soc_memory_layout.h"
/* XOR one core ID with this value to get the other core ID */
#define CORE_ID_XOR_SWAP (CORE_ID_PRO ^ CORE_ID_APP)
#define CORE_ID_REGVAL_XOR_SWAP (CORE_ID_REGVAL_PRO ^ CORE_ID_REGVAL_APP)

View file

@ -61,7 +61,7 @@ PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) {
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
uint32_t owner = mux->owner;
if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP) {
ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line);
mux->owner=portMUX_FREE_VAL;
}
@ -70,13 +70,13 @@ PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) {
/* Spin until we own the core */
RSR(PRID, coreID);
/* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
/* Note: coreID is the full 32 bit core ID (CORE_ID_REGVAL_PRO/CORE_ID_REGVAL_APP),
not the 0/1 value returned by xPortGetCoreID()
*/
otherCoreID = CORE_ID_XOR_SWAP ^ coreID;
otherCoreID = CORE_ID_REGVAL_XOR_SWAP ^ coreID;
do {
/* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO,
CORE_ID_APP:
/* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_REGVAL_PRO,
CORE_ID_REGVAL_APP:
- If portMUX_FREE_VAL, we want to atomically set to 'coreID'.
- If "our" coreID, we can drop through immediately.
@ -138,7 +138,7 @@ static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux) {
mux->lastLockedFn=fnName;
mux->lastLockedLine=line;
uint32_t owner = mux->owner;
if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP) {
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner);
}
#endif

View file

@ -144,8 +144,8 @@ static bool test_clear_bits;
static void IRAM_ATTR event_group_isr(void *arg)
{
portBASE_TYPE task_woken = pdFALSE;
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1;
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID());
if(test_set_bits){
xEventGroupSetBitsFromISR(eg, BITS, &task_woken);

View file

@ -103,16 +103,10 @@ static void receiver_task (void* arg){
static void IRAM_ATTR sender_ISR (void *arg)
{
int curcore = xPortGetCoreID();
if(curcore == 0){ //Clear timer interrupt
//Clear intr and pause via direct reg access as IRAM ISR cannot access timer APIs
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[0].config.enable = 0;
}else{
TIMERG0.int_clr_timers.t1 = 1;
TIMERG0.hw_timer[1].config.enable = 0;
}
timer_group_intr_clr_in_isr(TIMER_GROUP_0, curcore);
timer_group_set_counter_enable_in_isr(TIMER_GROUP_0, curcore, TIMER_PAUSE);
//Re-enable alarm
TIMERG0.hw_timer[curcore].config.alarm_en = 1;
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, curcore);
if(isr_give){ //Test vTaskNotifyGiveFromISR() on same core
notifs_sent++;

View file

@ -26,9 +26,8 @@ static volatile unsigned isr_count;
mutex semaphore to wake up another counter task */
static void timer_group0_isr(void *vp_arg)
{
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[TIMER_0].update = 1;
TIMERG0.hw_timer[TIMER_0].config.alarm_en = 1;
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0);
portBASE_TYPE higher_awoken = pdFALSE;
isr_count++;
xSemaphoreGiveFromISR(isr_semaphore, &higher_awoken);

View file

@ -123,7 +123,7 @@ volatile bool timer_isr_fired;
void IRAM_ATTR timer_group0_isr(void *vp_arg)
{
// Clear interrupt
TIMERG0.int_clr_timers.val = TIMERG0.int_st_timers.val;
timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_0|TIMER_1);
timer_isr_fired = true;
TaskHandle_t handle = vp_arg;

View file

@ -26,7 +26,7 @@
#define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA1_32KB 5000
#define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA512_32KB 4500
// AES-CBC hardware throughput (accounts for worst-case performance with PSRAM workaround)
#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.5
#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.2
// floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround)
#define IDF_PERFORMANCE_MAX_ESP32_CYCLES_PER_DIV 70
#define IDF_PERFORMANCE_MAX_ESP32_CYCLES_PER_SQRT 140

View file

@ -39,7 +39,7 @@ TEST_CASE("box tests", "[libsodium]")
extern int ed25519_convert_xmain(void);
TEST_CASE("ed25519_convert tests", "[libsodium]")
TEST_CASE("ed25519_convert tests", "[libsodium][timeout=60]")
{
printf("Running ed25519_convert\n");
TEST_ASSERT_EQUAL(0, ed25519_convert_xmain() );

@ -1 +1 @@
Subproject commit 61d840ff4778f4946c8743f7e412345abcd537f1
Subproject commit 663b2fdb41177c82f2aa5939e41aef54427d15cd

View file

@ -23,18 +23,19 @@ set_property(TARGET mbedtls PROPERTY SOURCES ${src_tls})
set(mbedtls_targets mbedtls mbedcrypto mbedx509)
# Add port files to mbedtls targets
target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/esp_hardware.c"
"${COMPONENT_PATH}/port/esp_sha.c"
target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/mbedtls_debug.c"
"${COMPONENT_DIR}/port/net_sockets.c")
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_hardware.c"
"${COMPONENT_DIR}/port/esp_mem.c"
"${COMPONENT_DIR}/port/esp_sha.c"
"${COMPONENT_DIR}/port/esp_sha1.c"
"${COMPONENT_DIR}/port/esp_sha256.c"
"${COMPONENT_DIR}/port/esp_sha512.c"
"${COMPONENT_DIR}/port/esp_timing.c"
"${COMPONENT_DIR}/port/mbedtls_debug.c"
"${COMPONENT_DIR}/port/net_sockets.c"
"${COMPONENT_DIR}/port/${idf_target}/esp_bignum.c"
"${COMPONENT_DIR}/port/${idf_target}/aes.c"
"${COMPONENT_DIR}/port/${idf_target}/sha.c"
"${COMPONENT_DIR}/port/${idf_target}/esp_bignum.c")
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_mem.c")
"${COMPONENT_DIR}/port/${idf_target}/sha.c")
foreach(target ${mbedtls_targets})
target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h")

View file

@ -49,6 +49,11 @@
*/
static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED;
static inline bool valid_key_length(const esp_aes_context *ctx)
{
return ctx->key_bytes == 128/8 || ctx->key_bytes == 192/8 || ctx->key_bytes == 256/8;
}
void esp_aes_acquire_hardware( void )
{
portENTER_CRITICAL(&aes_spinlock);
@ -93,6 +98,7 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key,
}
ctx->key_bytes = keybits / 8;
memcpy(ctx->key, key, ctx->key_bytes);
ctx->key_in_hardware = 0;
return 0;
}
@ -102,28 +108,47 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key,
*
* Call only while holding esp_aes_acquire_hardware().
*/
static inline void esp_aes_setkey_hardware( esp_aes_context *ctx, int mode)
static void esp_aes_setkey_hardware(esp_aes_context *ctx, int mode)
{
const uint32_t MODE_DECRYPT_BIT = 4;
unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT;
ctx->key_in_hardware = 0;
for (int i = 0; i < ctx->key_bytes/4; ++i) {
DPORT_REG_WRITE(AES_KEY_BASE + i * 4, *(((uint32_t *)ctx->key) + i));
ctx->key_in_hardware += 4;
}
DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2));
/* Fault injection check: all words of key data should have been written to hardware */
if (ctx->key_in_hardware < 16
|| ctx->key_in_hardware != ctx->key_bytes) {
abort();
}
}
/* Run a single 16 byte block of AES, using the hardware engine.
*
* Call only while holding esp_aes_acquire_hardware().
*/
static void esp_aes_block(const void *input, void *output)
static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output)
{
const uint32_t *input_words = (const uint32_t *)input;
uint32_t i0, i1, i2, i3;
uint32_t *output_words = (uint32_t *)output;
/* If no key is written to hardware yet, either the user hasn't called
mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec - meaning we also don't
know which mode to use - or a fault skipped the
key write to hardware. Treat this as a fatal error and zero the output block.
*/
if (ctx->key_in_hardware != ctx->key_bytes) {
bzero(output, 16);
return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
}
/* Storing i0,i1,i2,i3 in registers not an array
helps a lot with optimisations at -Os level */
i0 = input_words[0];
@ -152,11 +177,14 @@ static void esp_aes_block(const void *input, void *output)
Bypassing this check requires at least one additional fault.
*/
if(i0 == output_words[0] && i1 == output_words[1] && i2 == output_words[2] && i3 == output_words[3]) {
// calling two zeroing functions to narrow the
// window for a double-fault here
// calling zeroing functions to narrow the
// window for a double-fault of the abort step, here
memset(output, 0, 16);
mbedtls_platform_zeroize(output, 16);
abort();
}
return 0;
}
/*
@ -166,11 +194,18 @@ int esp_internal_aes_encrypt( esp_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] )
{
int r;
if (!valid_key_length(ctx)) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
esp_aes_acquire_hardware();
ctx->key_in_hardware = 0;
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
esp_aes_block(input, output);
r = esp_aes_block(ctx, input, output);
esp_aes_release_hardware();
return 0;
return r;
}
void esp_aes_encrypt( esp_aes_context *ctx,
@ -188,11 +223,18 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] )
{
int r;
if (!valid_key_length(ctx)) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
esp_aes_acquire_hardware();
ctx->key_in_hardware = 0;
esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT);
esp_aes_block(input, output);
r = esp_aes_block(ctx, input, output);
esp_aes_release_hardware();
return 0;
return r;
}
void esp_aes_decrypt( esp_aes_context *ctx,
@ -202,7 +244,6 @@ void esp_aes_decrypt( esp_aes_context *ctx,
esp_internal_aes_decrypt(ctx, input, output);
}
/*
* AES-ECB block encryption/decryption
*/
@ -211,12 +252,19 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] )
{
int r;
if (!valid_key_length(ctx)) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
esp_aes_acquire_hardware();
ctx->key_in_hardware = 0;
esp_aes_setkey_hardware(ctx, mode);
esp_aes_block(input, output);
r = esp_aes_block(ctx, input, output);
esp_aes_release_hardware();
return 0;
return r;
}
@ -240,14 +288,19 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx,
return ( ERR_ESP_AES_INVALID_INPUT_LENGTH );
}
if (!valid_key_length(ctx)) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
esp_aes_acquire_hardware();
ctx->key_in_hardware = 0;
esp_aes_setkey_hardware(ctx, mode);
if ( mode == ESP_AES_DECRYPT ) {
while ( length > 0 ) {
memcpy(temp, input_words, 16);
esp_aes_block(input_words, output_words);
esp_aes_block(ctx, input_words, output_words);
for ( i = 0; i < 4; i++ ) {
output_words[i] = output_words[i] ^ iv_words[i];
@ -266,7 +319,7 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx,
output_words[i] = input_words[i] ^ iv_words[i];
}
esp_aes_block(output_words, output_words);
esp_aes_block(ctx, output_words, output_words);
memcpy( iv_words, output_words, 16 );
input_words += 4;
@ -294,14 +347,19 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx,
int c;
size_t n = *iv_off;
if (!valid_key_length(ctx)) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
esp_aes_acquire_hardware();
ctx->key_in_hardware = 0;
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
if ( mode == ESP_AES_DECRYPT ) {
while ( length-- ) {
if ( n == 0 ) {
esp_aes_block(iv, iv );
esp_aes_block(ctx, iv, iv);
}
c = *input++;
@ -313,7 +371,7 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx,
} else {
while ( length-- ) {
if ( n == 0 ) {
esp_aes_block(iv, iv );
esp_aes_block(ctx, iv, iv);
}
iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
@ -342,13 +400,18 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx,
unsigned char c;
unsigned char ov[17];
if (!valid_key_length(ctx)) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
esp_aes_acquire_hardware();
ctx->key_in_hardware = 0;
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
while ( length-- ) {
memcpy( ov, iv, 16 );
esp_aes_block(iv, iv);
esp_aes_block(ctx, iv, iv);
if ( mode == ESP_AES_DECRYPT ) {
ov[16] = *input;
@ -382,13 +445,18 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx,
int c, i;
size_t n = *nc_off;
if (!valid_key_length(ctx)) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
esp_aes_acquire_hardware();
ctx->key_in_hardware = 0;
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
while ( length-- ) {
if ( n == 0 ) {
esp_aes_block(nonce_counter, stream_block);
esp_aes_block(ctx, nonce_counter, stream_block);
for ( i = 16; i > 0; i-- )
if ( ++nonce_counter[i - 1] != 0 ) {
@ -432,13 +500,17 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx,
return( MBEDTLS_ERR_AES_BAD_INPUT_DATA );
}
if (!valid_key_length(ctx)) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
esp_aes_acquire_hardware();
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
while( length-- ) {
if( n == 0 ) {
esp_aes_block( iv, iv );
esp_aes_block(ctx, iv, iv);
}
*output++ = *input++ ^ iv[n];

View file

@ -228,6 +228,7 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
{
uint32_t *digest_state_words = NULL;
uint32_t *reg_addr_buf = NULL;
uint32_t word_len = sha_length(sha_type)/4;
#ifndef NDEBUG
{
SemaphoreHandle_t *engine_state = sha_get_engine_state(sha_type);
@ -250,15 +251,25 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
if(sha_type == SHA2_384 || sha_type == SHA2_512) {
/* for these ciphers using 64-bit states, swap each pair of words */
DPORT_INTERRUPT_DISABLE(); // Disable interrupt only on current CPU.
for(int i = 0; i < sha_length(sha_type)/4; i += 2) {
for(int i = 0; i < word_len; i += 2) {
digest_state_words[i+1] = DPORT_SEQUENCE_REG_READ((uint32_t)&reg_addr_buf[i]);
digest_state_words[i] = DPORT_SEQUENCE_REG_READ((uint32_t)&reg_addr_buf[i+1]);
}
DPORT_INTERRUPT_RESTORE(); // restore the previous interrupt level
} else {
esp_dport_access_read_buffer(digest_state_words, (uint32_t)&reg_addr_buf[0], sha_length(sha_type)/4);
esp_dport_access_read_buffer(digest_state_words, (uint32_t)&reg_addr_buf[0], word_len);
}
esp_sha_unlock_memory_block();
/* Fault injection check: verify SHA engine actually ran,
state is not all zeroes.
*/
for (int i = 0; i < word_len; i++) {
if (digest_state_words[i] != 0) {
return;
}
}
abort(); // SHA peripheral returned all zero state, probably due to fault injection
}
void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block)

View file

@ -41,17 +41,13 @@ extern "C" {
/**
* \brief AES context structure
*
* \note buf is able to hold 32 extra bytes, which can be used:
* - for alignment purposes if VIA padlock is used, and/or
* - to simplify key expansion in the 256-bit case by
* generating an extra round key
*/
typedef struct {
uint8_t key_bytes;
volatile uint8_t key_in_hardware; /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */
uint8_t key[32];
} esp_aes_context;
/**
* \brief The AES XTS context-type definition.
*/

View file

@ -59,16 +59,6 @@ static int net_prepare( void )
return ( 0 );
}
static int mbedtls_net_errno(int fd)
{
int sock_errno = 0;
u32_t optlen = sizeof(sock_errno);
getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
return sock_errno;
}
/*
* Initialize a context
*/
@ -204,22 +194,19 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char
*
* Note: on a blocking socket this function always returns 0!
*/
static int net_would_block( const mbedtls_net_context *ctx, int *errout )
static int net_would_block( const mbedtls_net_context *ctx )
{
int error = mbedtls_net_errno(ctx->fd);
if ( errout ) {
*errout = error;
}
int error = errno;
/*
* Never return 'WOULD BLOCK' on a non-blocking socket
*/
if ( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK ) {
errno = error;
return ( 0 );
}
switch ( error ) {
switch ( errno = error ) {
#if defined EAGAIN
case EAGAIN:
#endif
@ -267,7 +254,7 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
}
if ( ret < 0 ) {
if ( net_would_block( bind_ctx, NULL ) != 0 ) {
if ( net_would_block( bind_ctx ) != 0 ) {
return ( MBEDTLS_ERR_SSL_WANT_READ );
}
@ -347,7 +334,6 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
{
int ret;
int fd = ((mbedtls_net_context *) ctx)->fd;
int error = 0;
if ( fd < 0 ) {
return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
@ -356,15 +342,15 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
ret = (int) read( fd, buf, len );
if ( ret < 0 ) {
if ( net_would_block( ctx, &error ) != 0 ) {
if ( net_would_block( ctx ) != 0 ) {
return ( MBEDTLS_ERR_SSL_WANT_READ );
}
if ( error == EPIPE || error == ECONNRESET ) {
if ( errno == EPIPE || errno == ECONNRESET ) {
return ( MBEDTLS_ERR_NET_CONN_RESET );
}
if ( error == EINTR ) {
if ( errno == EINTR ) {
return ( MBEDTLS_ERR_SSL_WANT_READ );
}
@ -422,8 +408,6 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
int ret;
int fd = ((mbedtls_net_context *) ctx)->fd;
int error = 0;
if ( fd < 0 ) {
return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
}
@ -431,15 +415,15 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
ret = (int) write( fd, buf, len );
if ( ret < 0 ) {
if ( net_would_block( ctx, &error ) != 0 ) {
if ( net_would_block( ctx ) != 0 ) {
return ( MBEDTLS_ERR_SSL_WANT_WRITE );
}
if ( error == EPIPE || error == ECONNRESET ) {
if ( errno == EPIPE || errno == ECONNRESET ) {
return ( MBEDTLS_ERR_NET_CONN_RESET );
}
if ( error == EINTR ) {
if ( errno == EINTR ) {
return ( MBEDTLS_ERR_SSL_WANT_WRITE );
}

View file

@ -1676,9 +1676,7 @@ static void _mdns_send_final_bye(bool include_ip)
size_t srv_count = 0;
mdns_srv_item_t * a = _mdns_server->services;
while (a) {
if (!a->service->instance) {
srv_count++;
}
srv_count++;
a = a->next;
}
if (!srv_count) {
@ -1688,9 +1686,7 @@ static void _mdns_send_final_bye(bool include_ip)
size_t i = 0;
a = _mdns_server->services;
while (a) {
if (!a->service->instance) {
services[i++] = a;
}
services[i++] = a;
a = a->next;
}
_mdns_send_bye(services, srv_count, include_ip);
@ -1699,7 +1695,7 @@ static void _mdns_send_final_bye(bool include_ip)
/**
* @brief Stop the responder on all services without instance
*/
static void _mdns_send_bye_all_pcbs_no_instance(void)
static void _mdns_send_bye_all_pcbs_no_instance(bool include_ip)
{
size_t srv_count = 0;
mdns_srv_item_t * a = _mdns_server->services;
@ -1721,7 +1717,7 @@ static void _mdns_send_bye_all_pcbs_no_instance(void)
}
a = a->next;
}
_mdns_send_bye(services, srv_count, false);
_mdns_send_bye(services, srv_count, include_ip);
}
/**
@ -3734,14 +3730,14 @@ static void _mdns_execute_action(mdns_action_t * action)
action->data.sys_event.event_id, action->data.sys_event.interface);
break;
case ACTION_HOSTNAME_SET:
_mdns_send_final_bye(true);
_mdns_send_bye_all_pcbs_no_instance(true);
free((char*)_mdns_server->hostname);
_mdns_server->hostname = action->data.hostname;
_mdns_restart_all_pcbs();
break;
case ACTION_INSTANCE_SET:
_mdns_send_bye_all_pcbs_no_instance();
_mdns_send_bye_all_pcbs_no_instance(false);
free((char*)_mdns_server->instance);
_mdns_server->instance = action->data.instance;
_mdns_restart_all_pcbs_no_instance();

@ -1 +1 @@
Subproject commit dc37d3a065f345a7358b8ff4553db0baceeb8ad6
Subproject commit 117eef2dad54e0f9e25b3005fcfc18e7695ff29e

View file

@ -287,7 +287,7 @@ gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, struct
char *temp_outbuf = strdup(ctxt->dsc->arg);
if (temp_outbuf == NULL) {
ESP_LOGE(TAG, "Error duplicating user description of characteristic");
return ESP_ERR_NO_MEM;
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
ssize_t temp_outlen = strlen(temp_outbuf);
@ -308,6 +308,9 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
ssize_t temp_outlen = 0;
uint8_t *temp_outbuf = NULL;
uint8_t *uuid = NULL;
uint8_t *data_buf = NULL;
uint16_t data_len = 0;
uint16_t data_buf_len = 0;
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
@ -328,7 +331,7 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
uuid = (uint8_t *) calloc(BLE_UUID128_VAL_LENGTH, sizeof(uint8_t));
if (!uuid) {
ESP_LOGE(TAG, "Error allocating memory for 128 bit UUID");
return ESP_ERR_NO_MEM;
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
rc = ble_uuid_flat(ctxt->chr->uuid, uuid);
@ -338,16 +341,32 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
return rc;
}
ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, om_len = %d",
ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, ctxt->om->om_len);
/* Save the length of entire data */
data_len = OS_MBUF_PKTLEN(ctxt->om);
ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, data_len = %d",
ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, data_len);
data_buf = calloc(1, data_len);
if (data_buf == NULL) {
ESP_LOGE(TAG, "Error allocating memory for characteristic value");
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
rc = ble_hs_mbuf_to_flat(ctxt->om, data_buf, data_len, &data_buf_len);
if (rc != 0) {
ESP_LOGE(TAG, "Error getting data from memory buffers");
return BLE_ATT_ERR_UNLIKELY;
}
ret = protocomm_req_handle(protoble_internal->pc_ble,
uuid128_to_handler(uuid),
conn_handle,
ctxt->om->om_data,
ctxt->om->om_len,
data_buf,
data_buf_len,
&temp_outbuf, &temp_outlen);
/* Release the 16 bytes allocated for uuid*/
free(uuid);
free(data_buf);
if (ret == ESP_OK) {
/* Save data address and length outbuf and outlen internally */

View file

@ -28,5 +28,5 @@ endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
priv_requires ${soc_name}
PRIV_REQUIRES ${soc_name}
LDFRAGMENTS linker.lf)

View file

@ -0,0 +1,285 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The LL layer for Timer Group register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "hal/timer_types.h"
#include "soc/timer_periph.h"
//Helper macro to get corresponding interrupt of a timer
#define TIMER_LL_GET_INTR(TIMER_IDX) ((TIMER_IDX)==TIMER_0? TIMER_INTR_T0: TIMER_INTR_T1)
#define TIMER_LL_GET_HW(TIMER_GROUP) ((TIMER_GROUP)==0? &TIMERG0: &TIMERG1)
_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
/**
* @brief Enable timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param intr_mask Interrupt enable mask
*
* @return None
*/
static inline void timer_ll_intr_enable(timg_dev_t *hw, timer_intr_t intr_mask)
{
hw->int_ena.val |= intr_mask;
}
/**
* @brief Disable timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param intr_mask Interrupt disable mask
*
* @return None
*/
static inline void timer_ll_intr_disable(timg_dev_t *hw, timer_intr_t intr_mask)
{
hw->int_ena.val &= (~intr_mask);
}
/**
* @brief Get timer interrupt status.
*
* @param hw Beginning address of the peripheral registers.
*
* @return Masked interrupt status
*/
static inline timer_intr_t timer_ll_intr_status_get(timg_dev_t *hw)
{
return hw->int_raw.val;
}
/**
* @brief Clear timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param intr_mask Interrupt mask to clear
*
* @return None
*/
static inline void timer_ll_intr_status_clear(timg_dev_t *hw, timer_intr_t intr_mask)
{
hw->int_clr_timers.val = intr_mask;
}
/**
* @brief Get counter vaule from time-base counter
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param timer_val Pointer to accept the counter value
*
* @return None
*/
static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val)
{
hw->hw_timer[timer_num].update = 1;
*timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
}
/**
* @brief Set counter status, enable or disable counter.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param counter_en Counter enable status
*
* @return None
*/
static inline void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, timer_start_t counter_en)
{
hw->hw_timer[timer_num].config.enable = counter_en;
}
/**
* @brief Get auto reload mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param reload Pointer to accept the auto reload mode
*
* @return None
*/
static inline bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.autoreload;
}
/**
* @brief Set the counter value to trigger the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_value Counter value to trigger the alarm
*
* @return None
*/
static inline void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
{
hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
}
/**
* @brief Get the counter value to trigger the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_value Pointer to accept the counter value to trigger the alarm
*
* @return None
*/
static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value)
{
*alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarm_high << 32) | (hw->hw_timer[timer_num].alarm_low);
}
/**
* @brief Set the alarm status, enable or disable the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_en true to enable, false to disable
*
* @return None
*/
static inline void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
{
hw->hw_timer[timer_num].config.alarm_en = alarm_en;
}
/**
* @brief Get the alarm status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_en Pointer to accept the alarm status
*
* @return None
*/
static inline void timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool *alarm_en)
{
*alarm_en = hw->hw_timer[timer_num].config.alarm_en;
}
/* WDT operations */
/**
* Unlock/lock the WDT register in case of mis-operations.
*
* @param hw Beginning address of the peripheral registers.
* @param protect true to lock, false to unlock before operations.
*/
FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect)
{
hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE);
}
/**
* Initialize WDT.
*
* @param hw Beginning address of the peripheral registers.
*
* @note Call ``timer_ll_wdt_set_protect first``
*/
FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw)
{
hw->wdt_config0.sys_reset_length=7; //3.2uS
hw->wdt_config0.cpu_reset_length=7; //3.2uS
//currently only level interrupt is supported
hw->wdt_config0.level_int_en = 1;
hw->wdt_config0.edge_int_en = 0;
}
FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us)
{
hw->wdt_config1.clk_prescale=80*tick_time_us;
}
FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw)
{
hw->wdt_feed = 1;
}
FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick)
{
switch (stage) {
case 0:
hw->wdt_config2=timeout_tick;
break;
case 1:
hw->wdt_config3=timeout_tick;
break;
case 2:
hw->wdt_config4=timeout_tick;
break;
case 3:
hw->wdt_config5=timeout_tick;
break;
default:
abort();
}
}
_Static_assert(TIMER_WDT_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
_Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
_Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
_Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior)
{
switch (stage) {
case 0:
hw->wdt_config0.stg0 = behavior;
break;
case 1:
hw->wdt_config0.stg1 = behavior;
break;
case 2:
hw->wdt_config0.stg2 = behavior;
break;
case 3:
hw->wdt_config0.stg3 = behavior;
break;
default:
abort();
}
}
FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable)
{
hw->wdt_config0.en = enable;
}
FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable)
{
hw->wdt_config0.flashboot_mod_en = enable;
}
#ifdef __cplusplus
}
#endif

View file

@ -48,7 +48,7 @@ extern "C" {
// After completing read operations, use DPORT_STALL_OTHER_CPU_END().
// This method uses stall other CPU while reading DPORT registers.
// Useful for compatibility, as well as for large consecutive readings.
// This method is slower, but must be used if ROM functions or
// This method is slower, but must be used if ROM functions or
// other code is called which accesses DPORT without any other workaround.
// *) The pre-readable APB register before reading the DPORT register
// helps synchronize the operation of the two CPUs,
@ -73,7 +73,7 @@ extern "C" {
*/
static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
return esp_dport_access_reg_read(reg);
@ -106,7 +106,7 @@ static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg)
*/
static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
return esp_dport_access_sequence_reg_read(reg);
@ -166,7 +166,7 @@ static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg)
*/
static inline uint32_t IRAM_ATTR DPORT_READ_PERI_REG(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
return esp_dport_access_reg_read(reg);

View file

@ -95,7 +95,7 @@
#define IS_DPORT_REG(_r) (((_r) >= DR_REG_DPORT_BASE) && (_r) <= DR_REG_DPORT_END)
#if !defined( BOOTLOADER_BUILD ) && !defined( CONFIG_FREERTOS_UNICORE ) && defined( ESP_PLATFORM )
#if !defined( BOOTLOADER_BUILD ) && defined( CONFIG_ESP32_DPORT_WORKAROUND ) && defined( ESP_PLATFORM )
#define ASSERT_IF_DPORT_REG(_r, OP) TRY_STATIC_ASSERT(!IS_DPORT_REG(_r), (Cannot use OP for DPORT registers use DPORT_##OP));
#else
#define ASSERT_IF_DPORT_REG(_r, OP)

View file

@ -88,14 +88,15 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver);
esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *driver, spi_flash_trans_t *trans);
/**
* Erase whole flash chip.
* Erase whole flash chip by using the erase chip (C7h) command.
*
* @param driver The driver context.
*/
void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver);
/**
* Erase a specific sector by its start address.
* Erase a specific sector by its start address through the sector erase (20h)
* command.
*
* @param driver The driver context.
* @param start_address Start address of the sector to erase.
@ -103,7 +104,8 @@ void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver);
void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address);
/**
* Erase a specific block by its start address.
* Erase a specific 64KB block by its start address through the 64KB block
* erase (D8h) command.
*
* @param driver The driver context.
* @param start_address Start address of the block to erase.
@ -111,7 +113,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_
void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address);
/**
* Program a page of the flash.
* Program a page of the flash using the page program (02h) command.
*
* @param driver The driver context.
* @param address Address of the page to program
@ -121,7 +123,8 @@ void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_a
void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length);
/**
* Read from the flash. The read command should be set by ``spi_flash_hal_configure_host_read_mode`` before.
* Read from the flash. Call ``spi_flash_hal_configure_host_read_mode`` to
* configure the read command before calling this function.
*
* @param driver The driver context.
* @param buffer Buffer to store the read data
@ -133,7 +136,7 @@ void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buf
esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len);
/**
* Enable or disable the write protection of the flash chip.
* @brief Send the write enable (06h) or write disable (04h) command to the flash chip.
*
* @param driver The driver context.
* @param wp true to enable the write protection, otherwise false.

View file

@ -0,0 +1,67 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <esp_bit_defs.h>
/**
* @brief Select a hardware timer from timer groups
*/
typedef enum {
TIMER_0 = 0, /*!<Select timer0 of GROUPx*/
TIMER_1 = 1, /*!<Select timer1 of GROUPx*/
TIMER_MAX,
} timer_idx_t;
/**
* @brief Decides whether timer is on or paused
*/
typedef enum {
TIMER_PAUSE = 0, /*!<Pause timer counter*/
TIMER_START = 1, /*!<Start timer counter*/
} timer_start_t;
/**
* @brief Interrupt types of the timer.
*/
//this is compatible with the value of esp32.
typedef enum {
TIMER_INTR_T0 = BIT(0), /*!< interrupt of timer 0 */
TIMER_INTR_T1 = BIT(1), /*!< interrupt of timer 1 */
TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */
} timer_intr_t;
FLAG_ATTR(timer_intr_t)
/**
* @brief Behavior of the watchdog if a stage times out.
*/
//this is compatible with the value of esp32.
typedef enum {
TIMER_WDT_OFF = 0, ///< The stage is turned off
TIMER_WDT_INT = 1, ///< The stage will trigger an interrupt
TIMER_WDT_RESET_CPU = 2, ///< The stage will reset the CPU
TIMER_WDT_RESET_SYSTEM = 3, ///< The stage will reset the whole system
} timer_wdt_behavior_t;
#ifdef __cplusplus
}
#endif

View file

@ -265,23 +265,13 @@ esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip)
{
VERIFY_OP(erase_chip);
CHECK_WRITE_ADDRESS(chip, 0, chip->size);
bool write_protect = false;
esp_err_t err = spiflash_start(chip);
if (err != ESP_OK) {
return err;
}
err = esp_flash_get_chip_write_protect(chip, &write_protect);
if (err == ESP_OK && write_protect) {
err = ESP_ERR_FLASH_PROTECTED;
}
if (err == ESP_OK) {
err = chip->chip_drv->erase_chip(chip);
}
err = chip->chip_drv->erase_chip(chip);
return spiflash_end(chip, err);
}
@ -292,7 +282,6 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
CHECK_WRITE_ADDRESS(chip, start, len);
uint32_t block_erase_size = chip->chip_drv->erase_block == NULL ? 0 : chip->chip_drv->block_erase_size;
uint32_t sector_size = chip->chip_drv->sector_size;
bool write_protect = false;
if (sector_size == 0 || (block_erase_size % sector_size) != 0) {
return ESP_ERR_FLASH_NOT_INITIALISED;
@ -310,16 +299,9 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
return err;
}
// Check for write protection on whole chip
if (chip->chip_drv->get_chip_write_protect != NULL) {
err = chip->chip_drv->get_chip_write_protect(chip, &write_protect);
if (err == ESP_OK && write_protect) {
err = ESP_ERR_FLASH_PROTECTED;
}
}
// Check for write protected regions overlapping the erase region
if (err == ESP_OK && chip->chip_drv->get_protected_regions != NULL && chip->chip_drv->num_protectable_regions > 0) {
if (chip->chip_drv->get_protected_regions != NULL &&
chip->chip_drv->num_protectable_regions > 0) {
uint64_t protected = 0;
err = chip->chip_drv->get_protected_regions(chip, &protected);
if (err == ESP_OK && protected != 0) {
@ -360,10 +342,10 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
return err;
}
esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protected)
esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *out_write_protected)
{
VERIFY_OP(get_chip_write_protect);
if (write_protected == NULL) {
if (out_write_protected == NULL) {
return ESP_ERR_INVALID_ARG;
}
@ -372,7 +354,7 @@ esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *wr
return err;
}
err = chip->chip_drv->get_chip_write_protect(chip, write_protected);
err = chip->chip_drv->get_chip_write_protect(chip, out_write_protected);
return spiflash_end(chip, err);
}

View file

@ -160,8 +160,6 @@ esp_err_t esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protec
* @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv'
* field).
*
* If write protection is enabled, destructive operations will fail with ESP_ERR_FLASH_PROTECTED.
*
* Some SPI flash chips may require a power cycle before write protect status can be cleared. Otherwise,
* write protection can be removed via a follow-up call to this function.
*

View file

@ -62,6 +62,8 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d
******************************************************************************/
/**
* @brief Read the Status Register read from RDSR (05h).
*
* High speed implementation of RDID through memspi interface relying on the
* ``common_command``.
*

View file

@ -90,10 +90,10 @@ struct spi_flash_chip_t {
uint32_t block_erase_size; /* Optimal (fastest) block size for multi-sector erases on this chip */
/* Read the write protect status of the entire chip. */
esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *write_protected);
esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *out_write_protected);
/* Set the write protect status of the entire chip. */
esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool write_protect_chip);
esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool chip_write_protect);
/* Number of individually write protectable regions on this chip. Range 0-63. */
uint8_t num_protectable_regions;
@ -135,9 +135,6 @@ struct spi_flash_chip_t {
/* Perform an encrypted write to the chip, using internal flash encryption hardware. */
esp_err_t (*write_encrypted)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
/* Set the write enable flag. This function is called internally by other functions in this structure, before a destructive
operation takes place. */
esp_err_t (*set_write_protect)(esp_flash_t *chip, bool write_protect);
/* Wait for the SPI flash chip to be idle (any write operation to be complete.) This function is both called from the higher-level API functions, and from other functions in this structure.

View file

@ -66,7 +66,7 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip);
esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size);
/**
* @brief Erase chip by using the generic erase chip (C7h) command.
* @brief Erase chip by using the generic erase chip command.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
*
@ -77,7 +77,7 @@ esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size);
esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip);
/**
* @brief Erase sector by using the generic sector erase (20h) command.
* @brief Erase sector by using the generic sector erase command.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param start_address Start address of the sector to erase
@ -89,7 +89,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip);
esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address);
/**
* @brief Erase block by using the generic 64KB block erase (D8h) command
* @brief Erase block by the generic 64KB block erase command
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param start_address Start address of the block to erase
@ -114,7 +114,7 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length);
/**
* @brief Perform a page program using the page program (02h) command.
* @brief Perform a page program using the page program command.
*
* @note Length of each call should not excced the limitation in
* ``chip->host->max_write_bytes``. This function is called in
@ -163,7 +163,7 @@ esp_err_t
spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
/**
* @brief Send the write enable (06h) command and verify the expected bit (1) in
* @brief Send the write enable or write disable command and verify the expected bit (1) in
* the status register is set.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
@ -171,13 +171,26 @@ spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, ui
*
* @return
* - ESP_OK if success
* - or other error passed from the ``wait_idle``, ``read_status`` or ``set_write_protect`` function of host driver
* - or other error passed from the ``wait_idle``, ``read_status`` or
* ``set_write_protect`` function of host driver
*/
esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect);
esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect);
/**
* @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write
* in progress bit) to be cleared.
* @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param out_write_protect Output of whether the write protect is set.
*
* @return
* - ESP_OK if success
* - or other error passed from the ``read_status`` function of host driver
*/
esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect);
/**
* @brief Read flash status via the RDSR command and wait for bit 0 (write in
* progress bit) to be cleared.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
* @param timeout_ms Time to wait before timeout, in ms.
@ -232,13 +245,15 @@ extern const spi_flash_chip_t esp_flash_chip_generic;
esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms);
/**
* @brief Utility function for set_read_mode chip_drv function
* @brief Utility function for set_read_mode chip_drv function. If required,
* set and check the QE bit in the flash chip to enable the QIO/QOUT mode.
*
* Most setting of read mode follows a common pattern, except for how to enable Quad I/O modes (QIO/QOUT).
* These use different commands to read/write the status register, and a different bit is set/cleared.
* Most chip QE enable follows a common pattern, though commands to read/write
* the status register may be different, as well as the position of QE bit.
*
* This is a generic utility function to implement set_read_mode() for this pattern. Also configures host
* registers via spi_flash_common_configure_host_read_mode().
* Registers to actually do Quad transtions and command to be sent in reading
* should also be configured via
* spi_flash_chip_generic_config_host_read_mode().
*
* @param qe_rdsr_command SPI flash command to read status register
* @param qe_wrsr_command SPI flash command to write status register
@ -250,7 +265,11 @@ esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_
esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit);
/**
* @brief Configure the host to use the specified read mode set in the ``chip->read_mode``.
* @brief Configure the host registers to use the specified read mode set in
* the ``chip->read_mode``.
*
* Usually called in chip_drv read() functions before actual reading
* transactions. Also prepare the command to be sent in read functions.
*
* @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted.
*

View file

@ -82,7 +82,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
{
esp_err_t err;
err = chip->chip_drv->set_write_protect(chip, false);
err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT);
}
@ -102,7 +102,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address)
{
esp_err_t err = chip->chip_drv->set_write_protect(chip, false);
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT);
}
@ -122,7 +122,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address)
{
esp_err_t err = chip->chip_drv->set_write_protect(chip, false);
esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT);
}
@ -185,7 +185,7 @@ esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, ui
page_len = page_size - (address % page_size);
}
err = chip->chip_drv->set_write_protect(chip, false);
err = chip->chip_drv->set_chip_write_protect(chip, false);
if (err == ESP_OK) {
err = chip->chip_drv->program_page(chip, buffer, address, page_len);
@ -205,7 +205,7 @@ esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *
return ESP_ERR_FLASH_UNSUPPORTED_HOST; // TODO
}
esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect)
esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect)
{
esp_err_t err = ESP_OK;
@ -215,17 +215,26 @@ esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_prot
chip->host->set_write_protect(chip->host, write_protect);
}
bool wp_read;
err = chip->chip_drv->get_chip_write_protect(chip, &wp_read);
if (err == ESP_OK && wp_read != write_protect) {
// WREN flag has not been set!
err = ESP_ERR_NOT_FOUND;
}
return err;
}
esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect)
{
esp_err_t err = ESP_OK;
uint8_t status;
assert(out_write_protect!=NULL);
err = chip->host->read_status(chip->host, &status);
if (err != ESP_OK) {
return err;
}
if ((status & SR_WREN) == 0) {
// WREN flag has not been set!
err = ESP_ERR_NOT_FOUND;
}
*out_write_protect = ((status & SR_WREN) == 0);
return err;
}
@ -329,7 +338,7 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm
ESP_EARLY_LOGV(TAG, "set_read_mode: status before 0x%x", sr);
if ((sr & qe_sr_bit) == 0) {
//some chips needs the write protect to be disabled before writing to Status Register
chip->chip_drv->set_write_protect(chip, false);
chip->chip_drv->set_chip_write_protect(chip, false);
sr |= qe_sr_bit;
spi_flash_trans_t t = {
@ -354,7 +363,7 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm
return ESP_ERR_FLASH_NO_RESPONSE;
}
chip->chip_drv->set_write_protect(chip, true);
chip->chip_drv->set_chip_write_protect(chip, true);
}
}
return ESP_OK;
@ -383,8 +392,8 @@ const spi_flash_chip_t esp_flash_chip_generic = {
.block_erase_size = 64 * 1024,
// TODO: figure out if generic chip-wide protection bits exist across some manufacturers
.get_chip_write_protect = NULL,
.set_chip_write_protect = NULL,
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
// Chip write protection regions do not appear to be standardised
// at all, this is implemented in chip-specific drivers only.
@ -399,7 +408,6 @@ const spi_flash_chip_t esp_flash_chip_generic = {
.page_size = 256,
.write_encrypted = spi_flash_chip_generic_write_encrypted,
.set_write_protect = spi_flash_chip_generic_write_enable,
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_read_mode = spi_flash_chip_generic_set_read_mode,
};

View file

@ -57,9 +57,8 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.sector_size = 4 * 1024,
.block_erase_size = 64 * 1024,
// TODO: support get/set chip write protect for ISSI flash
.get_chip_write_protect = NULL,
.set_chip_write_protect = NULL,
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
// TODO support protected regions on ISSI flash
.num_protectable_regions = 0,
@ -73,7 +72,6 @@ const spi_flash_chip_t esp_flash_chip_issi = {
.page_size = 256,
.write_encrypted = spi_flash_chip_generic_write_encrypted,
.set_write_protect = spi_flash_chip_generic_write_enable,
.wait_idle = spi_flash_chip_generic_wait_idle,
.set_read_mode = spi_flash_chip_issi_set_read_mode,
};

View file

@ -366,6 +366,36 @@ TEST_CASE("SPI flash erase large region", "[esp_flash]")
#endif
}
static void test_write_protection(esp_flash_t* chip)
{
bool wp = true;
esp_err_t ret = ESP_OK;
ret = esp_flash_get_chip_write_protect(chip, &wp);
TEST_ESP_OK(ret);
for (int i = 0; i < 4; i ++) {
bool wp_write = !wp;
ret = esp_flash_set_chip_write_protect(chip, wp_write);
TEST_ESP_OK(ret);
bool wp_read;
ret = esp_flash_get_chip_write_protect(chip, &wp_read);
TEST_ESP_OK(ret);
TEST_ASSERT(wp_read == wp_write);
wp = wp_read;
}
}
TEST_CASE("Test esp_flash can enable/disable write protetion", "[esp_flash]")
{
test_write_protection(NULL);
#ifndef SKIP_EXTENDED_CHIP_TEST
setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED);
test_write_protection(test_chip);
teardown_test_chip();
#endif
}
static const uint8_t large_const_buffer[16400] = {
203, // first byte
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
@ -491,5 +521,4 @@ static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, si
write_large_buffer(chip, part, source, length);
read_and_check(chip, part, source, length);
}
}

View file

@ -112,8 +112,8 @@ typedef struct {
static void IRAM_ATTR timer_isr(void* varg) {
block_task_arg_t* arg = (block_task_arg_t*) varg;
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[0].config.alarm_en = 1;
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0);
ets_delay_us(arg->delay_time_us);
arg->repeat_count++;
}

View file

@ -5,5 +5,5 @@ idf_component_register(SRCS "transport.c"
"transport_utils.c"
"transport_strcasestr.c"
INCLUDE_DIRS "include"
PRIVATE_INCLUDE_DIRS "private_include"
PRIV_INCLUDE_DIRS "private_include"
REQUIRES lwip esp-tls)

View file

@ -16,6 +16,7 @@
#define _ESP_TRANSPORT_SSL_H_
#include "esp_transport.h"
#include "esp_tls.h"
#ifdef __cplusplus
extern "C" {
@ -111,6 +112,20 @@ void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const c
*/
void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t);
/**
* @brief Set PSK key and hint for PSK server/client verification in esp-tls component.
* Important notes:
* - This function stores the pointer to data, rather than making a copy.
* So this data must remain valid until after the connection is cleaned up
* - ESP_TLS_PSK_VERIFICATION config option must be enabled in menuconfig
* - certificate verification takes priority so it must not be configured
* to enable PSK method.
*
* @param t ssl transport
* @param[in] psk_hint_key psk key and hint structure defined in esp_tls.h
*/
void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key);
#ifdef __cplusplus
}
#endif

View file

@ -169,6 +169,14 @@ void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t)
}
}
void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);
if (t && ssl) {
ssl->cfg.psk_hint_key = psk_hint_key;
}
}
void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len)
{
transport_ssl_t *ssl = esp_transport_get_context_data(t);

View file

@ -66,9 +66,29 @@ Case 2: API functions are declared with an extra context pointer (the FS driver
Synchronous input/output multiplexing
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you want to use synchronous input/output multiplexing by :cpp:func:`select`
then you need to register VFS with the functions :cpp:func:`start_select` and
:cpp:func:`end_select` similar to the following example:
Synchronous input/output multiplexing by :cpp:func:`select` is supported in the VFS component. The implementation
works in the following way.
1. :cpp:func:`select` is called with file descriptors which could belong to various VFS drivers.
2. The file descriptors are divided into groups each belonging to one VFS driver.
3. The file descriptors belonging to non-socket VFS drivers are handed over to the given VFS drivers by :cpp:func:`start_select`
described later on this page. This function represents the driver-specific implementation of :cpp:func:`select` for
the given driver. This should be a non-blocking call which means the function should immediately return after setting up
the environment for checking events related to the given file descriptors.
4. The file descriptors belonging to the socket VFS driver are handed over to the socket driver by
:cpp:func:`socket_select` described later on this page. This is a blocking call which means that it will return only
if there is an event related to socket file descriptors or a non-socket driver signals :cpp:func:`socket_select`
to exit.
5. Results are collected from each VFS driver and all drivers are stopped by deinitiazation
of the environment for checking events.
6. The :cpp:func:`select` call ends and returns the appropriate results.
Non-socket VFS drivers
""""""""""""""""""""""
If you want to use :cpp:func:`select` with a file descriptor belonging to a non-socket VFS driver
then you need to register the driver with functions :cpp:func:`start_select` and
:cpp:func:`end_select` similarly to the following example:
.. highlight:: c
@ -81,25 +101,57 @@ then you need to register VFS with the functions :cpp:func:`start_select` and
:cpp:func:`start_select` is called for setting up the environment for
detection of read/write/error conditions on file descriptors belonging to the
given VFS. :cpp:func:`end_select` is called to stop/deinitialize/free the
environment which was setup by :cpp:func:`start_select`. Please refer to the
given VFS driver.
:cpp:func:`end_select` is called to stop/deinitialize/free the
environment which was setup by :cpp:func:`start_select`.
Please refer to the
reference implementation for the UART peripheral in
:component_file:`vfs/vfs_uart.c` and most particularly to the functions
:cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select`, and
:cpp:func:`uart_end_select`.
:cpp:func:`uart_end_select` for more information.
Please check the following examples that demonstrate the use of :cpp:func:`select` with VFS file descriptors:
- :example:`peripherals/uart_select`
- :example:`system/select`
- :example:`peripherals/uart/uart_select`
- :example:`system/select`
<<<<<<< HEAD
If :cpp:func:`select` is used for socket file descriptors only then one can
enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option which can reduce the code
=======
If you use :cpp:func:`select` for socket file descriptors, you can enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code
>>>>>>> afc2fdf27... Review all the files in the esp-idf's api_ref/storage directory
size and improve performance.
Socket VFS drivers
""""""""""""""""""
A socket VFS driver is using its own internal implementation of :cpp:func:`select` and non-socket VFS drivers notify
it upon read/write/error conditions.
A socket VFS driver needs to be registered with the following functions defined:
.. highlight:: c
::
// In definition of esp_vfs_t:
.socket_select = &lwip_select,
.get_socket_select_semaphore = &lwip_get_socket_select_semaphore,
.stop_socket_select = &lwip_stop_socket_select,
.stop_socket_select_isr = &lwip_stop_socket_select_isr,
// ... other members initialized
:cpp:func:`socket_select` is the internal implementation of :cpp:func:`select` for the socket driver. It works only
with file descriptors belonging to the socket VFS.
:cpp:func:`get_socket_select_semaphore` returns the signalization object (semaphore) which will be used in non-socket
drivers to stop the waiting in :cpp:func:`socket_select`.
:cpp:func:`stop_socket_select` call is used to stop the waiting in :cpp:func:`socket_select` by passing the object
returned by :cpp:func:`get_socket_select_semaphore`.
:cpp:func:`stop_socket_select_isr` has the same functionality as :cpp:func:`stop_socket_select` but it can be used
from ISR.
Please see :component_file:`lwip/port/esp32/vfs_lwip.c` for a reference socket driver implementation using LWIP.
.. note::
If you use :cpp:func:`select` for socket file descriptors only then you can enable the
:envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code size and improve performance.
Paths
-----

View file

@ -236,7 +236,7 @@ typedef struct
#endif // CONFIG_VFS_SUPPORT_TERMIOS
/** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */
esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem);
esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args);
/** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */
int (*socket_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
/** called by VFS to interrupt the socket_select call when select is activated from a non-socket VFS driver; set only for the socket driver */
@ -246,7 +246,7 @@ typedef struct
/** end_select is called to stop the I/O multiplexing and deinitialize the environment created by start_select for the given VFS */
void* (*get_socket_select_semaphore)(void);
/** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */
void (*end_select)(void);
esp_err_t (*end_select)(void *end_select_args);
} esp_vfs_t;

View file

@ -31,6 +31,16 @@ typedef struct {
xSemaphoreHandle sem;
} test_task_param_t;
typedef struct {
fd_set *rdfds;
fd_set *wrfds;
fd_set *errfds;
int maxfds;
struct timeval *tv;
int select_ret;
xSemaphoreHandle sem;
} test_select_task_param_t;
static const char message[] = "Hello world!";
static int open_dummy_socket(void)
@ -420,73 +430,121 @@ TEST_CASE("poll() timeout", "[vfs]")
deinit(uart_fd, socket_fd);
}
static void select_task(void *param)
static void select_task(void *task_param)
{
const test_task_param_t *test_task_param = param;
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 100000,
};
const test_select_task_param_t *param = task_param;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(test_task_param->fd, &rfds);
int s = select(param->maxfds, param->rdfds, param->wrfds, param->errfds, param->tv);
TEST_ASSERT_EQUAL(param->select_ret, s);
int s = select(test_task_param->fd + 1, &rfds, NULL, NULL, &tv);
TEST_ASSERT_EQUAL(0, s); //timeout
if (test_task_param->sem) {
xSemaphoreGive(test_task_param->sem);
if (param->sem) {
xSemaphoreGive(param->sem);
}
vTaskDelete(NULL);
}
TEST_CASE("concurent selects work", "[vfs]")
static void inline start_select_task(test_select_task_param_t *param)
{
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 100000,//irrelevant
};
xTaskCreate(select_task, "select_task", 4*1024, (void *) param, 5, NULL);
}
TEST_CASE("concurrent selects work", "[vfs]")
{
int uart_fd, socket_fd;
init(&uart_fd, &socket_fd);
const int dummy_socket_fd = open_dummy_socket();
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(uart_fd, &rfds);
{
// Two tasks will wait for the same UART FD for reading and they will time-out
test_task_param_t test_task_param = {
.fd = uart_fd,
.sem = xSemaphoreCreateBinary(),
};
TEST_ASSERT_NOT_NULL(test_task_param.sem);
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 100000,
};
xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL);
vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select()
fd_set rdfds1;
FD_ZERO(&rdfds1);
FD_SET(uart_fd, &rdfds1);
int s = select(uart_fd + 1, &rfds, NULL, NULL, &tv);
TEST_ASSERT_EQUAL(-1, s); //this select should fail because two selects are accessing UART
//(the other one is waiting for the timeout)
TEST_ASSERT_EQUAL(EINTR, errno);
test_select_task_param_t param = {
.rdfds = &rdfds1,
.wrfds = NULL,
.errfds = NULL,
.maxfds = uart_fd + 1,
.tv = &tv,
.select_ret = 0, // expected timeout
.sem = xSemaphoreCreateBinary(),
};
TEST_ASSERT_NOT_NULL(param.sem);
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS));
fd_set rdfds2;
FD_ZERO(&rdfds2);
FD_SET(uart_fd, &rdfds2);
FD_SET(socket_fd, &rdfds2);
FD_SET(dummy_socket_fd, &rdfds2);
FD_ZERO(&rfds);
FD_SET(socket_fd, &rfds);
start_select_task(&param);
vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select()
test_task_param.fd = dummy_socket_fd;
int s = select(MAX(MAX(uart_fd, dummy_socket_fd), socket_fd) + 1, &rdfds2, NULL, NULL, &tv);
TEST_ASSERT_EQUAL(0, s); // timeout here as well
xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL);
vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select()
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS));
vSemaphoreDelete(param.sem);
}
s = select(socket_fd + 1, &rfds, NULL, NULL, &tv);
TEST_ASSERT_EQUAL(0, s); //this select should timeout as well as the concurrent one because
//concurrent socket select should work
{
// One tasks waits for UART reading and one for writing. The former will be successful and latter will
// time-out.
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS));
vSemaphoreDelete(test_task_param.sem);
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 100000,
};
fd_set wrfds1;
FD_ZERO(&wrfds1);
FD_SET(uart_fd, &wrfds1);
test_select_task_param_t param = {
.rdfds = NULL,
.wrfds = &wrfds1,
.errfds = NULL,
.maxfds = uart_fd + 1,
.tv = &tv,
.select_ret = 0, // expected timeout
.sem = xSemaphoreCreateBinary(),
};
TEST_ASSERT_NOT_NULL(param.sem);
start_select_task(&param);
fd_set rdfds2;
FD_ZERO(&rdfds2);
FD_SET(uart_fd, &rdfds2);
FD_SET(socket_fd, &rdfds2);
FD_SET(dummy_socket_fd, &rdfds2);
const test_task_param_t send_param = {
.fd = uart_fd,
.delay_ms = 50,
.sem = xSemaphoreCreateBinary(),
};
TEST_ASSERT_NOT_NULL(send_param.sem);
start_task(&send_param); // This task will write to UART which will be detected by select()
int s = select(MAX(MAX(uart_fd, dummy_socket_fd), socket_fd) + 1, &rdfds2, NULL, NULL, &tv);
TEST_ASSERT_EQUAL(1, s);
TEST_ASSERT(FD_ISSET(uart_fd, &rdfds2));
TEST_ASSERT_UNLESS(FD_ISSET(socket_fd, &rdfds2));
TEST_ASSERT_UNLESS(FD_ISSET(dummy_socket_fd, &rdfds2));
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS));
vSemaphoreDelete(param.sem);
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(send_param.sem, 1000 / portTICK_PERIOD_MS));
vSemaphoreDelete(send_param.sem);
}
deinit(uart_fd, socket_fd);
close(dummy_socket_fd);

View file

@ -794,13 +794,16 @@ int truncate(const char *path, off_t length)
return ret;
}
static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple)
static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, void **driver_args)
{
for (int i = 0; i < end_index; ++i) {
const vfs_entry_t *vfs = get_vfs_for_index(i);
const fds_triple_t *item = &vfs_fds_triple[i];
if (vfs && vfs->vfs.end_select && item->isset) {
vfs->vfs.end_select();
esp_err_t err = vfs->vfs.end_select(driver_args[i]);
if (err != ESP_OK) {
ESP_LOGD(TAG, "end_select failed: %s", esp_err_to_name(err));
}
}
}
}
@ -855,6 +858,8 @@ static void esp_vfs_log_fd_set(const char *fds_name, const fd_set *fds)
int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)
{
// NOTE: Please see the "Synchronous input/output multiplexing" section of the ESP-IDF Programming Guide
// (API Reference -> Storage -> Virtual Filesystem) for a general overview of the implementation of VFS select().
int ret = 0;
struct _reent* r = __getreent();
@ -947,6 +952,15 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds
}
}
void **driver_args = calloc(s_vfs_count, sizeof(void *));
if (driver_args == NULL) {
free(vfs_fds_triple);
__errno_r(r) = ENOMEM;
ESP_LOGD(TAG, "calloc is unsuccessful for driver args");
return -1;
}
for (int i = 0; i < s_vfs_count; ++i) {
const vfs_entry_t *vfs = get_vfs_for_index(i);
fds_triple_t *item = &vfs_fds_triple[i];
@ -958,16 +972,18 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds
esp_vfs_log_fd_set("readfds", &item->readfds);
esp_vfs_log_fd_set("writefds", &item->writefds);
esp_vfs_log_fd_set("errorfds", &item->errorfds);
esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem);
esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem,
driver_args + i);
if (err != ESP_OK) {
call_end_selects(i, vfs_fds_triple);
call_end_selects(i, vfs_fds_triple, driver_args);
(void) set_global_fd_sets(vfs_fds_triple, s_vfs_count, readfds, writefds, errorfds);
if (sel_sem.is_sem_local && sel_sem.sem) {
vSemaphoreDelete(sel_sem.sem);
sel_sem.sem = NULL;
}
free(vfs_fds_triple);
free(driver_args);
__errno_r(r) = EINTR;
ESP_LOGD(TAG, "start_select failed: %s", esp_err_to_name(err));
return -1;
@ -1006,7 +1022,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds
xSemaphoreTake(sel_sem.sem, ticks_to_wait);
}
call_end_selects(s_vfs_count, vfs_fds_triple); // for VFSs for start_select was called before
call_end_selects(s_vfs_count, vfs_fds_triple, driver_args); // for VFSs for start_select was called before
if (ret >= 0) {
ret += set_global_fd_sets(vfs_fds_triple, s_vfs_count, readfds, writefds, errorfds);
}
@ -1015,6 +1031,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds
sel_sem.sem = NULL;
}
free(vfs_fds_triple);
free(driver_args);
ESP_LOGD(TAG, "esp_vfs_select returns %d", ret);
esp_vfs_log_fd_set("readfds", readfds);

View file

@ -115,20 +115,21 @@ static vfs_uart_context_t* s_ctx[UART_NUM] = {
#endif
};
/* Lock ensuring that uart_select is used from only one task at the time */
static _lock_t s_one_select_lock;
typedef struct {
esp_vfs_select_sem_t select_sem;
fd_set *readfds;
fd_set *writefds;
fd_set *errorfds;
fd_set readfds_orig;
fd_set writefds_orig;
fd_set errorfds_orig;
} uart_select_args_t;
static esp_vfs_select_sem_t _select_sem = {.sem = NULL};
static fd_set *_readfds = NULL;
static fd_set *_writefds = NULL;
static fd_set *_errorfds = NULL;
static fd_set *_readfds_orig = NULL;
static fd_set *_writefds_orig = NULL;
static fd_set *_errorfds_orig = NULL;
static void uart_end_select(void);
static uart_select_args_t **s_registered_selects = NULL;
static int s_registered_select_num = 0;
static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED;
static esp_err_t uart_end_select(void *end_select_args);
static int uart_open(const char * path, int flags, int mode)
{
@ -347,132 +348,156 @@ static int uart_fsync(int fd)
return 0;
}
static void select_notif_callback(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken)
static esp_err_t register_select(uart_select_args_t *args)
{
switch (uart_select_notif) {
case UART_SELECT_READ_NOTIF:
if (FD_ISSET(uart_num, _readfds_orig)) {
FD_SET(uart_num, _readfds);
esp_vfs_select_triggered_isr(_select_sem, task_woken);
}
break;
case UART_SELECT_WRITE_NOTIF:
if (FD_ISSET(uart_num, _writefds_orig)) {
FD_SET(uart_num, _writefds);
esp_vfs_select_triggered_isr(_select_sem, task_woken);
}
break;
case UART_SELECT_ERROR_NOTIF:
if (FD_ISSET(uart_num, _errorfds_orig)) {
FD_SET(uart_num, _errorfds);
esp_vfs_select_triggered_isr(_select_sem, task_woken);
}
break;
esp_err_t ret = ESP_ERR_INVALID_ARG;
if (args) {
portENTER_CRITICAL(&s_registered_select_lock);
const int new_size = s_registered_select_num + 1;
if ((s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *))) == NULL) {
ret = ESP_ERR_NO_MEM;
} else {
s_registered_selects[s_registered_select_num] = args;
s_registered_select_num = new_size;
ret = ESP_OK;
}
portEXIT_CRITICAL(&s_registered_select_lock);
}
return ret;
}
static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t select_sem)
static esp_err_t unregister_select(uart_select_args_t *args)
{
if (_lock_try_acquire(&s_one_select_lock)) {
return ESP_ERR_INVALID_STATE;
esp_err_t ret = ESP_OK;
if (args) {
ret = ESP_ERR_INVALID_STATE;
portENTER_CRITICAL(&s_registered_select_lock);
for (int i = 0; i < s_registered_select_num; ++i) {
if (s_registered_selects[i] == args) {
const int new_size = s_registered_select_num - 1;
// The item is removed by overwriting it with the last item. The subsequent rellocation will drop the
// last item.
s_registered_selects[i] = s_registered_selects[new_size];
s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *));
if (s_registered_selects || new_size == 0) {
s_registered_select_num = new_size;
ret = ESP_OK;
} else {
ret = ESP_ERR_NO_MEM;
}
break;
}
}
portEXIT_CRITICAL(&s_registered_select_lock);
}
return ret;
}
const int max_fds = MIN(nfds, UART_NUM);
portENTER_CRITICAL(uart_get_selectlock());
if (_readfds || _writefds || _errorfds || _readfds_orig || _writefds_orig || _errorfds_orig || _select_sem.sem) {
portEXIT_CRITICAL(uart_get_selectlock());
uart_end_select();
return ESP_ERR_INVALID_STATE;
}
if ((_readfds_orig = malloc(sizeof(fd_set))) == NULL) {
portEXIT_CRITICAL(uart_get_selectlock());
uart_end_select();
return ESP_ERR_NO_MEM;
}
if ((_writefds_orig = malloc(sizeof(fd_set))) == NULL) {
portEXIT_CRITICAL(uart_get_selectlock());
uart_end_select();
return ESP_ERR_NO_MEM;
}
if ((_errorfds_orig = malloc(sizeof(fd_set))) == NULL) {
portEXIT_CRITICAL(uart_get_selectlock());
uart_end_select();
return ESP_ERR_NO_MEM;
}
//uart_set_select_notif_callback set the callbacks in UART ISR
for (int i = 0; i < max_fds; ++i) {
if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) {
uart_set_select_notif_callback(i, select_notif_callback);
static void select_notif_callback_isr(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken)
{
portENTER_CRITICAL_ISR(&s_registered_select_lock);
for (int i = 0; i < s_registered_select_num; ++i) {
uart_select_args_t *args = s_registered_selects[i];
if (args) {
switch (uart_select_notif) {
case UART_SELECT_READ_NOTIF:
if (FD_ISSET(uart_num, &args->readfds_orig)) {
FD_SET(uart_num, args->readfds);
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
}
break;
case UART_SELECT_WRITE_NOTIF:
if (FD_ISSET(uart_num, &args->writefds_orig)) {
FD_SET(uart_num, args->writefds);
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
}
break;
case UART_SELECT_ERROR_NOTIF:
if (FD_ISSET(uart_num, &args->errorfds_orig)) {
FD_SET(uart_num, args->errorfds);
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
}
break;
}
}
}
portEXIT_CRITICAL_ISR(&s_registered_select_lock);
}
_select_sem = select_sem;
static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
esp_vfs_select_sem_t select_sem, void **end_select_args)
{
const int max_fds = MIN(nfds, UART_NUM);
*end_select_args = NULL;
_readfds = readfds;
_writefds = writefds;
_errorfds = exceptfds;
uart_select_args_t *args = malloc(sizeof(uart_select_args_t));
*_readfds_orig = *readfds;
*_writefds_orig = *writefds;
*_errorfds_orig = *exceptfds;
if (args == NULL) {
return ESP_ERR_NO_MEM;
}
args->select_sem = select_sem;
args->readfds = readfds;
args->writefds = writefds;
args->errorfds = exceptfds;
args->readfds_orig = *readfds; // store the original values because they will be set to zero
args->writefds_orig = *writefds;
args->errorfds_orig = *exceptfds;
FD_ZERO(readfds);
FD_ZERO(writefds);
FD_ZERO(exceptfds);
portENTER_CRITICAL(uart_get_selectlock());
//uart_set_select_notif_callback sets the callbacks in UART ISR
for (int i = 0; i < max_fds; ++i) {
if (FD_ISSET(i, _readfds_orig)) {
if (FD_ISSET(i, &args->readfds_orig) || FD_ISSET(i, &args->writefds_orig) || FD_ISSET(i, &args->errorfds_orig)) {
uart_set_select_notif_callback(i, select_notif_callback_isr);
}
}
for (int i = 0; i < max_fds; ++i) {
if (FD_ISSET(i, &args->readfds_orig)) {
size_t buffered_size;
if (uart_get_buffered_data_len(i, &buffered_size) == ESP_OK && buffered_size > 0) {
// signalize immediately when data is buffered
FD_SET(i, _readfds);
esp_vfs_select_triggered(_select_sem);
FD_SET(i, readfds);
esp_vfs_select_triggered(args->select_sem);
}
}
}
portEXIT_CRITICAL(uart_get_selectlock());
// s_one_select_lock is not released on successfull exit - will be
// released in uart_end_select()
esp_err_t ret = register_select(args);
if (ret != ESP_OK) {
portEXIT_CRITICAL(uart_get_selectlock());
free(args);
return ret;
}
portEXIT_CRITICAL(uart_get_selectlock());
*end_select_args = args;
return ESP_OK;
}
static void uart_end_select(void)
static esp_err_t uart_end_select(void *end_select_args)
{
uart_select_args_t *args = end_select_args;
if (args) {
free(args);
}
portENTER_CRITICAL(uart_get_selectlock());
esp_err_t ret = unregister_select(args);
for (int i = 0; i < UART_NUM; ++i) {
uart_set_select_notif_callback(i, NULL);
}
_select_sem.sem = NULL;
_readfds = NULL;
_writefds = NULL;
_errorfds = NULL;
if (_readfds_orig) {
free(_readfds_orig);
_readfds_orig = NULL;
}
if (_writefds_orig) {
free(_writefds_orig);
_writefds_orig = NULL;
}
if (_errorfds_orig) {
free(_errorfds_orig);
_errorfds_orig = NULL;
}
portEXIT_CRITICAL(uart_get_selectlock());
_lock_release(&s_one_select_lock);
return ret;
}
#ifdef CONFIG_VFS_SUPPORT_TERMIOS

View file

@ -20,11 +20,17 @@
#include "crypto/md5.h"
#include "crypto/crypto.h"
#ifdef USE_MBEDTLS_CRYPTO
#include "mbedtls/sha1.h"
#endif
typedef struct SHA1Context SHA1_CTX;
void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
#ifndef USE_MBEDTLS_CRYPTO
/**
* sha1_vector - SHA-1 hash for data vector
* @num_elem: Number of elements in the data vector
@ -45,7 +51,49 @@ sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
SHA1Final(mac, &ctx);
return 0;
}
#else
/**
* sha1_vector - SHA-1 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 of failure
*/
int
sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
mbedtls_sha1_context ctx;
size_t i;
int ret;
mbedtls_sha1_init( &ctx );
if ((ret = mbedtls_sha1_starts_ret( &ctx)) != 0) {
goto exit;
}
for (i = 0; i < num_elem; i++) {
if ((ret = mbedtls_sha1_update_ret(&ctx, addr[i], len[i])) != 0) {
goto exit;
}
}
if ((ret = mbedtls_sha1_finish_ret( &ctx, mac)) != 0) {
goto exit;
}
exit:
mbedtls_sha1_free( &ctx );
if (ret) {
return -1;
}
return 0;
}
#endif
/* ===== start - public domain SHA1 implementation ===== */
@ -309,5 +357,4 @@ SHA1Final(unsigned char digest[20], SHA1_CTX* context)
os_memset(context->count, 0, 8);
os_memset(finalcount, 0, 8);
}
/* ===== end - public domain SHA1 implementation ===== */

View file

@ -18,10 +18,63 @@
#include "crypto/md5.h"
#include "crypto/crypto.h"
#ifdef USE_MBEDTLS_CRYPTO
#include "mbedtls/pkcs5.h"
/**
* pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
* @passphrase: ASCII passphrase
* @ssid: SSID
* @ssid_len: SSID length in bytes
* @iterations: Number of iterations to run
* @buf: Buffer for the generated key
* @buflen: Length of the buffer in bytes
* Returns: 0 on success, -1 of failure
*
* This function is used to derive PSK for WPA-PSK. For this protocol,
* iterations is set to 4096 and buflen to 32. This function is described in
* IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
*/
int
pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
mbedtls_md_context_t sha1_ctx;
const mbedtls_md_info_t *info_sha1;
int ret;
mbedtls_md_init( &sha1_ctx );
info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 );
if (info_sha1 == NULL) {
ret = -1;
goto exit;
}
if ((ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0) {
ret = -1;
goto exit;
}
ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, (const unsigned char*) passphrase, os_strlen(passphrase) , (const unsigned char*) ssid,
ssid_len, iterations, 32, buf );
if (ret != 0) {
ret = -1;
goto exit;
}
exit:
mbedtls_md_free( &sha1_ctx );
return ret;
}
#else
static int
pbkdf2_sha1_f(const char *passphrase, const char *ssid,
size_t ssid_len, int iterations, unsigned int count,
u8 *digest)
size_t ssid_len, int iterations, unsigned int count,
u8 *digest)
{
unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN];
int i, j;
@ -99,3 +152,4 @@ pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
return 0;
}
#endif

View file

@ -34,6 +34,9 @@
// Forces data to be placed to DMA-capable places
#define DMA_ATTR WORD_ALIGNED_ATTR DRAM_ATTR
// Forces a function to be inlined
#define FORCE_INLINE_ATTR static inline __attribute__((always_inline))
// Forces a string into DRAM instead of flash
// Use as ets_printf(DRAM_STR("Hello world!\n"));
#define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;}))
@ -45,7 +48,7 @@
// Forces bss variable into external memory. "
#define EXT_RAM_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__)
#else
#define EXT_RAM_ATTR
#define EXT_RAM_ATTR
#endif
// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst"
@ -73,6 +76,30 @@
// Forces to not inline function
#define NOINLINE_ATTR __attribute__((noinline))
// This allows using enum as flags in C++
// Format: FLAG_ATTR(flag_enum_t)
#ifdef __cplusplus
#define FLAG_ATTR_IMPL(TYPE, INT_TYPE) \
constexpr TYPE operator~ (TYPE a) { return (TYPE)~(INT_TYPE)a; } \
constexpr TYPE operator| (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a | (INT_TYPE)b); } \
constexpr TYPE operator& (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a & (INT_TYPE)b); } \
constexpr TYPE operator^ (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a ^ (INT_TYPE)b); } \
constexpr TYPE operator>> (TYPE a, int b) { return (TYPE)((INT_TYPE)a >> b); } \
constexpr TYPE operator<< (TYPE a, int b) { return (TYPE)((INT_TYPE)a << b); } \
TYPE& operator|=(TYPE& a, TYPE b) { a = a | b; return a; } \
TYPE& operator&=(TYPE& a, TYPE b) { a = a & b; return a; } \
TYPE& operator^=(TYPE& a, TYPE b) { a = a ^ b; return a; } \
TYPE& operator>>=(TYPE& a, int b) { a >>= b; return a; } \
TYPE& operator<<=(TYPE& a, int b) { a <<= b; return a; }
#define FLAG_ATTR_U32(TYPE) FLAG_ATTR_IMPL(TYPE, uint32_t)
#define FLAG_ATTR FLAG_ATTR_U32
#else
#define FLAG_ATTR(TYPE)
#endif
// Implementation for a unique custom section
//
// This prevents gcc producing "x causes a section type conflict with y"

View file

@ -40,3 +40,7 @@ a:hover {
.logo {
width: 240px !important;
}
a.internal::after{
content: ' ';
}

Some files were not shown because too many files have changed in this diff Show more