rebase the origin to the local

This commit is contained in:
Yulong 2017-11-13 02:20:02 -05:00
commit 2be5e73090
438 changed files with 21558 additions and 4135 deletions

2
.gitignore vendored
View file

@ -35,6 +35,8 @@ docs/man/
tools/unit-test-app/sdkconfig
tools/unit-test-app/sdkconfig.old
tools/unit-test-app/build
tools/unit-test-app/builds
tools/unit-test-app/output
# AWS IoT Examples require device-specific certs/keys
examples/protocols/aws_iot/*/main/certs/*.pem.*

View file

@ -113,19 +113,17 @@ build_esp_idf_tests:
<<: *build_template
artifacts:
paths:
- tools/unit-test-app/build/*.bin
- tools/unit-test-app/build/*.elf
- tools/unit-test-app/build/*.map
- tools/unit-test-app/build/download.config
- tools/unit-test-app/build/bootloader/*.bin
- tools/unit-test-app/output
- components/idf_test/unit_test/TestCaseAll.yml
- components/idf_test/unit_test/CIConfigs/*.yml
expire_in: 6 mos
script:
- cd tools/unit-test-app
- make TESTS_ALL=1
# cut last line in case make V=0/1 is set by default
- make print_flash_cmd | tail -n 1 > build/download.config
- make help # make sure kconfig tools are built in single process
- make ut-clean-all-configs
- export EXTRA_CFLAGS="-Werror -Werror=deprecated-declarations"
- export EXTRA_CXXFLAGS=${EXTRA_CFLAGS}
- make ut-build-all-configs TESTS_ALL=1
- python tools/UnitTestParser.py
.build_examples_template: &build_examples_template
@ -135,6 +133,7 @@ build_esp_idf_tests:
- build_examples/*/*/*/build/*.bin
- build_examples/*/*/*/build/*.elf
- build_examples/*/*/*/build/*.map
- build_examples/*/*/*/build/download.config
- build_examples/*/*/*/build/bootloader/*.bin
expire_in: 1 week
variables:
@ -413,21 +412,29 @@ check_submodule_sync:
assign_test:
<<: *build_template
stage: assign_test
dependencies:
- build_esp_idf_tests
- build_ssc
# gitlab ci do not support match job with RegEx or wildcard now in dependencies.
# we have a lot build example jobs. now we don't use dependencies, just download all artificats of build stage.
variables:
UT_BIN_PATH: "tools/unit-test-app/output"
OUTPUT_BIN_PATH: "test_bins/ESP32_IDF"
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
EXAMPLE_CONFIG_OUTPUT_PATH: "$CI_PROJECT_DIR/examples/test_configs"
artifacts:
paths:
- test_bins
- components/idf_test/*/CIConfigs
- components/idf_test/*/TC.sqlite
- $EXAMPLE_CONFIG_OUTPUT_PATH
expire_in: 1 mos
before_script: *add_gitlab_key_before
script:
# first move test bins together: test_bins/CHIP_SDK/TestApp/bin_files
- mkdir -p test_bins/ESP32_IDF/UT
- cp -r tools/unit-test-app/build/* test_bins/ESP32_IDF/UT
- cp -r SSC/ssc_bin/* test_bins/ESP32_IDF
- mkdir -p $OUTPUT_BIN_PATH
# copy and rename folder name to "UT_config"
- for CONFIG in $(ls $UT_BIN_PATH); do cp -r "$UT_BIN_PATH/$CONFIG" "$OUTPUT_BIN_PATH/UT_$CONFIG"; done
- cp -r SSC/ssc_bin/* $OUTPUT_BIN_PATH
# assign example tests
- python $TEST_FW_PATH/CIAssignExampleTest.py $IDF_PATH/examples $IDF_PATH/.gitlab-ci.yml $EXAMPLE_CONFIG_OUTPUT_PATH
# clone test script to assign tests
- git clone $TEST_SCRIPT_REPOSITORY
- cd auto_test_script
@ -437,6 +444,34 @@ assign_test:
# assgin integration test cases
- python CIAssignTestCases.py -t $IDF_PATH/components/idf_test/integration_test -c $IDF_PATH/.gitlab-ci.yml -b $IDF_PATH/test_bins
.example_test_template: &example_test_template
stage: test
when: on_success
only:
- master
- /^release\/v/
- /^v\d+\.\d+(\.\d+)?($|-)/
- triggers
# gitlab ci do not support match job with RegEx or wildcard now in dependencies.
# we have a lot build example jobs and the binaries them exceed the limitation of artifacts.
# we can't artifact them in one job. For example test jobs, download all artifacts from previous stages.
artifacts:
when: always
paths:
- $LOG_PATH
expire_in: 6 mos
variables:
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
TEST_CASE_PATH: "$CI_PROJECT_DIR/examples"
CONFIG_FILE: "$CI_PROJECT_DIR/examples/test_configs/$CI_JOB_NAME.yml"
LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS"
script:
# first test if config file exists, if not exist, exit 0
- test -e $CONFIG_FILE || exit 0
- cd $TEST_FW_PATH
# run test
- python Runner.py $TEST_CASE_PATH -c $CONFIG_FILE
.test_template: &test_template
stage: test
when: on_success
@ -507,47 +542,179 @@ nvs_compatible_test:
# run test
- python CIRunner.py -l "$LOG_PATH/$CI_JOB_NAME" -c $CONFIG_FILE -e $LOCAL_ENV_CONFIG_PATH -t $TEST_CASE_FILE_PATH -m $MODULE_UPDATE_FILE
example_test_001_01:
<<: *example_test_template
tags:
- ESP32
- Example_WIFI
UT_001_01:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_default
UT_001_02:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_default
UT_001_03:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_default
UT_001_04:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_default
UT_001_05:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_SDMODE
- UT_default
UT_001_06:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_SPIMODE
- UT_default
UT_001_07:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_default
UT_001_08:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_default
UT_002_01:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_release
UT_002_02:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_release
UT_002_03:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_release
UT_002_04:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_release
UT_002_05:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_SDMODE
- UT_release
UT_002_06:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_SPIMODE
- UT_release
UT_002_07:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_release
UT_002_08:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_release
UT_003_01:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_single_core
UT_003_02:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_single_core
UT_003_03:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_single_core
UT_003_04:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_single_core
UT_003_05:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_SDMODE
- UT_single_core
UT_003_06:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_SPIMODE
- UT_single_core
UT_003_07:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_single_core
UT_003_08:
<<: *unit_test_template
tags:
- ESP32_IDF
- UT_T1_1
- UT_single_core
IT_001_01:
<<: *test_template

14
Kconfig
View file

@ -93,7 +93,19 @@ config OPTIMIZATION_ASSERTIONS_DISABLED
endchoice # assertions
endmenu # Optimization level
config CXX_EXCEPTIONS
bool "Enable C++ exceptions"
default n
help
Enabling this option compiles all IDF C++ files with exception support enabled.
Disabling this option disables C++ exception support in all compiled files, and any libstdc++ code which throws
an exception will abort instead.
Enabling this option currently adds an additional 20KB of heap overhead, and 4KB of additional heap is allocated
the first time an exception is thrown in user code.
endmenu # Compiler Options
menu "Component config"
source "$COMPONENT_KCONFIGS"

View file

@ -63,13 +63,13 @@ config SYSVIEW_ENABLE
help
Enables supporrt for SEGGER SystemView tracing functionality.
if !FREERTOS_UNICORE
choice SYSVIEW_TS_SOURCE
prompt "ESP32 timer to use as SystemView timestamp source"
depends on SYSVIEW_ENABLE
default SYSVIEW_TS_SOURCE_TIMER_00
help
SystemView needs one source for timestamps when tracing events from both cores.
SystemView needs to use a hardware timer as the source of timestamps
when tracing
This option selects HW timer for it.
config SYSVIEW_TS_SOURCE_TIMER_00
@ -93,7 +93,6 @@ config SYSVIEW_TS_SOURCE_TIMER_11
Select this to use timer 1 of group 1
endchoice
endif #FREERTOS_UNICORE
config SYSVIEW_EVT_OVERFLOW_ENABLE
bool "Trace Buffer Overflow Event"

View file

@ -203,8 +203,6 @@ const static char *TAG = "esp_apptrace";
#define ESP_APPTRACE_LOGV( format, ... ) ESP_APPTRACE_LOG_LEV(V, ESP_LOG_VERBOSE, format, ##__VA_ARGS__)
#define ESP_APPTRACE_LOGO( format, ... ) ESP_APPTRACE_LOG_LEV(E, ESP_LOG_NONE, format, ##__VA_ARGS__)
#define ESP_APPTRACE_CPUTICKS2US(_t_) ((_t_)/(XT_CLOCK_FREQ/1000000))
// TODO: move these (and same definitions in trax.c to dport_reg.h)
#define TRACEMEM_MUX_PROBLK0_APPBLK1 0
#define TRACEMEM_MUX_BLK0_ONLY 1

View file

@ -15,23 +15,24 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_app_trace_util.h"
#include "esp_clk.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////// TIMEOUT /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// TODO: get actual clock from PLL config
#define ESP_APPTRACE_CPUTICKS2US(_t_) ((_t_)/(XT_CLOCK_FREQ/1000000))
#define ESP_APPTRACE_US2CPUTICKS(_t_) ((_t_)*(XT_CLOCK_FREQ/1000000))
#define ESP_APPTRACE_CPUTICKS2US(_t_, _cpu_freq_) ((_t_)/(_cpu_freq_/1000000))
#define ESP_APPTRACE_US2CPUTICKS(_t_, _cpu_freq_) ((_t_)*(_cpu_freq_/1000000))
esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo)
{
int cpu_freq = esp_clk_cpu_freq();
if (tmo->tmo != ESP_APPTRACE_TMO_INFINITE) {
unsigned cur = portGET_RUN_TIME_COUNTER_VALUE();
if (tmo->start <= cur) {
tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(cur - tmo->start);
tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(cur - tmo->start, cpu_freq);
} else {
tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(0xFFFFFFFF - tmo->start + cur);
tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(0xFFFFFFFF - tmo->start + cur, cpu_freq);
}
if (tmo->elapsed >= tmo->tmo) {
return ESP_ERR_TIMEOUT;
@ -54,7 +55,11 @@ esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *
// FIXME: if mux is busy it is not good idea to loop during the whole tmo with disabled IRQs.
// So we check mux state using zero tmo, restore IRQs and let others tasks/IRQs to run on this CPU
// while we are doing our own tmo check.
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
bool success = vPortCPUAcquireMutexTimeout(&lock->mux, 0, __FUNCTION__, __LINE__);
#else
bool success = vPortCPUAcquireMutexTimeout(&lock->mux, 0);
#endif
if (success) {
lock->int_state = int_state;
return ESP_OK;
@ -75,7 +80,11 @@ esp_err_t esp_apptrace_lock_give(esp_apptrace_lock_t *lock)
unsigned int_state = lock->int_state;
// after call to the following func we can not be sure that lock->int_state
// is not overwritten by other CPU who has acquired the mux just after we released it. See esp_apptrace_lock_take().
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
vPortCPUReleaseMutex(&lock->mux, __FUNCTION__, __LINE__);
#else
vPortCPUReleaseMutex(&lock->mux);
#endif
portEXIT_CRITICAL_NESTED(int_state);
return ESP_OK;
}

View file

@ -14,9 +14,9 @@
// This module implements runtime file I/O API for GCOV.
#include "esp_task_wdt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "soc/cpu.h"
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"

View file

@ -70,6 +70,7 @@ Revision: $Rev: 3734 $
#include "esp_app_trace.h"
#include "esp_app_trace_util.h"
#include "esp_intr_alloc.h"
#include "esp_clk.h"
extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
@ -85,14 +86,12 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
// The target device name
#define SYSVIEW_DEVICE_NAME "ESP32"
// Timer group timer divisor
#define SYSVIEW_TIMER_DIV 2
// Frequency of the timestamp.
#if CONFIG_FREERTOS_UNICORE == 0
#define SYSVIEW_TIMESTAMP_FREQ (TIMER_BASE_CLK/2)
#else
#define SYSVIEW_TIMESTAMP_FREQ (XT_CLOCK_FREQ)
#endif
#define SYSVIEW_TIMESTAMP_FREQ (esp_clk_apb_freq() / SYSVIEW_TIMER_DIV)
// System Frequency.
#define SYSVIEW_CPU_FREQ (XT_CLOCK_FREQ)
#define SYSVIEW_CPU_FREQ (esp_clk_cpu_freq())
// The lowest RAM address used for IDs (pointers)
#define SYSVIEW_RAM_BASE (0x3F400000)
@ -104,10 +103,8 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
#endif
#if CONFIG_FREERTOS_UNICORE == 0
static timer_idx_t s_ts_timer_idx;
static timer_group_t s_ts_timer_group;
#endif
// SystemView is single core specific: it implies that SEGGER_SYSVIEW_LOCK()
// disables IRQs (disables rescheduling globaly). So we can not use finite timeouts for locks and return error
@ -214,7 +211,6 @@ static void _cbSendSystemDesc(void) {
*
**********************************************************************
*/
#if CONFIG_FREERTOS_UNICORE == 0
static void SEGGER_SYSVIEW_TS_Init()
{
timer_config_t config;
@ -238,7 +234,7 @@ static void SEGGER_SYSVIEW_TS_Init()
config.alarm_en = 0;
config.auto_reload = 0;
config.counter_dir = TIMER_COUNT_UP;
config.divider = 2;
config.divider = SYSVIEW_TIMER_DIV;
config.counter_en = 0;
/*Configure timer*/
timer_init(s_ts_timer_group, s_ts_timer_idx, &config);
@ -247,14 +243,11 @@ static void SEGGER_SYSVIEW_TS_Init()
/*Enable timer interrupt*/
timer_start(s_ts_timer_group, s_ts_timer_idx);
}
#endif
void SEGGER_SYSVIEW_Conf(void) {
U32 disable_evts = 0;
#if CONFIG_FREERTOS_UNICORE == 0
SEGGER_SYSVIEW_TS_Init();
#endif
SEGGER_SYSVIEW_Init(SYSVIEW_TIMESTAMP_FREQ, SYSVIEW_CPU_FREQ,
&SYSVIEW_X_OS_TraceAPI, _cbSendSystemDesc);
SEGGER_SYSVIEW_SetRAMBase(SYSVIEW_RAM_BASE);

View file

@ -26,16 +26,6 @@ const static char *TAG = "segger_rtt";
#define SYSVIEW_EVENTS_BUF_SZ 255U
#if SYSVIEW_RTT_MAX_DATA_RATE > 0
#include "SEGGER_SYSVIEW_Conf.h"
#if CONFIG_FREERTOS_UNICORE == 0
#include "driver/timer.h"
#define SYSVIEW_TIMESTAMP_FREQ (TIMER_BASE_CLK/2)
#else
#define SYSVIEW_TIMESTAMP_FREQ (XT_CLOCK_FREQ)
#endif
#endif
// size of down channel data buf
#define SYSVIEW_DOWN_BUF_SIZE 32
#define SEGGER_HOST_WAIT_TMO 500 //us

View file

@ -67,7 +67,7 @@ static void esp_apptrace_test_timer_init(int timer_group, int timer_idx, uint32_
config.alarm_en = 1;
config.auto_reload = 1;
config.counter_dir = TIMER_COUNT_UP;
config.divider = 1;
config.divider = 2; //Range is 2 to 65536
config.intr_type = TIMER_INTR_LEVEL;
config.counter_en = TIMER_PAUSE;
/*Configure timer*/
@ -87,8 +87,6 @@ static void esp_apptrace_test_timer_init(int timer_group, int timer_idx, uint32_
#define ESP_APPTRACE_TEST_WRITE_FROM_ISR(_b_, _s_) esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, _b_, _s_, 0UL)
#define ESP_APPTRACE_TEST_WRITE_NOWAIT(_b_, _s_) esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, _b_, _s_, 0)
#define ESP_APPTRACE_TEST_CPUTICKS2US(_t_) ((_t_)/(XT_CLOCK_FREQ/1000000))
typedef struct {
uint8_t *buf;
uint32_t buf_sz;
@ -405,7 +403,7 @@ static void esp_apptrace_test_ts_init(int timer_group, int timer_idx)
config.alarm_en = 0;
config.auto_reload = 0;
config.counter_dir = TIMER_COUNT_UP;
config.divider = 1;
config.divider = 2; //Range is 2 to 65536
config.counter_en = 0;
/*Configure timer*/
timer_init(timer_group, timer_idx, &config);
@ -422,7 +420,7 @@ static void esp_apptrace_test_ts_cleanup()
config.alarm_en = 0;
config.auto_reload = 0;
config.counter_dir = TIMER_COUNT_UP;
config.divider = 1;
config.divider = 2; //Range is 2 to 65536
config.counter_en = 0;
/*Configure timer*/
timer_init(s_ts_timer_group, s_ts_timer_idx, &config);

View file

@ -43,6 +43,16 @@ config BOOTLOADER_SPI_WP_PIN
The default value (GPIO 7) is correct for WP pin on ESP32-D2WD integrated flash.
config BOOTLOADER_VDDSDIO_BOOST
bool "Increase VDDSDIO LDO voltage to 1.9V"
default y
help
If this option is enabled, and VDDSDIO LDO is set to 1.8V (using EFUSE
or MTDI bootstrapping pin), bootloader will change LDO settings to
output 1.9V instead. This helps prevent flash chip from browning out
during flash programming operations.
For 3.3V flash, this option has no effect.
endmenu # Bootloader

View file

@ -73,6 +73,8 @@ static void set_cache_and_start_app(uint32_t drom_addr,
uint32_t irom_size,
uint32_t entry_addr);
static void update_flash_config(const esp_image_header_t* pfhdr);
static void vddsdio_configure();
static void flash_gpio_configure();
static void clock_configure(void);
static void uart_console_configure(void);
static void wdt_reset_check(void);
@ -443,6 +445,8 @@ static bool load_boot_image(const bootloader_state_t *bs, int start_index, esp_i
void bootloader_main()
{
vddsdio_configure();
flash_gpio_configure();
clock_configure();
uart_console_configure();
wdt_reset_check();
@ -737,6 +741,105 @@ static void print_flash_info(const esp_image_header_t* phdr)
}
static void vddsdio_configure()
{
#if CONFIG_BOOTLOADER_VDDSDIO_BOOST
rtc_vddsdio_config_t cfg = rtc_vddsdio_get_config();
if (cfg.tieh == 0) { // 1.8V is used
cfg.drefh = 3;
cfg.drefm = 3;
cfg.drefl = 3;
cfg.force = 1;
cfg.enable = 1;
rtc_vddsdio_set_config(cfg);
ets_delay_us(10); // wait for regulator to become stable
}
#endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
}
#define FLASH_CLK_IO 6
#define FLASH_CS_IO 11
#define FLASH_SPIQ_IO 7
#define FLASH_SPID_IO 8
#define FLASH_SPIWP_IO 10
#define FLASH_SPIHD_IO 9
#define FLASH_IO_MATRIX_DUMMY_40M 1
#define FLASH_IO_MATRIX_DUMMY_80M 2
static void IRAM_ATTR flash_gpio_configure()
{
int spi_cache_dummy = 0;
int drv = 2;
#if CONFIG_FLASHMODE_QIO
spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; //qio 3
#elif CONFIG_FLASHMODE_QOUT
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; //qout 7
#elif CONFIG_FLASHMODE_DIO
spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; //dio 3
#elif CONFIG_FLASHMODE_DOUT
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; //dout 7
#endif
/* dummy_len_plus values defined in ROM for SPI flash configuration */
extern uint8_t g_rom_spiflash_dummy_len_plus[];
#if CONFIG_ESPTOOLPY_FLASHFREQ_40M
g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_40M;
g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_40M;
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_40M, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M
g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_80M;
g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_80M;
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_80M, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
drv = 3;
#endif
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
uint32_t pkg_ver = chip_ver & 0x7;
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) {
// For ESP32D2WD the SPI pins are already configured
ESP_LOGI(TAG, "Detected ESP32D2WD");
//flash clock signal should come from IO MUX.
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
// For ESP32PICOD2 the SPI pins are already configured
ESP_LOGI(TAG, "Detected ESP32PICOD2");
//flash clock signal should come from IO MUX.
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
// For ESP32PICOD4 the SPI pins are already configured
ESP_LOGI(TAG, "Detected ESP32PICOD4");
//flash clock signal should come from IO MUX.
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
} else {
ESP_LOGI(TAG, "Detected ESP32");
const uint32_t spiconfig = ets_efuse_get_spiconfig();
if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) {
gpio_matrix_out(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
gpio_matrix_out(FLASH_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
gpio_matrix_in(FLASH_SPIQ_IO, SPIQ_IN_IDX, 0);
gpio_matrix_out(FLASH_SPID_IO, SPID_OUT_IDX, 0, 0);
gpio_matrix_in(FLASH_SPID_IO, SPID_IN_IDX, 0);
gpio_matrix_out(FLASH_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
gpio_matrix_in(FLASH_SPIWP_IO, SPIWP_IN_IDX, 0);
gpio_matrix_out(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
gpio_matrix_in(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
//select pin function gpio
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
// flash clock signal should come from IO MUX.
// set drive ability for clock
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
}
}
}
static void clock_configure(void)
{
/* Set CPU to 80MHz. Keep other clocks unmodified. */

View file

@ -1,14 +1,96 @@
menuconfig BT_ENABLED
menu Bluetooth
config BT_ENABLED
bool "Bluetooth"
help
Select this option to enable Bluetooth and show the submenu with Bluetooth configuration choices.
menuconfig BLUEDROID_ENABLED
bool "Bluedroid Bluetooth stack enabled"
choice BTDM_CONTROLLER_PINNED_TO_CORE_CHOICE
prompt "The cpu core which bluetooth controller run"
depends on BT_ENABLED && !FREERTOS_UNICORE
help
Specify the cpu core to run bluetooth controller.
Can not specify no-affinity.
config BTDM_CONTROLLER_PINNED_TO_CORE_0
bool "Core 0 (PRO CPU)"
config BTDM_CONTROLLER_PINNED_TO_CORE_1
bool "Core 1 (APP CPU)"
depends on !FREERTOS_UNICORE
endchoice
config BTDM_CONTROLLER_PINNED_TO_CORE
int
default 0 if BTDM_CONTROLLER_PINNED_TO_CORE_0
default 1 if BTDM_CONTROLLER_PINNED_TO_CORE_1
default 0
choice BTDM_CONTROLLER_HCI_MODE_CHOICE
prompt "HCI mode"
depends on BT_ENABLED
default y
help
This enables the default Bluedroid Bluetooth stack
help
Speicify HCI mode as VHCI or UART(H4)
config BTDM_CONTROLLER_HCI_MODE_VHCI
bool "VHCI"
help
Normal option. Mostly, choose this VHCI when bluetooth host run on ESP32, too.
config BTDM_CONTROLLER_HCI_MODE_UART_H4
bool "UART(H4)"
help
If use external bluetooth host which run on other hardware and use UART as the HCI interface,
choose this option.
endchoice
menu "HCI UART(H4) Options"
visible if BTDM_CONTROLLER_HCI_MODE_UART_H4
config BT_HCI_UART_NO
int "UART Number for HCI"
depends on BTDM_CONTROLLER_HCI_MODE_UART_H4
range 1 2
default 1
help
Uart number for HCI. The available uart is UART1 and UART2.
config BT_HCI_UART_BAUDRATE
int "UART Baudrate for HCI"
depends on BTDM_CONTROLLER_HCI_MODE_UART_H4
range 115200 921600
default 921600
help
UART Baudrate for HCI. Please use standard baudrate.
endmenu
menuconfig BLUEDROID_ENABLED
bool "Bluedroid Enable"
depends on BTDM_CONTROLLER_HCI_MODE_VHCI
default y
help
This enables the default Bluedroid Bluetooth stack
choice BLUEDROID_PINNED_TO_CORE_CHOICE
prompt "The cpu core which Bluedroid run"
depends on BLUEDROID_ENABLED && !FREERTOS_UNICORE
help
Which the cpu core to run Bluedroid. Can choose core0 and core1.
Can not specify no-affinity.
config BLUEDROID_PINNED_TO_CORE_0
bool "Core 0 (PRO CPU)"
config BLUEDROID_PINNED_TO_CORE_1
bool "Core 1 (APP CPU)"
depends on !FREERTOS_UNICORE
endchoice
config BLUEDROID_PINNED_TO_CORE
int
depends on BLUEDROID_ENABLED
default 0 if BLUEDROID_PINNED_TO_CORE_0
default 1 if BLUEDROID_PINNED_TO_CORE_1
default 0
config BTC_TASK_STACK_SIZE
int "Bluetooth event (callback to application) task stack size"
@ -67,44 +149,6 @@ config BT_ACL_CONNECTIONS
help
Maximum BT/BLE connection count
#disable now for app cpu due to a known issue
config BTDM_CONTROLLER_RUN_APP_CPU
bool "Run controller on APP CPU"
depends on BT_ENABLED && !FREERTOS_UNICORE && 0
default n
help
Run controller on APP CPU.
config BTDM_CONTROLLER_RUN_CPU
int
depends on BT_ENABLED
default 1 if BTDM_CONTROLLER_RUN_APP_CPU
default 0
menuconfig BT_HCI_UART
bool "HCI use UART as IO"
depends on BT_ENABLED && !BLUEDROID_ENABLED
default n
help
Default HCI use VHCI, if this option choose, HCI will use UART(0/1/2) as IO.
Besides, it can set uart number and uart baudrate.
config BT_HCI_UART_NO
int "UART Number for HCI"
depends on BT_HCI_UART
range 1 2
default 1
help
Uart number for HCI.
config BT_HCI_UART_BAUDRATE
int "UART Baudrate for HCI"
depends on BT_HCI_UART
range 115200 921600
default 921600
help
UART Baudrate for HCI. Please use standard baudrate.
config SMP_ENABLE
bool
depends on BLUEDROID_ENABLED
@ -115,3 +159,5 @@ config BT_RESERVE_DRAM
hex
default 0x10000 if BT_ENABLED
default 0
endmenu

View file

@ -36,7 +36,9 @@ esp_err_t esp_bt_dev_set_device_name(const char *name)
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
if (!name){
return ESP_ERR_INVALID_ARG;
}
if (strlen(name) > ESP_DEV_DEVICE_NAME_MAX) {
return ESP_ERR_INVALID_ARG;
}

View file

@ -203,7 +203,9 @@ esp_err_t esp_ble_gap_update_whitelist(bool add_remove, esp_bd_addr_t remote_bda
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
if (!remote_bda){
return ESP_ERR_INVALID_SIZE;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_ACT_UPDATE_WHITE_LIST;

View file

@ -97,6 +97,7 @@ typedef enum {
ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT, /*!< When clear the bond device clear complete, the event comes */
ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT, /*!< When get the bond device list complete, the event comes */
ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT, /*!< When read the rssi complete, the event comes */
ESP_GAP_BLE_ADD_WHITELIST_COMPLETE_EVT, /*!< When add or remove whitelist complete, the event comes */
ESP_GAP_BLE_EVT_MAX,
} esp_gap_ble_cb_event_t;
@ -178,10 +179,20 @@ typedef enum {
/* relate to BTA_DM_BLE_SEC_xxx in bta_api.h */
typedef enum {
ESP_BLE_SEC_NONE = 0, /* relate to BTA_DM_BLE_SEC_NONE in bta_api.h */
ESP_BLE_SEC_ENCRYPT, /* relate to BTA_DM_BLE_SEC_ENCRYPT in bta_api.h */
ESP_BLE_SEC_ENCRYPT_NO_MITM, /* relate to BTA_DM_BLE_SEC_ENCRYPT_NO_MITM in bta_api.h */
ESP_BLE_SEC_ENCRYPT_MITM, /* relate to BTA_DM_BLE_SEC_ENCRYPT_MITM in bta_api.h */
ESP_BLE_SEC_ENCRYPT = 1, /* relate to BTA_DM_BLE_SEC_ENCRYPT in bta_api.h. If the device has already
bonded, the stack will used LTK to encrypt with the remote device directly.
Else if the device hasn't bonded, the stack will used the default authentication request
used the esp_ble_gap_set_security_param function set by the user. */
ESP_BLE_SEC_ENCRYPT_NO_MITM, /* relate to BTA_DM_BLE_SEC_ENCRYPT_NO_MITM in bta_api.h. If the device has already
bonded, the stack will check the LTK Whether the authentication request has been met, if met, used the LTK
to encrypt with the remote device directly, else Re-pair with the remote device.
Else if the device hasn't bonded, the stack will used NO MITM authentication request in the current link instead of
used the authreq in the esp_ble_gap_set_security_param function set by the user. */
ESP_BLE_SEC_ENCRYPT_MITM, /* relate to BTA_DM_BLE_SEC_ENCRYPT_MITM in bta_api.h. If the device has already
bonded, the stack will check the LTK Whether the authentication request has been met, if met, used the LTK
to encrypt with the remote device directly, else Re-pair with the remote device.
Else if the device hasn't bonded, the stack will used MITM authentication request in the current link instead of
used the authreq in the esp_ble_gap_set_security_param function set by the user. */
}esp_ble_sec_act_t;
typedef enum {
@ -462,6 +473,10 @@ typedef enum {
ESP_BLE_EVT_SCAN_RSP = 0x04, /*!< Scan Response (SCAN_RSP) */
} esp_ble_evt_type_t;
typedef enum{
ESP_BLE_WHITELIST_REMOVE = 0X00, /*!< remove mac from whitelist */
ESP_BLE_WHITELIST_ADD = 0X01, /*!< add address to whitelist */
}esp_ble_wl_opration;
/**
* @brief Gap callback parameters union
*/
@ -600,6 +615,13 @@ typedef union {
if the RSSI cannot be read, the RSSI metric shall be set to 127. */
esp_bd_addr_t remote_addr; /*!< The remote device address */
} read_rssi_cmpl; /*!< Event parameter of ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT */
/**
* @brief ESP_GAP_BLE_ADD_WHITELIST_COMPLETE_EVT
*/
struct ble_add_whitelist_cmpl_evt_param {
esp_bt_status_t status; /*!< Indicate the add or remove whitelist operation success status */
esp_ble_wl_opration wl_opration; /*!< The value is ESP_BLE_WHITELIST_ADD if add address to whitelist operation success, ESP_BLE_WHITELIST_REMOVE if remove address from the whitelist operation success */
} add_whitelist_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADD_WHITELIST_COMPLETE_EVT */
} esp_ble_gap_cb_param_t;
/**
@ -864,9 +886,9 @@ esp_err_t esp_ble_gap_read_rssi(esp_bd_addr_t remote_addr);
/**
* @brief Set a GAP security parameter value. Overrides the default value.
*
* @param[in] param_type :L the type of the param which to be set
* @param[in] param_type : the type of the param which to be set
* @param[in] value : the param value
* @param[out] len : the length of the param value
* @param[in] len : the length of the param value
*
* @return - ESP_OK : success
* - other : failed
@ -972,6 +994,12 @@ esp_err_t esp_ble_get_bond_device_list(int *dev_num, esp_ble_bond_dev_t *dev_lis
/**
* @brief This function is to disconnect the physical connection of the peer device
* gattc maybe have multiple virtual GATT server connections when multiple app_id registed.
* esp_ble_gattc_close (esp_gatt_if_t gattc_if, uint16_t conn_id) only close one virtual GATT server connection.
* if there exist other virtual GATT server connections, it does not disconnect the physical connection.
* esp_ble_gap_disconnect(esp_bd_addr_t remote_device) disconnect the physical connection directly.
*
*
*
* @param[in] remote_device : BD address of the peer device
*

View file

@ -63,6 +63,7 @@ typedef enum {
ESP_GATTC_UNREG_FOR_NOTIFY_EVT = 39, /*!< When unregister for notification of a service completes, the event comes */
ESP_GATTC_CONNECT_EVT = 40, /*!< When the ble physical connection is set up, the event comes */
ESP_GATTC_DISCONNECT_EVT = 41, /*!< When the ble physical connection disconnected, the event comes */
ESP_GATTC_READ_MUTIPLE_EVT = 42, /*!< When the ble characteristic or descriptor mutiple complete, the event comes */
} esp_gattc_cb_event_t;
@ -200,7 +201,6 @@ typedef union {
* @brief ESP_GATTC_CONNECT_EVT
*/
struct gattc_connect_evt_param {
esp_gatt_status_t status; /*!< Operation status */
uint16_t conn_id; /*!< Connection id */
esp_bd_addr_t remote_bda; /*!< Remote bluetooth device address */
} connect; /*!< Gatt client callback param of ESP_GATTC_CONNECT_EVT */
@ -209,7 +209,7 @@ typedef union {
* @brief ESP_GATTC_DISCONNECT_EVT
*/
struct gattc_disconnect_evt_param {
esp_gatt_status_t status; /*!< Operation status */
esp_gatt_conn_reason_t reason; /*!< disconnection reason */
uint16_t conn_id; /*!< Connection id */
esp_bd_addr_t remote_bda; /*!< Remote bluetooth device address */
} disconnect; /*!< Gatt client callback param of ESP_GATTC_DISCONNECT_EVT */

View file

@ -119,6 +119,8 @@ typedef union {
struct gatts_conf_evt_param {
esp_gatt_status_t status; /*!< Operation status */
uint16_t conn_id; /*!< Connection id */
uint16_t len; /*!< The indication or notification value length, len is valid when send notification or indication failed */
uint8_t *value; /*!< The indication or notification value , value is valid when send notification or indication failed */
} conf; /*!< Gatt server callback param of ESP_GATTS_CONF_EVT (confirm) */
/**
@ -193,7 +195,6 @@ typedef union {
struct gatts_connect_evt_param {
uint16_t conn_id; /*!< Connection id */
esp_bd_addr_t remote_bda; /*!< Remote bluetooth device address */
bool is_connected; /*!< Indicate it is connected or not */
} connect; /*!< Gatt server callback param of ESP_GATTS_CONNECT_EVT */
/**
@ -202,7 +203,7 @@ typedef union {
struct gatts_disconnect_evt_param {
uint16_t conn_id; /*!< Connection id */
esp_bd_addr_t remote_bda; /*!< Remote bluetooth device address */
bool is_connected; /*!< Indicate it is connected or not */
esp_gatt_conn_reason_t reason; /*!< Indicate the reason of disconnection */
} disconnect; /*!< Gatt server callback param of ESP_GATTS_DISCONNECT_EVT */
/**

View file

@ -525,7 +525,7 @@ void bta_dm_set_dev_name (tBTA_DM_MSG *p_data)
void bta_dm_update_white_list(tBTA_DM_MSG *p_data)
{
BTM_BleUpdateAdvWhitelist(p_data->white_list.add_remove, p_data->white_list.remote_addr);
BTM_BleUpdateAdvWhitelist(p_data->white_list.add_remove, p_data->white_list.remote_addr, p_data->white_list.add_wl_cb);
}
void bta_dm_ble_read_adv_tx_power(tBTA_DM_MSG *p_data)
@ -646,7 +646,6 @@ void bta_dm_process_remove_device(BD_ADDR bd_addr)
if (bta_dm_cb.p_sec_cback) {
tBTA_DM_SEC sec_event;
bdcpy(sec_event.link_down.bd_addr, bd_addr);
/* No connection, set status to success (acl disc code not valid) */
sec_event.link_down.status = HCI_SUCCESS;
bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &sec_event);
}
@ -4659,6 +4658,47 @@ void bta_dm_ble_observe (tBTA_DM_MSG *p_data)
}
}
}
/*******************************************************************************
**
** Function bta_dm_ble_scan
**
** Description This function set the preferred connection scan parameters.
**
** Parameters:
**
*******************************************************************************/
void bta_dm_ble_scan (tBTA_DM_MSG *p_data)
{
tBTM_STATUS status;
if (p_data->ble_scan.start) {
/*Save the callback to be called when a scan results are available */
bta_dm_search_cb.p_scan_cback = p_data->ble_scan.p_cback;
if ((status = BTM_BleScan(TRUE, p_data->ble_scan.duration,
bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb)) != BTM_CMD_STARTED) {
APPL_TRACE_WARNING(" %s start scan failed. status=0x%x\n", __FUNCTION__, status);
}
if (p_data->ble_scan.p_start_scan_cback) {
status = (status == BTM_CMD_STARTED ? BTA_SUCCESS : BTA_FAILURE);
p_data->ble_scan.p_start_scan_cback(status);
}
} else {
bta_dm_search_cb.p_scan_cback = NULL;
status = BTM_BleScan(FALSE, 0, NULL, NULL);
if (status != BTM_CMD_STARTED){
APPL_TRACE_WARNING(" %s stop scan failed, status=0x%x\n", __FUNCTION__, status);
}
if (p_data->ble_scan.p_stop_scan_cback) {
status = (status == BTM_CMD_STARTED ? BTA_SUCCESS : BTA_FAILURE);
p_data->ble_scan.p_stop_scan_cback(status);
}
}
}
/*******************************************************************************
**
** Function bta_dm_ble_set_adv_params

View file

@ -183,12 +183,13 @@ void BTA_DmSetDeviceName(char *p_name)
}
void BTA_DmUpdateWhiteList(BOOLEAN add_remove, BD_ADDR remote_addr)
void BTA_DmUpdateWhiteList(BOOLEAN add_remove, BD_ADDR remote_addr, tBTA_ADD_WHITELIST_CBACK *add_wl_cb)
{
tBTA_DM_API_UPDATE_WHITE_LIST *p_msg;
if ((p_msg = (tBTA_DM_API_UPDATE_WHITE_LIST *)osi_malloc(sizeof(tBTA_DM_API_UPDATE_WHITE_LIST))) != NULL) {
p_msg->hdr.event = BTA_DM_API_UPDATE_WHITE_LIST_EVT;
p_msg->add_remove = add_remove;
p_msg->add_wl_cb = add_wl_cb;
memcpy(p_msg->remote_addr, remote_addr, sizeof(BD_ADDR));
bta_sys_sendmsg(p_msg);
@ -2209,6 +2210,47 @@ extern void BTA_DmBleObserve(BOOLEAN start, UINT32 duration,
}
}
/*******************************************************************************
**
** Function BTA_DmBleScan
**
** Description This procedure keep the device listening for advertising
** events from a broadcast device.
**
** Parameters start: start or stop scan.
**
** Returns void
**
** Returns void.
**
*******************************************************************************/
extern void BTA_DmBleScan(BOOLEAN start, UINT32 duration,
tBTA_DM_SEARCH_CBACK *p_results_cb,
tBTA_START_STOP_SCAN_CMPL_CBACK *p_start_stop_scan_cb)
{
tBTA_DM_API_BLE_SCAN *p_msg;
APPL_TRACE_API("BTA_DmBleScan:start = %d ", start);
if ((p_msg = (tBTA_DM_API_BLE_SCAN *) osi_malloc(sizeof(tBTA_DM_API_BLE_SCAN))) != NULL) {
memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SCAN));
p_msg->hdr.event = BTA_DM_API_BLE_SCAN_EVT;
p_msg->start = start;
p_msg->duration = duration;
p_msg->p_cback = p_results_cb;
if (start){
p_msg->p_start_scan_cback = p_start_stop_scan_cb;
}
else {
p_msg->p_stop_scan_cback = p_start_stop_scan_cb;
}
bta_sys_sendmsg(p_msg);
}
}
/*******************************************************************************
**
** Function BTA_DmBleStopAdvertising

View file

@ -97,6 +97,7 @@ enum {
support the scan filter setting for the APP******/
BTA_DM_API_BLE_SCAN_FIL_PARAM_EVT,
BTA_DM_API_BLE_OBSERVE_EVT,
BTA_DM_API_BLE_SCAN_EVT,
BTA_DM_API_UPDATE_CONN_PARAM_EVT,
/*******This event added by Yulong at 2016/9/9 to
support the random address setting for the APP******/
@ -183,6 +184,7 @@ typedef struct {
BT_HDR hdr;
BOOLEAN add_remove;
BD_ADDR remote_addr;
tBTA_ADD_WHITELIST_CBACK *add_wl_cb;
}tBTA_DM_API_UPDATE_WHITE_LIST;
typedef struct {
@ -506,6 +508,17 @@ typedef struct {
tBTA_START_STOP_ADV_CMPL_CBACK *p_stop_adv_cback;
} tBTA_DM_API_BLE_OBSERVE;
/* Data type for start/stop scan */
typedef struct {
BT_HDR hdr;
BOOLEAN start;
UINT32 duration;
tBTA_DM_SEARCH_CBACK *p_cback;
tBTA_START_STOP_SCAN_CMPL_CBACK *p_start_scan_cback;
tBTA_START_STOP_SCAN_CMPL_CBACK *p_stop_scan_cback;
tBTA_START_STOP_ADV_CMPL_CBACK *p_stop_adv_cback;
} tBTA_DM_API_BLE_SCAN;
typedef struct {
BT_HDR hdr;
BD_ADDR remote_bda;
@ -758,6 +771,7 @@ typedef union {
tBTA_DM_API_BLE_SCAN_PARAMS ble_set_scan_params;
tBTA_DM_API_BLE_SCAN_FILTER_PARAMS ble_set_scan_fil_params;
tBTA_DM_API_BLE_OBSERVE ble_observe;
tBTA_DM_API_BLE_SCAN ble_scan;
tBTA_DM_API_ENABLE_PRIVACY ble_remote_privacy;
tBTA_DM_API_LOCAL_PRIVACY ble_local_privacy;
tBTA_DM_API_BLE_ADV_PARAMS ble_set_adv_params;
@ -1158,6 +1172,7 @@ extern void bta_dm_ble_set_conn_scan_params (tBTA_DM_MSG *p_data);
extern void bta_dm_close_gatt_conn(tBTA_DM_MSG *p_data);
#endif /* ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) && SDP_INCLUDED == TRUE) && (GATTC_INCLUDED == TRUE) */
extern void bta_dm_ble_observe (tBTA_DM_MSG *p_data);
extern void bta_dm_ble_scan (tBTA_DM_MSG *p_data);
extern void bta_dm_ble_update_conn_params (tBTA_DM_MSG *p_data);
extern void bta_dm_ble_disconnect (tBTA_DM_MSG *p_data);
extern void bta_dm_ble_set_rand_address(tBTA_DM_MSG *p_data);

View file

@ -91,6 +91,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = {
bta_dm_ble_set_scan_params, /* BTA_DM_API_BLE_SCAN_PARAM_EVT */
bta_dm_ble_set_scan_fil_params, /* BTA_DM_API_BLE_SCAN_FIL_PARAM_EVT */
bta_dm_ble_observe, /* BTA_DM_API_BLE_OBSERVE_EVT*/
bta_dm_ble_scan, /* BTA_DM_API_BLE_SCAN_EVT */
bta_dm_ble_update_conn_params, /* BTA_DM_API_UPDATE_CONN_PARAM_EVT */
/* This handler function added by
Yulong at 2016/9/9 to support the

View file

@ -84,7 +84,8 @@ static UINT16 bta_gattc_opcode_to_int_evt[] = {
BTA_GATTC_API_READ_EVT,
BTA_GATTC_API_WRITE_EVT,
BTA_GATTC_API_EXEC_EVT,
BTA_GATTC_API_CFG_MTU_EVT
BTA_GATTC_API_CFG_MTU_EVT,
BTA_GATTC_API_READ_MULTI_EVT
};
#if (BT_TRACE_VERBOSE == TRUE)
@ -711,7 +712,6 @@ void bta_gattc_conncback(tBTA_GATTC_RCB *p_rcb, tBTA_GATTC_DATA *p_data)
{
if (p_rcb) {
bta_gattc_send_connect_cback(p_rcb,
BTA_GATT_OK,
p_data->int_conn.remote_bda,
p_data->int_conn.hdr.layer_specific);
@ -730,7 +730,7 @@ void bta_gattc_disconncback(tBTA_GATTC_RCB *p_rcb, tBTA_GATTC_DATA *p_data)
{
if (p_rcb) {
bta_gattc_send_disconnect_cback(p_rcb,
BTA_GATT_OK,
p_data->int_conn.reason,
p_data->int_conn.remote_bda,
p_data->int_conn.hdr.layer_specific);
@ -793,7 +793,7 @@ void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
if (p_data->hdr.event == BTA_GATTC_API_CLOSE_EVT) {
cb_data.close.status = GATT_Disconnect(p_data->hdr.layer_specific);
} else if (p_data->hdr.event == BTA_GATTC_INT_DISCONN_EVT) {
cb_data.close.status = p_data->int_conn.reason;
cb_data.close.status = BTA_GATT_OK;
cb_data.close.reason = p_data->int_conn.reason;
}
@ -1228,8 +1228,12 @@ void bta_gattc_read_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
} else {
cb_data.read.handle = p_clcb->p_q_cmd->api_read.handle;
}
event = p_clcb->p_q_cmd->api_read.cmpl_evt;
if (p_clcb->p_q_cmd->hdr.event != BTA_GATTC_API_READ_MULTI_EVT) {
event = p_clcb->p_q_cmd->api_read.cmpl_evt;
} else {
event = p_clcb->p_q_cmd->api_read_multi.cmpl_evt;
}
cb_data.read.conn_id = p_clcb->bta_conn_id;
//free the command data store in the queue.
bta_gattc_free_command_data(p_clcb);
@ -1350,20 +1354,22 @@ void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
return;
}
if (p_clcb->p_q_cmd->hdr.event != bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) {
mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ;
if ( mapped_op > GATTC_OPTYPE_INDICATION) {
mapped_op = 0;
}
if (p_clcb->p_q_cmd->hdr.event != BTA_GATTC_API_READ_MULTI_EVT) {
mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ;
if ( mapped_op > GATTC_OPTYPE_INDICATION) {
mapped_op = 0;
}
#if (BT_TRACE_VERBOSE == TRUE)
APPL_TRACE_ERROR("expect op:(%s :0x%04x), receive unexpected operation (%s).",
bta_gattc_op_code_name[mapped_op] , p_clcb->p_q_cmd->hdr.event,
bta_gattc_op_code_name[op]);
APPL_TRACE_ERROR("expect op:(%s :0x%04x), receive unexpected operation (%s).",
bta_gattc_op_code_name[mapped_op] , p_clcb->p_q_cmd->hdr.event,
bta_gattc_op_code_name[op]);
#else
APPL_TRACE_ERROR("expect op:(%u :0x%04x), receive unexpected operation (%u).",
mapped_op , p_clcb->p_q_cmd->hdr.event, op);
APPL_TRACE_ERROR("expect op:(%u :0x%04x), receive unexpected operation (%u).",
mapped_op , p_clcb->p_q_cmd->hdr.event, op);
#endif
return;
return;
}
}
/* discard responses if service change indication is received before operation completed */

View file

@ -545,7 +545,7 @@ void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_read_multi,
p_buf->hdr.layer_specific = conn_id;
p_buf->auth_req = auth_req;
p_buf->num_attr = p_read_multi->num_attr;
p_buf->cmpl_evt = BTA_GATTC_READ_MUTIPLE_EVT;
if (p_buf->num_attr > 0) {
memcpy(p_buf->handles, p_read_multi->handles, sizeof(UINT16) * p_read_multi->num_attr);
}

View file

@ -187,6 +187,7 @@ tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb)
p_srvc_cb->cur_srvc_idx = 0;
p_srvc_cb->cur_char_idx = 0;
p_srvc_cb->next_avail_idx = 0;
p_srvc_cb->total_attr = 0;
}
return BTA_GATT_OK;

View file

@ -718,15 +718,13 @@ void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status
** Returns
**
*******************************************************************************/
void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status,
BD_ADDR remote_bda, UINT16 conn_id)
void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, BD_ADDR remote_bda, UINT16 conn_id)
{
tBTA_GATTC cb_data;
if (p_clreg->p_cback) {
memset(&cb_data, 0, sizeof(tBTA_GATTC));
cb_data.connect.status = status;
cb_data.connect.client_if = p_clreg->client_if;
cb_data.connect.conn_id = conn_id;
bdcpy(cb_data.connect.remote_bda, remote_bda);
@ -744,7 +742,7 @@ void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS sta
** Returns
**
*******************************************************************************/
void bta_gattc_send_disconnect_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status,
void bta_gattc_send_disconnect_cback( tBTA_GATTC_RCB *p_clreg, tGATT_DISCONN_REASON reason,
BD_ADDR remote_bda, UINT16 conn_id)
{
tBTA_GATTC cb_data;
@ -752,7 +750,7 @@ void bta_gattc_send_disconnect_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS
if (p_clreg->p_cback) {
memset(&cb_data, 0, sizeof(tBTA_GATTC));
cb_data.disconnect.status = status;
cb_data.disconnect.reason = reason;
cb_data.disconnect.client_if = p_clreg->client_if;
cb_data.disconnect.conn_id = conn_id;
bdcpy(cb_data.disconnect.remote_bda, remote_bda);

View file

@ -692,6 +692,15 @@ void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
cb_data.req_data.status = status;
cb_data.req_data.conn_id = p_msg->api_indicate.hdr.layer_specific;
cb_data.req_data.value =(uint8_t *)osi_malloc(p_msg->api_indicate.len);
if (cb_data.req_data.value != NULL){
memset(cb_data.req_data.value, 0, p_msg->api_indicate.len);
cb_data.req_data.data_len = p_msg->api_indicate.len;
memcpy(cb_data.req_data.value, p_msg->api_indicate.value, p_msg->api_indicate.len);
}else{
cb_data.req_data.data_len = 0;
APPL_TRACE_ERROR("%s, malloc failed", __func__);
}
(*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
}
} else {

View file

@ -474,8 +474,10 @@ void BTA_GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id,
void BTA_SetAttributeValue(UINT16 attr_handle, UINT16 length, UINT8 *value)
{
tBTA_GATTS_API_SET_ATTR_VAL *p_buf;
UINT16 len = sizeof(tBTA_GATTS_API_SET_ATTR_VAL);
if((p_buf = (tBTA_GATTS_API_SET_ATTR_VAL *)osi_malloc(
sizeof(tBTA_GATTS_API_SET_ATTR_VAL))) != NULL){
memset(p_buf, 0, len);
p_buf->hdr.event = BTA_GATTS_API_SET_ATTR_VAL_EVT;
p_buf->hdr.layer_specific = attr_handle;
p_buf->length = length;

View file

@ -402,6 +402,8 @@ typedef void (tBTA_SET_ADV_DATA_CMPL_CBACK) (tBTA_STATUS status);
typedef void (tBTA_START_ADV_CMPL_CBACK) (tBTA_STATUS status);
typedef tBTM_ADD_WHITELIST_CBACK tBTA_ADD_WHITELIST_CBACK;
typedef tBTM_SET_PKT_DATA_LENGTH_CBACK tBTA_SET_PKT_DATA_LENGTH_CBACK;
typedef tBTM_SET_LOCAL_PRIVACY_CBACK tBTA_SET_LOCAL_PRIVACY_CBACK;
@ -1410,7 +1412,7 @@ extern void BTA_DisableTestMode(void);
*******************************************************************************/
extern void BTA_DmSetDeviceName(char *p_name);
extern void BTA_DmUpdateWhiteList(BOOLEAN add_remove, BD_ADDR remote_addr);
extern void BTA_DmUpdateWhiteList(BOOLEAN add_remove, BD_ADDR remote_addr, tBTA_ADD_WHITELIST_CBACK *add_wl_cb);
extern void BTA_DmBleReadAdvTxPower(tBTA_CMPL_CB *cmpl_cb);
@ -2034,6 +2036,24 @@ extern void BTA_DmBleObserve(BOOLEAN start, UINT32 duration,
tBTA_DM_SEARCH_CBACK *p_results_cb,
tBTA_START_STOP_SCAN_CMPL_CBACK *p_start_stop_scan_cb);
/*******************************************************************************
**
** Function BTA_DmBleScan
**
** Description This procedure keep the device listening for advertising
** events from a broadcast device.
**
** Parameters start: start or stop observe.
** duration : Duration of the scan. Continuous scan if 0 is passed
** p_results_cb: Callback to be called with scan results
**
** Returns void
**
*******************************************************************************/
extern void BTA_DmBleScan(BOOLEAN start, UINT32 duration,
tBTA_DM_SEARCH_CBACK *p_results_cb,
tBTA_START_STOP_SCAN_CMPL_CBACK *p_start_stop_scan_cb);
extern void BTA_DmBleStopAdvertising(void);
extern void BTA_DmSetRandAddress(BD_ADDR rand_addr);

View file

@ -181,6 +181,7 @@ typedef UINT8 tBTA_GATT_STATUS;
#define BTA_GATTC_ADV_VSC_EVT 34 /* ADV VSC event */
#define BTA_GATTC_CONNECT_EVT 35 /* GATTC CONNECT event */
#define BTA_GATTC_DISCONNECT_EVT 36 /* GATTC DISCONNECT event */
#define BTA_GATTC_READ_MUTIPLE_EVT 37 /* GATTC Read mutiple event */
typedef UINT8 tBTA_GATTC_EVT;
@ -366,14 +367,13 @@ typedef struct {
} tBTA_GATTC_ENC_CMPL_CB;
typedef struct {
tBTA_GATT_STATUS status;
UINT16 conn_id;
tBTA_GATTC_IF client_if;
BD_ADDR remote_bda;
} tBTA_GATTC_CONNECT;
typedef struct {
tBTA_GATT_STATUS status;
tGATT_DISCONN_REASON reason;
UINT16 conn_id;
tBTA_GATTC_IF client_if;
BD_ADDR remote_bda;
@ -522,6 +522,8 @@ typedef struct {
UINT32 trans_id;
UINT16 conn_id;
tBTA_GATTS_REQ_DATA *p_data;
UINT16 data_len;
UINT8 *value;
} tBTA_GATTS_REQ;
typedef struct {

View file

@ -72,7 +72,11 @@ typedef UINT16 tBTA_GATTC_INT_EVT;
/* max client application GATTC can support */
#ifndef BTA_GATTC_CL_MAX
#define BTA_GATTC_CL_MAX 3 // 32
#if (GATT_MAX_PHY_CHANNEL > 3)
#define BTA_GATTC_CL_MAX GATT_MAX_PHY_CHANNEL
#else
#define BTA_GATTC_CL_MAX 3 // The origin value is 10
#endif
#endif
/* max known devices GATTC can support */
@ -165,6 +169,7 @@ typedef struct {
tBTA_GATT_AUTH_REQ auth_req;
UINT8 num_attr;
UINT16 handles[GATT_MAX_READ_MULTI_HANDLES];
tBTA_GATTC_EVT cmpl_evt;
}tBTA_GATTC_API_READ_MULTI;
typedef struct {
@ -434,9 +439,8 @@ extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *
extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data);
extern void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status,
BD_ADDR remote_bda, UINT16 conn_id, tBTA_TRANSPORT transport, UINT16 mtu);
extern void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status,
BD_ADDR remote_bda, UINT16 conn_id);
extern void bta_gattc_send_disconnect_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status,
extern void bta_gattc_send_connect_cback( tBTA_GATTC_RCB *p_clreg, BD_ADDR remote_bda, UINT16 conn_id);
extern void bta_gattc_send_disconnect_cback( tBTA_GATTC_RCB *p_clreg, tGATT_DISCONN_REASON reason,
BD_ADDR remote_bda, UINT16 conn_id);
extern void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg);
extern void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data);

View file

@ -184,29 +184,29 @@ bt_status_t btc_storage_get_ble_bonding_key(bt_bdaddr_t *remote_bd_addr,
*******************************************************************************/
static bt_status_t _btc_storage_remove_ble_bonding_keys(bt_bdaddr_t *remote_bd_addr)
{
int ret = 1;
int ret = 0;
bdstr_t bdstr;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
BTIF_TRACE_DEBUG(" %s in bd addr:%s",__FUNCTION__, bdstr);
if (btc_config_exist(bdstr, BTC_BLE_STORAGE_ADDR_TYPE_STR)) {
ret &= btc_config_remove(bdstr, BTC_BLE_STORAGE_ADDR_TYPE_STR);
ret |= btc_config_remove(bdstr, BTC_BLE_STORAGE_ADDR_TYPE_STR);
}
if (btc_config_exist(bdstr, BTC_BLE_STORAGE_LE_KEY_PENC_STR)) {
ret &= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_PENC_STR);
ret |= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_PENC_STR);
}
if (btc_config_exist(bdstr, BTC_BLE_STORAGE_LE_KEY_PID_STR)) {
ret &= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_PID_STR);
ret |= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_PID_STR);
}
if (btc_config_exist(bdstr, BTC_BLE_STORAGE_LE_KEY_PCSRK_STR)) {
ret &= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_PCSRK_STR);
ret |= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_PCSRK_STR);
}
if (btc_config_exist(bdstr, BTC_BLE_STORAGE_LE_KEY_LENC_STR)) {
ret &= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_LENC_STR);
ret |= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_LENC_STR);
}
if (btc_config_exist(bdstr, BTC_BLE_STORAGE_LE_KEY_LCSRK_STR)) {
ret &= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_LCSRK_STR);
ret |= btc_config_remove(bdstr, BTC_BLE_STORAGE_LE_KEY_LCSRK_STR);
}
//here don't remove section, because config_save will check it
_btc_storage_save();

View file

@ -467,12 +467,15 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg)
LOG_ERROR("BTA_DM_DEV_UNPAIRED_EVT");
memcpy(bd_addr.address, p_data->link_down.bd_addr, sizeof(BD_ADDR));
btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
//remove the bonded key in the config and nvs flash.
btc_storage_remove_ble_dev_type(&bd_addr, false);
btc_storage_remove_remote_addr_type(&bd_addr, false);
btc_storage_remove_ble_bonding_keys(&bd_addr);
param.remove_bond_dev_cmpl.status = ESP_BT_STATUS_FAIL;
if (p_data->link_down.status == HCI_SUCCESS) {
//remove the bonded key in the config and nvs flash.
btc_storage_remove_ble_dev_type(&bd_addr, false);
btc_storage_remove_remote_addr_type(&bd_addr, false);
param.remove_bond_dev_cmpl.status = btc_storage_remove_ble_bonding_keys(&bd_addr);
}
ble_msg.act = ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT;
param.remove_bond_dev_cmpl.status = (p_data->link_down.status == HCI_SUCCESS) ? ESP_BT_STATUS_SUCCESS : ESP_BT_STATUS_FAIL;
memcpy(param.remove_bond_dev_cmpl.bd_addr, p_data->link_down.bd_addr, sizeof(BD_ADDR));
#endif /* #if (SMP_INCLUDED == TRUE) */
break;

View file

@ -139,8 +139,8 @@ bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg
int btc_init(void)
{
xBtcQueue = xQueueCreate(BTC_TASK_QUEUE_NUM, sizeof(btc_msg_t));
xTaskCreatePinnedToCore(btc_task, "Btc_task", BTC_TASK_STACK_SIZE, NULL, BTC_TASK_PRIO, &xBtcTaskHandle, 0);
xBtcQueue = xQueueCreate(BTC_TASK_QUEUE_LEN, sizeof(btc_msg_t));
xTaskCreatePinnedToCore(btc_task, "Btc_task", BTC_TASK_STACK_SIZE, NULL, BTC_TASK_PRIO, &xBtcTaskHandle, BTC_TASK_PINNED_TO_CORE);
btc_gap_callback_init();
/* TODO: initial the profile_tab */

View file

@ -112,10 +112,6 @@ enum {
/* 5 frames is equivalent to 6.89*5*2.9 ~= 100 ms @ 44.1 khz, 20 ms mediatick */
#define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (5)
#define MEDIA_DATA_Q_LEN (1)
#define MEDIA_CTRL_Q_LEN (5)
#define COMBINED_MEDIA_Q_LEN (MEDIA_DATA_Q_LEN + MEDIA_CTRL_Q_LEN)
typedef struct {
UINT16 num_frames_to_be_processed;
UINT16 len;
@ -276,13 +272,13 @@ bool btc_a2dp_start_media_task(void)
APPL_TRACE_EVENT("## A2DP START MEDIA THREAD ##");
xBtcMediaQueueSet = xQueueCreateSet(COMBINED_MEDIA_Q_LEN);
xBtcMediaQueueSet = xQueueCreateSet(BTC_MEDIA_TASK_QUEUE_SET_LEN);
configASSERT(xBtcMediaQueueSet);
xBtcMediaDataQueue = xQueueCreate(MEDIA_DATA_Q_LEN, sizeof(void *));
xBtcMediaDataQueue = xQueueCreate(BTC_MEDIA_DATA_QUEUE_LEN, sizeof(void *));
configASSERT(xBtcMediaDataQueue);
xQueueAddToSet(xBtcMediaDataQueue, xBtcMediaQueueSet);
xBtcMediaCtrlQueue = xQueueCreate(MEDIA_CTRL_Q_LEN, sizeof(void *));
xBtcMediaCtrlQueue = xQueueCreate(BTC_MEDIA_CTRL_QUEUE_LEN, sizeof(void *));
configASSERT(xBtcMediaCtrlQueue);
xQueueAddToSet(xBtcMediaCtrlQueue, xBtcMediaQueueSet);

View file

@ -542,8 +542,8 @@ static void btc_ble_set_scan_params(esp_ble_scan_params_t *scan_params, tBLE_SCA
scan_params->scan_interval,
scan_params->scan_window,
scan_params->scan_type,
scan_params->own_addr_type,
scan_params->scan_filter_policy,
scan_params->own_addr_type,
scan_param_setup_cback);
} else {
btc_scan_params_callback(ESP_DEFAULT_GATT_IF, BTM_ILLEGAL_VALUE);
@ -681,6 +681,24 @@ static void btc_set_pkt_length_callback(UINT8 status, tBTM_LE_SET_PKT_DATA_LENGT
}
}
static void btc_add_whitelist_complete_callback(UINT8 status, tBTM_WL_OPERATION wl_opration)
{
esp_ble_gap_cb_param_t param;
bt_status_t ret;
btc_msg_t msg;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_GAP_BLE;
msg.act = ESP_GAP_BLE_ADD_WHITELIST_COMPLETE_EVT;
param.add_whitelist_cmpl.status = btc_hci_to_esp_status(status);
param.add_whitelist_cmpl.wl_opration = wl_opration;
ret = btc_transfer_context(&msg, &param,
sizeof(esp_ble_gap_cb_param_t), NULL);
if (ret != BT_STATUS_SUCCESS) {
LOG_ERROR("%s btc_transfer_context failed\n", __func__);
}
}
static void btc_set_local_privacy_callback(UINT8 status)
{
esp_ble_gap_cb_param_t param;
@ -741,17 +759,17 @@ static void btc_ble_start_scanning(uint32_t duration,
tBTA_START_STOP_SCAN_CMPL_CBACK *start_scan_cb)
{
if ((results_cb != NULL) && (start_scan_cb != NULL)) {
///Start scan the device
BTA_DmBleObserve(true, duration, results_cb, start_scan_cb);
//Start scan the device
BTA_DmBleScan(true, duration, results_cb, start_scan_cb);
} else {
LOG_ERROR("The scan duration or p_results_cb invalid\n");
LOG_ERROR("The start_scan_cb or results_cb invalid\n");
}
}
static void btc_ble_stop_scanning(tBTA_START_STOP_SCAN_CMPL_CBACK *stop_scan_cb)
{
uint8_t duration = 0;
BTA_DmBleObserve(false, duration, NULL, stop_scan_cb);
BTA_DmBleScan(false, duration, NULL, stop_scan_cb);
}
@ -805,14 +823,14 @@ static void btc_ble_set_rand_addr (BD_ADDR rand_addr)
BD_ADDR invalid_rand_addr_a, invalid_rand_addr_b;
memset(invalid_rand_addr_a, 0xff, sizeof(BD_ADDR));
memset(invalid_rand_addr_b, 0x00, sizeof(BD_ADDR));
invalid_rand_addr_b[BD_ADDR_LEN - 1] = invalid_rand_addr_b[BD_ADDR_LEN - 1] | BT_STATIC_RAND_ADDR_MASK;
if((rand_addr[BD_ADDR_LEN - 1] & BT_STATIC_RAND_ADDR_MASK) == BT_STATIC_RAND_ADDR_MASK
invalid_rand_addr_b[0] = invalid_rand_addr_b[0] | BT_STATIC_RAND_ADDR_MASK;
if((rand_addr[0] & BT_STATIC_RAND_ADDR_MASK) == BT_STATIC_RAND_ADDR_MASK
&& memcmp(invalid_rand_addr_a, rand_addr, BD_ADDR_LEN) != 0
&& memcmp(invalid_rand_addr_b, rand_addr, BD_ADDR_LEN) != 0){
BTA_DmSetRandAddress(rand_addr);
} else {
param.set_rand_addr_cmpl.status = ESP_BT_STATUS_INVALID_STATIC_RAND_ADDR;
LOG_ERROR("Invalid random address, the high bit should be 0b11, the random part shall not be to 1 or 0");
LOG_ERROR("Invalid random address, the high bit should be 0b11, all bits of the random part shall not be to 1 or 0");
}
} else {
param.set_rand_addr_cmpl.status = ESP_BT_STATUS_INVALID_STATIC_RAND_ADDR;
@ -1031,7 +1049,7 @@ void btc_gap_ble_call_handler(btc_msg_t *msg)
btc_ble_config_local_privacy(arg->cfg_local_privacy.privacy_enable, btc_set_local_privacy_callback);
break;
case BTC_GAP_BLE_ACT_UPDATE_WHITE_LIST:
BTA_DmUpdateWhiteList(arg->update_white_list.add_remove, arg->update_white_list.remote_bda);
BTA_DmUpdateWhiteList(arg->update_white_list.add_remove, arg->update_white_list.remote_bda, btc_add_whitelist_complete_callback);
break;
case BTC_GAP_BLE_ACT_READ_RSSI:
BTA_DmBleReadRSSI(arg->read_rssi.remote_addr, btc_read_ble_rssi_cmpl_callback);

View file

@ -128,7 +128,8 @@ static void btc_gattc_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src)
// Allocate buffer for request data if necessary
switch (msg->act) {
case BTA_GATTC_READ_DESCR_EVT:
case BTA_GATTC_READ_CHAR_EVT: {
case BTA_GATTC_READ_CHAR_EVT:
case BTA_GATTC_READ_MUTIPLE_EVT: {
if (p_src_data->read.p_value && p_src_data->read.p_value->p_value) {
p_dest_data->read.p_value = (tBTA_GATT_UNFMT *)osi_malloc(sizeof(tBTA_GATT_UNFMT) + p_src_data->read.p_value->len);
p_dest_data->read.p_value->p_value = (uint8_t *)(p_dest_data->read.p_value + 1);
@ -151,7 +152,8 @@ static void btc_gattc_free_req_data(btc_msg_t *msg)
tBTA_GATTC *arg = (tBTA_GATTC *)(msg->arg);
switch (msg->act) {
case BTA_GATTC_READ_DESCR_EVT:
case BTA_GATTC_READ_CHAR_EVT: {
case BTA_GATTC_READ_CHAR_EVT:
case BTA_GATTC_READ_MUTIPLE_EVT: {
if (arg->read.p_value) {
osi_free(arg->read.p_value);
}
@ -554,6 +556,7 @@ esp_gatt_status_t btc_ble_gattc_get_db(uint16_t conn_id, uint16_t start_handle,
db[i].attribute_handle = get_db[i].id;
db[i].start_handle = get_db[i].start_handle;
db[i].end_handle = get_db[i].end_handle;
db[i].properties = get_db[i].properties;
btc128_to_bta_uuid(&bta_uuid, get_db[i].uuid.uu);
bta_to_btc_uuid(&db[i].uuid, &bta_uuid);
}
@ -806,6 +809,11 @@ void btc_gattc_cb_handler(btc_msg_t *msg)
btc_gattc_cb_to_app(ESP_GATTC_READ_DESCR_EVT, gattc_if, &param);
break;
}
case BTA_GATTC_READ_MUTIPLE_EVT: {
set_read_value(&gattc_if, &param, &arg->read);
btc_gattc_cb_to_app(ESP_GATTC_READ_MUTIPLE_EVT, gattc_if, &param);
break;
}
case BTA_GATTC_WRITE_DESCR_EVT: {
tBTA_GATTC_WRITE *write = &arg->write;
@ -850,7 +858,6 @@ void btc_gattc_cb_handler(btc_msg_t *msg)
tBTA_GATTC_CONNECT *connect = &arg->connect;
gattc_if = connect->client_if;
param.connect.status = connect->status;
param.connect.conn_id = BTC_GATT_GET_CONN_ID(connect->conn_id);
memcpy(param.connect.remote_bda, connect->remote_bda, sizeof(esp_bd_addr_t));
btc_gattc_cb_to_app(ESP_GATTC_CONNECT_EVT, gattc_if, &param);
@ -871,7 +878,7 @@ void btc_gattc_cb_handler(btc_msg_t *msg)
tBTA_GATTC_DISCONNECT *disconnect = &arg->disconnect;
gattc_if = disconnect->client_if;
param.disconnect.status = disconnect->status;
param.disconnect.reason = disconnect->reason;
param.disconnect.conn_id = BTC_GATT_GET_CONN_ID(disconnect->conn_id);
memcpy(param.disconnect.remote_bda, disconnect->remote_bda, sizeof(esp_bd_addr_t));
btc_gattc_cb_to_app(ESP_GATTC_DISCONNECT_EVT, gattc_if, &param);

View file

@ -527,6 +527,11 @@ static void btc_gatts_cb_param_copy_free(btc_msg_t *msg, tBTA_GATTS *p_data)
osi_free(p_data->req_data.p_data);
}
break;
case BTA_GATTS_CONF_EVT:
if (p_data && p_data->req_data.value){
osi_free(p_data->req_data.value);
}
break;
default:
break;
}
@ -787,6 +792,12 @@ void btc_gatts_cb_handler(btc_msg_t *msg)
param.conf.conn_id = BTC_GATT_GET_CONN_ID(p_data->req_data.conn_id);
param.conf.status = p_data->req_data.status;
if (p_data->req_data.status != ESP_GATT_OK && p_data->req_data.value){
param.conf.len = p_data->req_data.data_len;
param.conf.value = p_data->req_data.value;
}else{
param.conf.len = 0;
}
btc_gatts_cb_to_app(ESP_GATTS_CONF_EVT, gatts_if, &param);
break;
case BTA_GATTS_CREATE_EVT:
@ -849,7 +860,6 @@ void btc_gatts_cb_handler(btc_msg_t *msg)
case BTA_GATTS_CONNECT_EVT:
gatts_if = p_data->conn.server_if;
param.connect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
param.connect.is_connected = true;
memcpy(param.connect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN);
btc_gatts_cb_to_app(ESP_GATTS_CONNECT_EVT, gatts_if, &param);
@ -857,7 +867,7 @@ void btc_gatts_cb_handler(btc_msg_t *msg)
case BTA_GATTS_DISCONNECT_EVT:
gatts_if = p_data->conn.server_if;
param.disconnect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
param.disconnect.is_connected = false;
param.disconnect.reason = p_data->conn.reason;
memcpy(param.disconnect.remote_bda, p_data->conn.remote_bda, ESP_BD_ADDR_LEN);
btc_gatts_cb_to_app(ESP_GATTS_DISCONNECT_EVT, gatts_if, &param);

View file

@ -442,9 +442,7 @@ void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap,
/* *p_auth_req by default is FALSE for devices with NoInputNoOutput; TRUE for other devices. */
if (bte_appl_cfg.ble_auth_req) {
*p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04);
}
*p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & BTA_LE_AUTH_REQ_MITM) | ((*p_auth_req) & BTA_LE_AUTH_REQ_MITM);
if (bte_appl_cfg.ble_io_cap <= 4) {
*p_io_cap = bte_appl_cfg.ble_io_cap;

View file

@ -101,8 +101,8 @@ static bool hal_open(const hci_hal_callbacks_t *upper_callbacks)
hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX);
xHciH4Queue = xQueueCreate(HCI_H4_QUEUE_NUM, sizeof(BtTaskEvt_t));
xTaskCreatePinnedToCore(hci_hal_h4_rx_handler, HCI_H4_TASK_NAME, HCI_H4_TASK_STACK_SIZE, NULL, HCI_H4_TASK_PRIO, &xHciH4TaskHandle, 0);
xHciH4Queue = xQueueCreate(HCI_H4_QUEUE_LEN, sizeof(BtTaskEvt_t));
xTaskCreatePinnedToCore(hci_hal_h4_rx_handler, HCI_H4_TASK_NAME, HCI_H4_TASK_STACK_SIZE, NULL, HCI_H4_TASK_PRIO, &xHciH4TaskHandle, HCI_H4_TASK_PINNED_TO_CORE);
//register vhci host cb
esp_vhci_host_register_callback(&vhci_host_cb);

View file

@ -107,8 +107,8 @@ int hci_start_up(void)
goto error;
}
xHciHostQueue = xQueueCreate(HCI_HOST_QUEUE_NUM, sizeof(BtTaskEvt_t));
xTaskCreatePinnedToCore(hci_host_thread_handler, HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, NULL, HCI_HOST_TASK_PRIO, &xHciHostTaskHandle, 0);
xHciHostQueue = xQueueCreate(HCI_HOST_QUEUE_LEN, sizeof(BtTaskEvt_t));
xTaskCreatePinnedToCore(hci_host_thread_handler, HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, NULL, HCI_HOST_TASK_PRIO, &xHciHostTaskHandle, HCI_HOST_TASK_PINNED_TO_CORE);
packet_fragmenter->init(&packet_fragmenter_callbacks);
hal->open(&hal_callbacks);

View file

@ -681,11 +681,15 @@
/* The maximum number of simultaneous channels that L2CAP can support. Up to 16*/
#ifndef MAX_L2CAP_CHANNELS
#if (CLASSIC_BT_INCLUDED == TRUE)
#define MAX_L2CAP_CHANNELS 8
#define MAX_L2CAP_CHANNELS 16
#else
#if (SMP_INCLUDED == FALSE)
#define MAX_L2CAP_CHANNELS MAX_ACL_CONNECTIONS //This is used in the BLE client when start connected with the peer device
#else
#define MAX_L2CAP_CHANNELS (MAX_ACL_CONNECTIONS * 2) //This is used in the BLE client when start connected with the peer device and in SMP
#endif ///SMP_INCLUDED == FALSE
#endif ///CLASSIC_BT_INCLUDED == TRUE
#endif
#endif ///MAX_L2CAP_CHANNELS
/* The maximum number of simultaneous applications that can register with L2CAP. */
#ifndef MAX_L2CAP_CLIENTS

View file

@ -57,26 +57,39 @@ typedef enum {
SIG_BTU_NUM,
} SIG_BTU_t;
#define TASK_PINNED_TO_CORE (CONFIG_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY)
#define HCI_HOST_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE)
#define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE)
#define HCI_HOST_TASK_PRIO (configMAX_PRIORITIES - 3)
#define HCI_HOST_TASK_NAME "hciHostT"
#define HCI_HOST_QUEUE_NUM 40
#define HCI_HOST_QUEUE_LEN 40
#define HCI_H4_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE)
#define HCI_H4_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE)
#define HCI_H4_TASK_PRIO (configMAX_PRIORITIES - 4)
#define HCI_H4_TASK_NAME "hciH4T"
#define HCI_H4_QUEUE_NUM 60
#define HCI_H4_QUEUE_LEN 60
#define BTU_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE)
#define BTU_TASK_STACK_SIZE (4096 + BT_TASK_EXTRA_STACK_SIZE)
#define BTU_TASK_PRIO (configMAX_PRIORITIES - 5)
#define BTU_TASK_NAME "btuT"
#define BTU_QUEUE_NUM 50
#define BTU_QUEUE_LEN 50
#define BTC_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE)
#define BTC_TASK_STACK_SIZE (CONFIG_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig
#define BTC_TASK_NAME "btcT"
#define BTC_TASK_PRIO (configMAX_PRIORITIES - 6)
#define BTC_TASK_QUEUE_NUM 60
#define BTC_TASK_QUEUE_LEN 60
#define BTC_MEDIA_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE)
#define BTC_MEDIA_TASK_STACK_SIZE (CONFIG_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE)
#define BTC_MEDIA_TASK_NAME "BtcMediaT"
#define BTC_MEDIA_TASK_PRIO (configMAX_PRIORITIES - 3)
#define BTC_MEDIA_DATA_QUEUE_LEN (1)
#define BTC_MEDIA_CTRL_QUEUE_LEN (5)
#define BTC_MEDIA_TASK_QUEUE_SET_LEN (BTC_MEDIA_DATA_QUEUE_LEN + BTC_MEDIA_CTRL_QUEUE_LEN)
#define TASK_POST_NON_BLOCKING (0)
#define TASK_POST_BLOCKING (portMAX_DELAY)

View file

@ -180,7 +180,11 @@ BOOLEAN BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key, tBTM_LE_
#if (BLE_PRIVACY_SPT == TRUE)
if (key_type == BTM_LE_KEY_PID || key_type == BTM_LE_KEY_LID) {
btm_ble_resolving_list_load_dev (p_dev_rec);
/* It will cause that scanner doesn't send scan request to advertiser
* which has sent IRK to us and we have stored the IRK in controller.
* It is a design problem of hardware. The temporal solution is not to
* send the key to the controller and then resolve the random address in host. */
//btm_ble_resolving_list_load_dev (p_dev_rec);
}
#endif
@ -1413,7 +1417,7 @@ tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 lin
switch (sec_act) {
case BTM_BLE_SEC_ENCRYPT:
if (link_role == BTM_ROLE_MASTER) {
if (link_role == BTM_ROLE_MASTER && (p_rec->ble.key_type & BTM_LE_KEY_PENC)) {
/* start link layer encryption using the security info stored */
cmd = btm_ble_start_encrypt(bd_addr, FALSE, NULL);
break;
@ -1422,7 +1426,7 @@ tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 lin
sec_request to request the master to encrypt the link */
case BTM_BLE_SEC_ENCRYPT_NO_MITM:
case BTM_BLE_SEC_ENCRYPT_MITM:
if (link_role == BTM_ROLE_MASTER) {
if ((link_role == BTM_ROLE_MASTER) && (sec_act != BTM_BLE_SEC_ENCRYPT)) {
auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM)
? SMP_AUTH_GEN_BOND : (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT);
btm_ble_link_sec_check (bd_addr, auth_req, &sec_req_act);
@ -2062,7 +2066,11 @@ UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data)
p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
/* add all bonded device into resolving list if IRK is available*/
btm_ble_resolving_list_load_dev(p_dev_rec);
/* It will cause that scanner doesn't send scan request to advertiser
* which has sent IRK to us and we have stored the IRK in controller.
* It is a design problem of hardware. The temporal solution is not to
* send the key to the controller and then resolve the random address in host. */
//btm_ble_resolving_list_load_dev(p_dev_rec);
#endif
}

View file

@ -41,7 +41,7 @@
#if (BLE_INCLUDED == TRUE)
static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state);
static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state);
static void btm_wl_update_to_controller(void);
// Unfortunately (for now?) we have to maintain a copy of the device whitelist
// on the host to determine if a device is pending to be connected or not. This
@ -185,9 +185,10 @@ BOOLEAN btm_add_dev_to_controller (BOOLEAN to_add, BD_ADDR bd_addr)
else {
BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
started = btsnd_hcic_ble_remove_from_white_list (addr_type, bd_addr);
if (to_add) {
started = btsnd_hcic_ble_add_white_list (addr_type, bd_addr);
}else{
started = btsnd_hcic_ble_remove_from_white_list (addr_type, bd_addr);
}
}
@ -253,7 +254,7 @@ void btm_enq_wl_dev_operation(BOOLEAN to_add, BD_ADDR bd_addr)
** the white list.
**
*******************************************************************************/
BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr)
BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBTM_ADD_WHITELIST_CBACK *add_wl_cb)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
@ -261,6 +262,10 @@ BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr)
BTM_TRACE_DEBUG("%s Whitelist full, unable to add device", __func__);
return FALSE;
}
if (add_wl_cb){
//save add whitelist complete callback
p_cb->add_wl_cb = add_wl_cb;
}
if (to_add) {
/* added the bd_addr to the connection hash map queue */
@ -273,8 +278,8 @@ BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr)
btm_suspend_wl_activity(p_cb->wl_state);
/* save the bd_addr to the btm_cb env */
btm_enq_wl_dev_operation(to_add, bd_addr);
/* save the ba_addr to the controller white list & start the auto connet */
btm_resume_wl_activity(p_cb->wl_state);
/* save the ba_addr to the controller white list */
btm_wl_update_to_controller();
return TRUE;
}
@ -336,9 +341,16 @@ void btm_ble_white_list_init(UINT8 white_list_size)
void btm_ble_add_2_white_list_complete(UINT8 status)
{
BTM_TRACE_EVENT("%s status=%d", __func__, status);
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
if (status == HCI_SUCCESS) {
--btm_cb.ble_ctr_cb.white_list_avail_size;
}
// add whitelist complete callback
if (p_cb->add_wl_cb)
{
(*p_cb->add_wl_cb)(status, BTM_WHITELIST_ADD);
}
}
/*******************************************************************************
@ -350,11 +362,16 @@ void btm_ble_add_2_white_list_complete(UINT8 status)
*******************************************************************************/
void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
UNUSED(evt_len);
BTM_TRACE_EVENT ("%s status=%d", __func__, *p);
if (*p == HCI_SUCCESS) {
++btm_cb.ble_ctr_cb.white_list_avail_size;
}
if (p_cb->add_wl_cb)
{
(*p_cb->add_wl_cb)(*p, BTM_WHITELIST_REMOVE);
}
}
/*******************************************************************************
@ -594,14 +611,32 @@ static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state)
** Returns none.
**
*******************************************************************************/
static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state)
void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state)
{
btm_ble_resume_bg_conn();
if (wl_state & BTM_BLE_WL_ADV) {
btm_ble_start_adv();
}
}
/*******************************************************************************
**
** Function btm_wl_update_to_controller
**
** Description This function is to update white list to controller
**
** Returns none.
**
*******************************************************************************/
static void btm_wl_update_to_controller(void)
{
/* whitelist will be added in the btm_ble_resume_bg_conn(), we do not
support background connection now, so we nedd to use btm_execute_wl_dev_operation
to add whitelist directly ,if we support background connection in the future,
please delete btm_execute_wl_dev_operation(). */
btm_execute_wl_dev_operation();
}
/*******************************************************************************
**

View file

@ -74,10 +74,12 @@ static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb,
tBLE_ADDR_TYPE *p_peer_addr_type,
tBLE_ADDR_TYPE *p_own_addr_type);
static void btm_ble_stop_observe(void);
static void btm_ble_stop_discover(void);
#define BTM_BLE_INQ_RESULT 0x01
#define BTM_BLE_OBS_RESULT 0x02
#define BTM_BLE_SEL_CONN_RESULT 0x04
#define BTM_BLE_DISCO_RESULT 0x08
/* LE states combo bit to check */
const UINT8 btm_le_state_combo_tbl[BTM_BLE_STATE_MAX][BTM_BLE_STATE_MAX][2] = {
@ -244,9 +246,9 @@ void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn
** Returns void
**
*******************************************************************************/
BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR remote_bda)
BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR remote_bda, tBTM_ADD_WHITELIST_CBACK *add_wl_cb)
{
return btm_update_dev_to_white_list(add_remove, remote_bda);
return btm_update_dev_to_white_list(add_remove, remote_bda, add_wl_cb);
}
/*******************************************************************************
@ -424,6 +426,84 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT32 duration,
}
/*******************************************************************************
**
** Function BTM_BleScan
**
** Description This procedure keep the device listening for advertising
** events from a broadcast device.
**
** Parameters start: start or stop scan.
** white_list: use white list in observer mode or not.
**
** Returns void
**
*******************************************************************************/
tBTM_STATUS BTM_BleScan(BOOLEAN start, UINT32 duration,
tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb)
{
tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
tBTM_STATUS status = BTM_WRONG_MODE;
if (!controller_get_interface()->supports_ble()) {
return BTM_ILLEGAL_VALUE;
}
if (start) {
/* shared inquiry database, do not allow scan if any inquiry is active */
if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
BTM_TRACE_ERROR("%s scan already active", __func__);
return status;
}
btm_cb.ble_ctr_cb.p_scan_results_cb = p_results_cb;
btm_cb.ble_ctr_cb.p_scan_cmpl_cb = p_cmpl_cb;
status = BTM_CMD_STARTED;
/* scan is not started */
if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
/* assume observe always not using white list */
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
/* enable resolving list */
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
#endif
// if not set scan params, set defalult scan params
if (!p_inq->scan_params_set)
{
/* allow config of scan type */
p_inq->scan_type = BTM_BLE_SCAN_MODE_ACTI;
p_inq->scan_interval = BTM_BLE_GAP_DISC_SCAN_INT;
p_inq->scan_window = BTM_BLE_GAP_DISC_SCAN_WIN;
p_inq->sfp = BTM_BLE_DEFAULT_SFP;
p_inq->scan_params_set = TRUE;
btsnd_hcic_ble_set_scan_params(p_inq->scan_type, p_inq->scan_interval,
p_inq->scan_window,
btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
p_inq->sfp);
}
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
status = btm_ble_start_scan();
}
if (status == BTM_CMD_STARTED) {
btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_DISCOVER_ACTIVE;
if (duration != 0)
/* start observer timer */
{
btu_start_timer (&btm_cb.ble_ctr_cb.scan_timer_ent, BTU_TTYPE_BLE_SCAN, duration);
}
}
} else if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
status = BTM_CMD_STARTED;
btm_ble_stop_discover();
} else {
BTM_TRACE_ERROR("%s scan not active\n", __func__);
}
return status;
}
/*******************************************************************************
**
** Function BTM_BleBroadcast
@ -882,7 +962,7 @@ void BTM_BleClearBgConnDev(void)
BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda)
{
BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove);
return btm_update_dev_to_white_list(add_remove, remote_bda);
return btm_update_dev_to_white_list(add_remove, remote_bda, NULL);
}
/*******************************************************************************
@ -1263,6 +1343,7 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
p_cb->scan_interval = scan_interval;
p_cb->scan_window = scan_window;
p_cb->sfp = scan_filter_policy;
p_cb->scan_params_set = TRUE;
btsnd_hcic_ble_set_scan_params(p_cb->scan_type, (UINT16)scan_interval,
(UINT16)scan_window,
@ -2470,6 +2551,10 @@ UINT8 btm_ble_is_discoverable(BD_ADDR bda, UINT8 evt_type, UINT8 *p)
if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
rt |= BTM_BLE_OBS_RESULT;
}
/* for discover, always "discoverable */
if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
rt |= BTM_BLE_DISCO_RESULT;
}
if (BTM_BLE_IS_SEL_CONN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity) &&
(evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_CONNECT_DIR_EVT)) {
@ -2884,10 +2969,12 @@ void btm_ble_process_adv_pkt (UINT8 *p_data)
*******************************************************************************/
static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
{
tINQ_DB_ENT *p_i;
tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
tBTM_INQ_RESULTS_CB *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
tBTM_INQ_RESULTS_CB *p_scan_results_cb = btm_cb.ble_ctr_cb.p_scan_results_cb;
tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
BOOLEAN update = TRUE;
UINT8 result = 0;
@ -2902,7 +2989,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
/* scan repsonse to be updated */
(!p_i->scan_rsp))) {
update = TRUE;
} else if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
} else if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
update = FALSE;
} else {
/* if yes, skip it */
@ -2968,6 +3055,9 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
(p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
}
if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
(p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
}
}
}
@ -3088,6 +3178,41 @@ static void btm_ble_stop_observe(void)
(p_obs_cb)((tBTM_INQUIRY_CMPL *) &btm_cb.btm_inq_vars.inq_cmpl_info);
}
}
/*******************************************************************************
**
** Function btm_ble_stop_observe
**
** Description Stop the BLE Observe.
**
** Returns void
**
*******************************************************************************/
static void btm_ble_stop_discover(void)
{
tBTM_BLE_CB *p_ble_cb = & btm_cb.ble_ctr_cb;
tBTM_CMPL_CB *p_scan_cb = p_ble_cb->p_scan_cmpl_cb;
btu_stop_timer (&p_ble_cb->scan_timer_ent);
p_ble_cb->scan_activity &= ~BTM_LE_DISCOVER_ACTIVE;
p_ble_cb->p_scan_results_cb = NULL;
p_ble_cb->p_scan_cmpl_cb = NULL;
if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
/* Clear the inquiry callback if set */
btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
btm_cb.ble_ctr_cb.inq_var.state = BTM_BLE_STOP_SCAN;
/* stop discovery now */
btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
}
if (p_scan_cb) {
(p_scan_cb)((tBTM_INQUIRY_CMPL *) &btm_cb.btm_inq_vars.inq_cmpl_info);
}
}
/*******************************************************************************
**
** Function btm_ble_adv_states_operation
@ -3260,7 +3385,9 @@ void btm_ble_timeout(TIMER_LIST_ENT *p_tle)
case BTU_TTYPE_BLE_OBSERVE:
btm_ble_stop_observe();
break;
case BTU_TTYPE_BLE_SCAN:
btm_ble_stop_discover();
break;
case BTU_TTYPE_BLE_INQUIRY:
btm_ble_stop_inquiry();
break;

View file

@ -168,8 +168,8 @@ void BTU_StartUp(void)
osi_mutex_new(&btu_l2cap_alarm_lock);
xBtuQueue = xQueueCreate(BTU_QUEUE_NUM, sizeof(BtTaskEvt_t));
xTaskCreatePinnedToCore(btu_task_thread_handler, BTU_TASK_NAME, BTU_TASK_STACK_SIZE, NULL, BTU_TASK_PRIO, &xBtuTaskHandle, 0);
xBtuQueue = xQueueCreate(BTU_QUEUE_LEN, sizeof(BtTaskEvt_t));
xTaskCreatePinnedToCore(btu_task_thread_handler, BTU_TASK_NAME, BTU_TASK_STACK_SIZE, NULL, BTU_TASK_PRIO, &xBtuTaskHandle, BTU_TASK_PINNED_TO_CORE);
btu_task_post(SIG_BTU_START_UP, NULL, TASK_POST_BLOCKING);

View file

@ -385,6 +385,7 @@ static void btu_general_alarm_process(TIMER_LIST_ENT *p_tle)
case BTU_TTYPE_BLE_GAP_LIM_DISC:
case BTU_TTYPE_BLE_RANDOM_ADDR:
case BTU_TTYPE_BLE_GAP_FAST_ADV:
case BTU_TTYPE_BLE_SCAN:
case BTU_TTYPE_BLE_OBSERVE:
btm_ble_timeout(p_tle);
break;

View file

@ -567,7 +567,6 @@ tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_handle, U
tGATT_VALUE indication;
BT_HDR *p_msg;
tGATT_VALUE *p_buf;
tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
@ -591,12 +590,16 @@ tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_handle, U
indication.auth_req = GATT_AUTH_REQ_NONE;
if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) {
/* TODO: need to further check whether deleting pending queue here cause reducing transport performance */
/*
GATT_TRACE_DEBUG ("Add a pending indication");
if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) != NULL) {
cmd_status = GATT_SUCCESS;
} else {
cmd_status = GATT_NO_RESOURCES;
}
*/
return GATT_BUSY;
} else {
if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL) {
@ -723,7 +726,9 @@ tGATT_STATUS GATTS_SetAttributeValue(UINT16 attr_handle, UINT16 length, UINT8 *v
GATT_TRACE_DEBUG("GATTS_SetAttributeValue: attr_handle: %u length: %u \n",
attr_handle, length);
if (length <= 0){
return GATT_INVALID_ATTR_LEN;
}
if ((p_decl = gatt_find_hdl_buffer_by_attr_handle(attr_handle)) == NULL) {
GATT_TRACE_DEBUG("Service not created\n");
return GATT_INVALID_HANDLE;

View file

@ -421,6 +421,8 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
if (is_prepare_write_valid){
if((queue_data->p_attr->p_value != NULL) && (queue_data->p_attr->p_value->attr_val.attr_val != NULL)){
memcpy(queue_data->p_attr->p_value->attr_val.attr_val+queue_data->offset, queue_data->value, queue_data->len);
//don't forget to increase the attribute value length in the gatts database.
queue_data->p_attr->p_value->attr_val.attr_len += queue_data->len;
}
}
osi_free(queue_data);

View file

@ -2416,7 +2416,7 @@ BOOLEAN gatt_add_bg_dev_list(tGATT_REG *p_reg, BD_ADDR bd_addr, BOOLEAN is_init
p_dev->listen_gif[i] = gatt_if;
if (i == 0) {
ret = BTM_BleUpdateAdvWhitelist(TRUE, bd_addr);
ret = BTM_BleUpdateAdvWhitelist(TRUE, bd_addr, NULL);
} else {
ret = TRUE;
}
@ -2556,7 +2556,7 @@ BOOLEAN gatt_remove_bg_dev_from_list(tGATT_REG *p_reg, BD_ADDR bd_addr, BOOLEAN
}
if (p_dev->listen_gif[0] == 0) {
ret = BTM_BleUpdateAdvWhitelist(FALSE, p_dev->remote_bda);
ret = BTM_BleUpdateAdvWhitelist(FALSE, p_dev->remote_bda, NULL);
} else {
ret = TRUE;
}
@ -2617,7 +2617,7 @@ void gatt_deregister_bgdev_list(tGATT_IF gatt_if)
}
if (p_dev_list->listen_gif[0] == 0) {
BTM_BleUpdateAdvWhitelist(FALSE, p_dev_list->remote_bda);
BTM_BleUpdateAdvWhitelist(FALSE, p_dev_list->remote_bda, NULL);
}
}
}

View file

@ -146,6 +146,11 @@ typedef struct {
UINT16 supervision_tout;
}tBTM_LE_UPDATE_CONN_PRAMS;
typedef enum{
BTM_WHITELIST_REMOVE = 0X00,
BTM_WHITELIST_ADD = 0X01,
}tBTM_WL_OPERATION;
typedef void (tBTM_DEV_STATUS_CB) (tBTM_DEV_STATUS status);
@ -177,6 +182,8 @@ typedef void (tBTM_UPDATE_CONN_PARAM_CBACK) (UINT8 status, BD_ADDR bd_addr, tBTM
typedef void (tBTM_SET_PKT_DATA_LENGTH_CBACK) (UINT8 status, tBTM_LE_SET_PKT_DATA_LENGTH_PARAMS *data_length_params);
typedef void (tBTM_ADD_WHITELIST_CBACK) (UINT8 status, tBTM_WL_OPERATION wl_opration);
typedef void (tBTM_SET_LOCAL_PRIVACY_CBACK) (UINT8 status);
@ -234,7 +241,7 @@ typedef void (tBTM_SET_LOCAL_PRIVACY_CBACK) (UINT8 status);
/* inquiry activity mask */
#define BTM_BR_INQ_ACTIVE_MASK (BTM_GENERAL_INQUIRY_ACTIVE|BTM_LIMITED_INQUIRY_ACTIVE|BTM_PERIODIC_INQUIRY_ACTIVE) /* BR/EDR inquiry activity mask */
#define BTM_BLE_SCAN_ACTIVE_MASK 0xF0 /* LE scan activity mask */
#define BTM_BLE_SCAN_ACTIVE_MASK 0x01F0 /* LE scan activity mask */
#define BTM_BLE_INQ_ACTIVE_MASK (BTM_LE_GENERAL_INQUIRY_ACTIVE|BTM_LE_LIMITED_INQUIRY_ACTIVE) /* LE inquiry activity mask*/
#define BTM_INQUIRY_ACTIVE_MASK (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK) /* inquiry activity mask */

View file

@ -1207,6 +1207,22 @@ tBTM_STATUS BTM_BleWriteScanRspRaw(UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_le
tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT32 duration,
tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb);
/*******************************************************************************
**
** Function BTM_BleScan
**
** Description This procedure keep the device listening for advertising
** events from a broadcast device.
**
** Parameters start: start or stop scan.
**
** Returns void
**
*******************************************************************************/
//extern
tBTM_STATUS BTM_BleScan(BOOLEAN start, UINT32 duration,
tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb);
/*******************************************************************************
**
@ -1695,7 +1711,7 @@ void BTM_BleTurnOnPrivacyOnRemote(BD_ADDR bd_addr,
**
*******************************************************************************/
//extern
BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR emote_bda);
BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR emote_bda, tBTM_ADD_WHITELIST_CBACK *add_wl_cb);
/*******************************************************************************
**

View file

@ -86,13 +86,15 @@ typedef UINT8 tBTM_BLE_SEC_REQ_ACT;
#define BTM_BLE_IS_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
/* LE scan activity bit mask, continue with LE inquiry bits */
#define BTM_LE_SELECT_CONN_ACTIVE 0x40 /* selection connection is in progress */
#define BTM_LE_OBSERVE_ACTIVE 0x80 /* observe is in progress */
#define BTM_LE_SELECT_CONN_ACTIVE 0x0040 /* selection connection is in progress */
#define BTM_LE_OBSERVE_ACTIVE 0x0080 /* observe is in progress */
#define BTM_LE_DISCOVER_ACTIVE 0x0100 /* scan is in progress */
/* BLE scan activity mask checking */
#define BTM_BLE_IS_SCAN_ACTIVE(x) ((x) & BTM_BLE_SCAN_ACTIVE_MASK)
#define BTM_BLE_IS_INQ_ACTIVE(x) ((x) & BTM_BLE_INQUIRY_MASK)
#define BTM_BLE_IS_OBS_ACTIVE(x) ((x) & BTM_LE_OBSERVE_ACTIVE)
#define BTM_BLE_IS_DISCO_ACTIVE(x) ((x) & BTM_LE_DISCOVER_ACTIVE)
#define BTM_BLE_IS_SEL_CONN_ACTIVE(x) ((x) & BTM_LE_SELECT_CONN_ACTIVE)
/* BLE ADDR type ID bit */
@ -136,6 +138,7 @@ typedef struct {
typedef struct {
UINT16 discoverable_mode;
UINT16 connectable_mode;
BOOLEAN scan_params_set;
UINT32 scan_window;
UINT32 scan_interval;
UINT8 scan_type; /* current scan type: active or passive */
@ -294,7 +297,7 @@ typedef void (tBTM_DATA_LENGTH_CHANGE_CBACK) (UINT16 max_tx_length, UINT16 max_r
/* Define BLE Device Management control structure
*/
typedef struct {
UINT8 scan_activity; /* LE scan activity mask */
UINT16 scan_activity; /* LE scan activity mask */
/*****************************************************
** BLE Inquiry
@ -306,6 +309,11 @@ typedef struct {
tBTM_CMPL_CB *p_obs_cmpl_cb;
TIMER_LIST_ENT obs_timer_ent;
/* scan callback and timer */
tBTM_INQ_RESULTS_CB *p_scan_results_cb;
tBTM_CMPL_CB *p_scan_cmpl_cb;
TIMER_LIST_ENT scan_timer_ent;
/* background connection procedure cb value */
tBTM_BLE_CONN_TYPE bg_conn_type;
UINT32 scan_int;
@ -314,6 +322,7 @@ typedef struct {
/* white list information */
UINT8 white_list_avail_size;
tBTM_ADD_WHITELIST_CBACK *add_wl_cb;
tBTM_BLE_WL_STATE wl_state;
fixed_queue_t *conn_pending_q;
@ -357,7 +366,6 @@ tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration);
void btm_ble_stop_scan(void);
void btm_clear_all_pending_le_entry(void);
void btm_ble_stop_scan();
BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int,
UINT32 scan_win, UINT8 addr_type_own,
UINT8 scan_filter_policy);
@ -405,7 +413,7 @@ void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size);
UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr);
/* white list function */
BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr);
BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBTM_ADD_WHITELIST_CBACK *add_wl_cb);
void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy);
void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy);
void btm_ble_clear_white_list (void);

View file

@ -160,9 +160,8 @@ typedef void (*tBTU_EVENT_CALLBACK)(BT_HDR *p_hdr);
#define BTU_TTYPE_BLE_GAP_FAST_ADV 106
#define BTU_TTYPE_BLE_OBSERVE 107
#define BTU_TTYPE_UCD_TO 108
#define BTU_TTYPE_BLE_SCAN 109
/* This is the inquiry response information held by BTU, and available

View file

@ -1469,7 +1469,8 @@ typedef struct {
#define HCI_FEATURE_SWITCH_MASK 0x20
#define HCI_FEATURE_SWITCH_OFF 0
#define HCI_SWITCH_SUPPORTED(x) ((x)[HCI_FEATURE_SWITCH_OFF] & HCI_FEATURE_SWITCH_MASK)
// temporarily disable ROLE_SWITCH since there is an issue to be fixed
#define HCI_SWITCH_SUPPORTED(x) (0 & ((x)[HCI_FEATURE_SWITCH_OFF] & HCI_FEATURE_SWITCH_MASK))
#define HCI_FEATURE_HOLD_MODE_MASK 0x40
#define HCI_FEATURE_HOLD_MODE_OFF 0

View file

@ -505,8 +505,8 @@ static BOOLEAN l2cble_start_conn_update (tL2C_LCB *p_lcb)
up to what has been requested during connection establishement */
if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM &&
/* current connection interval is greater than default min */
p_lcb->waiting_update_conn_min_interval > BTM_BLE_CONN_INT_MIN) {
/* use 7.5 ms as fast connection parameter, 0 slave latency */
p_lcb->current_used_conn_interval > BTM_BLE_CONN_INT_MAX_DEF) {
/* use 6 * 1.25 = 7.5 ms as fast connection parameter, 0 slave latency */
min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN;
slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF;

View file

@ -1506,9 +1506,11 @@ tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid)
p_ccb->tx_mps = L2CAP_FCR_TX_BUF_SIZE - 32;
p_ccb->xmit_hold_q = fixed_queue_new(SIZE_MAX);
#if (CLASSIC_BT_INCLUDED == TRUE)
p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
p_ccb->fcrb.retrans_q = fixed_queue_new(SIZE_MAX);
p_ccb->fcrb.waiting_for_ack_q = fixed_queue_new(SIZE_MAX);
#endif ///CLASSIC_BT_INCLUDED == TRUE
p_ccb->cong_sent = FALSE;
p_ccb->buff_quota = 2; /* This gets set after config */
@ -1632,6 +1634,15 @@ void l2cu_release_ccb (tL2C_CCB *p_ccb)
fixed_queue_free(p_ccb->xmit_hold_q, osi_free_func);
p_ccb->xmit_hold_q = NULL;
#if (CLASSIC_BT_INCLUDED == TRUE)
fixed_queue_free(p_ccb->fcrb.srej_rcv_hold_q, osi_free_func);
fixed_queue_free(p_ccb->fcrb.retrans_q, osi_free_func);
fixed_queue_free(p_ccb->fcrb.waiting_for_ack_q, osi_free_func);
p_ccb->fcrb.srej_rcv_hold_q = NULL;
p_ccb->fcrb.retrans_q = NULL;
p_ccb->fcrb.waiting_for_ack_q = NULL;
#endif ///CLASSIC_BT_INCLUDED == TRUE
#if (CLASSIC_BT_INCLUDED == TRUE)
l2c_fcr_cleanup (p_ccb);

View file

@ -1221,25 +1221,16 @@ void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
switch (p_cb->selected_association_model) {
case SMP_MODEL_ENCRYPTION_ONLY: /* TK = 0, go calculate Confirm */
if (p_cb->role == HCI_ROLE_MASTER &&
((p_cb->peer_auth_req & SMP_AUTH_YN_BIT) != 0) &&
((p_cb->loc_auth_req & SMP_AUTH_YN_BIT) == 0)) {
SMP_TRACE_ERROR ("IO capability does not meet authentication requirement\n");
failure = SMP_PAIR_AUTH_FAIL;
p = (tSMP_INT_DATA *)&failure;
int_evt = SMP_AUTH_CMPL_EVT;
} else {
p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) \n", p_cb->sec_level );
p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) \n", p_cb->sec_level );
key.key_type = SMP_KEY_TYPE_TK;
key.p_data = p_cb->tk;
p = (tSMP_INT_DATA *)&key;
key.key_type = SMP_KEY_TYPE_TK;
key.p_data = p_cb->tk;
p = (tSMP_INT_DATA *)&key;
memset(p_cb->tk, 0, BT_OCTET16_LEN);
/* TK, ready */
int_evt = SMP_KEY_READY_EVT;
}
memset(p_cb->tk, 0, BT_OCTET16_LEN);
/* TK, ready */
int_evt = SMP_KEY_READY_EVT;
break;
case SMP_MODEL_PASSKEY:

View file

@ -24,6 +24,7 @@
#include "freertos/semphr.h"
#include "freertos/xtensa_api.h"
#include "freertos/portmacro.h"
#include "xtensa/core-macros.h"
#include "esp_types.h"
#include "esp_system.h"
#include "esp_task.h"
@ -33,6 +34,9 @@
#include "bt.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "esp_ipc.h"
#include "driver/periph_ctrl.h"
#if CONFIG_BT_ENABLED
@ -134,6 +138,7 @@ struct osi_funcs_t {
int32_t (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
void (* _task_delete)(void *task_handle);
bool (* _is_in_isr)(void);
int (* _cause_sw_intr_to_core)(int core_id, int intr_no);
void *(* _malloc)(uint32_t size);
void (* _free)(void *p);
int32_t (* _read_efuse_mac)(uint8_t mac[6]);
@ -147,6 +152,10 @@ static esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STA
static portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED;
#ifdef CONFIG_PM_ENABLE
static esp_pm_lock_handle_t s_pm_lock;
#endif
static void IRAM_ATTR interrupt_disable(void)
{
portENTER_CRITICAL(&global_int_mux);
@ -269,6 +278,26 @@ static bool IRAM_ATTR is_in_isr_wrapper(void)
return (bool)xPortInIsrContext();
}
static void IRAM_ATTR cause_sw_intr(void *arg)
{
/* just convert void * to int, because the width is the same */
uint32_t intr_no = (uint32_t)arg;
XTHAL_SET_INTSET((1<<intr_no));
}
static int IRAM_ATTR cause_sw_intr_to_core_wrapper(int core_id, int intr_no)
{
esp_err_t err = ESP_OK;
if (xPortGetCoreID() == core_id) {
cause_sw_intr((void *)intr_no);
} else {
err = esp_ipc_call(core_id, cause_sw_intr, (void *)intr_no);
}
return err;
}
static int32_t IRAM_ATTR read_mac_wrapper(uint8_t mac[6])
{
return esp_read_mac(mac, ESP_MAC_BT);
@ -310,6 +339,7 @@ static struct osi_funcs_t osi_funcs = {
._task_create = task_create_wrapper,
._task_delete = task_delete_wrapper,
._is_in_isr = is_in_isr_wrapper,
._cause_sw_intr_to_core = cause_sw_intr_to_core_wrapper,
._malloc = malloc,
._free = free,
._read_efuse_mac = read_mac_wrapper,
@ -340,10 +370,10 @@ static uint32_t btdm_config_mask_load(void)
mask |= BTDM_CFG_BT_DATA_RELEASE;
}
#ifdef CONFIG_BT_HCI_UART
#if CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4
mask |= BTDM_CFG_HCI_UART;
#endif
#ifdef CONFIG_BTDM_CONTROLLER_RUN_APP_CPU
#if CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE == 1
mask |= BTDM_CFG_CONTROLLER_RUN_APP_CPU;
#endif
return mask;
@ -442,14 +472,27 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
return ESP_ERR_INVALID_ARG;
}
#ifdef CONFIG_PM_ENABLE
esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock);
if (err != ESP_OK) {
return err;
}
#endif
btdm_osi_funcs_register(&osi_funcs);
btdm_controller_mem_init();
periph_module_enable(PERIPH_BT_MODULE);
btdm_cfg_mask = btdm_config_mask_load();
ret = btdm_controller_init(btdm_cfg_mask, cfg);
if (ret) {
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_delete(s_pm_lock);
s_pm_lock = NULL;
#endif
return ESP_ERR_NO_MEM;
}
@ -467,7 +510,15 @@ esp_err_t esp_bt_controller_deinit(void)
return ESP_ERR_NO_MEM;
}
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_SHUTDOWN;
periph_module_disable(PERIPH_BT_MODULE);
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_delete(s_pm_lock);
s_pm_lock = NULL;
#endif
return ESP_OK;
}
@ -484,6 +535,10 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
return ESP_ERR_INVALID_ARG;
}
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire(s_pm_lock);
#endif
esp_phy_load_cal_and_init();
if (btdm_bb_init_flag == false) {
@ -519,6 +574,10 @@ esp_err_t esp_bt_controller_disable(void)
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
}
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_pm_lock);
#endif
return ESP_OK;
}

View file

@ -78,7 +78,6 @@ typedef enum {
ESP_BT_CONTROLLER_STATUS_IDLE = 0,
ESP_BT_CONTROLLER_STATUS_INITED,
ESP_BT_CONTROLLER_STATUS_ENABLED,
ESP_BT_CONTROLLER_STATUS_SHUTDOWN,
ESP_BT_CONTROLLER_STATUS_NUM,
} esp_bt_controller_status_t;

@ -1 +1 @@
Subproject commit 2d33374ca531f92859640f1d055fc4f28d60dfdc
Subproject commit 8e62573de3dd9565b2209a3e8fe19a9900320b77

View file

@ -1 +1 @@
CFLAGS += -DWITH_POSIX
CPPFLAGS += -DWITH_POSIX

View file

@ -185,7 +185,9 @@ esp_err_t esp_console_run(const char* cmdline, int* cmd_ret)
size_t argc = esp_console_split_argv(s_tmp_line_buf, argv,
s_config.max_cmdline_args);
if (argc == 0) {
return ESP_ERR_INVALID_ARG;
}
const cmd_item_t* cmd = find_command_by_name(argv[0]);
if (cmd == NULL) {
return ESP_ERR_NOT_FOUND;

View file

@ -107,6 +107,8 @@ esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd);
* @param[out] cmd_ret return code from the command (set if command was run)
* @return
* - ESP_OK, if command was run
* - ESP_ERR_INVALID_ARG, if the command line is empty, or only contained
* whitespace
* - ESP_ERR_NOT_FOUND, if command with given name wasn't registered
* - ESP_ERR_INVALID_STATE, if esp_console_init wasn't called
*/

View file

@ -1,3 +1,11 @@
# Mark __cxa_guard_dummy as undefined so that implementation of static guards
# is taken from cxx_guards.o instead of libstdc++.a
COMPONENT_ADD_LDFLAGS += -u __cxa_guard_dummy
ifndef CONFIG_CXX_EXCEPTIONS
# If exceptions are disabled, ensure our fatal exception
# hooks are preferentially linked over libstdc++ which
# has full exception support
COMPONENT_ADD_LDFLAGS += -u __cxx_fatal_exception
endif

View file

@ -0,0 +1,87 @@
#include <cstdlib>
#include <cstdio>
#include <exception>
#include <bits/functexcept.h>
#include <sdkconfig.h>
#ifndef CONFIG_CXX_EXCEPTIONS
const char *FATAL_EXCEPTION = "Fatal C++ exception: ";
extern "C" void __cxx_fatal_exception(void)
{
abort();
}
extern "C" void __cxx_fatal_exception_message(const char *msg)
{
printf("%s%s\n", FATAL_EXCEPTION, msg);
abort();
}
extern "C" void __cxx_fatal_exception_int(int i)
{
printf("%s (%d)\n", FATAL_EXCEPTION, i);
abort();
}
void std::__throw_bad_exception(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_bad_alloc(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_bad_cast(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_bad_typeid(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_logic_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_domain_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_invalid_argument(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_length_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_out_of_range(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_out_of_range_fmt(const char*, ...) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_runtime_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_range_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_overflow_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_underflow_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_ios_failure(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
void std::__throw_system_error(int) __attribute__((alias("__cxx_fatal_exception_int")));
void std::__throw_bad_function_call(void) __attribute__((alias("__cxx_fatal_exception")));
void std::__throw_future_error(int) __attribute__((alias("__cxx_fatal_exception_int")));
/* The following definitions are needed because libstdc++ is also compiled with
__throw_exception_again defined to throw, and some other exception code in a few places.
This cause exception handler code to be emitted in the library even though it's mostly
unreachable (as any libstdc++ "throw" will first call one of the above stubs, which will abort).
If these are left out, a bunch of unwanted exception handler code is linked.
Note: these function prototypes are not correct.
*/
extern "C" void __cxa_allocate_exception(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_begin_catch(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_end_catch(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_get_exception_ptr(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_free_exception(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_rethrow(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_throw(void) __attribute__((alias("__cxx_fatal_exception")));
extern "C" void __cxa_call_terminate(void) __attribute__((alias("__cxx_fatal_exception")));
bool std::uncaught_exception() __attribute__((alias("__cxx_fatal_exception")));
#endif // CONFIG_CXX_EXCEPTIONS

View file

@ -92,7 +92,6 @@ public:
static SlowInit slowinit(taskId);
ESP_LOGD(TAG, "obj=%d after static init, task=%d\n", obj, taskId);
xSemaphoreGive(s_slow_init_sem);
vTaskDelay(10);
vTaskDelete(NULL);
}
private:
@ -133,6 +132,8 @@ TEST_CASE("static initialization guards work as expected", "[cxx]")
TEST_ASSERT_TRUE(xSemaphoreTake(s_slow_init_sem, 500/portTICK_PERIOD_MS));
}
vSemaphoreDelete(s_slow_init_sem);
vTaskDelay(10); // Allow tasks to clean up, avoids race with leak detector
}
struct GlobalInitTest
@ -187,6 +188,27 @@ TEST_CASE("before scheduler has started, static initializers work correctly", "[
TEST_ASSERT_EQUAL(2, StaticInitTestBeforeScheduler::order);
}
#ifdef CONFIG_CXX_EXCEPTIONS
TEST_CASE("c++ exceptions work", "[cxx]")
{
/* Note: This test currently trips the memory leak threshold
as libunwind allocates ~4KB of data on first exception. */
int thrown_value;
try
{
throw 20;
}
catch (int e)
{
thrown_value = e;
}
TEST_ASSERT_EQUAL(20, thrown_value);
printf("OK?\n");
}
#endif
/* These test cases pull a lot of code from libstdc++ and are disabled for now
*/
#if 0

View file

@ -23,6 +23,7 @@
#include "freertos/xtensa_api.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
#include "freertos/event_groups.h"
#include "soc/dport_reg.h"
#include "soc/i2c_struct.h"
#include "soc/i2c_reg.h"
@ -43,12 +44,13 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
#define I2C_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
#define I2C_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
#define I2C_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
#define I2C_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
#define I2C_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
#define I2C_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
#define I2C_DRIVER_ERR_STR "i2c driver install error"
#define I2C_DRIVER_MALLOC_ERR_STR "i2c driver malloc error"
#define I2C_NUM_ERROR_STR "i2c number error"
#define I2C_TIMEING_VAL_ERR_STR "i2c timing value error"
#define I2C_ADDR_ERROR_STR "i2c null address error"
#define I2C_DRIVER_NOT_INSTALL_ERR_STR "i2c driver not installed"
#define I2C_SLAVE_BUFFER_LEN_ERR_STR "i2c buffer size too short for slave mode"
@ -60,13 +62,20 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
#define I2C_CMD_MALLOC_ERR_STR "i2c command link malloc error"
#define I2C_TRANS_MODE_ERR_STR "i2c trans mode error"
#define I2C_MODE_ERR_STR "i2c mode error"
#define I2C_SDA_IO_ERR_STR "sda gpio number error"
#define I2C_SCL_IO_ERR_STR "scl gpio number error"
#define I2C_CMD_LINK_INIT_ERR_STR "i2c command link error"
#define I2C_GPIO_PULLUP_ERR_STR "this i2c pin do not support internal pull-up"
#define I2C_FIFO_FULL_THRESH_VAL (28)
#define I2C_FIFO_EMPTY_THRESH_VAL (5)
#define I2C_IO_INIT_LEVEL (1)
#define I2C_SDA_IO_ERR_STR "sda gpio number error"
#define I2C_SCL_IO_ERR_STR "scl gpio number error"
#define I2C_CMD_LINK_INIT_ERR_STR "i2c command link error"
#define I2C_GPIO_PULLUP_ERR_STR "this i2c pin do not support internal pull-up"
#define I2C_FIFO_FULL_THRESH_VAL (28)
#define I2C_FIFO_EMPTY_THRESH_VAL (5)
#define I2C_IO_INIT_LEVEL (1)
#define I2C_CMD_ALIVE_INTERVAL_TICK (1000 / portTICK_PERIOD_MS)
#define I2C_CMD_EVT_ALIVE (BIT0)
#define I2C_CMD_EVT_DONE (BIT1)
#define I2C_SLAVE_TIMEOUT_DEFAULT (32000) /* I2C slave timeout value, APB clock cycle number */
#define I2C_SLAVE_SDA_SAMPLE_DEFAULT (10) /* I2C slave sample time after scl positive edge default value */
#define I2C_SLAVE_SDA_HOLD_DEFAULT (10) /* I2C slave hold time after scl negative edge default value */
#define I2C_MASTER_TOUT_CNUM_DEFAULT (8) /* I2C master timeout cycle number of I2C clock, after which the timeout interrupt will be triggered */
typedef struct {
uint8_t byte_num; /*!< cmd byte number */
@ -95,19 +104,20 @@ typedef enum {
I2C_STATUS_IDLE, /*!< idle status for current master command */
I2C_STATUS_ACK_ERROR, /*!< ack error status for current master command */
I2C_STATUS_DONE, /*!< I2C command done */
I2C_STATUS_TIMEOUT, /*!< I2C bus status error, and operation timeout */
} i2c_status_t;
typedef struct {
int i2c_num; /*!< I2C port number */
int mode; /*!< I2C mode, master or slave */
intr_handle_t intr_handle; /*!< I2C interrupt handle*/
int cmd_idx; /*!< record current command index, for master mode */
int status; /*!< record current command status, for master mode */
int rx_cnt; /*!< record current read index, for master mode */
uint8_t data_buf[I2C_FIFO_LEN]; /*!< a buffer to store i2c fifo data */
i2c_cmd_desc_t cmd_link; /*!< I2C command link */
xSemaphoreHandle cmd_sem; /*!< semaphore to sync command status */
EventGroupHandle_t cmd_evt; /*!< I2C command event bits */
xSemaphoreHandle cmd_mux; /*!< semaphore to lock command process */
size_t tx_fifo_remain; /*!< tx fifo remain length, for master mode */
size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */
@ -123,6 +133,7 @@ typedef struct {
static i2c_obj_t *p_i2c_obj[I2C_NUM_MAX] = {0};
static void i2c_isr_handler_default(void* arg);
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num);
static esp_err_t IRAM_ATTR i2c_hw_fsm_reset(i2c_port_t i2c_num);
/*
For i2c master mode, we don't need to use a buffer for the data, the APIs will execute the master commands
@ -131,7 +142,6 @@ we should free or modify the source data only after the i2c_master_cmd_begin fun
For i2c slave mode, we need a data buffer to stash the sending and receiving data, because the hardware fifo
has only 32 bytes.
*/
esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t slv_tx_buf_len,
int intr_alloc_flags)
{
@ -185,12 +195,12 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);
goto err;
}
intr_mask |= ( I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M );
intr_mask |= ( I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M);
} else {
//semaphore to sync sending process, because we only have 32 bytes for hardware fifo.
p_i2c->cmd_sem = xSemaphoreCreateBinary();
p_i2c->cmd_mux = xSemaphoreCreateMutex();
if (p_i2c->cmd_sem == NULL || p_i2c->cmd_mux == NULL) {
p_i2c->cmd_evt = xEventGroupCreate();
if (p_i2c->cmd_mux == NULL || p_i2c->cmd_evt == NULL) {
ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);
goto err;
}
@ -203,6 +213,7 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
p_i2c->rx_buf_length = 0;
p_i2c->tx_ring_buf = NULL;
p_i2c->tx_buf_length = 0;
intr_mask |= I2C_ARBITRATION_LOST_INT_ENA_M | I2C_TIME_OUT_INT_ST_M;
}
} else {
ESP_LOGE(I2C_TAG, I2C_DRIVER_ERR_STR);
@ -212,11 +223,11 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
i2c_isr_register(i2c_num, i2c_isr_handler_default, p_i2c_obj[i2c_num], intr_alloc_flags, &p_i2c_obj[i2c_num]->intr_handle);
intr_mask |= ( I2C_TRANS_COMPLETE_INT_ENA_M |
I2C_TRANS_START_INT_ENA_M |
I2C_ARBITRATION_LOST_INT_ENA_M |
I2C_ACK_ERR_INT_ENA_M |
I2C_RXFIFO_OVF_INT_ENA_M |
I2C_SLAVE_TRAN_COMP_INT_ENA_M );
SET_PERI_REG_MASK(I2C_INT_ENA_REG(i2c_num), intr_mask);
I2C_SLAVE_TRAN_COMP_INT_ENA_M);
I2C[i2c_num]->int_clr.val = intr_mask;
I2C[i2c_num]->int_ena.val = intr_mask;
return ESP_OK;
err:
@ -232,8 +243,9 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
p_i2c_obj[i2c_num]->tx_ring_buf = NULL;
p_i2c_obj[i2c_num]->tx_buf_length = 0;
}
if (p_i2c_obj[i2c_num]->cmd_sem) {
vSemaphoreDelete(p_i2c_obj[i2c_num]->cmd_sem);
if (p_i2c_obj[i2c_num]->cmd_evt) {
vEventGroupDelete(p_i2c_obj[i2c_num]->cmd_evt);
p_i2c_obj[i2c_num]->cmd_evt = NULL;
}
if (p_i2c_obj[i2c_num]->cmd_mux) {
vSemaphoreDelete(p_i2c_obj[i2c_num]->cmd_mux);
@ -249,6 +261,26 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
return ESP_FAIL;
}
static esp_err_t i2c_hw_enable(i2c_port_t i2c_num)
{
if (i2c_num == I2C_NUM_0) {
periph_module_enable(PERIPH_I2C0_MODULE);
} else if (i2c_num == I2C_NUM_1) {
periph_module_enable(PERIPH_I2C1_MODULE);
}
return ESP_OK;
}
static esp_err_t i2c_hw_disable(i2c_port_t i2c_num)
{
if (i2c_num == I2C_NUM_0) {
periph_module_disable(PERIPH_I2C0_MODULE);
} else if (i2c_num == I2C_NUM_1) {
periph_module_disable(PERIPH_I2C1_MODULE);
}
return ESP_OK;
}
esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
@ -256,17 +288,7 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
uint32_t intr_mask = I2C_MASTER_TRAN_COMP_INT_ENA_M |
I2C_TIME_OUT_INT_ENA_M |
I2C_TRANS_COMPLETE_INT_ENA_M |
I2C_TRANS_START_INT_ENA_M |
I2C_TX_SEND_EMPTY_INT_ENA_M |
I2C_ARBITRATION_LOST_INT_ENA_M |
I2C_ACK_ERR_INT_ENA_M |
I2C_RXFIFO_OVF_INT_ENA_M |
I2C_RX_REC_FULL_INT_ENA_M |
I2C_SLAVE_TRAN_COMP_INT_ENA_M;
CLEAR_PERI_REG_MASK(I2C_INT_ENA_REG(i2c_num), intr_mask);
I2C[i2c_num]->int_ena.val = 0;
esp_intr_free(p_i2c->intr_handle);
p_i2c->intr_handle = NULL;
@ -274,8 +296,9 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
xSemaphoreTake(p_i2c->cmd_mux, portMAX_DELAY);
vSemaphoreDelete(p_i2c->cmd_mux);
}
if (p_i2c->cmd_sem) {
vSemaphoreDelete(p_i2c->cmd_sem);
if (p_i2c_obj[i2c_num]->cmd_evt) {
vEventGroupDelete(p_i2c_obj[i2c_num]->cmd_evt);
p_i2c_obj[i2c_num]->cmd_evt = NULL;
}
if (p_i2c->slv_rx_mux) {
vSemaphoreDelete(p_i2c->slv_rx_mux);
@ -297,6 +320,8 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
free(p_i2c_obj[i2c_num]);
p_i2c_obj[i2c_num] = NULL;
i2c_hw_disable(i2c_num);
return ESP_OK;
}
@ -320,12 +345,13 @@ esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num)
return ESP_OK;
}
static void i2c_isr_handler_default(void* arg)
static void IRAM_ATTR i2c_isr_handler_default(void* arg)
{
i2c_obj_t* p_i2c = (i2c_obj_t*) arg;
int i2c_num = p_i2c->i2c_num;
uint32_t status = I2C[i2c_num]->int_status.val;
int idx = 0;
portBASE_TYPE HPTaskAwoken = pdFALSE;
while (status != 0) {
status = I2C[i2c_num]->int_status.val;
@ -345,6 +371,8 @@ static void i2c_isr_handler_default(void* arg)
I2C[i2c_num]->int_clr.trans_start = 1;
} else if (status & I2C_TIME_OUT_INT_ST_M) {
I2C[i2c_num]->int_clr.time_out = 1;
p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT;
i2c_master_cmd_begin_static(i2c_num);
} else if (status & I2C_TRANS_COMPLETE_INT_ST_M) {
I2C[i2c_num]->int_clr.trans_complete = 1;
if (p_i2c->mode == I2C_MODE_SLAVE) {
@ -366,6 +394,8 @@ static void i2c_isr_handler_default(void* arg)
I2C[i2c_num]->int_clr.master_tran_comp = 1;
} else if (status & I2C_ARBITRATION_LOST_INT_ST_M) {
I2C[i2c_num]->int_clr.arbitration_lost = 1;
p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT;
i2c_master_cmd_begin_static(i2c_num);
} else if (status & I2C_SLAVE_TRAN_COMP_INT_ST_M) {
I2C[i2c_num]->int_clr.slave_tran_comp = 1;
} else if (status & I2C_END_DETECT_INT_ST_M) {
@ -406,6 +436,12 @@ static void i2c_isr_handler_default(void* arg)
I2C[i2c_num]->int_clr.val = status;
}
}
if (p_i2c->mode == I2C_MODE_MASTER) {
xEventGroupSetBitsFromISR(p_i2c->cmd_evt, I2C_CMD_EVT_ALIVE, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
}
esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode)
@ -432,6 +468,101 @@ esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode,
return ESP_OK;
}
/* Some slave device will die by accident and keep the SDA in low level,
* in this case, master should send several clock to make the slave release the bus.
* Slave mode of ESP32 might also get in wrong state that held the SDA low,
* in this case, master device could send a stop signal to make esp32 slave release the bus.
**/
static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
int sda_in_sig = 0, scl_in_sig = 0;
if (i2c_num == I2C_NUM_0) {
sda_in_sig = I2CEXT0_SDA_IN_IDX;
scl_in_sig = I2CEXT0_SCL_IN_IDX;
} else if (i2c_num == I2C_NUM_1) {
sda_in_sig = I2CEXT1_SDA_IN_IDX;
scl_in_sig = I2CEXT1_SCL_IN_IDX;
}
int scl_io = GPIO.func_in_sel_cfg[scl_in_sig].func_sel;
int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel;
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((GPIO_IS_VALID_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
if (gpio_get_level(sda_io) == 1) {
return ESP_OK;
}
gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD);
gpio_set_direction(sda_io, GPIO_MODE_OUTPUT_OD);
gpio_set_level(scl_io, 0);
gpio_set_level(sda_io, 0);
for (int i = 0; i < 9; i++) {
gpio_set_level(scl_io, 1);
gpio_set_level(scl_io, 0);
}
gpio_set_level(scl_io, 1);
gpio_set_level(sda_io, 1);
i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
return ESP_OK;
}
/**if the power and SDA/SCL wires are in proper condition, everything works find with reading the slave.
* If we remove the power supply for the slave during I2C is reading, or directly connect SDA or SCL to ground,
* this would cause the I2C FSM get stuck in wrong state, all we can do is to reset the I2C hardware in this case.
**/
static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
uint32_t ctr = I2C[i2c_num]->ctr.val;
uint32_t fifo_conf = I2C[i2c_num]->fifo_conf.val;
uint32_t scl_low_period = I2C[i2c_num]->scl_low_period.val;
uint32_t scl_high_period = I2C[i2c_num]->scl_high_period.val;
uint32_t scl_start_hold = I2C[i2c_num]->scl_start_hold.val;
uint32_t scl_rstart_setup = I2C[i2c_num]->scl_rstart_setup.val;
uint32_t scl_stop_hold = I2C[i2c_num]->scl_stop_hold.val;
uint32_t scl_stop_setup = I2C[i2c_num]->scl_stop_setup.val;
uint32_t sda_hold = I2C[i2c_num]->sda_hold.val;
uint32_t sda_sample = I2C[i2c_num]->sda_sample.val;
uint32_t timeout = I2C[i2c_num]->timeout.val;
uint32_t scl_filter_cfg = I2C[i2c_num]->scl_filter_cfg.val;
uint32_t sda_filter_cfg = I2C[i2c_num]->sda_filter_cfg.val;
uint32_t slave_addr = I2C[i2c_num]->slave_addr.val;
//to reset the I2C hw module, we need re-enable the hw
i2c_hw_disable(i2c_num);
i2c_master_clear_bus(i2c_num);
i2c_hw_enable(i2c_num);
I2C[i2c_num]->int_ena.val = 0;
I2C[i2c_num]->ctr.val = ctr & (~I2C_TRANS_START_M);
I2C[i2c_num]->fifo_conf.val = fifo_conf;
I2C[i2c_num]->scl_low_period.val = scl_low_period;
I2C[i2c_num]->scl_high_period.val = scl_high_period;
I2C[i2c_num]->scl_start_hold.val = scl_start_hold;
I2C[i2c_num]->scl_rstart_setup.val = scl_rstart_setup;
I2C[i2c_num]->scl_stop_hold.val = scl_stop_hold;
I2C[i2c_num]->scl_stop_setup.val = scl_stop_setup;
I2C[i2c_num]->sda_hold.val = sda_hold;
I2C[i2c_num]->sda_sample.val = sda_sample;
I2C[i2c_num]->timeout.val = timeout;
I2C[i2c_num]->scl_filter_cfg.val = scl_filter_cfg;
I2C[i2c_num]->sda_filter_cfg.val = sda_filter_cfg;
uint32_t intr_mask = ( I2C_TRANS_COMPLETE_INT_ENA_M
| I2C_TRANS_START_INT_ENA_M
| I2C_ACK_ERR_INT_ENA_M
| I2C_RXFIFO_OVF_INT_ENA_M
| I2C_SLAVE_TRAN_COMP_INT_ENA_M
| I2C_TIME_OUT_INT_ENA_M);
if (I2C[i2c_num]->ctr.ms_mode == I2C_MODE_SLAVE) {
I2C[i2c_num]->slave_addr.val = slave_addr;
intr_mask |= ( I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M);
} else {
intr_mask |= I2C_ARBITRATION_LOST_INT_ENA_M;
}
I2C[i2c_num]->int_clr.val = intr_mask;
I2C[i2c_num]->int_ena.val = intr_mask;
return ESP_OK;
}
esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
@ -443,12 +574,7 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
if (ret != ESP_OK) {
return ret;
}
if (i2c_num == I2C_NUM_0) {
periph_module_enable(PERIPH_I2C0_MODULE);
} else if (i2c_num == I2C_NUM_1) {
periph_module_enable(PERIPH_I2C1_MODULE);
}
i2c_hw_enable(i2c_num);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
I2C[i2c_num]->ctr.rx_lsb_first = I2C_DATA_MODE_MSB_FIRST; //set rx data msb first
I2C[i2c_num]->ctr.tx_lsb_first = I2C_DATA_MODE_MSB_FIRST; //set tx data msb first
@ -464,26 +590,30 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
I2C[i2c_num]->fifo_conf.fifo_addr_cfg_en = 0;
I2C[i2c_num]->fifo_conf.rx_fifo_full_thrhd = I2C_FIFO_FULL_THRESH_VAL;
I2C[i2c_num]->fifo_conf.tx_fifo_empty_thrhd = I2C_FIFO_EMPTY_THRESH_VAL;
I2C[i2c_num]->int_ena.rx_fifo_full = 1;
I2C[i2c_num]->ctr.trans_start = 0;
I2C[i2c_num]->timeout.tout = I2C_SLAVE_TIMEOUT_DEFAULT;
//set timing for data
I2C[i2c_num]->sda_hold.time = I2C_SLAVE_SDA_HOLD_DEFAULT;
I2C[i2c_num]->sda_sample.time = I2C_SLAVE_SDA_SAMPLE_DEFAULT;
} else {
I2C[i2c_num]->fifo_conf.nonfifo_en = 0;
int cycle = (I2C_APB_CLK_FREQ / i2c_conf->master.clk_speed);
int half_cycle = cycle / 2;
I2C[i2c_num]->timeout.tout = cycle * I2C_MASTER_TOUT_CNUM_DEFAULT;
//set timing for data
I2C[i2c_num]->sda_hold.time = half_cycle / 2;
I2C[i2c_num]->sda_sample.time = half_cycle / 2;
I2C[i2c_num]->scl_low_period.period = half_cycle;
I2C[i2c_num]->scl_high_period.period = half_cycle;
//set timing for start signal
I2C[i2c_num]->scl_start_hold.time = half_cycle;
I2C[i2c_num]->scl_rstart_setup.time = half_cycle;
//set timing for stop signal
I2C[i2c_num]->scl_stop_hold.time = half_cycle;
I2C[i2c_num]->scl_stop_setup.time = half_cycle;
}
//set frequency
int half_cycle = ( I2C_APB_CLK_FREQ / i2c_conf->master.clk_speed ) / 2;
I2C[i2c_num]->scl_low_period.period = half_cycle - 1;
I2C[i2c_num]->scl_high_period.period = ( I2C_APB_CLK_FREQ / i2c_conf->master.clk_speed ) - half_cycle - 1;
//set timing for start signal
I2C[i2c_num]->scl_start_hold.time = half_cycle;
I2C[i2c_num]->scl_rstart_setup.time = half_cycle;
//set timing for stop signal
I2C[i2c_num]->scl_stop_hold.time = half_cycle;
I2C[i2c_num]->scl_stop_setup.time = half_cycle;
//set timing for data
I2C[i2c_num]->sda_hold.time = half_cycle / 2;
I2C[i2c_num]->sda_sample.time = half_cycle / 2;
//set timeout of receving data
I2C[i2c_num]->timeout.tout = 200000;
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
return ESP_OK;
}
@ -491,6 +621,9 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((high_period <= I2C_SCL_HIGH_PERIOD_V) && (high_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((low_period <= I2C_SCL_LOW_PERIOD_V) && (low_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
I2C[i2c_num]->scl_high_period.period = high_period;
I2C[i2c_num]->scl_low_period.period = low_period;
@ -515,6 +648,9 @@ esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period)
esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((hold_time <= I2C_SCL_START_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((setup_time <= I2C_SCL_RSTART_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C[i2c_num]->scl_start_hold.time = hold_time;
I2C[i2c_num]->scl_rstart_setup.time = setup_time;
return ESP_OK;
@ -537,6 +673,9 @@ esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int* setup_time, int* hold_ti
esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((setup_time <= I2C_SCL_STOP_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((hold_time <= I2C_SCL_STOP_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C[i2c_num]->scl_stop_hold.time = hold_time;
I2C[i2c_num]->scl_stop_setup.time = setup_time;
return ESP_OK;
@ -559,6 +698,9 @@ esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int* setup_time, int* hold_tim
esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((sample_time <= I2C_SDA_SAMPLE_TIME_V) && (sample_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((hold_time <= I2C_SDA_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C[i2c_num]->sda_hold.time = hold_time;
I2C[i2c_num]->sda_sample.time = sample_time;
return ESP_OK;
@ -578,6 +720,26 @@ esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_ti
return ESP_OK;
}
esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((timeout <= I2C_SDA_SAMPLE_TIME_V) && (timeout > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
I2C[i2c_num]->timeout.tout = timeout;
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
return ESP_OK;
}
esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int* timeout)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
if (timeout) {
*timeout = I2C[i2c_num]->timeout.tout;
}
return ESP_OK;
}
esp_err_t i2c_isr_register(i2c_port_t i2c_num, void (*fn)(void*), void * arg, int intr_alloc_flags, intr_handle_t *handle)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
@ -600,17 +762,20 @@ esp_err_t i2c_isr_free(intr_handle_t handle)
return esp_intr_free(handle);
}
esp_err_t i2c_set_pin(i2c_port_t i2c_num, gpio_num_t sda_io_num, gpio_num_t scl_io_num, gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode)
esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode)
{
I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(((GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num))), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io_num)) ||
I2C_CHECK(((sda_io_num < 0) || ((GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num)))), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(scl_io_num < 0 ||
(GPIO_IS_VALID_OUTPUT_GPIO(scl_io_num)) ||
(GPIO_IS_VALID_GPIO(scl_io_num) && mode == I2C_MODE_SLAVE),
I2C_SCL_IO_ERR_STR,
ESP_ERR_INVALID_ARG);
I2C_CHECK((sda_pullup_en == GPIO_PULLUP_ENABLE && GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num)) ||
I2C_CHECK(sda_io_num < 0 ||
(sda_pullup_en == GPIO_PULLUP_ENABLE && GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num)) ||
sda_pullup_en == GPIO_PULLUP_DISABLE, I2C_GPIO_PULLUP_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((scl_pullup_en == GPIO_PULLUP_ENABLE && GPIO_IS_VALID_OUTPUT_GPIO(scl_io_num)) ||
I2C_CHECK(scl_io_num < 0 ||
(scl_pullup_en == GPIO_PULLUP_ENABLE && GPIO_IS_VALID_OUTPUT_GPIO(scl_io_num)) ||
scl_pullup_en == GPIO_PULLUP_DISABLE, I2C_GPIO_PULLUP_ERR_STR, ESP_ERR_INVALID_ARG);
int sda_in_sig, sda_out_sig, scl_in_sig, scl_out_sig;
@ -633,6 +798,7 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, gpio_num_t sda_io_num, gpio_num_t scl_
gpio_set_level(sda_io_num, I2C_IO_INIT_LEVEL);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO);
gpio_set_direction(sda_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
if (sda_pullup_en == GPIO_PULLUP_ENABLE) {
gpio_set_pull_mode(sda_io_num, GPIO_PULLUP_ONLY);
} else {
@ -824,17 +990,22 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
{
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
portBASE_TYPE HPTaskAwoken = pdFALSE;
//This should never happen
if (p_i2c->mode == I2C_MODE_SLAVE) {
return;
}
if (p_i2c->status == I2C_STATUS_DONE) {
return;
} else if (p_i2c->status == I2C_STATUS_ACK_ERROR) {
} else if ((p_i2c->status == I2C_STATUS_ACK_ERROR)
|| (p_i2c->status == I2C_STATUS_TIMEOUT)) {
I2C[i2c_num]->int_ena.end_detect = 0;
I2C[i2c_num]->int_clr.end_detect = 1;
I2C[i2c_num]->int_ena.master_tran_comp = 0;
xSemaphoreGiveFromISR(p_i2c->cmd_sem, &HPTaskAwoken);
if(p_i2c->status == I2C_STATUS_TIMEOUT) {
I2C[i2c_num]->int_clr.time_out = 1;
I2C[i2c_num]->int_ena.val = 0;
}
xEventGroupSetBitsFromISR(p_i2c->cmd_evt, I2C_CMD_EVT_DONE, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
@ -853,7 +1024,7 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
}
if (p_i2c->cmd_link.head == NULL) {
p_i2c->cmd_link.cur = NULL;
xSemaphoreGiveFromISR(p_i2c->cmd_sem, &HPTaskAwoken);
xEventGroupSetBitsFromISR(p_i2c->cmd_evt, I2C_CMD_EVT_DONE, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
@ -917,29 +1088,31 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
}
}
I2C[i2c_num]->int_clr.end_detect = 1;
I2C[i2c_num]->int_clr.master_tran_comp = 1;
I2C[i2c_num]->int_ena.end_detect = 1;
I2C[i2c_num]->int_ena.master_tran_comp = 1;
I2C[i2c_num]->ctr.trans_start = 0;
I2C[i2c_num]->ctr.trans_start = 1;
return;
}
esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, portBASE_TYPE ticks_to_wait)
esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait)
{
I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_NOT_INSTALL_ERR_STR, ESP_ERR_INVALID_STATE);
I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_MASTER, I2C_MASTER_MODE_ERR_STR, ESP_ERR_INVALID_STATE);
I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
esp_err_t ret;
esp_err_t ret = ESP_FAIL;
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
portBASE_TYPE res = xSemaphoreTake(p_i2c->cmd_mux, ticks_to_wait);
if (res == pdFALSE) {
return ESP_ERR_TIMEOUT;
}
xSemaphoreTake(p_i2c->cmd_sem, 0);
xEventGroupClearBits(p_i2c->cmd_evt, I2C_CMD_EVT_DONE | I2C_CMD_EVT_ALIVE);
if (p_i2c->status == I2C_STATUS_TIMEOUT
|| I2C[i2c_num]->status_reg.bus_busy == 1) {
i2c_hw_fsm_reset(i2c_num);
}
i2c_reset_tx_fifo(i2c_num);
i2c_reset_rx_fifo(i2c_num);
i2c_cmd_desc_t* cmd = (i2c_cmd_desc_t*) cmd_handle;
@ -956,21 +1129,59 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
//start send commands, at most 32 bytes one time, isr handler will process the remaining commands.
i2c_master_cmd_begin_static(i2c_num);
ticks_to_wait = ticks_end - xTaskGetTickCount();
res = xSemaphoreTake(p_i2c->cmd_sem, ticks_to_wait);
if (res == pdFALSE) {
ret = ESP_ERR_TIMEOUT;
} else if (p_i2c->status == I2C_STATUS_ACK_ERROR) {
ret = ESP_FAIL;
if (ticks_to_wait == portMAX_DELAY) {
} else if (ticks_to_wait == 0) {
} else {
ret = ESP_OK;
ticks_to_wait = ticks_end - xTaskGetTickCount();
}
// Wait event bits
EventBits_t uxBits;
while (1) {
TickType_t wait_time = (ticks_to_wait < (I2C_CMD_ALIVE_INTERVAL_TICK) ? ticks_to_wait : (I2C_CMD_ALIVE_INTERVAL_TICK));
// In master mode, since we don't have an interrupt to detective bus error or FSM state, what we do here is to make
// sure the interrupt mechanism for master mode is still working.
// If the command sending is not finished and there is no interrupt any more, the bus is probably dead caused by external noise.
uxBits = xEventGroupWaitBits(p_i2c->cmd_evt, I2C_CMD_EVT_ALIVE | I2C_CMD_EVT_DONE, false, false, wait_time);
if (uxBits) {
if (uxBits & I2C_CMD_EVT_DONE) {
xEventGroupClearBits(p_i2c->cmd_evt, I2C_CMD_EVT_DONE);
if (p_i2c->status == I2C_STATUS_TIMEOUT) {
// If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
// I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
i2c_hw_fsm_reset(i2c_num);
ret = ESP_ERR_TIMEOUT;
} else if (p_i2c->status == I2C_STATUS_ACK_ERROR) {
ret = ESP_FAIL;
} else {
ret = ESP_OK;
}
break;
}
if (uxBits & I2C_CMD_EVT_ALIVE) {
xEventGroupClearBits(p_i2c->cmd_evt, I2C_CMD_EVT_ALIVE);
}
} else {
ret = ESP_ERR_TIMEOUT;
// If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
// I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
i2c_hw_fsm_reset(i2c_num);
break;
}
if (ticks_to_wait == portMAX_DELAY) {
} else {
TickType_t now = xTaskGetTickCount();
ticks_to_wait = ticks_end > now ? (ticks_end - now) : 0;
}
}
p_i2c->status = I2C_STATUS_DONE;
xSemaphoreGive(p_i2c->cmd_mux);
return ret;
}
int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, portBASE_TYPE ticks_to_wait)
int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType_t ticks_to_wait)
{
I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL);
I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_FAIL);
@ -1000,7 +1211,7 @@ int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, portBASE
return cnt;
}
static int i2c_slave_read(i2c_port_t i2c_num, uint8_t* data, size_t max_size, portBASE_TYPE ticks_to_wait)
static int i2c_slave_read(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait)
{
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
size_t size = 0;
@ -1012,7 +1223,7 @@ static int i2c_slave_read(i2c_port_t i2c_num, uint8_t* data, size_t max_size, po
return size;
}
int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, portBASE_TYPE ticks_to_wait)
int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait)
{
I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL);
I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_FAIL);
@ -1044,4 +1255,3 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, po

View file

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <math.h>
#include <esp_types.h>
#include "freertos/FreeRTOS.h"
@ -22,6 +23,8 @@
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc.h"
#include "soc/efuse_reg.h"
#include "rom/lldesc.h"
#include "driver/gpio.h"
@ -45,7 +48,9 @@ static const char* I2S_TAG = "I2S";
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
#define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE)
#define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER)
#define APLL_MIN_FREQ (350000000)
#define APLL_MAX_FREQ (500000000)
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
/**
* @brief DMA buffer object
*
@ -77,12 +82,28 @@ typedef struct {
int bytes_per_sample; /*!< Bytes per sample*/
int bits_per_sample; /*!< Bits per sample*/
i2s_mode_t mode; /*!< I2S Working mode*/
int use_apll; /*!< I2S use APLL clock */
} i2s_obj_t;
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
/**
* @brief Pre define APLL parameters, save compute time
* | bits_per_sample | rate | sdm0 | sdm1 | sdm2 | odir
*/
static const int apll_predefine[][6] = {
{16, 11025, 38, 80, 5, 31},
{16, 16000, 147, 107, 5, 21},
{16, 22050, 130, 152, 5, 15},
{16, 32000, 129, 212, 5, 10},
{16, 44100, 15, 8, 5, 6},
{16, 48000, 136, 212, 5, 6},
{16, 96000, 143, 212, 5, 2},
{0, 0, 0, 0, 0, 0}
};
static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len);
static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma);
static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num)
@ -166,6 +187,125 @@ static esp_err_t i2s_isr_register(i2s_port_t i2s_num, uint8_t intr_alloc_flags,
return esp_intr_alloc(ETS_I2S0_INTR_SOURCE + i2s_num, intr_alloc_flags, fn, arg, handle);
}
static float i2s_get_apll_real_rate(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir)
{
int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000;
uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0);
if (is_rev0) {
sdm0 = 0;
sdm1 = 0;
}
float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4);
if (fout < APLL_MIN_FREQ || fout > APLL_MAX_FREQ) {
return 9999999;
}
float fpll = fout / (2 * (odir+2)); //== fi2s (N=1, b=0, a=1)
return fpll/(8*4*bits_per_sample); //fbck = fi2s/bck_div
}
/**
* @brief APLL calculate function, was described by following:
* APLL Output frequency is given by the formula:
*
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
* apll_freq = fout / ((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 - 600 MHz.
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
* * sdm0 frequency adjustment parameter, 0..255
* * sdm1 frequency adjustment parameter, 0..255
* * sdm2 frequency adjustment parameter, 0..63
* * o_div frequency divider, 0..31
*
* The most accurate way to find the sdm0..2 and odir parameters is to loop through them all,
* then apply the above formula, finding the closest frequency to the desired one.
* But 256*256*64*32 = 134.217.728 loops are too slow with ESP32
* 1. We will choose the parameters with the highest level of change,
* With 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9,
* Take average frequency close to the desired frequency, and select sdm2
* 2. Next, we look for sequences of less influential and more detailed parameters,
* also by taking the average of the largest and smallest frequencies closer to the desired frequency.
* 3. And finally, loop through all the most detailed of the parameters, finding the best desired frequency
*
* @param[in] rate The sample rate
* @param[in] bits_per_sample The bits per sample
* @param[out] sdm0 The sdm 0
* @param[out] sdm1 The sdm 1
* @param[out] sdm2 The sdm 2
* @param[out] odir The odir
*
* @return ESP_FAIL or ESP_OK
*/
static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir)
{
int _odir, _sdm0, _sdm1, _sdm2, i;
float avg;
float min_rate, max_rate, min_diff;
if (rate < APLL_I2S_MIN_RATE) {
return ESP_FAIL;
}
//check pre-define apll parameters
i = 0;
while (apll_predefine[i][0]) {
if (apll_predefine[i][0] == bits_per_sample && apll_predefine[i][0] == rate) {
*sdm0 = apll_predefine[i][1];
*sdm1 = apll_predefine[i][2];
*sdm2 = apll_predefine[i][3];
*odir = apll_predefine[i][4];
return ESP_OK;
}
i++;
}
*sdm0 = 0;
*sdm1 = 0;
*sdm2 = 0;
*odir = 0;
min_diff = 99999;
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, _sdm2, 0);
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, 0, _sdm2, 31);
avg = (max_rate + min_rate)/2;
if(abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm2 = _sdm2;
}
}
min_diff = 99999;
for (_odir = 0; _odir < 32; _odir ++) {
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, *sdm2, _odir);
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, 0, *sdm2, _odir);
avg = (max_rate + min_rate)/2;
if(abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*odir = _odir;
}
}
min_diff = 99999;
for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) {
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, _sdm1, *sdm2, *odir);
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, _sdm1, *sdm2, *odir);
avg = (max_rate + min_rate)/2;
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm1 = _sdm1;
}
}
min_diff = 99999;
for (_sdm0 = 0; _sdm0 < 256; _sdm0 ++) {
avg = i2s_get_apll_real_rate(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir);
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm0 = _sdm0;
}
}
return ESP_OK;
}
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch)
{
int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs)
@ -204,6 +344,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
i2s_stop(i2s_num);
uint32_t cur_mode = 0;
if (p_i2s_obj[i2s_num]->channel_num != ch) {
p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1;
@ -278,7 +419,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
}
double mclk;
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_DAC_BUILT_IN) {
if (p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
//DAC uses bclk as sample clock, not WS. WS can be something arbitrary.
//Rate as given to this function is the intended sample rate;
//According to the TRM, WS clk equals to the sample rate, and bclk is double the speed of WS
@ -310,19 +451,33 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
mclk = clkmInteger + denom * clkmDecimals;
bck = factor/(bits * channel);
}
I2S[i2s_num]->clkm_conf.clka_en = 0;
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
I2S[i2s_num]->clkm_conf.clkm_div_b = clkmDecimals;
I2S[i2s_num]->clkm_conf.clkm_div_num = clkmInteger;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck;
int sdm0, sdm1, sdm2, odir;
if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate(rate, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) {
rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir);
I2S[i2s_num]->clkm_conf.clkm_div_num = 1;
I2S[i2s_num]->clkm_conf.clkm_div_b = 0;
I2S[i2s_num]->clkm_conf.clkm_div_a = 1;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = 8;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = 8;
I2S[i2s_num]->clkm_conf.clka_en = 1;
double real_rate = i2s_get_apll_real_rate(bits, sdm0, sdm1, sdm2, odir);
ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, real_rate, bits, 1, 8, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 1, 0);
} else {
I2S[i2s_num]->clkm_conf.clka_en = 0;
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
I2S[i2s_num]->clkm_conf.clkm_div_b = clkmDecimals;
I2S[i2s_num]->clkm_conf.clkm_div_num = clkmInteger;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck;
double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2);
ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals);
}
I2S[i2s_num]->sample_rate_conf.tx_bits_mod = bits;
I2S[i2s_num]->sample_rate_conf.rx_bits_mod = bits;
double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2);
ESP_LOGI(I2S_TAG, "Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals);
// wait all writing on-going finish
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) {
xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux);
@ -528,6 +683,11 @@ esp_err_t i2s_stop(i2s_port_t i2s_num)
I2S[i2s_num]->lc_conf.in_rst = 0;
I2S[i2s_num]->lc_conf.out_rst = 1;
I2S[i2s_num]->lc_conf.out_rst = 0;
I2S[i2s_num]->conf.tx_reset = 1;
I2S[i2s_num]->conf.tx_reset = 0;
I2S[i2s_num]->conf.rx_reset = 1;
I2S[i2s_num]->conf.rx_reset = 0;
I2S_EXIT_CRITICAL();
return 0;
}
@ -535,7 +695,7 @@ esp_err_t i2s_stop(i2s_port_t i2s_num)
esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode)
{
I2S_CHECK((dac_mode < I2S_DAC_CHANNEL_MAX), "i2s dac mode error", ESP_ERR_INVALID_ARG);
if(dac_mode == I2S_DAC_CHANNEL_DISABLE) {
if (dac_mode == I2S_DAC_CHANNEL_DISABLE) {
dac_output_disable(DAC_CHANNEL_1);
dac_output_disable(DAC_CHANNEL_2);
dac_i2s_disable();
@ -554,6 +714,13 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode)
return ESP_OK;
}
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel)
{
I2S_CHECK((adc_unit < ADC_UNIT_2), "i2s ADC unit error, only support ADC1 for now", ESP_ERR_INVALID_ARG);
// For now, we only support SAR ADC1.
return adc_i2s_mode_init(adc_unit, adc_channel);
}
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
@ -568,7 +735,7 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
ESP_LOGE(I2S_TAG, "ws_io_num error");
return ESP_FAIL;
}
if (pin->data_out_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_out_num)) {
if (pin->data_out_num != -1 && !GPIO_IS_VALID_OUTPUT_GPIO(pin->data_out_num)) {
ESP_LOGE(I2S_TAG, "data_out_num error");
return ESP_FAIL;
}
@ -669,10 +836,14 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate)
I2S_CHECK((p_i2s_obj[i2s_num]->bytes_per_sample > 0), "bits_per_sample not set", ESP_ERR_INVALID_ARG);
return i2s_set_clk(i2s_num, rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num);
}
static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_config)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK((i2s_config), "param null", ESP_ERR_INVALID_ARG);
I2S_CHECK(!((i2s_config->mode & I2S_MODE_ADC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S ADC built-in only support on I2S0", ESP_ERR_INVALID_ARG);
I2S_CHECK(!((i2s_config->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S DAC built-in only support on I2S0", ESP_ERR_INVALID_ARG);
I2S_CHECK(!((i2s_config->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), "I2S DAC PDM only support on I2S0", ESP_ERR_INVALID_ARG);
if (i2s_num == I2S_NUM_1) {
periph_module_enable(PERIPH_I2S1_MODULE);
@ -680,23 +851,27 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
periph_module_enable(PERIPH_I2S0_MODULE);
}
if(i2s_config->mode & I2S_MODE_ADC_BUILT_IN) {
//in ADC built-in mode, we need to call i2s_set_adc_mode to
//initialize the specific ADC channel.
//in the current stage, we only support ADC1 and single channel mode.
//In default data mode, the ADC data is in 12-bit resolution mode.
adc_power_on();
}
// configure I2S data port interface.
i2s_reset_fifo(i2s_num);
//reset i2s
I2S[i2s_num]->conf.tx_reset = 1;
I2S[i2s_num]->conf.tx_reset = 0;
I2S[i2s_num]->conf.rx_reset = 1;
I2S[i2s_num]->conf.rx_reset = 0;
//reset dma
I2S[i2s_num]->lc_conf.in_rst = 1;
I2S[i2s_num]->lc_conf.in_rst = 0;
I2S[i2s_num]->lc_conf.out_rst = 1;
I2S[i2s_num]->lc_conf.out_rst = 0;
//Enable and configure DMA
I2S[i2s_num]->lc_conf.check_owner = 0;
I2S[i2s_num]->lc_conf.out_loop_test = 0;
@ -707,7 +882,6 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
I2S[i2s_num]->lc_conf.indscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_eof_mode = 1;
I2S[i2s_num]->conf2.lcd_en = 0;
I2S[i2s_num]->conf2.camera_en = 0;
I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 0;
@ -751,9 +925,10 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
}
}
if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) {
if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
I2S[i2s_num]->conf2.lcd_en = 1;
I2S[i2s_num]->conf.tx_right_first = 1;
I2S[i2s_num]->conf2.camera_en = 0;
}
if (i2s_config->mode & I2S_MODE_PDM) {
@ -813,6 +988,8 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
I2S[i2s_num]->conf.rx_slave_mod = 1; //RX Slave
}
}
p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll;
return ESP_OK;
}
@ -873,7 +1050,12 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
return err;
}
i2s_stop(i2s_num);
i2s_param_config(i2s_num, i2s_config);
err = i2s_param_config(i2s_num, i2s_config);
if (err != ESP_OK) {
i2s_driver_uninstall(i2s_num);
ESP_LOGE(I2S_TAG, "I2S param configure error");
return err;
}
if (i2s_queue) {
p_i2s_obj[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t));
@ -914,6 +1096,10 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
p_i2s_obj[i2s_num]->i2s_queue = NULL;
}
if(p_i2s_obj[i2s_num]->use_apll) {
rtc_clk_apll_enable(0, 0, 0, 0, 0);
}
free(p_i2s_obj[i2s_num]);
p_i2s_obj[i2s_num] = NULL;

View file

@ -20,24 +20,38 @@ extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "driver/gpio.h"
#include "soc/adc_channel.h"
typedef enum {
ADC_ATTEN_0db = 0, /*!<The input voltage of ADC will be reduced to about 1/1 */
ADC_ATTEN_2_5db = 1, /*!<The input voltage of ADC will be reduced to about 1/1.34 */
ADC_ATTEN_6db = 2, /*!<The input voltage of ADC will be reduced to about 1/2 */
ADC_ATTEN_11db = 3, /*!<The input voltage of ADC will be reduced to about 1/3.6*/
ADC_ATTEN_DB_0 = 0, /*!<The input voltage of ADC will be reduced to about 1/1 */
ADC_ATTEN_DB_2_5 = 1, /*!<The input voltage of ADC will be reduced to about 1/1.34 */
ADC_ATTEN_DB_6 = 2, /*!<The input voltage of ADC will be reduced to about 1/2 */
ADC_ATTEN_DB_11 = 3, /*!<The input voltage of ADC will be reduced to about 1/3.6*/
ADC_ATTEN_MAX,
} adc_atten_t;
typedef enum {
ADC_WIDTH_9Bit = 0, /*!< ADC capture width is 9Bit*/
ADC_WIDTH_10Bit = 1, /*!< ADC capture width is 10Bit*/
ADC_WIDTH_11Bit = 2, /*!< ADC capture width is 11Bit*/
ADC_WIDTH_12Bit = 3, /*!< ADC capture width is 12Bit*/
ADC_WIDTH_BIT_9 = 0, /*!< ADC capture width is 9Bit*/
ADC_WIDTH_BIT_10 = 1, /*!< ADC capture width is 10Bit*/
ADC_WIDTH_BIT_11 = 2, /*!< ADC capture width is 11Bit*/
ADC_WIDTH_BIT_12 = 3, /*!< ADC capture width is 12Bit*/
ADC_WIDTH_MAX,
} adc_bits_width_t;
//this definitions are only for being back-compatible
#define ADC_ATTEN_0db ADC_ATTEN_DB_0
#define ADC_ATTEN_2_5db ADC_ATTEN_DB_2_5
#define ADC_ATTEN_6db ADC_ATTEN_DB_6
#define ADC_ATTEN_11db ADC_ATTEN_DB_11
//this definitions are only for being back-compatible
#define ADC_WIDTH_9Bit ADC_WIDTH_BIT_9
#define ADC_WIDTH_10Bit ADC_WIDTH_BIT_10
#define ADC_WIDTH_11Bit ADC_WIDTH_BIT_11
#define ADC_WIDTH_12Bit ADC_WIDTH_BIT_12
typedef enum {
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO36 */
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO37 */
@ -64,11 +78,56 @@ typedef enum {
ADC2_CHANNEL_MAX,
} adc2_channel_t;
typedef enum {
ADC_CHANNEL_0 = 0, /*!< ADC channel */
ADC_CHANNEL_1, /*!< ADC channel */
ADC_CHANNEL_2, /*!< ADC channel */
ADC_CHANNEL_3, /*!< ADC channel */
ADC_CHANNEL_4, /*!< ADC channel */
ADC_CHANNEL_5, /*!< ADC channel */
ADC_CHANNEL_6, /*!< ADC channel */
ADC_CHANNEL_7, /*!< ADC channel */
ADC_CHANNEL_8, /*!< ADC channel */
ADC_CHANNEL_9, /*!< ADC channel */
ADC_CHANNEL_MAX,
} adc_channel_t;
typedef enum {
ADC_UNIT_1 = 1, /*!< SAR ADC 1*/
ADC_UNIT_2 = 2, /*!< SAR ADC 2, not supported yet*/
ADC_UNIT_BOTH = 3, /*!< SAR ADC 1 and 2, not supported yet */
ADC_UNIT_ALTER = 7, /*!< SAR ADC 1 and 2 alternative mode, not supported yet */
ADC_UNIT_MAX,
} adc_unit_t;
typedef enum {
ADC_ENCODE_12BIT, /*!< ADC to I2S data format, [15:12]-channel [11:0]-12 bits ADC data */
ADC_ENCODE_11BIT, /*!< ADC to I2S data format, [15]-1 [14:11]-channel [10:0]-11 bits ADC data */
ADC_ENCODE_MAX,
} adc_i2s_encode_t;
typedef enum {
ADC_I2S_DATA_SRC_IO_SIG = 0, /*!< I2S data from GPIO matrix signal */
ADC_I2S_DATA_SRC_ADC = 1, /*!< I2S data from ADC */
ADC_I2S_DATA_SRC_MAX,
} adc_i2s_source_t;
/**
* @brief Configure ADC1 capture width.
*
* @brief Get the gpio number of a specific ADC1 channel.
*
* @param channel Channel to get the gpio number
*
* @param gpio_num output buffer to hold the gpio number
*
* @return
* - ESP_OK if success
* - ESP_ERR_INVALID_ARG if channal not valid
*/
esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num);
/**
* @brief Configure ADC1 capture width, meanwhile enable output invert for ADC1.
* The configuration is for all channels of ADC1
*
* @param width_bit Bit capture width for ADC1
*
* @return
@ -77,6 +136,16 @@ typedef enum {
*/
esp_err_t adc1_config_width(adc_bits_width_t width_bit);
/**
* @brief Configure ADC capture width.
* @param adc_unit ADC unit index
* @param width_bit Bit capture width for ADC unit.
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit);
/**
* @brief Configure the ADC1 channel, including setting attenuation.
*
@ -89,10 +158,10 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit);
*
* When VDD_A is 3.3V:
*
* - 0dB attenuaton (ADC_ATTEN_0db) gives full-scale voltage 1.1V
* - 2.5dB attenuation (ADC_ATTEN_2_5db) gives full-scale voltage 1.5V
* - 6dB attenuation (ADC_ATTEN_6db) gives full-scale voltage 2.2V
* - 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V (see note below)
* - 0dB attenuaton (ADC_ATTEN_DB_0) gives full-scale voltage 1.1V
* - 2.5dB attenuation (ADC_ATTEN_DB_2_5) gives full-scale voltage 1.5V
* - 6dB attenuation (ADC_ATTEN_DB_6) gives full-scale voltage 2.2V
* - 11dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9V (see note below)
*
* @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured
* bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.)
@ -134,6 +203,62 @@ int adc1_get_raw(adc1_channel_t channel);
int adc1_get_voltage(adc1_channel_t channel) __attribute__((deprecated));
/** @endcond */
/**
* @brief Power on SAR ADC
*/
void adc_power_on();
/**
* @brief Power off SAR ADC
*/
void adc_power_off();
/**
* @brief Initialize ADC pad
* @param adc_unit ADC unit index
* @param channel ADC channel index
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel);
/**
* @brief Set ADC data invert
* @param adc_unit ADC unit index
* @param inv_en whether enable data invert
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_set_data_inv(adc_unit_t adc_unit, bool inv_en);
/**
* @brief Set ADC source clock
* @param clk_div ADC clock divider, ADC clock is divided from APB clock
* @return
* - ESP_OK success
*/
esp_err_t adc_set_clk_div(uint8_t clk_div);
/**
* @brief Set I2S data source
* @param src I2S DMA data source, I2S DMA can get data from digital signals or from ADC.
* @return
* - ESP_OK success
*/
esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src);
/**
* @brief Initialize I2S ADC mode
* @param adc_unit ADC unit index
* @param channel ADC channel index
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel);
/**
* @brief Configure ADC1 to be usable by the ULP
*
@ -161,6 +286,70 @@ void adc1_ulp_enable();
*/
int hall_sensor_read();
/**
* @brief Get the gpio number of a specific ADC2 channel.
*
* @param channel Channel to get the gpio number
*
* @param gpio_num output buffer to hold the gpio number
*
* @return
* - ESP_OK if success
* - ESP_ERR_INVALID_ARG if channal not valid
*/
esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num);
/**
* @brief Configure the ADC2 channel, including setting attenuation.
*
* @note This function also configures the input GPIO pin mux to
* connect it to the ADC2 channel. It must be called before calling
* ``adc2_get_raw()`` for this channel.
*
* The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage,
* usually 3.3V) requires setting >0dB signal attenuation for that ADC channel.
*
* When VDD_A is 3.3V:
*
* - 0dB attenuaton (ADC_ATTEN_0db) gives full-scale voltage 1.1V
* - 2.5dB attenuation (ADC_ATTEN_2_5db) gives full-scale voltage 1.5V
* - 6dB attenuation (ADC_ATTEN_6db) gives full-scale voltage 2.2V
* - 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V (see note below)
*
* @note The full-scale voltage is the voltage corresponding to a maximum reading
* (depending on ADC2 configured bit width, this value is: 4095 for 12-bits, 2047
* for 11-bits, 1023 for 10-bits, 511 for 9 bits.)
*
* @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage.
*
* @param channel ADC2 channel to configure
* @param atten Attenuation level
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten);
/**
* @brief Take an ADC2 reading on a single channel
*
* @note For a given channel, ``adc2_config_channel_atten()``
* must be called before the first time this function is called. If Wi-Fi is started via ``esp_wifi_start()``, this
* function will always fail with ``ESP_ERR_TIMEOUT``.
*
* @param channel ADC2 channel to read
*
* @param width_bit Bit capture width for ADC2
*
* @param raw_out the variable to hold the output data.
*
* @return
* - ESP_OK if success
* - ESP_ERR_TIMEOUT the WIFI is started, using the ADC2
*/
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int* raw_out);
/**
* @brief Output ADC2 reference voltage to gpio 25 or 26 or 27
*

View file

@ -0,0 +1,52 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DRIVER_ADC2_INTERNAL_H_
#define _DRIVER_ADC2_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
/**
* @brief For WIFI module to claim the usage of ADC2.
*
* Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``.
* The WIFI module may have to wait for a short time for the current conversion (if exist) to finish.
*
* @return
* - ESP_OK success
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
*/
esp_err_t adc2_wifi_acquire();
/**
* @brief For WIFI module to let other tasks use the ADC2 when WIFI is not work.
*
* Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``.
* Call this function to release the occupation of ADC2 by WIFI.
*
* @return always return ESP_OK.
*/
esp_err_t adc2_wifi_release();
#ifdef __cplusplus
}
#endif
#endif /*_DRIVER_ADC2_INTERNAL_H_*/

View file

@ -29,6 +29,19 @@ typedef enum {
DAC_CHANNEL_MAX,
} dac_channel_t;
/**
* @brief Get the gpio number of a specific DAC channel.
*
* @param channel Channel to get the gpio number
*
* @param gpio_num output buffer to hold the gpio number
*
* @return
* - ESP_OK if success
* - ESP_ERR_INVALID_ARG if channal not valid
*/
esp_err_t dac_pad_get_io_num(dac_channel_t channel, gpio_num_t *gpio_num);
/** @cond */
/**
* @brief Set DAC output voltage.

View file

@ -200,7 +200,7 @@ esp_err_t i2c_isr_free(intr_handle_t handle);
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_pin(i2c_port_t i2c_num, gpio_num_t sda_io_num, gpio_num_t scl_io_num,
esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num,
gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode);
/**
@ -341,7 +341,7 @@ esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle);
* - ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode.
* - ESP_ERR_TIMEOUT Operation timeout because the bus is busy.
*/
esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, portBASE_TYPE ticks_to_wait);
esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait);
/**
* @brief I2C slave write data to internal ringbuffer, when tx fifo empty, isr will fill the hardware
@ -358,7 +358,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
* - ESP_FAIL(-1) Parameter error
* - Others(>=0) The number of data bytes that pushed to the I2C slave buffer.
*/
int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, portBASE_TYPE ticks_to_wait);
int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType_t ticks_to_wait);
/**
* @brief I2C slave read data from internal buffer. When I2C slave receive data, isr will copy received data
@ -375,7 +375,7 @@ int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, portBASE
* - ESP_FAIL(-1) Parameter error
* - Others(>=0) The number of data bytes that read from I2C slave buffer.
*/
int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, portBASE_TYPE ticks_to_wait);
int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait);
/**
* @brief set I2C master clock period
@ -481,6 +481,25 @@ esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time
*/
esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_time);
/**
* @brief set I2C timeout value
* @param i2c_num I2C port number
* @param timeout timeout value for I2C bus (unit: APB 80Mhz clock cycle)
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout);
/**
* @brief get I2C timeout value
* @param i2c_num I2C port number
* @param timeout pointer to get timeout value
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int* timeout);
/**
* @brief set I2C data transfer mode
*

View file

@ -26,6 +26,7 @@
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "driver/periph_ctrl.h"
#include "driver/adc.h"
#include "freertos/semphr.h"
#ifdef __cplusplus
@ -118,10 +119,12 @@ typedef enum {
I2S_MODE_TX = 4,
I2S_MODE_RX = 8,
I2S_MODE_DAC_BUILT_IN = 16, /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/
//I2S_MODE_ADC_BUILT_IN = 32, /*!< Currently not supported yet, will be added for the next version*/
I2S_MODE_ADC_BUILT_IN = 32, /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
I2S_MODE_PDM = 64,
} i2s_mode_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
*
@ -135,6 +138,7 @@ typedef struct {
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
int use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
} i2s_config_t;
/**
@ -402,6 +406,17 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
*/
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch);
/**
* @brief Set built-in ADC mode for I2S DMA, this function will initialize ADC pad,
* and set ADC parameters.
* @param adc_unit SAR ADC unit index
* @param adc_channel ADC channel index
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel);
#ifdef __cplusplus
}
#endif

View file

@ -26,6 +26,7 @@ extern "C" {
#define LEDC_APB_CLK_HZ (APB_CLK_FREQ)
#define LEDC_REF_CLK_HZ (1*1000000)
#define LEDC_ERR_DUTY (0xFFFFFFFF)
typedef enum {
LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */
@ -206,10 +207,10 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
* @param channel LEDC channel(0-7), select from ledc_channel_t
*
* @return
* - (-1) parameter error
* - LEDC_ERR_DUTY if parameter error
* - Others Current LEDC duty
*/
int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
/**
* @brief LEDC set gradient
@ -329,7 +330,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint
* - ESP_ERR_INVALID_STATE Fade function not installed.
* - ESP_FAIL Fade function init error
*/
esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int scale, int cycle_num);
esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int scale, int cycle_num);
/**
* @brief Set LEDC fade function, with a limited time. Should call ledc_fade_func_install() before calling this function.
@ -346,7 +347,7 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel
* - ESP_ERR_INVALID_STATE Fade function not installed.
* - ESP_FAIL Fade function init error
*/
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int max_fade_time_ms);
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int max_fade_time_ms);
/**
* @brief Install ledc fade function. This function will occupy interrupt of LEDC module.

View file

@ -18,59 +18,76 @@
extern "C" {
#endif
#define PCNT_PIN_NOT_USED (-1) /*!< Pin are not used */
#define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */
/**
* @brief Selection of available modes that determine the counter's action depending on the state of the control signal's input GPIO
* @note Configuration covers two actions, one for high, and one for low level on the control input
*/
typedef enum {
PCNT_MODE_KEEP = 0, /*!< Control mode: won't change counter mode*/
PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase);*/
PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition)*/
PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase) */
PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition) */
PCNT_MODE_MAX
} pcnt_ctrl_mode_t;
/**
* @brief Selection of available modes that determine the counter's action on the edge of the pulse signal's input GPIO
* @note Configuration covers two actions, one for positive, and one for negative edge on the pulse input
*/
typedef enum {
PCNT_COUNT_DIS = 0, /*!< Counter mode: Inhibit counter(counter value will not change in this condition)*/
PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value*/
PCNT_COUNT_DEC = 2, /*!< Counter mode: Decrease counter value*/
PCNT_COUNT_DIS = 0, /*!< Counter mode: Inhibit counter(counter value will not change in this condition) */
PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value */
PCNT_COUNT_DEC = 2, /*!< Counter mode: Decrease counter value */
PCNT_COUNT_MAX
} pcnt_count_mode_t;
/**
* @brief Selection of all available PCNT units
*/
typedef enum {
PCNT_UNIT_0 = 0, /*!< PCNT unit0 */
PCNT_UNIT_1 = 1, /*!< PCNT unit1 */
PCNT_UNIT_2 = 2, /*!< PCNT unit2 */
PCNT_UNIT_3 = 3, /*!< PCNT unit3 */
PCNT_UNIT_4 = 4, /*!< PCNT unit4 */
PCNT_UNIT_5 = 5, /*!< PCNT unit5 */
PCNT_UNIT_6 = 6, /*!< PCNT unit6 */
PCNT_UNIT_7 = 7, /*!< PCNT unit7 */
PCNT_UNIT_0 = 0, /*!< PCNT unit 0 */
PCNT_UNIT_1 = 1, /*!< PCNT unit 1 */
PCNT_UNIT_2 = 2, /*!< PCNT unit 2 */
PCNT_UNIT_3 = 3, /*!< PCNT unit 3 */
PCNT_UNIT_4 = 4, /*!< PCNT unit 4 */
PCNT_UNIT_5 = 5, /*!< PCNT unit 5 */
PCNT_UNIT_6 = 6, /*!< PCNT unit 6 */
PCNT_UNIT_7 = 7, /*!< PCNT unit 7 */
PCNT_UNIT_MAX,
} pcnt_unit_t;
/**
* @brief Selection of channels available for a single PCNT unit
*/
typedef enum {
PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel0 */
PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel1 */
PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel 0 */
PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel 1 */
PCNT_CHANNEL_MAX,
} pcnt_channel_t;
/**
* @brief Selection of counter's events the may trigger an interrupt
*/
typedef enum {
PCNT_EVT_L_LIM = 0, /*!< PCNT watch point event: Minimum counter value */
PCNT_EVT_H_LIM = 1, /*!< PCNT watch point event: Maximum counter value*/
PCNT_EVT_THRES_0 = 2, /*!< PCNT watch point event: threshold0 value event*/
PCNT_EVT_THRES_1 = 3, /*!< PCNT watch point event: threshold1 value event*/
PCNT_EVT_ZERO = 4, /*!< PCNT watch point event: counter value zero event*/
PCNT_EVT_H_LIM = 1, /*!< PCNT watch point event: Maximum counter value */
PCNT_EVT_THRES_0 = 2, /*!< PCNT watch point event: threshold0 value event */
PCNT_EVT_THRES_1 = 3, /*!< PCNT watch point event: threshold1 value event */
PCNT_EVT_ZERO = 4, /*!< PCNT watch point event: counter value zero event */
PCNT_EVT_MAX
} pcnt_evt_type_t;
/**
* @brief Pulse Counter configure struct
* @brief Pulse Counter configuration for a single channel
*/
typedef struct {
int pulse_gpio_num; /*!< Pulse input gpio_num, if you want to use gpio16, pulse_gpio_num = 16, a negative value will be ignored */
int ctrl_gpio_num; /*!< Contol signal input gpio_num, a negative value will be ignored*/
pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode*/
pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode*/
pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode*/
pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode*/
int pulse_gpio_num; /*!< Pulse input GPIO number, if you want to use GPIO16, enter pulse_gpio_num = 16, a negative value will be ignored */
int ctrl_gpio_num; /*!< Control signal input GPIO number, a negative value will be ignored */
pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode */
pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode */
pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode */
pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode */
int16_t counter_h_lim; /*!< Maximum counter value */
int16_t counter_l_lim; /*!< Minimum counter value */
pcnt_unit_t unit; /*!< PCNT unit number */
@ -150,7 +167,7 @@ esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit);
esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit);
/**
* @brief Disable PCNT interrupt for PCNT uint
* @brief Disable PCNT interrupt for PCNT unit
*
* @param pcnt_unit PCNT unit number
*
@ -219,10 +236,10 @@ esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16
*
* @param fn Interrupt handler function.
* @param arg Parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @return
* - ESP_OK Success
@ -236,11 +253,9 @@ esp_err_t pcnt_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags,
* @param unit PCNT unit number
* @param channel PCNT channel number
* @param pulse_io Pulse signal input GPIO
* @note
* Set to PCNT_PIN_NOT_USED if unused.
* @param ctrl_io Control signal input GPIO
* @note
* Set to PCNT_PIN_NOT_USED if unused.
*
* @note Set the signal input to PCNT_PIN_NOT_USED if unused.
*
* @return
* - ESP_OK Success
@ -329,8 +344,8 @@ esp_err_t pcnt_set_mode(pcnt_unit_t unit, pcnt_channel_t channel,
* .pulse_gpio_num = 4, //set gpio4 as pulse input gpio
* .ctrl_gpio_num = 5, //set gpio5 as control gpio
* .channel = PCNT_CHANNEL_0, //use unit 0 channel 0
* .lctrl_mode = PCNT_MODE_REVERSE, //when control signal is low ,reverse the primary counter mode(inc->dec/dec->inc)
* .hctrl_mode = PCNT_MODE_KEEP, //when control signal is high,keep the primary counter mode
* .lctrl_mode = PCNT_MODE_REVERSE, //when control signal is low, reverse the primary counter mode(inc->dec/dec->inc)
* .hctrl_mode = PCNT_MODE_KEEP, //when control signal is high, keep the primary counter mode
* .pos_mode = PCNT_COUNT_INC, //increment the counter
* .neg_mode = PCNT_COUNT_DIS, //keep the counter value
* .counter_h_lim = 10,

View file

@ -49,6 +49,10 @@ typedef enum {
PERIPH_SDIO_SLAVE_MODULE,
PERIPH_CAN_MODULE,
PERIPH_EMAC_MODULE,
PERIPH_RNG_MODULE,
PERIPH_WIFI_MODULE,
PERIPH_BT_MODULE,
PERIPH_WIFI_BT_COMMON_MODULE,
} periph_module_t;
/**
@ -56,6 +60,7 @@ typedef enum {
*
* @param[in] periph : Peripheral module name
*
* Clock for the module will be ungated, and reset de-asserted.
*
* @return NULL
*
@ -67,12 +72,28 @@ void periph_module_enable(periph_module_t periph);
*
* @param[in] periph : Peripheral module name
*
* Clock for the module will be gated, reset asserted.
*
* @return NULL
*
*/
void periph_module_disable(periph_module_t periph);
/**
* @brief reset peripheral module
*
* @param[in] periph : Peripheral module name
*
* Reset will asserted then de-assrted for the peripheral.
*
* Calling this function does not enable or disable the clock for the module.
*
* @return NULL
*
*/
void periph_module_reset(periph_module_t periph);
#ifdef __cplusplus
}
#endif

View file

@ -102,6 +102,7 @@ typedef struct {
#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
esp_err_t error; /*!< error returned from transfer */
int timeout_ms; /*!< response timeout, in milliseconds */
} sdmmc_command_t;
/**
@ -127,6 +128,7 @@ typedef struct {
esp_err_t (*set_card_clk)(int slot, uint32_t freq_khz); /*!< host function to set card clock frequency */
esp_err_t (*do_transaction)(int slot, sdmmc_command_t* cmdinfo); /*!< host function to do a transaction */
esp_err_t (*deinit)(void); /*!< host function to deinitialize the driver */
int command_timeout_ms; /*!< timeout, in milliseconds, of a single command. Set to 0 to use the default value. */
} sdmmc_host_t;
/**

View file

@ -53,6 +53,7 @@ typedef struct {
*/
struct spi_slave_transaction_t {
size_t length; ///< Total data length, in bits
size_t trans_len; ///< Transaction data length, in bits
const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase
void *rx_buffer; ///< Pointer to receive buffer, or NULL for no MISO phase
void *user; ///< User-defined variable. Can be used to store eg transaction ID.

View file

@ -26,7 +26,8 @@ extern "C" {
#endif
#define TIMER_BASE_CLK (APB_CLK_FREQ)
#define TIMER_BASE_CLK (APB_CLK_FREQ) /*!< Frequency of the clock on the input of the timer groups */
/**
* @brief Selects a Timer-Group out of 2 available groups
*/
@ -90,15 +91,15 @@ typedef enum {
} timer_autoreload_t;
/**
* @brief timer configure struct
* @brief Data structure with timer's configuration settings
*/
typedef struct {
bool alarm_en; /*!< Timer alarm enable */
bool counter_en; /*!< Counter enable */
bool alarm_en; /*!< Timer alarm enable */
bool counter_en; /*!< Counter enable */
timer_intr_mode_t intr_type; /*!< Interrupt mode */
timer_count_dir_t counter_dir; /*!< Counter direction */
bool auto_reload; /*!< Timer auto-reload */
uint16_t divider; /*!< Counter clock divider*/
bool auto_reload; /*!< Timer auto-reload */
uint32_t divider; /*!< Counter clock divider. The divider's range is from from 2 to 65536. */
} timer_config_t;
@ -202,13 +203,13 @@ esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num,
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param divider Timer clock divider value.
* @param divider Timer clock divider value. The divider's range is from from 2 to 65536.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider);
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint32_t divider);
/**
* @brief Set timer alarm value.
@ -249,27 +250,23 @@ esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num,
*/
esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en);
/**
* @brief register Timer interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
* @brief Register Timer interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
*
* @param group_num Timer group number
* @param timer_num Timer index of timer group
* @param fn Interrupt handler function.
* @note
* In case the this is called with the INIRAM flag, code inside the handler function can
* only call functions in IRAM, so it cannot call other timer APIs.
* Use direct register access to access timers from inside the ISR in this case.
*
* @param arg Parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Function pointer error.
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param 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.
* Use direct register access to configure timers from inside the ISR in this case.
*
* @return
* - ESP_OK Success

View file

@ -31,8 +31,8 @@ typedef enum {
TOUCH_PAD_NUM5, /*!< Touch pad channel 5 is GPIO12*/
TOUCH_PAD_NUM6, /*!< Touch pad channel 6 is GPIO14*/
TOUCH_PAD_NUM7, /*!< Touch pad channel 7 is GPIO27*/
TOUCH_PAD_NUM8, /*!< Touch pad channel 8 is GPIO32*/
TOUCH_PAD_NUM9, /*!< Touch pad channel 9 is GPIO33*/
TOUCH_PAD_NUM8, /*!< Touch pad channel 8 is GPIO33*/
TOUCH_PAD_NUM9, /*!< Touch pad channel 9 is GPIO32*/
TOUCH_PAD_MAX,
} touch_pad_t;

View file

@ -35,7 +35,7 @@ extern "C" {
#include "soc/uart_channel.h"
#define UART_FIFO_LEN (128) /*!< Length of the hardware FIFO buffers */
#define UART_INTR_MASK 0x1ff /*!< mask of all UART interrupts */
#define UART_INTR_MASK 0x1ff /*!< Mask of all UART interrupts */
#define UART_LINE_INV_MASK (0x3f << 19) /*!< TBD */
#define UART_BITRATE_MAX 5000000 /*!< Max bit rate supported by UART */
#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */
@ -73,7 +73,7 @@ typedef enum {
typedef enum {
UART_NUM_0 = 0x0, /*!< UART base address 0x3ff40000*/
UART_NUM_1 = 0x1, /*!< UART base address 0x3ff50000*/
UART_NUM_2 = 0x2, /*!< UART base address 0x3ff6E000*/
UART_NUM_2 = 0x2, /*!< UART base address 0x3ff6e000*/
UART_NUM_MAX,
} uart_port_t;
@ -81,7 +81,7 @@ typedef enum {
* @brief UART parity constants
*/
typedef enum {
UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/
UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/
UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/
UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/
} uart_parity_t;
@ -101,12 +101,13 @@ typedef enum {
* @brief UART configuration parameters for uart_param_config function
*/
typedef struct {
int baud_rate; /*!< UART baudrate*/
int baud_rate; /*!< UART baud rate*/
uart_word_length_t data_bits; /*!< UART byte size*/
uart_parity_t parity; /*!< UART parity mode*/
uart_stop_bits_t stop_bits; /*!< UART stop bits*/
uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode(cts/rts)*/
uint8_t rx_flow_ctrl_thresh ; /*!< UART HW RTS threshold*/
uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode (cts/rts)*/
uint8_t rx_flow_ctrl_thresh; /*!< UART HW RTS threshold*/
bool use_ref_tick; /*!< Set to true if UART should be clocked from REF_TICK */
} uart_config_t;
/**
@ -114,13 +115,13 @@ typedef struct {
*/
typedef struct {
uint32_t intr_enable_mask; /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/
uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold(unit: time of sending one byte)*/
uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold (unit: time of sending one byte)*/
uint8_t txfifo_empty_intr_thresh; /*!< UART TX empty interrupt threshold.*/
uint8_t rxfifo_full_thresh; /*!< UART RX full interrupt threshold.*/
} uart_intr_config_t;
/**
* @brief UART event types used in the ringbuffer
* @brief UART event types used in the ring buffer
*/
typedef enum {
UART_DATA, /*!< UART data event*/
@ -181,7 +182,7 @@ esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bi
esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits);
/**
* @brief Set UART stop bits.
* @brief Get UART stop bits.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param stop_bits Pointer to accept value of UART stop bits.
@ -193,7 +194,7 @@ esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits);
esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bits);
/**
* @brief Set UART parity.
* @brief Set UART parity mode.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param parity_mode the enum of uart parity configuration
@ -230,7 +231,7 @@ esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode);
esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate);
/**
* @brief Get UART bit-rate.
* @brief Get UART baud rate.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param baudrate Pointer to accept value of UART baud rate
@ -247,7 +248,9 @@ esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param inverse_mask Choose the wires that need to be inverted.
* Inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR operation.
* Inverse_mask should be chosen from
UART_INVERSE_RXD / UART_INVERSE_TXD / UART_INVERSE_RTS / UART_INVERSE_CTS,
combined with OR operation.
*
* @return
* - ESP_OK Success
@ -260,8 +263,8 @@ esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask);
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param flow_ctrl Hardware flow control mode
* @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN).
* Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set.
* @param rx_thresh Threshold of Hardware RX flow control (0 ~ UART_FIFO_LEN).
* Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set.
*
* @return
* - ESP_OK Success
@ -298,9 +301,9 @@ esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flo
/**
* @brief Clear UART interrupt status
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param clr_mask Bit mask of the status that to be cleared.
* enable_mask should be chosen from the fields of register UART_INT_CLR_REG.
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param clr_mask Bit mask of the interrupt status to be cleared.
* The bit mask should be composed from the fields of register UART_INT_CLR_REG.
*
* @return
* - ESP_OK Success
@ -311,9 +314,9 @@ esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask);
/**
* @brief Set UART interrupt enable
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param enable_mask Bit mask of the enable bits.
* enable_mask should be chosen from the fields of register UART_INT_ENA_REG.
* The bit mask should be composed from the fields of register UART_INT_ENA_REG.
*
* @return
* - ESP_OK Success
@ -324,9 +327,9 @@ esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);
/**
* @brief Clear UART interrupt enable bits
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param disable_mask Bit mask of the disable bits.
* disable_mask should be chosen from the fields of register UART_INT_ENA_REG.
* The bit mask should be composed from the fields of register UART_INT_ENA_REG.
*
* @return
* - ESP_OK Success
@ -334,9 +337,8 @@ esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);
*/
esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask);
/**
* @brief Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
* @brief Enable UART RX interrupt (RX_FULL & RX_TIMEOUT INTERRUPT)
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
*
@ -347,7 +349,7 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask);
esp_err_t uart_enable_rx_intr(uart_port_t uart_num);
/**
* @brief Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
* @brief Disable UART RX interrupt (RX_FULL & RX_TIMEOUT INTERRUPT)
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
*
@ -358,7 +360,7 @@ esp_err_t uart_enable_rx_intr(uart_port_t uart_num);
esp_err_t uart_disable_rx_intr(uart_port_t uart_num);
/**
* @brief Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
* @brief Disable UART TX interrupt (TX_FULL & TX_TIMEOUT INTERRUPT)
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
*
@ -369,7 +371,7 @@ esp_err_t uart_disable_rx_intr(uart_port_t uart_num);
esp_err_t uart_disable_tx_intr(uart_port_t uart_num);
/**
* @brief Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
* @brief Enable UART TX interrupt (TX_FULL & TX_TIMEOUT INTERRUPT)
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param enable 1: enable; 0: disable
@ -382,15 +384,15 @@ esp_err_t uart_disable_tx_intr(uart_port_t uart_num);
esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
/**
* @brief register UART interrupt handler(ISR).
* @brief Register UART interrupt handler (ISR).
*
* @note UART ISR handler will be attached to the same CPU core that this function is running on.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param fn Interrupt handler function.
* @param arg parameter for handler function
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
@ -400,7 +402,6 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
*/
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags, uart_isr_handle_t *handle);
/**
* @brief Free UART interrupt handler registered by uart_isr_register. Must be called on the same core as
* uart_isr_register was called.
@ -417,13 +418,16 @@ esp_err_t uart_isr_free(uart_port_t uart_num);
* @brief Set UART pin number
*
* @note Internal signal can be output to multiple GPIO pads.
* Only one GPIO pad can connect with input signal.
* Only one GPIO pad can connect with input signal.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param tx_io_num UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
* @param rx_io_num UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
* @param rts_io_num UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
* @param cts_io_num UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
* @note Instead of GPIO number a macro 'UART_PIN_NO_CHANGE' may be provided
to keep the currently allocated pin.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param tx_io_num UART TX pin GPIO number.
* @param rx_io_num UART RX pin GPIO number.
* @param rts_io_num UART RTS pin GPIO number.
* @param cts_io_num UART CTS pin GPIO number.
*
* @return
* - ESP_OK Success
@ -432,11 +436,11 @@ esp_err_t uart_isr_free(uart_port_t uart_num);
esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num);
/**
* @brief UART set RTS level (before inverse)
* UART rx hardware flow control should not be set.
* @brief Manually set the UART RTS pin level.
* @note UART must be configured with hardware flow control disabled.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param level 1: RTS output low(active); 0: RTS output high(block)
* @param level 1: RTS output low (active); 0: RTS output high (block)
*
* @return
* - ESP_OK Success
@ -445,9 +449,9 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r
esp_err_t uart_set_rts(uart_port_t uart_num, int level);
/**
* @brief UART set DTR level (before inverse)
* @brief Manually set the UART DTR pin level.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param level 1: DTR output low; 0: DTR output high
*
* @return
@ -457,9 +461,22 @@ esp_err_t uart_set_rts(uart_port_t uart_num, int level);
esp_err_t uart_set_dtr(uart_port_t uart_num, int level);
/**
* @brief UART parameter configure
* @brief Set UART idle interval after tx FIFO is empty
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param idle_num idle interval after tx FIFO is empty(unit: the time it takes to send one bit
* under current baudrate)
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_tx_idle_num(uart_port_t uart_num, uint16_t idle_num);
/**
* @brief Set UART configuration parameters.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param uart_config UART parameter settings
*
* @return
@ -469,9 +486,9 @@ esp_err_t uart_set_dtr(uart_port_t uart_num, int level);
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);
/**
* @brief UART interrupt configure
* @brief Configure UART interrupts.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param intr_conf UART interrupt settings
*
* @return
@ -485,18 +502,18 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
*
* UART ISR handler will be attached to the same CPU core that this function is running on.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param rx_buffer_size UART RX ring buffer size, rx_buffer_size should be greater than UART_FIFO_LEN.
* @param tx_buffer_size UART TX ring buffer size.
* If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..
* @note tx_buffer_size should be greater than UART_FIFO_LEN.
* @note Rx_buffer_size should be greater than UART_FIFO_LEN. Tx_buffer_size should be either zero or greater than UART_FIFO_LEN.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param rx_buffer_size UART RX ring buffer size.
* @param tx_buffer_size UART TX ring buffer size.
* If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out.
* @param queue_size UART event queue size/depth.
* @param uart_queue UART event queue handle (out param). On success, a new queue handle is written here to provide
* access to UART events. If set to NULL, driver will not use an event queue.
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. Do not set ESP_INTR_FLAG_IRAM here
* (the driver's ISR handler is not located in IRAM)
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. Do not set ESP_INTR_FLAG_IRAM here
* (the driver's ISR handler is not located in IRAM)
*
* @return
* - ESP_OK Success
@ -507,7 +524,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
/**
* @brief Uninstall UART driver.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
*
* @return
* - ESP_OK Success
@ -516,9 +533,9 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
esp_err_t uart_driver_delete(uart_port_t uart_num);
/**
* @brief Wait UART TX FIFO empty
* @brief Wait until UART TX FIFO is empty.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param ticks_to_wait Timeout, count in RTOS ticks
*
* @return
@ -531,59 +548,59 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait);
/**
* @brief Send data to the UART port from a given buffer and length.
*
* This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full.
* This function will not wait for enough space in TX FIFO. It will just fill the available TX FIFO and return when the FIFO is full.
* @note This function should only be used when UART TX buffer is not enabled.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param buffer data buffer address
* @param len data length to send
* @param buffer data buffer address
* @param len data length to send
*
* @return
* - (-1) Parameter error
* - OTHERS(>=0) The number of data that pushed to the TX FIFO
* - OTHERS (>=0) The number of bytes pushed to the TX FIFO
*/
int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);
/**
* @brief Send data to the UART port from a given buffer and length,
*
* If parameter tx_buffer_size is set to zero:
* If the UART driver's parameter 'tx_buffer_size' is set to zero:
* This function will not return until all the data have been sent out, or at least pushed into TX FIFO.
*
* Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,
* then, UART ISR will move data from ring buffer to TX FIFO gradually.
* Otherwise, if the 'tx_buffer_size' > 0, this function will return after copying all the data to tx ring buffer,
* UART ISR will then move data from the ring buffer to TX FIFO gradually.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param src data buffer address
* @param size data length to send
* @param src data buffer address
* @param size data length to send
*
* @return
* - (-1) Parameter error
* - OTHERS(>=0) The number of data that pushed to the TX FIFO
* - OTHERS (>=0) The number of bytes pushed to the TX FIFO
*/
int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size);
/**
* @brief Send data to the UART port from a given buffer and length,
* @brief Send data to the UART port from a given buffer and length.
*
* If parameter tx_buffer_size is set to zero:
* If the UART driver's parameter 'tx_buffer_size' is set to zero:
* This function will not return until all the data and the break signal have been sent out.
* After all data send out, send a break signal.
* After all data is sent out, send a break signal.
*
* Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,
* then, UART ISR will move data from ring buffer to TX FIFO gradually.
* After all data send out, send a break signal.
* Otherwise, if the 'tx_buffer_size' > 0, this function will return after copying all the data to tx ring buffer,
* UART ISR will then move data from the ring buffer to TX FIFO gradually.
* After all data sent out, send a break signal.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param src data buffer address
* @param size data length to send
* @param brk_len break signal length (unit: time of one data bit at current_baudrate)
* @param brk_len break signal length (unit: the time it takes to send a complete byte
including start, stop and parity bits at current_baudrate)
*
* @return
* - (-1) Parameter error
* - OTHERS(>=0) The number of data that pushed to the TX FIFO
* - OTHERS (>=0) The number of bytes pushed to the TX FIFO
*/
int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len);
/**
@ -596,7 +613,7 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t si
*
* @return
* - (-1) Error
* - Others return a char data from uart fifo.
* - OTHERS (>=0) The number of bytes read from UART FIFO
*/
int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait);
@ -612,10 +629,10 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
esp_err_t uart_flush(uart_port_t uart_num);
/**
* @brief UART get RX ring buffer cached data length
* @brief UART get RX ring buffer cached data length
*
* @param uart_num UART port number.
* @param size Pointer of size_t to accept cached data length
* @param uart_num UART port number.
* @param size Pointer of size_t to accept cached data length
*
* @return
* - ESP_OK Success
@ -624,11 +641,11 @@ esp_err_t uart_flush(uart_port_t uart_num);
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);
/**
* @brief UART disable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
* @brief UART disable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detects a series of one same character, the interrupt will be triggered.
*
* @param uart_num UART port number.
* @param uart_num UART port number.
*
* @return
* - ESP_OK Success
@ -637,183 +654,22 @@ esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);
esp_err_t uart_disable_pattern_det_intr(uart_port_t uart_num);
/**
* @brief UART enable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
* @brief UART enable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
*
* @param uart_num UART port number.
* @param pattern_chr character of the pattern
* @param chr_num number of the character, 8bit value.
* @param chr_tout timeout of the interval between each pattern characters, 24bit value, unit is APB(80Mhz) clock cycle.
* @param post_idle idle time after the last pattern character, 24bit value, unit is APB(80Mhz) clock cycle.
* @param pre_idle idle time before the first pattern character, 24bit value, unit is APB(80Mhz) clock cycle.
* @param chr_tout timeout of the interval between each pattern characters, 24bit value, unit is APB (80Mhz) clock cycle.
* @param post_idle idle time after the last pattern character, 24bit value, unit is APB (80Mhz) clock cycle.
* @param pre_idle idle time before the first pattern character, 24bit value, unit is APB (80Mhz) clock cycle.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle);
/***************************EXAMPLE**********************************
*
*
* ----------------EXAMPLE OF UART SETTING ---------------------
* @code{c}
* //1. Setup UART
* #include "freertos/queue.h"
* //a. Set UART parameter
* int uart_num = 0; //uart port number
* uart_config_t uart_config = {
* .baud_rate = 115200, //baudrate
* .data_bits = UART_DATA_8_BITS, //data bit mode
* .parity = UART_PARITY_DISABLE, //parity mode
* .stop_bits = UART_STOP_BITS_1, //stop bit mode
* .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, //hardware flow control(cts/rts)
* .rx_flow_ctrl_thresh = 120, //flow control threshold
* };
* uart_param_config(uart_num, &uart_config);
* //b1. Setup UART driver(with UART queue)
* QueueHandle_t uart_queue;
* //parameters here are just an example, tx buffer size is 2048
* uart_driver_install(uart_num, 1024 * 2, 1024 * 2, 10, &uart_queue, 0);
* //b2. Setup UART driver(without UART queue)
* //parameters here are just an example, tx buffer size is 0
* uart_driver_install(uart_num, 1024 * 2, 0, 10, NULL, 0);
*@endcode
*-----------------------------------------------------------------------------*
* @code{c}
* //2. Set UART pin
* //set UART pin, not needed if use default pins.
* uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 15, 13);
* @endcode
*-----------------------------------------------------------------------------*
* @code{c}
* //3. Read data from UART.
* uint8_t data[128];
* int length = 0;
* length = uart_read_bytes(uart_num, data, sizeof(data), 100);
* @endcode
*-----------------------------------------------------------------------------*
* @code{c}
* //4. Write data to UART.
* char* test_str = "This is a test string.\n"
* uart_write_bytes(uart_num, (const char*)test_str, strlen(test_str));
* @endcode
*-----------------------------------------------------------------------------*
* @code{c}
* //5. Write data to UART, end with a break signal.
* uart_write_bytes_with_break(0, "test break\n",strlen("test break\n"), 100);
* @endcode
*-----------------------------------------------------------------------------*
* @code{c}
* //6. an example of echo test with hardware flow control on UART1
* void uart_loop_back_test()
* {
* int uart_num = 1;
* uart_config_t uart_config = {
* .baud_rate = 115200,
* .data_bits = UART_DATA_8_BITS,
* .parity = UART_PARITY_DISABLE,
* .stop_bits = UART_STOP_BITS_1,
* .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
* .rx_flow_ctrl_thresh = 122,
* };
* //Configure UART1 parameters
* uart_param_config(uart_num, &uart_config);
* //Set UART1 pins(TX: IO16, RX: IO17, RTS: IO18, CTS: IO19)
* uart_set_pin(uart_num, 16, 17, 18, 19);
* //Install UART driver( We don't need an event queue here)
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 0, NULL, 0);
* uint8_t data[1000];
* while(1) {
* //Read data from UART
* int len = uart_read_bytes(uart_num, data, sizeof(data), 10);
* //Write data back to UART
* uart_write_bytes(uart_num, (const char*)data, len);
* }
* }
* @endcode
*-----------------------------------------------------------------------------*
* @code{c}
* //7. An example of using UART event queue on UART0.
* #include "freertos/queue.h"
* //A queue to handle UART event.
* QueueHandle_t uart0_queue;
* static const char *TAG = "uart_example";
* void uart_task(void *pvParameters)
* {
* int uart_num = (int)pvParameters;
* uart_event_t event;
* size_t size = 1024;
* uint8_t* dtmp = (uint8_t*)malloc(size);
* for(;;) {
* //Waiting for UART event.
* if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
* ESP_LOGI(TAG, "uart[%d] event:", uart_num);
* switch(event.type) {
* memset(dtmp, 0, size);
* //Event of UART receving data
* case UART_DATA:
* ESP_LOGI(TAG,"data, len: %d", event.size);
* int len = uart_read_bytes(uart_num, dtmp, event.size, 10);
* ESP_LOGI(TAG, "uart read: %d", len);
* break;
* //Event of HW FIFO overflow detected
* case UART_FIFO_OVF:
* ESP_LOGI(TAG, "hw fifo overflow\n");
* break;
* //Event of UART ring buffer full
* case UART_BUFFER_FULL:
* ESP_LOGI(TAG, "ring buffer full\n");
* break;
* //Event of UART RX break detected
* case UART_BREAK:
* ESP_LOGI(TAG, "uart rx break\n");
* break;
* //Event of UART parity check error
* case UART_PARITY_ERR:
* ESP_LOGI(TAG, "uart parity error\n");
* break;
* //Event of UART frame error
* case UART_FRAME_ERR:
* ESP_LOGI(TAG, "uart frame error\n");
* break;
* //Others
* default:
* ESP_LOGI(TAG, "uart event type: %d\n", event.type);
* break;
* }
* }
* }
* free(dtmp);
* dtmp = NULL;
* vTaskDelete(NULL);
* }
*
* void uart_queue_test()
* {
* int uart_num = 0;
* uart_config_t uart_config = {
* .baud_rate = 115200,
* .data_bits = UART_DATA_8_BITS,
* .parity = UART_PARITY_DISABLE,
* .stop_bits = UART_STOP_BITS_1,
* .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
* .rx_flow_ctrl_thresh = 122,
* };
* //Set UART parameters
* uart_param_config(uart_num, &uart_config);
* //Set UART pins,(-1: default pin, no change.)
* uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
* //Set UART log level
* esp_log_level_set(TAG, ESP_LOG_INFO);
* //Install UART driver, and get the queue.
* uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, &uart0_queue, 0);
* //Create a task to handler UART event from ISR
* xTaskCreate(uart_task, "uTask", 1024, (void*)uart_num, 10, NULL);
* }
* @endcode
*
***************************END OF EXAMPLE**********************************/
#ifdef __cplusplus
}

View file

@ -34,7 +34,7 @@ static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
typedef struct {
uint16_t speed_mode;
uint16_t direction;
int target_duty;
uint32_t target_duty;
int cycle_num;
int scale;
ledc_fade_mode_t mode;
@ -352,9 +352,9 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
return ESP_OK;
}
int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
{
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, (-1));
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, (LEDC_ERR_DUTY));
uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4);
return duty;
}
@ -418,7 +418,7 @@ void IRAM_ATTR ledc_fade_isr(void* arg)
//fade object not initialized yet.
continue;
}
int duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
uint32_t duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
if (duty_cur == s_ledc_fade_rec[speed_mode][channel]->target_duty) {
if (s_ledc_fade_rec[speed_mode][channel]->mode == LEDC_FADE_WAIT_DONE) {
xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken);
@ -428,7 +428,7 @@ void IRAM_ATTR ledc_fade_isr(void* arg)
}
continue;
}
int duty_tar = s_ledc_fade_rec[speed_mode][channel]->target_duty;
uint32_t duty_tar = s_ledc_fade_rec[speed_mode][channel]->target_duty;
int scale = s_ledc_fade_rec[speed_mode][channel]->scale;
if (scale == 0) {
continue;
@ -497,18 +497,18 @@ static esp_err_t ledc_fade_channel_init_check(ledc_mode_t speed_mode, ledc_chann
}
}
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int max_fade_time_ms)
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int max_fade_time_ms)
{
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
LEDC_CHECK(channel < LEDC_CHANNEL_MAX, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK , LEDC_FADE_INIT_ERROR_STR, ESP_FAIL);
int timer_sel = LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel;
int max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num)) - 1;
uint32_t max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num)) - 1;
LEDC_CHECK(target_duty <= max_duty, LEDC_FADE_TARGET_ERR_STR, ESP_ERR_INVALID_ARG);
uint32_t freq = ledc_get_freq(speed_mode, timer_sel);
int duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
int duty_delta = target_duty > duty_cur ? target_duty - duty_cur : duty_cur - target_duty;
uint32_t duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
uint32_t duty_delta = target_duty > duty_cur ? target_duty - duty_cur : duty_cur - target_duty;
if (duty_delta == 0) {
return ESP_OK;
@ -528,21 +528,21 @@ esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel
return ledc_set_fade_with_step(speed_mode, channel, target_duty, scale, cycle_num);
}
esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int scale, int cycle_num)
esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int scale, int cycle_num)
{
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
LEDC_CHECK(channel < LEDC_CHANNEL_MAX, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK , LEDC_FADE_INIT_ERROR_STR, ESP_FAIL);
int timer_sel = LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel;
int max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num)) - 1;
uint32_t max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num)) - 1;
LEDC_CHECK(target_duty <= max_duty, LEDC_FADE_TARGET_ERR_STR, ESP_ERR_INVALID_ARG);
//disable the interrupt, so the operation will not mess up
ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_DISABLE);
portENTER_CRITICAL(&ledc_spinlock);
int duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
int duty_delta = target_duty > duty_cur ? target_duty - duty_cur : duty_cur - target_duty;
uint32_t duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
uint32_t duty_delta = target_duty > duty_cur ? target_duty - duty_cur : duty_cur - target_duty;
if (duty_delta == 0) {
portEXIT_CRITICAL(&ledc_spinlock);
return ESP_OK;

View file

@ -21,230 +21,194 @@
static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED;
/* Static functions to return register address & mask for clk_en / rst of each peripheral */
static uint32_t get_clk_en_mask(periph_module_t periph);
static uint32_t get_rst_en_mask(periph_module_t periph);
static uint32_t get_clk_en_reg(periph_module_t periph);
static uint32_t get_rst_en_reg(periph_module_t periph);
void periph_module_enable(periph_module_t periph)
{
portENTER_CRITICAL(&periph_spinlock);
switch(periph) {
case PERIPH_RMT_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST);
break;
case PERIPH_LEDC_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
break;
case PERIPH_UART0_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
break;
case PERIPH_UART1_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
break;
case PERIPH_UART2_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
break;
case PERIPH_I2C0_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT0_RST);
break;
case PERIPH_I2C1_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT1_RST);
break;
case PERIPH_I2S0_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
break;
case PERIPH_I2S1_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
break;
case PERIPH_TIMG0_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
break;
case PERIPH_TIMG1_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
break;
case PERIPH_PWM0_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM0_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM0_RST);
break;
case PERIPH_PWM1_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM1_RST);
break;
case PERIPH_PWM2_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM2_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM2_RST);
break;
case PERIPH_PWM3_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM3_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM3_RST);
break;
case PERIPH_UHCI0_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI0_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI0_RST);
break;
case PERIPH_UHCI1_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
break;
case PERIPH_PCNT_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST);
break;
case PERIPH_SPI_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
break;
case PERIPH_HSPI_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
break;
case PERIPH_VSPI_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
break;
case PERIPH_SPI_DMA_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_DMA_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
break;
case PERIPH_SDMMC_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_SDIO_HOST_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_SDIO_HOST_RST);
break;
case PERIPH_SDIO_SLAVE_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_SDIOSLAVE_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_SDIO_RST);
break;
case PERIPH_CAN_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
break;
case PERIPH_EMAC_MODULE:
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_EMAC_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_EMAC_RST);
break;
default:
break;
}
DPORT_SET_PERI_REG_MASK(get_clk_en_reg(periph), get_clk_en_mask(periph));
DPORT_CLEAR_PERI_REG_MASK(get_rst_en_reg(periph), get_rst_en_mask(periph));
portEXIT_CRITICAL(&periph_spinlock);
}
void periph_module_disable(periph_module_t periph)
{
portENTER_CRITICAL(&periph_spinlock);
switch(periph) {
case PERIPH_RMT_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST);
break;
case PERIPH_LEDC_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
break;
case PERIPH_UART0_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
break;
case PERIPH_UART1_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
break;
case PERIPH_UART2_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
break;
case PERIPH_I2C0_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT0_RST);
break;
case PERIPH_I2C1_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT1_RST);
break;
case PERIPH_I2S0_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
break;
case PERIPH_I2S1_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
break;
case PERIPH_TIMG0_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
break;
case PERIPH_TIMG1_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
break;
case PERIPH_PWM0_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM0_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM0_RST);
break;
case PERIPH_PWM1_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM1_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM1_RST);
break;
case PERIPH_PWM2_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM2_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM2_RST);
break;
case PERIPH_PWM3_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM3_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM3_RST);
break;
case PERIPH_UHCI0_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI0_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI0_RST);
break;
case PERIPH_UHCI1_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
break;
case PERIPH_PCNT_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST);
break;
case PERIPH_SPI_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
break;
case PERIPH_HSPI_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
break;
case PERIPH_VSPI_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
break;
case PERIPH_SPI_DMA_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_DMA_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
break;
case PERIPH_SDMMC_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_SDIO_HOST_EN);
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_SDIO_HOST_RST);
break;
case PERIPH_SDIO_SLAVE_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_SDIOSLAVE_EN);
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_SDIO_RST);
break;
case PERIPH_CAN_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
break;
case PERIPH_EMAC_MODULE:
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_EMAC_EN);
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_EMAC_RST);
break;
default:
break;
}
DPORT_CLEAR_PERI_REG_MASK(get_clk_en_reg(periph), get_clk_en_mask(periph));
DPORT_SET_PERI_REG_MASK(get_rst_en_reg(periph), get_rst_en_mask(periph));
portEXIT_CRITICAL(&periph_spinlock);
}
void periph_module_reset(periph_module_t periph)
{
portENTER_CRITICAL(&periph_spinlock);
DPORT_SET_PERI_REG_MASK(get_rst_en_reg(periph), get_rst_en_mask(periph));
DPORT_CLEAR_PERI_REG_MASK(get_rst_en_reg(periph), get_rst_en_mask(periph));
portEXIT_CRITICAL(&periph_spinlock);
}
static uint32_t get_clk_en_mask(periph_module_t periph)
{
switch(periph) {
case PERIPH_RMT_MODULE:
return DPORT_RMT_CLK_EN;
case PERIPH_LEDC_MODULE:
return DPORT_LEDC_CLK_EN;
case PERIPH_UART0_MODULE:
return DPORT_UART_CLK_EN;
case PERIPH_UART1_MODULE:
return DPORT_UART1_CLK_EN;
case PERIPH_UART2_MODULE:
return DPORT_UART2_CLK_EN;
case PERIPH_I2C0_MODULE:
return DPORT_I2C_EXT0_CLK_EN;
case PERIPH_I2C1_MODULE:
return DPORT_I2C_EXT1_CLK_EN;
case PERIPH_I2S0_MODULE:
return DPORT_I2S0_CLK_EN;
case PERIPH_I2S1_MODULE:
return DPORT_I2S1_CLK_EN;
case PERIPH_TIMG0_MODULE:
return DPORT_TIMERGROUP_CLK_EN;
case PERIPH_TIMG1_MODULE:
return DPORT_TIMERGROUP1_CLK_EN;
case PERIPH_PWM0_MODULE:
return DPORT_PWM0_CLK_EN;
case PERIPH_PWM1_MODULE:
return DPORT_PWM1_CLK_EN;
case PERIPH_PWM2_MODULE:
return DPORT_PWM2_CLK_EN;
case PERIPH_PWM3_MODULE:
return DPORT_PWM3_CLK_EN;
case PERIPH_UHCI0_MODULE:
return DPORT_UHCI0_CLK_EN;
case PERIPH_UHCI1_MODULE:
return DPORT_UHCI1_CLK_EN;
case PERIPH_PCNT_MODULE:
return DPORT_PCNT_CLK_EN;
case PERIPH_SPI_MODULE:
return DPORT_SPI_CLK_EN_1;
case PERIPH_HSPI_MODULE:
return DPORT_SPI_CLK_EN;
case PERIPH_VSPI_MODULE:
return DPORT_SPI_CLK_EN_2;
case PERIPH_SPI_DMA_MODULE:
return DPORT_SPI_DMA_CLK_EN;
case PERIPH_SDMMC_MODULE:
return DPORT_WIFI_CLK_SDIO_HOST_EN;
case PERIPH_SDIO_SLAVE_MODULE:
return DPORT_WIFI_CLK_SDIOSLAVE_EN;
case PERIPH_CAN_MODULE:
return DPORT_CAN_CLK_EN;
case PERIPH_EMAC_MODULE:
return DPORT_WIFI_CLK_EMAC_EN;
case PERIPH_RNG_MODULE:
return DPORT_WIFI_CLK_RNG_EN;
case PERIPH_WIFI_MODULE:
return DPORT_WIFI_CLK_WIFI_EN_M;
case PERIPH_BT_MODULE:
return DPORT_WIFI_CLK_BT_EN_M;
case PERIPH_WIFI_BT_COMMON_MODULE:
return DPORT_WIFI_CLK_WIFI_BT_COMMON_M;
default:
return 0;
}
}
static uint32_t get_rst_en_mask(periph_module_t periph)
{
switch(periph) {
case PERIPH_RMT_MODULE:
return DPORT_RMT_RST;
case PERIPH_LEDC_MODULE:
return DPORT_LEDC_RST;
case PERIPH_UART0_MODULE:
return DPORT_UART_RST;
case PERIPH_UART1_MODULE:
return DPORT_UART1_RST;
case PERIPH_UART2_MODULE:
return DPORT_UART2_RST;
case PERIPH_I2C0_MODULE:
return DPORT_I2C_EXT0_RST;
case PERIPH_I2C1_MODULE:
return DPORT_I2C_EXT1_RST;
case PERIPH_I2S0_MODULE:
return DPORT_I2S0_RST;
case PERIPH_I2S1_MODULE:
return DPORT_I2S1_RST;
case PERIPH_TIMG0_MODULE:
return DPORT_TIMERGROUP_RST;
case PERIPH_TIMG1_MODULE:
return DPORT_TIMERGROUP1_RST;
case PERIPH_PWM0_MODULE:
return DPORT_PWM0_RST;
case PERIPH_PWM1_MODULE:
return DPORT_PWM1_RST;
case PERIPH_PWM2_MODULE:
return DPORT_PWM2_RST;
case PERIPH_PWM3_MODULE:
return DPORT_PWM3_RST;
case PERIPH_UHCI0_MODULE:
return DPORT_UHCI0_RST;
case PERIPH_UHCI1_MODULE:
return DPORT_UHCI1_RST;
case PERIPH_PCNT_MODULE:
return DPORT_PCNT_RST;
case PERIPH_SPI_MODULE:
return DPORT_SPI_RST_1;
case PERIPH_HSPI_MODULE:
return DPORT_SPI_RST;
case PERIPH_VSPI_MODULE:
return DPORT_SPI_RST_2;
case PERIPH_SPI_DMA_MODULE:
return DPORT_SPI_DMA_RST;
case PERIPH_SDMMC_MODULE:
return DPORT_SDIO_HOST_RST;
case PERIPH_SDIO_SLAVE_MODULE:
return DPORT_SDIO_RST;
case PERIPH_CAN_MODULE:
return DPORT_CAN_RST;
case PERIPH_EMAC_MODULE:
return DPORT_EMAC_RST;
case PERIPH_WIFI_MODULE:
case PERIPH_BT_MODULE:
case PERIPH_WIFI_BT_COMMON_MODULE:
return 0;
default:
return 0;
}
}
static bool is_wifi_clk_peripheral(periph_module_t periph)
{
/* A small subset of peripherals use WIFI_CLK_EN_REG and
CORE_RST_EN_REG for their clock & reset registers */
switch(periph) {
case PERIPH_SDMMC_MODULE:
case PERIPH_SDIO_SLAVE_MODULE:
case PERIPH_EMAC_MODULE:
case PERIPH_RNG_MODULE:
case PERIPH_WIFI_MODULE:
case PERIPH_BT_MODULE:
case PERIPH_WIFI_BT_COMMON_MODULE:
return true;
default:
return false;
}
}
static uint32_t get_clk_en_reg(periph_module_t periph)
{
return is_wifi_clk_peripheral(periph) ? DPORT_WIFI_CLK_EN_REG : DPORT_PERIP_CLK_EN_REG;
}
static uint32_t get_rst_en_reg(periph_module_t periph)
{
return is_wifi_clk_peripheral(periph) ? DPORT_CORE_RST_EN_REG : DPORT_PERIP_RST_EN_REG;
}

View file

@ -351,8 +351,10 @@ esp_err_t rmt_set_tx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_th
{
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
if(en) {
RMT_CHECK(evt_thresh < 256, "RMT EVT THRESH ERR", ESP_ERR_INVALID_ARG);
RMT_CHECK(evt_thresh <= 256, "RMT EVT THRESH ERR", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rmt_spinlock);
RMT.tx_lim_ch[channel].limit = evt_thresh;
portEXIT_CRITICAL(&rmt_spinlock);
rmt_set_tx_wrap_en(channel, true);
rmt_set_intr_enable_mask(BIT(channel + 24));
} else {
@ -424,8 +426,6 @@ esp_err_t rmt_config(const rmt_config_t* rmt_param)
/*Set idle level */
RMT.conf_ch[channel].conf1.idle_out_en = rmt_param->tx_config.idle_output_en;
RMT.conf_ch[channel].conf1.idle_out_lv = idle_level;
portEXIT_CRITICAL(&rmt_spinlock);
/*Set carrier*/
RMT.conf_ch[channel].conf0.carrier_en = carrier_en;
if (carrier_en) {
@ -441,6 +441,8 @@ esp_err_t rmt_config(const rmt_config_t* rmt_param)
RMT.carrier_duty_ch[channel].high = 0;
RMT.carrier_duty_ch[channel].low = 0;
}
portEXIT_CRITICAL(&rmt_spinlock);
ESP_LOGD(RMT_TAG, "Rmt Tx Channel %u|Gpio %u|Sclk_Hz %u|Div %u|Carrier_Hz %u|Duty %u",
channel, gpio_num, rmt_source_clk_hz, clk_div, carrier_freq_hz, carrier_duty_percent);

View file

@ -20,6 +20,8 @@
#include "soc/sens_struct.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_cntl_struct.h"
#include "soc/syscon_reg.h"
#include "soc/syscon_struct.h"
#include "rtc_io.h"
#include "touch_pad.h"
#include "adc.h"
@ -40,6 +42,18 @@
#include "rom/queue.h"
#define ADC_FSM_RSTB_WAIT_DEFAULT (8)
#define ADC_FSM_START_WAIT_DEFAULT (5)
#define ADC_FSM_STANDBY_WAIT_DEFAULT (100)
#define ADC_FSM_TIME_KEEP (-1)
#define ADC_MAX_MEAS_NUM_DEFAULT (255)
#define ADC_MEAS_NUM_LIM_DEFAULT (1)
#define SAR_ADC_CLK_DIV_DEFUALT (2)
#define ADC_PATT_LEN_MAX (16)
#define TOUCH_PAD_FILTER_FACTOR_DEFAULT (16)
#define TOUCH_PAD_SHIFT_DEFAULT (4)
#define DAC_ERR_STR_CHANNEL_ERROR "DAC channel error"
static const char *RTC_MODULE_TAG = "RTC_MODULE";
#define RTC_MODULE_CHECK(a, str, ret_val) if (!(a)) { \
@ -52,16 +66,38 @@ static const char *RTC_MODULE_TAG = "RTC_MODULE";
return (ret_val); \
}
#define ADC_CHECK_UNIT(unit) RTC_MODULE_CHECK(adc_unit < ADC_UNIT_2, "ADC unit error, only support ADC1 for now", ESP_ERR_INVALID_ARG)
#define ADC1_CHECK_FUNCTION_RET(fun_ret) if(fun_ret!=ESP_OK){\
ESP_LOGE(RTC_MODULE_TAG,"%s:%d\n",__FUNCTION__,__LINE__);\
return ESP_FAIL;\
}
#define DAC_ERR_STR_CHANNEL_ERROR "DAC channel error"
#define ADC2_CHECK_FUNCTION_RET(fun_ret) do { if(fun_ret!=ESP_OK){\
ESP_LOGE(RTC_MODULE_TAG,"%s:%d\n",__FUNCTION__,__LINE__);\
return ESP_FAIL;\
} }while (0)
portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED;
static SemaphoreHandle_t rtc_touch_mux = NULL;
/*
In ADC2, there're two locks used for different cases:
1. lock shared with app and WIFI:
when wifi using the ADC2, we assume it will never stop,
so app checks the lock and returns immediately if failed.
2. lock shared between tasks:
when several tasks sharing the ADC2, we want to guarantee
all the requests will be handled.
Since conversions are short (about 31us), app returns the lock very soon,
we use a spinlock to stand there waiting to do conversions one by one.
adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock.
*/
//prevent ADC2 being used by wifi and other tasks at the same time.
static _lock_t adc2_wifi_lock = NULL;
//prevent ADC2 being used by tasks (regardless of WIFI)
portMUX_TYPE adc2_spinlock = portMUX_INITIALIZER_UNLOCKED;
typedef struct {
TimerHandle_t timer;
@ -72,6 +108,12 @@ typedef struct {
} touch_pad_filter_t;
static touch_pad_filter_t *s_touch_pad_filter = NULL;
typedef enum {
ADC_FORCE_FSM = 0x0,
ADC_FORCE_DISABLE = 0x2,
ADC_FORCE_ENABLE = 0x3,
} adc_force_mode_t;
//Reg,Mux,Fun,IE,Up,Down,Rtc_number
const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
{RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, RTC_IO_TOUCH_PAD1_HOLD_M, RTC_CNTL_TOUCH_PAD1_HOLD_FORCE_M, RTC_IO_TOUCH_PAD1_DRV_V, RTC_IO_TOUCH_PAD1_DRV_S, RTCIO_GPIO0_CHANNEL}, //0
@ -412,8 +454,6 @@ static esp_err_t touch_pad_get_io_num(touch_pad_t touch_num, gpio_num_t *gpio_nu
return ESP_OK;
}
#define TOUCH_PAD_FILTER_FACTOR_DEFAULT (16)
#define TOUCH_PAD_SHIFT_DEFAULT (4)
static uint32_t _touch_filter_iir(uint32_t in_now, uint32_t out_last, uint32_t k)
{
if (k == 0) {
@ -510,8 +550,16 @@ esp_err_t touch_pad_set_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t slope,
portENTER_CRITICAL(&rtc_spinlock);
//set tie opt value, high or low level seem no difference for counter
RTCIO.touch_pad[touch_num].tie_opt = opt;
//workaround for touch pad DAC mismatch on tp8 and tp9
touch_pad_t touch_pad_wrap = touch_num;
if (touch_num == TOUCH_PAD_NUM9) {
touch_pad_wrap = TOUCH_PAD_NUM8;
} else if (touch_num == TOUCH_PAD_NUM8) {
touch_pad_wrap = TOUCH_PAD_NUM9;
}
//touch sensor set slope for charging and discharging.
RTCIO.touch_pad[touch_num].dac = slope;
RTCIO.touch_pad[touch_pad_wrap].dac = slope;
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
@ -521,7 +569,14 @@ esp_err_t touch_pad_get_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t *slope
RTC_MODULE_CHECK((touch_num < TOUCH_PAD_MAX), "touch IO error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
if (slope) {
*slope = RTCIO.touch_pad[touch_num].dac;
//workaround for touch pad DAC mismatch on tp8 and tp9
touch_pad_t touch_pad_wrap = touch_num;
if (touch_num == TOUCH_PAD_NUM9) {
touch_pad_wrap = TOUCH_PAD_NUM8;
} else if (touch_num == TOUCH_PAD_NUM8) {
touch_pad_wrap = TOUCH_PAD_NUM9;
}
*slope = RTCIO.touch_pad[touch_pad_wrap].dac;
}
if (opt) {
*opt = RTCIO.touch_pad[touch_num].tie_opt;
@ -871,11 +926,269 @@ esp_err_t touch_pad_filter_delete()
}
/*---------------------------------------------------------------
ADC
ADC Common
---------------------------------------------------------------*/
static esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num)
static esp_err_t adc_set_fsm_time(int rst_wait, int start_wait, int standby_wait, int sample_cycle)
{
RTC_MODULE_CHECK(channel < ADC1_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
// Internal FSM reset wait time
if (rst_wait >= 0) {
SYSCON.saradc_fsm.rstb_wait = rst_wait;
}
// Internal FSM start wait time
if (start_wait >= 0) {
SYSCON.saradc_fsm.start_wait = start_wait;
}
// Internal FSM standby wait time
if (standby_wait >= 0) {
SYSCON.saradc_fsm.standby_wait = standby_wait;
}
// Internal FSM standby sample cycle
if (sample_cycle >= 0) {
SYSCON.saradc_fsm.sample_cycle = sample_cycle;
}
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
static esp_err_t adc_set_data_format(adc_i2s_encode_t mode)
{
portENTER_CRITICAL(&rtc_spinlock);
//data format:
//0: ADC_ENCODE_12BIT [15:12]-channel [11:0]-12 bits ADC data
//1: ADC_ENCODE_11BIT [15]-1 [14:11]-channel [10:0]-11 bits ADC data, the resolution should not be larger than 11 bits in this case.
SYSCON.saradc_ctrl.data_sar_sel = mode;
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
static esp_err_t adc_set_measure_limit(uint8_t meas_num, bool lim_en)
{
portENTER_CRITICAL(&rtc_spinlock);
// Set max measure number
SYSCON.saradc_ctrl2.max_meas_num = meas_num;
// Enable max measure number limit
SYSCON.saradc_ctrl2.meas_num_limit = lim_en;
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
static esp_err_t adc_set_work_mode(adc_unit_t adc_unit)
{
portENTER_CRITICAL(&rtc_spinlock);
if (adc_unit == ADC_UNIT_1) {
// saradc mode sel : 0--single saradc; 1--double saradc; 2--alternative saradc
SYSCON.saradc_ctrl.work_mode = 0;
//ENABLE ADC 0: ADC1 1: ADC2, only work for single SAR mode
SYSCON.saradc_ctrl.sar_sel = 0;
} else if (adc_unit == ADC_UNIT_2) {
// saradc mode sel : 0--single saradc; 1--double saradc; 2--alternative saradc
SYSCON.saradc_ctrl.work_mode = 0;
//ENABLE ADC1 0: SAR1 1: SAR2 only work for single SAR mode
SYSCON.saradc_ctrl.sar_sel = 1;
} else if (adc_unit == ADC_UNIT_BOTH) {
// saradc mode sel : 0--single saradc; 1--double saradc; 2--alternative saradc
SYSCON.saradc_ctrl.work_mode = 1;
} else if (adc_unit == ADC_UNIT_ALTER) {
// saradc mode sel : 0--single saradc; 1--double saradc; 2--alternative saradc
SYSCON.saradc_ctrl.work_mode = 2;
}
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
static esp_err_t adc_set_atten(adc_unit_t adc_unit, adc_channel_t channel, adc_atten_t atten)
{
ADC_CHECK_UNIT(adc_unit);
if (adc_unit & ADC_UNIT_1) {
RTC_MODULE_CHECK((adc1_channel_t)channel < ADC1_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG);
}
RTC_MODULE_CHECK(atten < ADC_ATTEN_MAX, "ADC Atten Err", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
if (adc_unit & ADC_UNIT_1) {
//SAR1_atten
SET_PERI_REG_BITS(SENS_SAR_ATTEN1_REG, SENS_SAR1_ATTEN_VAL_MASK, atten, (channel * 2));
}
if (adc_unit & ADC_UNIT_2) {
//SAR2_atten
SET_PERI_REG_BITS(SENS_SAR_ATTEN2_REG, SENS_SAR2_ATTEN_VAL_MASK, atten, (channel * 2));
}
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
void adc_power_on()
{
portENTER_CRITICAL(&rtc_spinlock);
SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_FSM;
portEXIT_CRITICAL(&rtc_spinlock);
}
void adc_power_off()
{
portENTER_CRITICAL(&rtc_spinlock);
//Bit1 0:Fsm 1: SW mode
//Bit0 0:SW mode power down 1: SW mode power on
SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_DISABLE;
portEXIT_CRITICAL(&rtc_spinlock);
}
esp_err_t adc_set_clk_div(uint8_t clk_div)
{
portENTER_CRITICAL(&rtc_spinlock);
// ADC clock devided from APB clk, 80 / 2 = 40Mhz,
SYSCON.saradc_ctrl.sar_clk_div = clk_div;
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src)
{
RTC_MODULE_CHECK(src < ADC_I2S_DATA_SRC_MAX, "ADC i2s data source error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
// 1: I2S input data is from SAR ADC (for DMA) 0: I2S input data is from GPIO matrix
SYSCON.saradc_ctrl.data_to_i2s = src;
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel)
{
ADC_CHECK_UNIT(adc_unit);
gpio_num_t gpio_num = 0;
if (adc_unit & ADC_UNIT_1) {
RTC_MODULE_CHECK((adc1_channel_t) channel < ADC1_CHANNEL_MAX, "ADC1 channel error", ESP_ERR_INVALID_ARG);
ADC1_CHECK_FUNCTION_RET(adc1_pad_get_io_num((adc1_channel_t) channel, &gpio_num));
ADC1_CHECK_FUNCTION_RET(rtc_gpio_init(gpio_num));
ADC1_CHECK_FUNCTION_RET(rtc_gpio_output_disable(gpio_num));
ADC1_CHECK_FUNCTION_RET(rtc_gpio_input_disable(gpio_num));
ADC1_CHECK_FUNCTION_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING));
}
return ESP_OK;
}
esp_err_t adc_set_data_inv(adc_unit_t adc_unit, bool inv_en)
{
portENTER_CRITICAL(&rtc_spinlock);
if (adc_unit & ADC_UNIT_1) {
// Enable ADC data invert
SENS.sar_read_ctrl.sar1_data_inv = inv_en;
}
if (adc_unit & ADC_UNIT_2) {
// Enable ADC data invert
SENS.sar_read_ctrl2.sar2_data_inv = inv_en;
}
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t bits)
{
ADC_CHECK_UNIT(adc_unit);
RTC_MODULE_CHECK(bits < ADC_WIDTH_MAX, "ADC bit width error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
if (adc_unit & ADC_UNIT_1) {
SENS.sar_start_force.sar1_bit_width = bits;
SENS.sar_read_ctrl.sar1_sample_bit = bits;
}
if (adc_unit & ADC_UNIT_2) {
SENS.sar_start_force.sar2_bit_width = bits;
SENS.sar_read_ctrl2.sar2_sample_bit = bits;
}
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
/*-------------------------------------------------------------------------------------
* ADC I2S
*------------------------------------------------------------------------------------*/
static esp_err_t adc_set_i2s_data_len(adc_unit_t adc_unit, int patt_len)
{
ADC_CHECK_UNIT(adc_unit);
RTC_MODULE_CHECK((patt_len < ADC_PATT_LEN_MAX) && (patt_len > 0), "ADC pattern length error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
if(adc_unit & ADC_UNIT_1) {
SYSCON.saradc_ctrl.sar1_patt_len = patt_len - 1;
}
if(adc_unit & ADC_UNIT_2) {
SYSCON.saradc_ctrl.sar2_patt_len = patt_len - 1;
}
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
static esp_err_t adc_set_i2s_data_pattern(adc_unit_t adc_unit, int seq_num, adc_channel_t channel, adc_bits_width_t bits, adc_atten_t atten)
{
ADC_CHECK_UNIT(adc_unit);
if (adc_unit & ADC_UNIT_1) {
RTC_MODULE_CHECK((adc1_channel_t) channel < ADC1_CHANNEL_MAX, "ADC1 channel error", ESP_ERR_INVALID_ARG);
}
RTC_MODULE_CHECK(bits < ADC_WIDTH_MAX, "ADC bit width error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(atten < ADC_ATTEN_MAX, "ADC Atten Err", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&rtc_spinlock);
//Configure pattern table, each 8 bit defines one channel
//[7:4]-channel [3:2]-bit width [1:0]- attenuation
//BIT WIDTH: 3: 12BIT 2: 11BIT 1: 10BIT 0: 9BIT
//ATTEN: 3: ATTEN = 11dB 2: 6dB 1: 2.5dB 0: 0dB
uint8_t val = (channel << 4) | (bits << 2) | (atten << 0);
if (adc_unit & ADC_UNIT_1) {
SYSCON.saradc_sar1_patt_tab[seq_num / 4] &= (~(0xff << ((3 - (seq_num % 4)) * 8)));
SYSCON.saradc_sar1_patt_tab[seq_num / 4] |= (val << ((3 - (seq_num % 4)) * 8));
}
if (adc_unit & ADC_UNIT_2) {
SYSCON.saradc_sar2_patt_tab[seq_num / 4] &= (~(0xff << ((3 - (seq_num % 4)) * 8)));
SYSCON.saradc_sar2_patt_tab[seq_num / 4] |= (val << ((3 - (seq_num % 4)) * 8));
}
portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK;
}
esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel)
{
ADC_CHECK_UNIT(adc_unit);
if (adc_unit & ADC_UNIT_1) {
RTC_MODULE_CHECK((adc1_channel_t) channel < ADC1_CHANNEL_MAX, "ADC1 channel error", ESP_ERR_INVALID_ARG);
}
uint8_t table_len = 1;
//POWER ON SAR
adc_power_on();
adc_gpio_init(adc_unit, channel);
adc_set_i2s_data_len(adc_unit, table_len);
adc_set_i2s_data_pattern(adc_unit, 0, channel, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11);
portENTER_CRITICAL(&rtc_spinlock);
if (adc_unit & ADC_UNIT_1) {
//switch SARADC into DIG channel
SENS.sar_read_ctrl.sar1_dig_force = 1;
}
if (adc_unit & ADC_UNIT_2) {
//switch SARADC into DIG channel
SENS.sar_read_ctrl2.sar2_dig_force = 1;
//1: SAR ADC2 is controlled by DIG ADC2 CTRL 0: SAR ADC2 is controlled by PWDET CTRL
SYSCON.saradc_ctrl.sar2_mux = 1;
}
portEXIT_CRITICAL(&rtc_spinlock);
adc_set_i2s_data_source(ADC_I2S_DATA_SRC_ADC);
adc_set_clk_div(SAR_ADC_CLK_DIV_DEFUALT);
// Set internal FSM wait time.
adc_set_fsm_time(ADC_FSM_RSTB_WAIT_DEFAULT, ADC_FSM_START_WAIT_DEFAULT, ADC_FSM_STANDBY_WAIT_DEFAULT,
ADC_FSM_TIME_KEEP);
adc_set_work_mode(adc_unit);
adc_set_data_format(ADC_ENCODE_12BIT);
adc_set_measure_limit(ADC_MAX_MEAS_NUM_DEFAULT, ADC_MEAS_NUM_LIM_DEFAULT);
//Invert The Level, Invert SAR ADC1 data
adc_set_data_inv(adc_unit, true);
return ESP_OK;
}
/*-------------------------------------------------------------------------------------
* ADC1
*------------------------------------------------------------------------------------*/
esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num)
{
RTC_MODULE_CHECK(channel < ADC1_CHANNEL_MAX, "ADC1 Channel Err", ESP_ERR_INVALID_ARG);
switch (channel) {
case ADC1_CHANNEL_0:
@ -909,69 +1222,51 @@ static esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_nu
return ESP_OK;
}
static esp_err_t adc1_pad_init(adc1_channel_t channel)
{
gpio_num_t gpio_num = 0;
ADC1_CHECK_FUNCTION_RET(adc1_pad_get_io_num(channel, &gpio_num));
ADC1_CHECK_FUNCTION_RET(rtc_gpio_init(gpio_num));
ADC1_CHECK_FUNCTION_RET(rtc_gpio_output_disable(gpio_num));
ADC1_CHECK_FUNCTION_RET(rtc_gpio_input_disable(gpio_num));
ADC1_CHECK_FUNCTION_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING));
return ESP_OK;
}
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
{
RTC_MODULE_CHECK(channel < ADC1_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(atten <= ADC_ATTEN_11db, "ADC Atten Err", ESP_ERR_INVALID_ARG);
adc1_pad_init(channel);
portENTER_CRITICAL(&rtc_spinlock);
SET_PERI_REG_BITS(SENS_SAR_ATTEN1_REG, 3, atten, (channel * 2)); //SAR1_atten
portEXIT_CRITICAL(&rtc_spinlock);
RTC_MODULE_CHECK(atten < ADC_ATTEN_MAX, "ADC Atten Err", ESP_ERR_INVALID_ARG);
adc_gpio_init(ADC_UNIT_1, channel);
adc_set_atten(ADC_UNIT_1, channel, atten);
return ESP_OK;
}
esp_err_t adc1_config_width(adc_bits_width_t width_bit)
{
portENTER_CRITICAL(&rtc_spinlock);
SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR1_BIT_WIDTH_V, width_bit, SENS_SAR1_BIT_WIDTH_S); //SAR2_BIT_WIDTH[1:0]=0x3, SAR1_BIT_WIDTH[1:0]=0x3
//Invert the adc value,the Output value is invert
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DATA_INV);
//Set The adc sample width,invert adc value,must
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_BIT_V, width_bit, SENS_SAR1_SAMPLE_BIT_S); //digital sar1_bit_width[1:0]=3
portEXIT_CRITICAL(&rtc_spinlock);
RTC_MODULE_CHECK(width_bit < ADC_WIDTH_MAX, "ADC bit width error", ESP_ERR_INVALID_ARG);
adc_set_data_width(ADC_UNIT_1, width_bit);
adc_set_data_inv(ADC_UNIT_1, true);
return ESP_OK;
}
int adc1_get_raw(adc1_channel_t channel)
{
uint16_t adc_value;
RTC_MODULE_CHECK(channel < ADC1_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG);
adc_power_on();
portENTER_CRITICAL(&rtc_spinlock);
//Adc Controler is Rtc module,not ulp coprocessor
SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, 1, 1, SENS_MEAS1_START_FORCE_S); //force pad mux and force start
//Bit1=0:Fsm Bit1=1(Bit0=0:PownDown Bit10=1:Powerup)
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S); //force XPD_SAR=0, use XPD_FSM
SENS.sar_meas_start1.meas1_start_force = 1;
//Disable Amp Bit1=0:Fsm Bit1=1(Bit0=0:PownDown Bit10=1:Powerup)
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_AMP, 0x2, SENS_FORCE_XPD_AMP_S); //force XPD_AMP=0
SENS.sar_meas_wait2.force_xpd_amp = 0x2;
//Open the ADC1 Data port Not ulp coprocessor
SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, 1, 1, SENS_SAR1_EN_PAD_FORCE_S); //open the ADC1 data port
SENS.sar_meas_start1.sar1_en_pad_force = 1;
//Select channel
SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD, (1 << channel), SENS_SAR1_EN_PAD_S); //pad enable
SET_PERI_REG_BITS(SENS_SAR_MEAS_CTRL_REG, 0xfff, 0x0, SENS_AMP_RST_FB_FSM_S); //[11:8]:short ref ground, [7:4]:short ref, [3:0]:rst fb
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT1, 0x1, SENS_SAR_AMP_WAIT1_S);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT2, 0x1, SENS_SAR_AMP_WAIT2_S);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_SAR_AMP_WAIT3, 0x1, SENS_SAR_AMP_WAIT3_S);
while (GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR1_REG, 0x7, SENS_MEAS_STATUS_S) != 0); //wait det_fsm==0
SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, 1, 0, SENS_MEAS1_START_SAR_S); //start force 0
SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, 1, 1, SENS_MEAS1_START_SAR_S); //start force 1
while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0) {}; //read done
adc_value = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DATA_SAR, SENS_MEAS1_DATA_SAR_S);
SENS.sar_meas_start1.sar1_en_pad = (1 << channel);
SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0;
SENS.sar_meas_ctrl.amp_short_ref_fsm = 0;
SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0;
SENS.sar_meas_wait1.sar_amp_wait1 = 1;
SENS.sar_meas_wait1.sar_amp_wait2 = 1;
SENS.sar_meas_wait2.sar_amp_wait3 = 1;
while (SENS.sar_slave_addr1.meas_status != 0);
SENS.sar_meas_start1.meas1_start_sar = 0;
SENS.sar_meas_start1.meas1_start_sar = 1;
while (SENS.sar_meas_start1.meas1_done_sar == 0);
adc_value = SENS.sar_meas_start1.meas1_data_sar;
portEXIT_CRITICAL(&rtc_spinlock);
return adc_value;
}
@ -982,18 +1277,170 @@ int adc1_get_voltage(adc1_channel_t channel) //Deprecated. Use adc1_get_raw()
void adc1_ulp_enable(void)
{
adc_power_on();
portENTER_CRITICAL(&rtc_spinlock);
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_FORCE);
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD_FORCE_M);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_AMP, 0x2, SENS_FORCE_XPD_AMP_S);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S);
SET_PERI_REG_BITS(SENS_SAR_MEAS_CTRL_REG, 0xfff, 0x0, SENS_AMP_RST_FB_FSM_S); //[11:8]:short ref ground, [7:4]:short ref, [3:0]:rst fb
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT1, 0x1, SENS_SAR_AMP_WAIT1_S);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT2, 0x1, SENS_SAR_AMP_WAIT2_S);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_SAR_AMP_WAIT3, 0x1, SENS_SAR_AMP_WAIT3_S);
SENS.sar_meas_start1.meas1_start_force = 0;
SENS.sar_meas_start1.sar1_en_pad_force = 0;
SENS.sar_meas_wait2.force_xpd_amp = 0x2;
SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0;
SENS.sar_meas_ctrl.amp_short_ref_fsm = 0;
SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0;
SENS.sar_meas_wait1.sar_amp_wait1 = 0x1;
SENS.sar_meas_wait1.sar_amp_wait2 = 0x1;
SENS.sar_meas_wait2.sar_amp_wait3 = 0x1;
portEXIT_CRITICAL(&rtc_spinlock);
}
/*---------------------------------------------------------------
ADC2
---------------------------------------------------------------*/
esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num)
{
RTC_MODULE_CHECK(channel < ADC2_CHANNEL_MAX, "ADC2 Channel Err", ESP_ERR_INVALID_ARG);
switch (channel) {
case ADC2_CHANNEL_0:
*gpio_num = ADC2_CHANNEL_0_GPIO_NUM;
break;
case ADC2_CHANNEL_1:
*gpio_num = ADC2_CHANNEL_1_GPIO_NUM;
break;
case ADC2_CHANNEL_2:
*gpio_num = ADC2_CHANNEL_2_GPIO_NUM;
break;
case ADC2_CHANNEL_3:
*gpio_num = ADC2_CHANNEL_3_GPIO_NUM;
break;
case ADC2_CHANNEL_4:
*gpio_num = ADC2_CHANNEL_4_GPIO_NUM;
break;
case ADC2_CHANNEL_5:
*gpio_num = ADC2_CHANNEL_5_GPIO_NUM;
break;
case ADC2_CHANNEL_6:
*gpio_num = ADC2_CHANNEL_6_GPIO_NUM;
break;
case ADC2_CHANNEL_7:
*gpio_num = ADC2_CHANNEL_7_GPIO_NUM;
break;
case ADC2_CHANNEL_8:
*gpio_num = ADC2_CHANNEL_8_GPIO_NUM;
break;
case ADC2_CHANNEL_9:
*gpio_num = ADC2_CHANNEL_9_GPIO_NUM;
break;
default:
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
esp_err_t adc2_wifi_acquire()
{
//lazy initialization
//for wifi, block until acquire the lock
_lock_acquire( &adc2_wifi_lock );
ESP_LOGD( RTC_MODULE_TAG, "Wi-Fi takes adc2 lock." );
return ESP_OK;
}
esp_err_t adc2_wifi_release()
{
RTC_MODULE_CHECK((uint32_t*)adc2_wifi_lock != NULL, "wifi release called before acquire", ESP_ERR_INVALID_STATE );
_lock_release( &adc2_wifi_lock );
ESP_LOGD( RTC_MODULE_TAG, "Wi-Fi returns adc2 lock." );
return ESP_OK;
}
static esp_err_t adc2_pad_init(adc2_channel_t channel)
{
gpio_num_t gpio_num = 0;
ADC2_CHECK_FUNCTION_RET(adc2_pad_get_io_num(channel, &gpio_num));
ADC2_CHECK_FUNCTION_RET(rtc_gpio_init(gpio_num));
ADC2_CHECK_FUNCTION_RET(rtc_gpio_output_disable(gpio_num));
ADC2_CHECK_FUNCTION_RET(rtc_gpio_input_disable(gpio_num));
ADC2_CHECK_FUNCTION_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING));
return ESP_OK;
}
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
{
RTC_MODULE_CHECK(channel < ADC2_CHANNEL_MAX, "ADC2 Channel Err", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(atten <= ADC_ATTEN_11db, "ADC2 Atten Err", ESP_ERR_INVALID_ARG);
adc2_pad_init(channel);
portENTER_CRITICAL( &adc2_spinlock );
//lazy initialization
//avoid collision with other tasks
if ( _lock_try_acquire( &adc2_wifi_lock ) == -1 ) {
//try the lock, return if failed (wifi using).
portEXIT_CRITICAL( &adc2_spinlock );
return ESP_ERR_TIMEOUT;
}
SENS.sar_atten2 = ( SENS.sar_atten2 & ~(3<<(channel*2)) ) | ((atten&3) << (channel*2));
_lock_release( &adc2_wifi_lock );
portEXIT_CRITICAL( &adc2_spinlock );
return ESP_OK;
}
static inline void adc2_config_width(adc_bits_width_t width_bit)
{
portENTER_CRITICAL(&rtc_spinlock);
//sar_start_force shared with ADC1
SENS.sar_start_force.sar2_bit_width = width_bit;
portEXIT_CRITICAL(&rtc_spinlock);
//Invert the adc value,the Output value is invert
SENS.sar_read_ctrl2.sar2_data_inv = 1;
//Set The adc sample width,invert adc value,must digital sar2_bit_width[1:0]=3
SENS.sar_read_ctrl2.sar2_sample_bit = width_bit;
//Take the control from WIFI
SENS.sar_read_ctrl2.sar2_pwdet_force = 0;
}
//registers in critical section with adc1:
//SENS_SAR_START_FORCE_REG,
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int* raw_out)
{
uint16_t adc_value = 0;
RTC_MODULE_CHECK(channel < ADC2_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG);
//in critical section with whole rtc module
adc_power_on();
//avoid collision with other tasks
portENTER_CRITICAL(&adc2_spinlock);
//lazy initialization
//try the lock, return if failed (wifi using).
if ( _lock_try_acquire( &adc2_wifi_lock ) == -1 ) {
portEXIT_CRITICAL( &adc2_spinlock );
return ESP_ERR_TIMEOUT;
}
//in critical section with whole rtc module
adc2_config_width( width_bit );
//Adc Controler is Rtc module,not ulp coprocessor
SENS.sar_meas_start2.meas2_start_force = 1; //force pad mux and force start
//Open the ADC2 Data port Not ulp coprocessor
SENS.sar_meas_start2.sar2_en_pad_force = 1; //open the ADC2 data port
//Select channel
SENS.sar_meas_start2.sar2_en_pad = 1 << channel; //pad enable
SENS.sar_meas_start2.meas2_start_sar = 0; //start force 0
SENS.sar_meas_start2.meas2_start_sar = 1; //start force 1
while (SENS.sar_meas_start2.meas2_done_sar == 0) {}; //read done
adc_value = SENS.sar_meas_start2.meas2_data_sar;
_lock_release( &adc2_wifi_lock );
portEXIT_CRITICAL(&adc2_spinlock);
*raw_out = (int)adc_value;
return ESP_OK;
}
esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
{
int channel;
@ -1014,19 +1461,19 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
rtc_gpio_pullup_dis(gpio);
rtc_gpio_pulldown_dis(gpio);
SET_PERI_REG_BITS(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN, 0, RTC_CNTL_DBG_ATTEN_S); //Check DBG effect outside sleep mode
RTCCNTL.bias_conf.dbg_atten = 0; //Check DBG effect outside sleep mode
//set dtest (MUX_SEL : 0 -> RTC; 1-> vdd_sar2)
SET_PERI_REG_BITS(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_DTEST_RTC, 1, RTC_CNTL_DTEST_RTC_S); //Config test mux to route v_ref to ADC2 Channels
RTCCNTL.test_mux.dtest_rtc = 1; //Config test mux to route v_ref to ADC2 Channels
//set ent
SET_PERI_REG_MASK(RTC_CNTL_TEST_MUX_REG, RTC_CNTL_ENT_RTC_M);
RTCCNTL.test_mux.ent_rtc = 1;
//set sar2_en_test
SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_SAR2_EN_TEST_M);
SENS.sar_start_force.sar2_en_test = 1;
//force fsm
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); //Select power source of ADC
SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_ENABLE; //Select power source of ADC
//set sar2 en force
SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD_FORCE_M); //Pad bitmap controlled by SW
SENS.sar_meas_start2.sar2_en_pad_force = 1; //Pad bitmap controlled by SW
//set en_pad for channels 7,8,9 (bits 0x380)
SET_PERI_REG_BITS(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, 1<<channel, SENS_SAR2_EN_PAD_S);
SENS.sar_meas_start2.sar2_en_pad = 1<<channel;
return ESP_OK;
}
@ -1034,7 +1481,7 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio)
/*---------------------------------------------------------------
DAC
---------------------------------------------------------------*/
static esp_err_t dac_pad_get_io_num(dac_channel_t channel, gpio_num_t *gpio_num)
esp_err_t dac_pad_get_io_num(dac_channel_t channel, gpio_num_t *gpio_num)
{
RTC_MODULE_CHECK((channel >= DAC_CHANNEL_1) && (channel < DAC_CHANNEL_MAX), DAC_ERR_STR_CHANNEL_ERROR, ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(gpio_num, "Param null", ESP_ERR_INVALID_ARG);
@ -1177,20 +1624,23 @@ static int hall_sensor_get_value() //hall sensor without LNA
int Sens_Vp1;
int Sens_Vn1;
int hall_value;
adc_power_on();
portENTER_CRITICAL(&rtc_spinlock);
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE_M); // hall sens force enable
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_XPD_HALL); // xpd hall
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE_M); // phase force
CLEAR_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE); // hall phase
SENS.sar_touch_ctrl1.xpd_hall_force = 1; // hall sens force enable
RTCIO.hall_sens.xpd_hall = 1; // xpd hall
SENS.sar_touch_ctrl1.hall_phase_force = 1; // phase force
RTCIO.hall_sens.hall_phase = 0; // hall phase
Sens_Vp0 = adc1_get_raw(ADC1_CHANNEL_0);
Sens_Vn0 = adc1_get_raw(ADC1_CHANNEL_3);
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE);
RTCIO.hall_sens.hall_phase = 1;
Sens_Vp1 = adc1_get_raw(ADC1_CHANNEL_0);
Sens_Vn1 = adc1_get_raw(ADC1_CHANNEL_3);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S);
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE);
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE);
SENS.sar_touch_ctrl1.xpd_hall_force = 0;
SENS.sar_touch_ctrl1.hall_phase_force = 0;
portEXIT_CRITICAL(&rtc_spinlock);
hall_value = (Sens_Vp1 - Sens_Vp0) - (Sens_Vn1 - Sens_Vn0);
@ -1199,10 +1649,10 @@ static int hall_sensor_get_value() //hall sensor without LNA
int hall_sensor_read()
{
adc1_pad_init(ADC1_CHANNEL_0);
adc1_pad_init(ADC1_CHANNEL_3);
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_0db);
adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_0db);
adc_gpio_init(ADC_UNIT_1, ADC1_CHANNEL_0);
adc_gpio_init(ADC_UNIT_1, ADC1_CHANNEL_3);
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0);
adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_0);
return hall_sensor_get_value();
}

View file

@ -15,6 +15,7 @@
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
@ -33,13 +34,6 @@
*/
#define SDMMC_DMA_DESC_CNT 4
/* Max delay value is mostly useful for cases when CD pin is not used, and
* the card is removed. In this case, SDMMC peripheral may not always return
* CMD_DONE / DATA_DONE interrupts after signaling the error. This delay works
* as a safety net in such cases.
*/
#define SDMMC_MAX_EVT_WAIT_DELAY_MS 1000
static const char* TAG = "sdmmc_req";
typedef enum {
@ -74,6 +68,9 @@ static sdmmc_desc_t s_dma_desc[SDMMC_DMA_DESC_CNT];
static sdmmc_transfer_state_t s_cur_transfer = { 0 };
static QueueHandle_t s_request_mutex;
static bool s_is_app_cmd; // This flag is set if the next command is an APP command
#ifdef CONFIG_PM_ENABLE
static esp_pm_lock_handle_t s_pm_lock;
#endif
static esp_err_t handle_idle_state_events();
static sdmmc_hw_cmd_t make_hw_cmd(sdmmc_command_t* cmd);
@ -90,12 +87,24 @@ esp_err_t sdmmc_host_transaction_handler_init()
return ESP_ERR_NO_MEM;
}
s_is_app_cmd = false;
#ifdef CONFIG_PM_ENABLE
esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "sdmmc", &s_pm_lock);
if (err != ESP_OK) {
vSemaphoreDelete(s_request_mutex);
s_request_mutex = NULL;
return err;
}
#endif
return ESP_OK;
}
void sdmmc_host_transaction_handler_deinit()
{
assert(s_request_mutex);
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_delete(s_pm_lock);
s_pm_lock = NULL;
#endif
vSemaphoreDelete(s_request_mutex);
s_request_mutex = NULL;
}
@ -103,6 +112,9 @@ void sdmmc_host_transaction_handler_deinit()
esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo)
{
xSemaphoreTake(s_request_mutex, portMAX_DELAY);
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire(s_pm_lock);
#endif
// dispose of any events which happened asynchronously
handle_idle_state_events();
// convert cmdinfo to hardware register value
@ -148,6 +160,9 @@ esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo)
}
}
s_is_app_cmd = (ret == ESP_OK && cmdinfo->opcode == MMC_APP_CMD);
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_pm_lock);
#endif
xSemaphoreGive(s_request_mutex);
return ret;
}
@ -206,7 +221,7 @@ static esp_err_t handle_idle_state_events()
static esp_err_t handle_event(sdmmc_command_t* cmd, sdmmc_req_state_t* state)
{
sdmmc_event_t evt;
esp_err_t err = sdmmc_host_wait_for_event(SDMMC_MAX_EVT_WAIT_DELAY_MS / portTICK_PERIOD_MS, &evt);
esp_err_t err = sdmmc_host_wait_for_event(cmd->timeout_ms / portTICK_PERIOD_MS, &evt);
if (err != ESP_OK) {
ESP_LOGE(TAG, "sdmmc_host_wait_for_event returned 0x%x", err);
if (err == ESP_ERR_TIMEOUT) {

View file

@ -396,8 +396,7 @@ bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t
ret = false;
} else {
//Reset DMA
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
periph_module_reset( PERIPH_SPI_DMA_MODULE );
ret = true;
}
portEXIT_CRITICAL(&dmaworkaround_mux);
@ -415,8 +414,7 @@ void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
dmaworkaround_channels_busy[dmachan-1] = 0;
if (dmaworkaround_waiting_for_chan == dmachan) {
//Reset DMA
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
periph_module_reset( PERIPH_SPI_DMA_MODULE );
dmaworkaround_waiting_for_chan = 0;
//Call callback
dmaworkaround_cb(dmaworkaround_cb_arg);

View file

@ -47,6 +47,7 @@ queue and re-enabling the interrupt will trigger the interrupt again, which can
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_pm.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/xtensa_api.h"
@ -84,6 +85,9 @@ typedef struct {
bool no_gpio_matrix;
int dma_chan;
int max_transfer_sz;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
} spi_host_t;
struct spi_device_t {
@ -129,6 +133,13 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
spihost[host]=malloc(sizeof(spi_host_t));
if (spihost[host]==NULL) goto nomem;
memset(spihost[host], 0, sizeof(spi_host_t));
#ifdef CONFIG_PM_ENABLE
esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
&spihost[host]->pm_lock);
if (err != ESP_OK) {
goto nomem;
}
#endif //CONFIG_PM_ENABLE
spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER|SPICOMMON_BUSFLAG_QUAD, &native);
spihost[host]->no_gpio_matrix=native;
@ -180,9 +191,15 @@ nomem:
if (spihost[host]) {
free(spihost[host]->dmadesc_tx);
free(spihost[host]->dmadesc_rx);
#ifdef CONFIG_PM_ENABLE
if (spihost[host]->pm_lock) {
esp_pm_lock_delete(spihost[host]->pm_lock);
}
#endif
}
free(spihost[host]);
spicommon_periph_free(host);
spicommon_dma_chan_free(dma_chan);
return ESP_ERR_NO_MEM;
}
@ -198,6 +215,9 @@ esp_err_t spi_bus_free(spi_host_device_t host)
if ( spihost[host]->dma_chan > 0 ) {
spicommon_dma_chan_free ( spihost[host]->dma_chan );
}
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_delete(spihost[host]->pm_lock);
#endif
spihost[host]->hw->slave.trans_inten=0;
spihost[host]->hw->slave.trans_done=0;
esp_intr_free(spihost[host]->intr);
@ -411,6 +431,10 @@ static void IRAM_ATTR spi_intr(void *arg)
if (i==NO_CS) {
//No packet waiting. Disable interrupt.
esp_intr_disable(host->intr);
#ifdef CONFIG_PM_ENABLE
//Release APB frequency lock
esp_pm_lock_release(host->pm_lock);
#endif
} else {
host->hw->slave.trans_done=0; //clear int bit
//We have a transaction. Send it.
@ -648,6 +672,9 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
// else use the original buffer (forced-conversion) or assign to NULL
trans_buf.buffer_to_send = (uint32_t*)txdata;
}
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire(handle->host->pm_lock);
#endif
r=xQueueSend(handle->trans_queue, (void*)&trans_buf, ticks_to_wait);
if (!r) return ESP_ERR_TIMEOUT;

View file

@ -26,6 +26,7 @@
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_pm.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/xtensa_api.h"
@ -60,6 +61,9 @@ typedef struct {
QueueHandle_t trans_queue;
QueueHandle_t ret_queue;
int dma_chan;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
} spi_slave_t;
static spi_slave_t *spihost[3];
@ -68,12 +72,21 @@ static void IRAM_ATTR spi_intr(void *arg);
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, int dma_chan)
{
bool native, claimed;
bool native, spi_chan_claimed, dma_chan_claimed;
//We only support HSPI/VSPI, period.
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
claimed = spicommon_periph_claim(host);
SPI_CHECK(claimed, "host already in use", ESP_ERR_INVALID_STATE);
spi_chan_claimed=spicommon_periph_claim(host);
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
if ( dma_chan != 0 ) {
dma_chan_claimed=spicommon_dma_chan_claim(dma_chan);
if ( !dma_chan_claimed ) {
spicommon_periph_free( host );
SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE);
}
}
spihost[host] = malloc(sizeof(spi_slave_t));
if (spihost[host] == NULL) goto nomem;
@ -97,6 +110,15 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
//We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most.
spihost[host]->max_transfer_sz = 16 * 4;
}
#ifdef CONFIG_PM_ENABLE
esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave",
&spihost[host]->pm_lock);
if (err != ESP_OK) {
goto nomem;
}
// Lock APB frequency while SPI slave driver is in use
esp_pm_lock_acquire(spihost[host]->pm_lock);
#endif //CONFIG_PM_ENABLE
//Create queues
spihost[host]->trans_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
@ -175,10 +197,17 @@ nomem:
if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
free(spihost[host]->dmadesc_tx);
free(spihost[host]->dmadesc_rx);
#ifdef CONFIG_PM_ENABLE
if (spihost[host]->pm_lock) {
esp_pm_lock_release(spihost[host]->pm_lock);
esp_pm_lock_delete(spihost[host]->pm_lock);
}
#endif
}
free(spihost[host]);
spihost[host] = NULL;
spicommon_periph_free(host);
spicommon_dma_chan_free(dma_chan);
return ESP_ERR_NO_MEM;
}
@ -188,8 +217,15 @@ esp_err_t spi_slave_free(spi_host_device_t host)
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue);
if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
if ( spihost[host]->dma_chan > 0 ) {
spicommon_dma_chan_free ( spihost[host]->dma_chan );
}
free(spihost[host]->dmadesc_tx);
free(spihost[host]->dmadesc_rx);
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(spihost[host]->pm_lock);
esp_pm_lock_delete(spihost[host]->pm_lock);
#endif //CONFIG_PM_ENABLE
free(spihost[host]);
spihost[host] = NULL;
spicommon_periph_free(host);
@ -289,12 +325,20 @@ static void IRAM_ATTR spi_intr(void *arg)
if (!host->hw->slave.trans_done) return;
if (host->cur_trans) {
//when data of cur_trans->length are all sent, the slv_rdata_bit
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
//the length sent.
host->cur_trans->trans_len = host->hw->slv_rd_bit.slv_rdata_bit;
if ( host->cur_trans->trans_len == host->cur_trans->length - 1 ) {
host->cur_trans->trans_len++;
}
if (host->dma_chan == 0 && host->cur_trans->rx_buffer) {
//Copy result out
uint32_t *data = host->cur_trans->rx_buffer;
for (int x = 0; x < host->cur_trans->length; x += 32) {
for (int x = 0; x < host->cur_trans->trans_len; x += 32) {
uint32_t word;
int len = host->cur_trans->length - x;
int len = host->cur_trans->trans_len - x;
if (len > 32) len = 32;
word = host->hw->data_buf[(x / 32)];
memcpy(&data[x / 32], &word, (len + 7) / 8);

View file

@ -0,0 +1,115 @@
/*
Tests for the adc2 device driver
*/
#include "esp_system.h"
#include "driver/adc.h"
#include "driver/dac.h"
#include "unity.h"
#include "esp_system.h"
#include "esp_event_loop.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "nvs_flash.h"
static const char* TAG = "test_adc2";
#define DEFAULT_SSID "TEST_SSID"
#define DEFAULT_PWD "TEST_PASS"
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
printf("ev_handle_called.\n");
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
//do not actually connect in test case
//;
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
ESP_LOGI(TAG, "got ip:%s\n",
ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
TEST_ESP_OK(esp_wifi_connect());
break;
default:
break;
}
return ESP_OK;
}
TEST_CASE("adc2 work with wifi","[adc]")
{
int read_raw;
int target_value;
//adc and dac init
TEST_ESP_OK( dac_output_enable( DAC_CHANNEL_1 ));
TEST_ESP_OK( dac_output_enable( DAC_CHANNEL_2 ));
TEST_ESP_OK( dac_output_voltage( DAC_CHANNEL_1, 30 ));
TEST_ESP_OK( dac_output_voltage( DAC_CHANNEL_2, 60 ));
TEST_ESP_OK( adc2_config_channel_atten( ADC2_CHANNEL_8, ADC_ATTEN_0db ));
TEST_ESP_OK( adc2_config_channel_atten( ADC2_CHANNEL_9, ADC_ATTEN_0db ));
//init wifi
printf("nvs init\n");
esp_err_t r = nvs_flash_init();
if (r == ESP_ERR_NVS_NO_FREE_PAGES) {
printf("no free pages, erase..\n");
TEST_ESP_OK(nvs_flash_erase());
r = nvs_flash_init();
}
TEST_ESP_OK( r);
tcpip_adapter_init();
TEST_ESP_OK(esp_event_loop_init(event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
TEST_ESP_OK(esp_wifi_init(&cfg));
wifi_config_t wifi_config = {
.sta = {
.ssid = DEFAULT_SSID,
.password = DEFAULT_PWD
},
};
TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_STA));
TEST_ESP_OK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
//test read value
TEST_ESP_OK( adc2_get_raw( ADC2_CHANNEL_8, ADC_WIDTH_12Bit, &read_raw ));
target_value = 30*4096*3/256; //3 = 3.3/1.1
printf("dac set: %d, adc read: %d (target_value: %d)\n", 30, read_raw, target_value );
TEST_ASSERT_INT_WITHIN( 600, target_value, read_raw );
TEST_ESP_OK( adc2_get_raw( ADC2_CHANNEL_9, ADC_WIDTH_12Bit, &read_raw ));
target_value = 60*4096*3/256;
printf("dac set: %d, adc read: %d (target_value: %d)\n", 60, read_raw, target_value );
TEST_ASSERT_INT_WITHIN( 600, target_value, read_raw );
//now start wifi
printf("wifi start...\n");
TEST_ESP_OK(esp_wifi_start());
//test reading during wifi on
TEST_ASSERT_EQUAL( adc2_get_raw( ADC2_CHANNEL_8, ADC_WIDTH_12Bit, &read_raw ), ESP_ERR_TIMEOUT );
TEST_ASSERT_EQUAL( adc2_get_raw( ADC2_CHANNEL_9, ADC_WIDTH_12Bit, &read_raw ), ESP_ERR_TIMEOUT );
//wifi stop again
printf("wifi stop...\n");
TEST_ESP_OK( esp_wifi_stop() );
TEST_ESP_OK(esp_wifi_deinit());
nvs_flash_deinit();
//test read value
TEST_ESP_OK( adc2_get_raw( ADC2_CHANNEL_8, ADC_WIDTH_12Bit, &read_raw ));
target_value = 30*4096*3/256; //3 = 3.3/1.1
printf("dac set: %d, adc read: %d (target_value: %d)\n", 30, read_raw, target_value );
TEST_ASSERT_INT_WITHIN( 600, target_value, read_raw );
TEST_ESP_OK( adc2_get_raw( ADC2_CHANNEL_9, ADC_WIDTH_12Bit, &read_raw ));
target_value = 60*4096*3/256;
printf("dac set: %d, adc read: %d (target_value: %d)\n", 60, read_raw, target_value );
TEST_ASSERT_INT_WITHIN( 600, target_value, read_raw );
printf("test passed...\n");
TEST_IGNORE_MESSAGE("this test case is ignored due to the critical memory leak of tcpip_adapter and event_loop.");
}

View file

@ -0,0 +1,141 @@
/*
Tests for the spi_slave device driver
*/
#include <string.h>
#include "unity.h"
#include "driver/spi_master.h"
#include "driver/spi_slave.h"
#include "esp_log.h"
#define PIN_NUM_MISO 25
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 19
#define PIN_NUM_CS 22
static const char MASTER_TAG[] = "test_master";
static const char SLAVE_TAG[] = "test_slave";
#define MASTER_SEND {0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43}
#define SLAVE_SEND { 0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 }
static inline void int_connect( uint32_t gpio, uint32_t sigo, uint32_t sigi )
{
gpio_matrix_out( gpio, sigo, false, false );
gpio_matrix_in( gpio, sigi, false );
}
static void master_init_nodma( spi_device_handle_t* spi)
{
esp_err_t ret;
spi_bus_config_t buscfg={
.miso_io_num=PIN_NUM_MISO,
.mosi_io_num=PIN_NUM_MOSI,
.sclk_io_num=PIN_NUM_CLK,
.quadwp_io_num=-1,
.quadhd_io_num=-1
};
spi_device_interface_config_t devcfg={
.clock_speed_hz=4*1000*1000, //currently only up to 4MHz for internel connect
.mode=0, //SPI mode 0
.spics_io_num=PIN_NUM_CS, //CS pin
.queue_size=7, //We want to be able to queue 7 transactions at a time
.pre_cb=NULL,
.cs_ena_posttrans=1,
};
//Initialize the SPI bus
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 0);
TEST_ASSERT(ret==ESP_OK);
//Attach the LCD to the SPI bus
ret=spi_bus_add_device(HSPI_HOST, &devcfg, spi);
TEST_ASSERT(ret==ESP_OK);
}
static void slave_init()
{
//Configuration for the SPI bus
spi_bus_config_t buscfg={
.mosi_io_num=PIN_NUM_MOSI,
.miso_io_num=PIN_NUM_MISO,
.sclk_io_num=PIN_NUM_CLK
};
//Configuration for the SPI slave interface
spi_slave_interface_config_t slvcfg={
.mode=0,
.spics_io_num=PIN_NUM_CS,
.queue_size=3,
.flags=0,
};
//Enable pull-ups on SPI lines so we don't detect rogue pulses when no master is connected.
gpio_set_pull_mode(PIN_NUM_MOSI, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(PIN_NUM_CLK, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(PIN_NUM_CS, GPIO_PULLUP_ONLY);
//Initialize SPI slave interface
TEST_ESP_OK( spi_slave_initialize(VSPI_HOST, &buscfg, &slvcfg, 2) );
}
TEST_CASE("test slave startup","[spi]")
{
uint8_t master_txbuf[320]=MASTER_SEND;
uint8_t master_rxbuf[320];
uint8_t slave_txbuf[320]=SLAVE_SEND;
uint8_t slave_rxbuf[320];
spi_device_handle_t spi;
//initial master
master_init_nodma( &spi );
//initial slave
slave_init();
//do internal connection
int_connect( PIN_NUM_MOSI, HSPID_OUT_IDX, VSPIQ_IN_IDX );
int_connect( PIN_NUM_MISO, VSPIQ_OUT_IDX, HSPID_IN_IDX );
int_connect( PIN_NUM_CS, HSPICS0_OUT_IDX, VSPICS0_IN_IDX );
int_connect( PIN_NUM_CLK, HSPICLK_OUT_IDX, VSPICLK_IN_IDX );
for ( int i = 0; i < 3; i ++ ) {
//slave send
spi_slave_transaction_t slave_t;
spi_slave_transaction_t* out;
memset(&slave_t, 0, sizeof(spi_slave_transaction_t));
slave_t.length=8*32;
slave_t.tx_buffer=slave_txbuf+2*i;
slave_t.rx_buffer=slave_rxbuf;
TEST_ESP_OK( spi_slave_queue_trans( VSPI_HOST, &slave_t, portMAX_DELAY ) );
//send
spi_transaction_t t = {};
t.length = 32*(i+1);
if ( t.length != 0 ) {
t.tx_buffer = master_txbuf+i;
t.rx_buffer = master_rxbuf+i;
}
spi_device_transmit( spi, (spi_transaction_t*)&t );
//wait for end
TEST_ESP_OK( spi_slave_get_trans_result( VSPI_HOST, &out, portMAX_DELAY ) );
//show result
ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len);
ESP_LOG_BUFFER_HEX( "master tx", t.tx_buffer, t.length/8 );
ESP_LOG_BUFFER_HEX( "master rx", t.rx_buffer, t.length/8 );
ESP_LOG_BUFFER_HEX( "slave tx", slave_t.tx_buffer, (slave_t.trans_len+7)/8);
ESP_LOG_BUFFER_HEX( "slave rx", slave_t.rx_buffer, (slave_t.trans_len+7)/8);
TEST_ASSERT_EQUAL_HEX8_ARRAY( t.tx_buffer, slave_t.rx_buffer, t.length/8 );
TEST_ASSERT_EQUAL_HEX8_ARRAY( slave_t.tx_buffer, t.rx_buffer, t.length/8 );
TEST_ASSERT_EQUAL( t.length, slave_t.trans_len );
//clean
memset( master_rxbuf, 0x66, sizeof(master_rxbuf));
memset( slave_rxbuf, 0x66, sizeof(slave_rxbuf));
}
TEST_ASSERT(spi_slave_free(VSPI_HOST) == ESP_OK);
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
TEST_ASSERT(spi_bus_free(HSPI_HOST) == ESP_OK);
ESP_LOGI(MASTER_TAG, "test passed.");
}

View file

@ -35,6 +35,7 @@ static const char* TIMER_TAG = "timer_group";
#define TIMER_AUTORELOAD_ERROR "HW TIMER AUTORELOAD ERROR"
#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};
static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
@ -123,14 +124,15 @@ esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num,
return ESP_OK;
}
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider)
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint32_t divider)
{
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);
TIMER_CHECK(divider > 1 && divider < 65537, DIVIDER_RANGE_ERROR, ESP_ERR_INVALID_ARG);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
int timer_en = TG[group_num]->hw_timer[timer_num].config.enable;
TG[group_num]->hw_timer[timer_num].config.enable = 0;
TG[group_num]->hw_timer[timer_num].config.divider = divider;
TG[group_num]->hw_timer[timer_num].config.divider = (uint16_t) divider;
TG[group_num]->hw_timer[timer_num].config.enable = timer_en;
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;
@ -209,6 +211,7 @@ esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer
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);
TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
TIMER_CHECK(config->divider > 1 && config->divider < 65537, DIVIDER_RANGE_ERROR, ESP_ERR_INVALID_ARG);
if(group_num == 0) {
periph_module_enable(PERIPH_TIMG0_MODULE);
@ -217,7 +220,7 @@ esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer
}
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
TG[group_num]->hw_timer[timer_num].config.autoreload = config->auto_reload;
TG[group_num]->hw_timer[timer_num].config.divider = config->divider;
TG[group_num]->hw_timer[timer_num].config.divider = (uint16_t) config->divider;
TG[group_num]->hw_timer[timer_num].config.enable = config->counter_en;
TG[group_num]->hw_timer[timer_num].config.increase = config->counter_dir;
TG[group_num]->hw_timer[timer_num].config.alarm_en = config->alarm_en;
@ -236,10 +239,11 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer
config->alarm_en = TG[group_num]->hw_timer[timer_num].config.alarm_en;
config->auto_reload = TG[group_num]->hw_timer[timer_num].config.autoreload;
config->counter_dir = TG[group_num]->hw_timer[timer_num].config.increase;
config->counter_dir = TG[group_num]->hw_timer[timer_num].config.divider;
config->divider = (TG[group_num]->hw_timer[timer_num].config.divider == 0 ?
65536 : TG[group_num]->hw_timer[timer_num].config.divider);
config->counter_en = TG[group_num]->hw_timer[timer_num].config.enable;
if(TG[group_num]->hw_timer[timer_num].config.level_int_en) {
config->intr_type =TIMER_INTR_LEVEL;
config->intr_type = TIMER_INTR_LEVEL;
}
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK;

View file

@ -18,6 +18,7 @@
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_clk.h"
#include "malloc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
@ -42,6 +43,7 @@ static const char* UART_TAG = "uart";
#define UART_EMPTY_THRESH_DEFAULT (10)
#define UART_FULL_THRESH_DEFAULT (120)
#define UART_TOUT_THRESH_DEFAULT (10)
#define UART_TX_IDLE_NUM_DEFAULT (0)
#define UART_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
#define UART_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
#define UART_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
@ -172,13 +174,25 @@ esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode)
esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK((baud_rate <= UART_BITRATE_MAX), "baud_rate error", ESP_FAIL);
uint32_t clk_div = (((UART_CLK_FREQ) << 4) / baud_rate);
esp_err_t ret = ESP_OK;
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
UART[uart_num]->clk_div.div_int = clk_div >> 4;
UART[uart_num]->clk_div.div_frag = clk_div & 0xf;
int uart_clk_freq;
if (UART[uart_num]->conf0.tick_ref_always_on == 0) {
/* this UART has been configured to use REF_TICK */
uart_clk_freq = REF_CLK_FREQ;
} else {
uart_clk_freq = esp_clk_apb_freq();
}
uint32_t clk_div = (((uart_clk_freq) << 4) / baud_rate);
if (clk_div < 16) {
/* baud rate is too high for this clock frequency */
ret = ESP_ERR_INVALID_ARG;
} else {
UART[uart_num]->clk_div.div_int = clk_div >> 4;
UART[uart_num]->clk_div.div_frag = clk_div & 0xf;
}
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
return ESP_OK;
return ret;
}
esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate)
@ -456,6 +470,17 @@ esp_err_t uart_set_dtr(uart_port_t uart_num, int level)
return ESP_OK;
}
esp_err_t uart_set_tx_idle_num(uart_port_t uart_num, uint16_t idle_num)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK((idle_num <= UART_TX_IDLE_NUM_V), "uart idle num error", ESP_FAIL);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
UART[uart_num]->idle_conf.tx_idle_num = idle_num;
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
return ESP_OK;
}
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config)
{
esp_err_t r;
@ -468,17 +493,20 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf
} else if(uart_num == UART_NUM_2) {
periph_module_enable(PERIPH_UART2_MODULE);
}
r=uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh);
if (r!=ESP_OK) return r;
r=uart_set_baudrate(uart_num, uart_config->baud_rate);
if (r!=ESP_OK) return r;
r = uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh);
if (r != ESP_OK) return r;
UART[uart_num]->conf0.val = (
(uart_config->parity << UART_PARITY_S)
| (uart_config->data_bits << UART_BIT_NUM_S)
| ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0)
| UART_TICK_REF_ALWAYS_ON_M);
r=uart_set_stop_bits(uart_num, uart_config->stop_bits);
UART[uart_num]->conf0.val =
(uart_config->parity << UART_PARITY_S)
| (uart_config->data_bits << UART_BIT_NUM_S)
| ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0)
| (uart_config->use_ref_tick ? 0 : UART_TICK_REF_ALWAYS_ON_M);
r = uart_set_baudrate(uart_num, uart_config->baud_rate);
if (r != ESP_OK) return r;
r = uart_set_tx_idle_num(uart_num, UART_TX_IDLE_NUM_DEFAULT);
if (r != ESP_OK) return r;
r = uart_set_stop_bits(uart_num, uart_config->stop_bits);
return r;
}
@ -874,7 +902,7 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t si
int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
UART_CHECK((buf), "uart_num error", (-1));
UART_CHECK((buf), "uart data null", (-1));
UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));
uint8_t* data = NULL;
size_t size;
@ -1111,5 +1139,15 @@ esp_err_t uart_driver_delete(uart_port_t uart_num)
free(p_uart_obj[uart_num]);
p_uart_obj[uart_num] = NULL;
if (uart_num != CONFIG_CONSOLE_UART_NUM ) {
if(uart_num == UART_NUM_0) {
periph_module_disable(PERIPH_UART0_MODULE);
} else if(uart_num == UART_NUM_1) {
periph_module_disable(PERIPH_UART1_MODULE);
} else if(uart_num == UART_NUM_2) {
periph_module_disable(PERIPH_UART2_MODULE);
}
}
return ESP_OK;
}

View file

@ -127,6 +127,13 @@ config SPIRAM_MALLOC_ALWAYSINTERNAL
than this size in internal memory, while allocations larger than this will be done from external RAM.
If allocation from the preferred region fails, an attempt is made to allocate from the non-preferred
region instead, so malloc() will not suddenly fail when either internal or external memory is full.
config WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST
bool "Try to allocate memories of WiFi and LWIP in SPIRAM firstly. If failed, allocate internal memory"
depends on SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC
default "n"
help
Try to allocate memories of WiFi and LWIP in SPIRAM firstly. If failed, try to allocate internal memory then.
config SPIRAM_MALLOC_RESERVE_INTERNAL
int "Reserve this amount of bytes for data that specifically needs to be in DMA or internal memory"
@ -527,11 +534,10 @@ config INT_WDT_CHECK_CPU1
Also detect if interrupts on CPU 1 are disabled for too long.
config TASK_WDT
bool "Initialize Task Watchdog on startup"
bool "Task watchdog"
default y
help
This watchdog timer can be used to make sure individual tasks are still running.
The Task Watchdog timer can be initialized at run time as well
config TASK_WDT_PANIC
bool "Invoke panic handler when Task Watchdog is triggered"
@ -540,46 +546,33 @@ config TASK_WDT_PANIC
help
Normally, the Task Watchdog will only print out a warning if it detects it has not
been fed. If this is enabled, it will invoke the panic handler instead, which
can then halt or reboot the chip. This can also be configured at run time
by reinitializing the task watchdog.
can then halt or reboot the chip.
config TASK_WDT_TIMEOUT_S
int "Task watchdog timeout (ms)"
int "Task watchdog timeout (seconds)"
depends on TASK_WDT
range 1 60000
default 5000
range 1 60
default 5
help
Timeout for the task WDT, in ms.
Timeout for the task WDT, in seconds.
config TASK_WDT_CHECK_IDLE_TASK_CPU0
bool "Add CPU0 idle task to task watchdog on startup"
config TASK_WDT_CHECK_IDLE_TASK
bool "Task watchdog watches CPU0 idle task"
depends on TASK_WDT
default y
help
With this turned on, the CPU0 idle task will be added to the task watchdog
on startup. Adding the idle task to the task watchdog allows for the detection
of CPU starvation. The idle task not being called is usually a symptom of another
With this turned on, the task WDT can detect if the idle task is not called within the task
watchdog timeout period. The idle task not being called usually is a symptom of another
task hoarding the CPU. It is also a bad thing because FreeRTOS household tasks depend on the
idle task getting some runtime every now and then.
idle task getting some runtime every now and then. Take Care: With this disabled, this
watchdog will trigger if no tasks register themselves within the timeout value.
config TASK_WDT_CHECK_IDLE_TASK_CPU1
bool "Add CPU0 idle task to task watchdog on startup"
depends on TASK_WDT && !FREERTOS_UNICORE
bool "Task watchdog also watches CPU1 idle task"
depends on TASK_WDT_CHECK_IDLE_TASK && !FREERTOS_UNICORE
default y
help
With this turned on, the CPU1 idle task will also be added to the task watchdog
on startup.
config TASK_WDT_LEGACY_BEHAVIOR
bool "Use legacy behavior for task watchdog"
depends on TASK_WDT
default n
help
Task wdt legacy behavior will add a task to the wdt list on its first
call to esp_task_wdt_feed(). Furthermore, tasks can only remove
themselves from the wdt task list when calling esp_task_wdt_delete().
Therefore esp_task_wdt_delete() should be called with no parameters
when legacy behavior is enabled.
Also check the idle task that runs on CPU1.
#The brownout detector code is disabled (by making it depend on a nonexisting symbol) because the current revision of ESP32
#silicon has a bug in the brown-out detector, rendering it unusable for resetting the CPU.
@ -791,44 +784,52 @@ config ESP32_WIFI_STATIC_RX_BUFFER_NUM
range 2 25
default 10
help
Set the number of WiFi static rx buffers. Each buffer takes approximately 1.6KB of RAM.
Set the number of WiFi static RX buffers. Each buffer takes approximately 1.6KB of RAM.
The static rx buffers are allocated when esp_wifi_init is called, they are not freed
until esp_wifi_deinit is called.
WiFi hardware use these buffers to receive packets, generally larger number for higher
throughput but more memory, smaller number for lower throughput but less memory.
until esp_wifi_deinit is called.
WiFi hardware use these buffers to receive all 802.11 frames.
A higher number may allow higher throughput but increases memory use.
config ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM
int "Max number of WiFi dynamic RX buffers"
range 0 128
default 32
help
Set the number of WiFi dynamic rx buffers, 0 means no limitation for dynamic rx buffer
allocation. The size of dynamic rx buffers is not fixed.
For each received packet in static rx buffers, WiFi driver makes a copy
to dynamic rx buffers and then deliver it to high layer stack. The dynamic rx buffer
is freed when the application, such as socket, successfully received the packet.
For some applications, the WiFi driver receiving speed is faster than application
consuming speed, we may run out of memory if no limitation for the dynamic rx buffer
number. Generally the number of dynamic rx buffer should be no less than static
rx buffer number if it is not 0.
Set the number of WiFi dynamic RX buffers, 0 means unlimited RX buffers will be allocated
(provided sufficient free RAM). The size of each dynamic RX buffer depends on the size of
the received data frame.
For each received data frame, the WiFi driver makes a copy to an RX buffer and then delivers
it to the high layer TCP/IP stack. The dynamic RX buffer is freed after the higher layer has
successfully received the data frame.
For some applications, WiFi data frames may be received faster than the application can
process them. In these cases we may run out of memory if RX buffer number is unlimited (0).
If a dynamic RX buffer limit is set, it should be at least the number of static RX buffers.
choice ESP32_WIFI_TX_BUFFER
prompt "Type of WiFi TX buffers"
default ESP32_WIFI_DYNAMIC_TX_BUFFER
help
Select type of WiFi tx buffers and show the submenu with the number of WiFi tx buffers choice.
If "STATIC" is selected, WiFi tx buffers are allocated when WiFi is initialized and released
when WiFi is de-initialized. If "DYNAMIC" is selected, WiFi tx buffer is allocated when tx
data is delivered from LWIP to WiFi and released when tx data is sent out by WiFi.
The size of each static tx buffers is fixed to about 1.6KB and the size of dynamic tx buffers is
depend on the length of the data delivered from LWIP.
If PSRAM is enabled, "STATIC" should be selected to guarantee enough WiFi tx buffers.
If PSRAM is disabled, "DYNAMIC" should be selected to improve the utilization of RAM.
Select type of WiFi TX buffers:
If "Static" is selected, WiFi TX buffers are allocated when WiFi is initialized and released
when WiFi is de-initialized. The size of each static TX buffer is fixed to about 1.6KB.
If "Dynamic" is selected, each WiFi TX buffer is allocated as needed when a data frame is
delivered to the Wifi driver from the TCP/IP stack. The buffer is freed after the data frame
has been sent by the WiFi driver. The size of each dynamic TX buffer depends on the length
of each data frame sent by the TCP/IP layer.
If PSRAM is enabled, "Static" should be selected to guarantee enough WiFi TX buffers.
If PSRAM is disabled, "Dynamic" should be selected to improve the utilization of RAM.
config ESP32_WIFI_STATIC_TX_BUFFER
bool "STATIC"
bool "Static"
config ESP32_WIFI_DYNAMIC_TX_BUFFER
bool "DYNAMIC"
bool "Dynamic"
depends on !SPIRAM_USE_MALLOC
endchoice
@ -840,27 +841,31 @@ config ESP32_WIFI_TX_BUFFER_TYPE
config ESP32_WIFI_STATIC_TX_BUFFER_NUM
int "Max number of WiFi static TX buffers"
depends on ESP32_WIFI_STATIC_TX_BUFFER
range 16 64
default 32
range 6 64
default 16
help
Set the number of WiFi static tx buffers. Each buffer takes approximately 1.6KB of RAM.
The static rx buffers are allocated when esp_wifi_init is called, they are not released
until esp_wifi_deinit is called.
For each tx packet from high layer stack, WiFi driver make a copy of it. For some applications,
especially the UDP application, the high layer deliver speed is faster than the WiFi tx
speed, we may run out of static tx buffers.
Set the number of WiFi static TX buffers. Each buffer takes approximately 1.6KB of RAM.
The static RX buffers are allocated when esp_wifi_init() is called, they are not released
until esp_wifi_deinit() is called.
For each transmitted data frame from the higher layer TCP/IP stack, the WiFi driver makes a
copy of it in a TX buffer. For some applications especially UDP applications, the upper
layer can deliver frames faster than WiFi layer can transmit. In these cases, we may run out
of TX buffers.
config ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM
int "Max number of WiFi dynamic TX buffers"
depends on ESP32_WIFI_DYNAMIC_TX_BUFFER
range 16 64
range 16 128
default 32
help
Set the number of WiFi dynamic tx buffers, 0 means no limitation for dynamic tx buffer
allocation. The size of dynamic tx buffers is not fixed.
For each tx packet from high layer stack, WiFi driver make a copy of it. For some applications,
especially the UDP application, the high layer deliver speed is faster than the WiFi tx
speed, we may run out of memory if no limitation for the dynamic tx buffer number.
Set the number of WiFi dynamic TX buffers. The size of each dynamic TX buffer is not fixed,
it depends on the size of each transmitted data frame.
For each transmitted frame from the higher layer TCP/IP stack, the WiFi driver makes a copy
of it in a TX buffer. For some applications, especially UDP applications, the upper layer
can deliver frames faster than WiFi layer can transmit. In these cases, we may run out of TX
buffers.
config ESP32_WIFI_AMPDU_ENABLED
bool "WiFi AMPDU"
@ -940,3 +945,68 @@ config ESP32_PHY_MAX_TX_POWER
default ESP32_PHY_MAX_WIFI_TX_POWER
endmenu # PHY
menu "Power Management"
config PM_ENABLE
bool "Support for power management"
default n
help
If enabled, application is compiled with support for power management.
This option has run-time overhead (increased interrupt latency,
longer time to enter idle state), and it also reduces accuracy of
RTOS ticks and timers used for timekeeping.
Enable this option if application uses power management APIs.
config PM_DFS_INIT_AUTO
bool "Enable dynamic frequency scaling (DFS) at startup"
depends on PM_ENABLE
default n
help
If enabled, startup code configures dynamic frequency scaling.
Max CPU frequency is set to CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ setting,
min frequency is set to XTAL frequency.
If disabled, DFS will not be active until the application
configures it using esp_pm_configure function.
config PM_USE_RTC_TIMER_REF
bool "Use RTC timer to prevent time drift (EXPERIMENTAL)"
depends on PM_ENABLE && (ESP32_TIME_SYSCALL_USE_RTC || ESP32_TIME_SYSCALL_USE_RTC_FRC1)
default n
help
When APB clock frequency changes, high-resolution timer (esp_timer)
scale and base value need to be adjusted. Each adjustment may cause
small error, and over time such small errors may cause time drift.
If this option is enabled, RTC timer will be used as a reference to
compensate for the drift.
It is recommended that this option is only used if 32k XTAL is selected
as RTC clock source.
config PM_PROFILING
bool "Enable profiling counters for PM locks"
depends on PM_ENABLE
default n
help
If enabled, esp_pm_* functions will keep track of the amount of time
each of the power management locks has been held, and esp_pm_dump_locks
function will print this information.
This feature can be used to analyze which locks are preventing the chip
from going into a lower power state, and see what time the chip spends
in each power saving mode. This feature does incur some run-time
overhead, so should typically be disabled in production builds.
config PM_TRACE
bool "Enable debug tracing of PM using GPIOs"
depends on PM_ENABLE
default n
help
If enabled, some GPIOs will be used to signal events such as RTOS ticks,
frequency switching, entry/exit from idle state. Refer to pm_trace.c
file for the list of GPIOs.
This feature is intended to be used when analyzing/debugging behavior
of power management implementation, and should be kept disabled in
applications.
endmenu # "Power Management"

View file

@ -15,10 +15,12 @@
#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/time.h>
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_clk.h"
#include "esp_clk_internal.h"
#include "rom/ets_sys.h"
#include "rom/uart.h"
#include "rom/rtc.h"
@ -27,6 +29,7 @@
#include "soc/rtc_cntl_reg.h"
#include "soc/dport_reg.h"
#include "soc/i2s_reg.h"
#include "driver/periph_ctrl.h"
#include "xtensa/core-macros.h"
/* Number of cycles to wait from the 32k XTAL oscillator to consider it running.
@ -40,14 +43,13 @@
static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk);
// g_ticks_us defined in ROMs for PRO and APP CPU
extern uint32_t g_ticks_per_us_pro;
extern uint32_t g_ticks_per_us_app;
static const char* TAG = "clk";
/*
* This function is not exposed as an API at this point,
* because FreeRTOS doesn't yet support dynamic changing of
* CPU frequency. Also we need to implement hooks for
* components which want to be notified of CPU frequency
* changes.
*/
void esp_clk_init(void)
{
rtc_config_t cfg = RTC_CONFIG_DEFAULT();
@ -90,10 +92,19 @@ void esp_clk_init(void)
XTHAL_SET_CCOUNT( XTHAL_GET_CCOUNT() * freq_after / freq_before );
}
int IRAM_ATTR esp_clk_cpu_freq(void)
{
return g_ticks_per_us_pro * 1000000;
}
int IRAM_ATTR esp_clk_apb_freq(void)
{
return MIN(g_ticks_per_us_pro, 80) * 1000000;
}
void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
{
extern uint32_t g_ticks_per_us_pro; // g_ticks_us defined in ROM for PRO CPU
extern uint32_t g_ticks_per_us_app; // same defined for APP CPU
/* Update scale factors used by ets_delay_us */
g_ticks_per_us_pro = ticks_per_us;
g_ticks_per_us_app = ticks_per_us;
}
@ -226,4 +237,7 @@ void esp_perip_clk_init(void)
/* Disable WiFi/BT/SDIO clocks. */
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk);
/* Enable RNG clock. */
periph_module_enable(PERIPH_RNG_MODULE);
}

View file

@ -40,7 +40,7 @@ COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/libhal.a \
#The cache workaround also needs a c++ standard library recompiled with the workaround.
ifdef CONFIG_SPIRAM_CACHE_WORKAROUND
COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/libstdcc++-cache-workaround.a
COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/libstdc++-psram-workaround.a
endif
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))

View file

@ -23,6 +23,7 @@
#include "esp_panic.h"
#include "esp_partition.h"
#include "esp_clk.h"
#if CONFIG_ESP32_ENABLE_COREDUMP
#define LOG_LOCAL_LEVEL CONFIG_ESP32_CORE_DUMP_LOG_LEVEL
@ -522,10 +523,11 @@ void esp_core_dump_to_uart(XtExcFrame *frame)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
ESP_COREDUMP_LOGI("Press Enter to print core dump to UART...");
tm_end = xthal_get_ccount() / (XT_CLOCK_FREQ / 1000) + CONFIG_ESP32_CORE_DUMP_UART_DELAY;
const int cpu_ticks_per_ms = esp_clk_cpu_freq() / 1000;
tm_end = xthal_get_ccount() / cpu_ticks_per_ms + CONFIG_ESP32_CORE_DUMP_UART_DELAY;
ch = esp_core_dump_uart_get_char();
while (!(ch == '\n' || ch == '\r')) {
tm_cur = xthal_get_ccount() / (XT_CLOCK_FREQ / 1000);
tm_cur = xthal_get_ccount() / cpu_ticks_per_ms;
if (tm_cur >= tm_end)
break;
ch = esp_core_dump_uart_get_char();

View file

@ -64,8 +64,10 @@
#include "esp_app_trace.h"
#include "esp_efuse.h"
#include "esp_spiram.h"
#include "esp_clk.h"
#include "esp_clk_internal.h"
#include "esp_timer.h"
#include "esp_pm.h"
#include "pm_impl.h"
#include "trax.h"
#define STRINGIFY(s) STRINGIFY2(s)
@ -150,6 +152,7 @@ void IRAM_ATTR call_start_cpu0()
}
#if CONFIG_SPIRAM_BOOT_INIT
esp_spiram_init_cache();
if (esp_spiram_init() != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Failed to init external RAM!");
abort();
@ -286,9 +289,18 @@ void start_cpu0_default(void)
esp_clk_init();
esp_perip_clk_init();
intr_matrix_clear();
#ifndef CONFIG_CONSOLE_UART_NONE
uart_div_modify(CONFIG_CONSOLE_UART_NUM, (rtc_clk_apb_freq_get() << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
#endif
#ifdef CONFIG_PM_ENABLE
const int uart_clk_freq = REF_CLK_FREQ;
/* When DFS is enabled, use REFTICK as UART clock source */
CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON);
#else
const int uart_clk_freq = APB_CLK_FREQ;
#endif // CONFIG_PM_DFS_ENABLE
uart_div_modify(CONFIG_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
#endif // CONFIG_CONSOLE_UART_NONE
#if CONFIG_BROWNOUT_DET
esp_brownout_init();
#endif
@ -323,6 +335,9 @@ void start_cpu0_default(void)
do_global_ctors();
#if CONFIG_INT_WDT
esp_int_wdt_init();
#endif
#if CONFIG_TASK_WDT
esp_task_wdt_init();
#endif
esp_cache_err_int_init();
esp_crosscore_int_init();
@ -333,6 +348,18 @@ void start_cpu0_default(void)
spi_flash_init();
/* init default OS-aware flash access critical section */
spi_flash_guard_set(&g_flash_guard_default_ops);
#ifdef CONFIG_PM_ENABLE
esp_pm_impl_init();
#ifdef CONFIG_PM_DFS_INIT_AUTO
rtc_cpu_freq_t max_freq;
rtc_clk_cpu_freq_from_mhz(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, &max_freq);
esp_pm_config_esp32_t cfg = {
.max_cpu_freq = max_freq,
.min_cpu_freq = RTC_CPU_FREQ_XTAL
};
esp_pm_configure(&cfg);
#endif //CONFIG_PM_DFS_INIT_AUTO
#endif //CONFIG_PM_ENABLE
#if CONFIG_ESP32_ENABLE_COREDUMP
esp_core_dump_init();
@ -375,8 +402,10 @@ void start_cpu1_default(void)
static void do_global_ctors(void)
{
#ifdef CONFIG_CXX_EXCEPTIONS
static struct object ob;
__register_frame_info( __eh_frame, &ob );
#endif
void (**p)(void);
for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
@ -397,30 +426,6 @@ static void main_task(void* args)
#endif
//Enable allocation in region where the startup stacks were located.
heap_caps_enable_nonos_stack_heaps();
//Initialize task wdt
#ifdef CONFIG_TASK_WDT
#ifdef CONFIG_TASK_WDT_PANIC
esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, true);
#else
esp_task_wdt_init(CONFIG_TASK_WDT_TIMEOUT_S, false);
#endif
#endif
//Add IDLE 0 to task wdt
#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
if(idle_0 != NULL){
esp_task_wdt_add(idle_0);
}
#endif
//Add IDLE 1 to task wdt
#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
if(idle_1 != NULL){
esp_task_wdt_add(idle_1);
}
#endif
app_main();
vTaskDelete(NULL);
}

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