Merge branch 'master' into feature/esp32s2beta_update

This commit is contained in:
Angus Gratton
2019-08-08 13:44:24 +10:00
committed by Angus Gratton
2414 changed files with 160787 additions and 45783 deletions

View File

@@ -1,43 +1,40 @@
set(COMPONENT_SRCS "can.c"
"gpio.c"
"i2c.c"
"i2s.c"
"ledc.c"
"pcnt.c"
"periph_ctrl.c"
"rmt.c"
"rtc_module.c"
"sdspi_crc.c"
"sdspi_host.c"
"sdspi_transaction.c"
"sigmadelta.c"
"spi_common.c"
"spi_master.c"
"spi_slave.c"
"timer.c"
"uart.c")
set(srcs
"can.c"
"gpio.c"
"i2c.c"
"i2s.c"
"ledc.c"
"pcnt.c"
"periph_ctrl.c"
"rmt.c"
"rtc_module.c"
"sdspi_crc.c"
"sdspi_host.c"
"sdspi_transaction.c"
"sigmadelta.c"
"spi_common.c"
"spi_master.c"
"spi_slave.c"
"timer.c"
"uart.c")
if(CONFIG_IDF_TARGET_ESP32)
# SDMMC and MCPWM are in ESP32 only.
list(APPEND COMPONENT_SRCS "mcpwm.c"
"sdio_slave.c"
"sdmmc_host.c"
"sdmmc_transaction.c")
list(APPEND srcs "mcpwm.c"
"sdio_slave.c"
"sdmmc_host.c"
"sdmmc_transaction.c")
endif()
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "include/driver")
set(COMPONENT_REQUIRES esp_ringbuf soc) #cannot totally hide soc headers, since there are a lot arguments in the driver are chip-dependent
if(CONFIG_IDF_TARGET_ESP32S2BETA)
list(APPEND COMPONENT_SRCS "${CONFIG_IDF_TARGET}/rtc_tempsensor.c"
"${CONFIG_IDF_TARGET}/rtc_touchpad.c")
list(APPEND COMPONENT_ADD_INCLUDEDIRS "${CONFIG_IDF_TARGET}/include")
list(APPEND srcs "${CONFIG_IDF_TARGET}/rtc_tempsensor.c"
"${CONFIG_IDF_TARGET}/rtc_touchpad.c")
endif()
register_component()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include" "${CONFIG_IDF_TARGET}/include"
PRIV_INCLUDE_DIRS "include/driver"
REQUIRES esp_ringbuf soc) #cannot totally hide soc headers, since there are a lot arguments in the driver are chip-dependent
if(GCC_NOT_5_2_0)
# uses C11 atomic feature

View File

@@ -354,7 +354,7 @@ static void can_alert_handler(uint32_t alert_code, int *alert_req)
}
}
static void can_intr_handler_err_warn(can_status_reg_t *status, BaseType_t *task_woken, int *alert_req)
static void can_intr_handler_err_warn(can_status_reg_t *status, int *alert_req)
{
if (status->bus) {
if (status->error) {
@@ -479,10 +479,15 @@ static void can_intr_handler_main(void *arg)
status.val = can_get_status();
intr_reason.val = (p_can_obj != NULL) ? can_get_interrupt_reason() : 0; //Incase intr occurs whilst driver is being uninstalled
#ifdef __clang_analyzer__
if (intr_reason.val == 0) { // Teach clang-tidy that all bitfields are zero if a register is zero; othewise it warns about p_can_obj null dereference
intr_reason.err_warn = intr_reason.err_passive = intr_reason.bus_err = intr_reason.arb_lost = intr_reason.rx = intr_reason.tx = 0;
}
#endif
//Handle error counter related interrupts
if (intr_reason.err_warn) {
//Triggers when Bus-Status or Error-status bits change
can_intr_handler_err_warn(&status, &task_woken, &alert_req);
can_intr_handler_err_warn(&status, &alert_req);
}
if (intr_reason.err_passive) {
//Triggers when entering/returning error passive/active state

View File

@@ -22,21 +22,34 @@
#include "soc/rtc_cntl_reg.h"
#include "soc/gpio_periph.h"
#include "esp_log.h"
#include "esp_ipc.h"
static const char* GPIO_TAG = "gpio";
#define GPIO_CHECK(a, str, ret_val) \
if (!(a)) { \
ESP_LOGE(GPIO_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
#define GPIO_ISR_CORE_ID_UNINIT (3)
typedef struct {
gpio_isr_t fn; /*!< isr function */
void* args; /*!< isr function args */
} gpio_isr_func_t;
// Used by the IPC call to register the interrupt service routine.
typedef struct {
int source; /*!< ISR source */
int intr_alloc_flags; /*!< ISR alloc flag */
void (*fn)(void*); /*!< ISR function */
void *arg; /*!< ISR function args*/
void *handle; /*!< ISR handle */
esp_err_t ret;
} gpio_isr_alloc_t;
static const char* GPIO_TAG = "gpio";
static gpio_isr_func_t* gpio_isr_func = NULL;
static gpio_isr_handle_t gpio_isr_handle;
static uint32_t isr_core_id = GPIO_ISR_CORE_ID_UNINIT;
static portMUX_TYPE gpio_spinlock = portMUX_INITIALIZER_UNLOCKED;
esp_err_t gpio_pullup_en(gpio_num_t gpio_num)
@@ -118,7 +131,6 @@ static void gpio_intr_status_clr(gpio_num_t gpio_num)
static esp_err_t gpio_intr_enable_on_core (gpio_num_t gpio_num, uint32_t core_id)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
gpio_intr_status_clr(gpio_num);
#if CONFIG_IDF_TARGET_ESP32
if (core_id == 0) {
@@ -136,7 +148,13 @@ static esp_err_t gpio_intr_enable_on_core (gpio_num_t gpio_num, uint32_t core_id
esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
{
return gpio_intr_enable_on_core (gpio_num, xPortGetCoreID());
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_spinlock);
if(isr_core_id == GPIO_ISR_CORE_ID_UNINIT) {
isr_core_id = xPortGetCoreID();
}
portEXIT_CRITICAL(&gpio_spinlock);
return gpio_intr_enable_on_core (gpio_num, isr_core_id);
}
esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
@@ -377,16 +395,15 @@ static void IRAM_ATTR gpio_intr_service(void* arg)
if (gpio_isr_func == NULL) {
return;
}
//read status to get interrupt status for GPIO0-31
const uint32_t gpio_intr_status = GPIO.status;
const uint32_t gpio_intr_status = (isr_core_id == 0) ? GPIO.pcpu_int : GPIO.acpu_int;
if (gpio_intr_status) {
gpio_isr_loop(gpio_intr_status, 0);
GPIO.status_w1tc = gpio_intr_status;
}
//read status1 to get interrupt status for GPIO32-39
const uint32_t gpio_intr_status_h = GPIO.status1.intr_st;
const uint32_t gpio_intr_status_h = (isr_core_id == 0) ? GPIO.pcpu_int1.intr : GPIO.acpu_int1.intr;
if (gpio_intr_status_h) {
gpio_isr_loop(gpio_intr_status_h, 32);
GPIO.status1_w1tc.intr_st = gpio_intr_status_h;
@@ -428,12 +445,12 @@ esp_err_t gpio_install_isr_service(int intr_alloc_flags)
esp_err_t ret;
portENTER_CRITICAL(&gpio_spinlock);
gpio_isr_func = (gpio_isr_func_t*) calloc(GPIO_NUM_MAX, sizeof(gpio_isr_func_t));
portEXIT_CRITICAL(&gpio_spinlock);
if (gpio_isr_func == NULL) {
ret = ESP_ERR_NO_MEM;
} else {
ret = gpio_isr_register(gpio_intr_service, NULL, intr_alloc_flags, &gpio_isr_handle);
}
portEXIT_CRITICAL(&gpio_spinlock);
return ret;
}
@@ -446,14 +463,37 @@ void gpio_uninstall_isr_service()
esp_intr_free(gpio_isr_handle);
free(gpio_isr_func);
gpio_isr_func = NULL;
isr_core_id = GPIO_ISR_CORE_ID_UNINIT;
portEXIT_CRITICAL(&gpio_spinlock);
return;
}
static void gpio_isr_register_on_core_static(void *param)
{
gpio_isr_alloc_t *p = (gpio_isr_alloc_t *)param;
//We need to check the return value.
p->ret = esp_intr_alloc(p->source, p->intr_alloc_flags, p->fn, p->arg, p->handle);
}
esp_err_t gpio_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, gpio_isr_handle_t *handle)
{
GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG);
return esp_intr_alloc(ETS_GPIO_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
gpio_isr_alloc_t p;
p.source = ETS_GPIO_INTR_SOURCE;
p.intr_alloc_flags = intr_alloc_flags;
p.fn = fn;
p.arg = arg;
p.handle = handle;
portENTER_CRITICAL(&gpio_spinlock);
if(isr_core_id == GPIO_ISR_CORE_ID_UNINIT) {
isr_core_id = xPortGetCoreID();
}
portEXIT_CRITICAL(&gpio_spinlock);
esp_err_t ret = esp_ipc_call_blocking(isr_core_id, gpio_isr_register_on_core_static, (void *)&p);
if(ret != ESP_OK || p.ret != ESP_OK) {
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)

View File

@@ -91,6 +91,7 @@ typedef struct {
bool use_apll; /*!< I2S use APLL clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */
int fixed_mclk; /*!< I2S fixed MLCK clock */
double real_rate;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
@@ -185,6 +186,12 @@ esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num)
return ESP_OK;
}
float i2s_get_clk(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
return p_i2s_obj[i2s_num]->real_rate;
}
static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle)
{
return esp_intr_alloc(i2s_periph_signal[i2s_num].irq, intr_alloc_flags, fn, arg, handle);
@@ -265,7 +272,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, 0);
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, 31);
avg = (max_rate + min_rate)/2;
if(abs(avg - rate) < min_diff) {
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm2 = _sdm2;
}
@@ -275,11 +282,21 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, *sdm2, _odir);
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, *sdm2, _odir);
avg = (max_rate + min_rate)/2;
if(abs(avg - rate) < min_diff) {
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*odir = _odir;
}
}
min_diff = APLL_MAX_FREQ;
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, *odir);
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, *odir);
avg = (max_rate + min_rate)/2;
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm2 = _sdm2;
}
}
min_diff = APLL_MAX_FREQ;
for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) {
@@ -479,6 +496,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
I2S[i2s_num]->clkm_conf.clk_sel = 1;
#endif
double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir);
p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale;
ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0);
} else {
@@ -493,6 +511,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
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);
p_i2s_obj[i2s_num]->real_rate = real_rate;
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);
}

View File

@@ -509,6 +509,16 @@ 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 get clock set on particular port number.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - actual clock set by i2s driver
*/
float i2s_get_clk(i2s_port_t i2s_num);
/**
* @brief Set built-in ADC mode for I2S DMA, this function will initialize ADC pad,
* and set ADC parameters.

View File

@@ -458,15 +458,23 @@ static inline uint32_t MMC_RSP_BITS(uint32_t *src, int start, int len)
#define SD_IO_CIS_SIZE 0x17000
/* CIS tuple codes (based on PC Card 16) */
#define SD_IO_CISTPL_NULL 0x00
#define SD_IO_CISTPL_VERS_1 0x15
#define SD_IO_CISTPL_MANFID 0x20
#define SD_IO_CISTPL_FUNCID 0x21
#define SD_IO_CISTPL_FUNCE 0x22
#define SD_IO_CISTPL_END 0xff
#define CISTPL_CODE_NULL 0x00
#define CISTPL_CODE_DEVICE 0x01
#define CISTPL_CODE_CHKSUM 0x10
#define CISTPL_CODE_VERS1 0x15
#define CISTPL_CODE_ALTSTR 0x16
#define CISTPL_CODE_CONFIG 0x1A
#define CISTPL_CODE_CFTABLE_ENTRY 0x1B
#define CISTPL_CODE_MANFID 0x20
#define CISTPL_CODE_FUNCID 0x21
#define TPLFID_FUNCTION_SDIO 0x0c
#define CISTPL_CODE_FUNCE 0x22
#define CISTPL_CODE_VENDER_BEGIN 0x80
#define CISTPL_CODE_VENDER_END 0x8F
#define CISTPL_CODE_SDIO_STD 0x91
#define CISTPL_CODE_SDIO_EXT 0x92
#define CISTPL_CODE_END 0xFF
/* CISTPL_FUNCID codes */
#define TPLFID_FUNCTION_SDIO 0x0c
/* Timing */
#define SDMMC_TIMING_LEGACY 0

View File

@@ -1,9 +1,9 @@
// Copyright 2010-2018 Espressif Systems (Shanghai) PTE LTD
// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
@@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DRIVER_SPI_COMMON_H_
#define _DRIVER_SPI_COMMON_H_
#pragma once
#include <stdint.h>
#include <stdbool.h>
@@ -62,35 +60,6 @@ extern "C"
*/
#define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len))
/**
* Transform unsigned integer of length <= 32 bits to the format which can be
* sent by the SPI driver directly.
*
* E.g. to send 9 bits of data, you can:
*
* uint16_t data = SPI_SWAP_DATA_TX(0x145, 9);
*
* Then points tx_buffer to ``&data``.
*
* @param data Data to be sent, can be uint8_t, uint16_t or uint32_t. @param
* len Length of data to be sent, since the SPI peripheral sends from the MSB,
* this helps to shift the data to the MSB.
*/
#define SPI_SWAP_DATA_TX(data, len) __builtin_bswap32((uint32_t)data<<(32-len))
/**
* Transform received data of length <= 32 bits to the format of an unsigned integer.
*
* E.g. to transform the data of 15 bits placed in a 4-byte array to integer:
*
* uint16_t data = SPI_SWAP_DATA_RX(*(uint32_t*)t->rx_data, 15);
*
* @param data Data to be rearranged, can be uint8_t, uint16_t or uint32_t.
* @param len Length of data received, since the SPI peripheral writes from
* the MSB, this helps to shift the data to the LSB.
*/
#define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len))
/**
* @brief This is a configuration structure for a SPI bus.
*
@@ -116,6 +85,50 @@ typedef struct {
} spi_bus_config_t;
/**
* @brief Initialize a SPI bus
*
* @warning For now, only supports HSPI and VSPI.
*
* @param host SPI peripheral that controls this bus
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
* @param dma_chan Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel
* for a SPI bus allows transfers on the bus to have sizes only limited by the amount of
* internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of
* bytes transfered to a maximum of 64. Set to 0 if only the SPI flash uses
* this bus.
*
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
* DMA-capable memory.
*
* @warning The ISR of SPI is always executed on the core which calls this
* function. Never starve the ISR on this core or the SPI transactions will not
* be handled.
*
* @return
* - ESP_ERR_INVALID_ARG if configuration is invalid
* - ESP_ERR_INVALID_STATE if host already is in use
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan);
/**
* @brief Free a SPI bus
*
* @warning In order for this to succeed, all devices have to be removed first.
*
* @param host SPI peripheral to free
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
* - ESP_OK on success
*/
esp_err_t spi_bus_free(spi_host_device_t host);
/** @cond */ //Doxygen command to hide deprecated function (or non-public) from API Reference
/**
* @brief Try to claim a SPI peripheral
*
@@ -124,6 +137,8 @@ typedef struct {
* @param host Peripheral to claim
* @param source The caller indentification string.
*
* @note This public API is deprecated.
*
* @return True if peripheral is claimed successfully; false if peripheral already is claimed.
*/
bool spicommon_periph_claim(spi_host_device_t host, const char* source);
@@ -145,6 +160,8 @@ bool spicommon_periph_claim(spi_host_device_t host, const char* source);
*
* @param host Peripheral to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_periph_in_use(spi_host_device_t host);
@@ -153,6 +170,9 @@ bool spicommon_periph_in_use(spi_host_device_t host);
* @brief Return the SPI peripheral so another driver can claim it.
*
* @param host Peripheral to return
*
* @note This public API is deprecated.
*
* @return True if peripheral is returned successfully; false if peripheral was free to claim already.
*/
bool spicommon_periph_free(spi_host_device_t host);
@@ -164,6 +184,8 @@ bool spicommon_periph_free(spi_host_device_t host);
*
* @param dma_chan channel to claim
*
* @note This public API is deprecated.
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_claim(int dma_chan);
@@ -173,6 +195,8 @@ bool spicommon_dma_chan_claim(int dma_chan);
*
* @param dma_chan DMA channel to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_dma_chan_in_use(int dma_chan);
@@ -182,10 +206,13 @@ bool spicommon_dma_chan_in_use(int dma_chan);
*
* @param dma_chan channel to return
*
* @note This public API is deprecated.
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_free(int dma_chan);
/// @note macros deprecated from public API
#define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode
#define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode
#define SPICOMMON_BUSFLAG_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
@@ -206,6 +233,9 @@ bool spicommon_dma_chan_free(int dma_chan);
* the arguments. Depending on the IO-pads requested, the routing is done either using the
* IO_mux or using the GPIO matrix.
*
* @note This public API is deprecated. Please call ``spi_bus_initialize`` for master
* bus initialization and ``spi_slave_initialize`` for slave initialization.
*
* @param host SPI peripheral to be routed
* @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins
* @param dma_chan DMA-channel (1 or 2) to use, or 0 for no DMA.
@@ -234,18 +264,9 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
/**
* @brief Free the IO used by a SPI peripheral
* @deprecated Use spicommon_bus_free_io_cfg instead.
*
* @param host SPI peripheral to be freed
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_free_io(spi_host_device_t host) __attribute__((deprecated));
/**
* @brief Free the IO used by a SPI peripheral
* @note This public API is deprecated. Please call ``spi_bus_free`` for master
* bus deinitialization and ``spi_slave_free`` for slave deinitialization.
*
* @param bus_cfg Bus config struct which defines which pins to be used.
*
@@ -258,6 +279,8 @@ esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg);
/**
* @brief Initialize a Chip Select pin for a specific SPI peripheral
*
* @note This public API is deprecated. Please call corresponding device initialization
* functions.
*
* @param host SPI peripheral
* @param cs_io_num GPIO pin to route
@@ -265,59 +288,61 @@ esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg);
* @param force_gpio_matrix If true, CS will always be routed through the GPIO matrix. If false,
* if the GPIO number allows it, the routing will happen through the IO_mux.
*/
void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix);
/**
* @brief Free a chip select line
* @deprecated Use spicommon_cs_io, which inputs the gpio num rather than the cs id instead.
*
* @param host SPI peripheral
* @param cs_num CS id to free
*/
void spicommon_cs_free(spi_host_device_t host, int cs_num) __attribute__((deprecated));
/**
* @brief Free a chip select line
*
* @param cs_gpio_num CS gpio num to free
*
* @note This public API is deprecated.
*/
void spicommon_cs_free_io(int cs_gpio_num);
/**
* @brief Setup a DMA link chain
* @brief Check whether all pins used by a host are through IOMUX.
*
* This routine will set up a chain of linked DMA descriptors in the array pointed to by
* ``dmadesc``. Enough DMA descriptors will be used to fit the buffer of ``len`` bytes in, and the
* descriptors will point to the corresponding positions in ``buffer`` and linked together. The
* end result is that feeding ``dmadesc[0]`` into DMA hardware results in the entirety ``len`` bytes
* of ``data`` being read or written.
* @param host SPI peripheral
*
* @param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ``len`` bytes
* @param len Length of buffer
* @param data Data buffer to use for DMA transfer
* @param isrx True if data is to be written into ``data``, false if it's to be read from ``data``.
* @note This public API is deprecated.
*
* @return false if any pins are through the GPIO matrix, otherwise true.
*/
void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx);
bool spicommon_bus_using_iomux(spi_host_device_t host);
/**
* @brief Get the position of the hardware registers for a specific SPI host
* @brief Check whether all pins used by a host are through IOMUX.
*
* @param host The SPI host
* @param host SPI peripheral
*
* @return A register descriptor stuct pointer, pointed at the hardware registers
* @note This public API is deprecated.
*
* @return false if any pins are through the GPIO matrix, otherwise true.
*/
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
bool spicommon_bus_using_iomux(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI host
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqsource_for_host(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI DMA
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqdma_source_for_host(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI DMA
*
@@ -349,6 +374,8 @@ typedef void(*dmaworkaround_cb_t)(void *arg);
* @param cb Callback to call in case DMA channel cannot be reset immediately
* @param arg Argument to the callback
*
* @note This public API is deprecated.
*
* @return True when a DMA reset could be executed immediately. False when it could not; in this
* case the callback will be called with the specified argument when the logic can execute
* a reset, after that reset.
@@ -359,6 +386,8 @@ bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void
/**
* @brief Check if a DMA reset is requested but has not completed yet
*
* @note This public API is deprecated.
*
* @return True when a DMA reset is requested but hasn't completed yet. False otherwise.
*/
bool spicommon_dmaworkaround_reset_in_progress();
@@ -369,6 +398,8 @@ bool spicommon_dmaworkaround_reset_in_progress();
*
* A call to this function tells the workaround logic that this channel will
* not be affected by a global SPI DMA reset.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_idle(int dmachan);
@@ -377,13 +408,13 @@ void spicommon_dmaworkaround_idle(int dmachan);
*
* A call to this function tells the workaround logic that this channel will
* be affected by a global SPI DMA reset, and a reset like that should not be attempted.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_transfer_active(int dmachan);
/** @endcond */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,9 +1,9 @@
// Copyright 2010-2018 Espressif Systems (Shanghai) PTE LTD
// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
@@ -12,14 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DRIVER_SPI_MASTER_H_
#define _DRIVER_SPI_MASTER_H_
#pragma once
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
//for spi_bus_initialization funcions. to be back-compatible
#include "driver/spi_common.h"
/** SPI master clock is divided by 80MHz apb clock. Below defines are example frequencies, and are accurate. Be free to specify a random frequency, it will be rounded to closest frequency (to macros below if above 8MHz).
@@ -164,47 +161,6 @@ typedef struct {
typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a SPI bus
/**
* @brief Initialize a SPI bus
*
* @warning For now, only supports HSPI and VSPI.
*
* @param host SPI peripheral that controls this bus
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
* @param dma_chan Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel
* for a SPI bus allows transfers on the bus to have sizes only limited by the amount of
* internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of
* bytes transfered to a maximum of 32.
*
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
* DMA-capable memory.
*
* @warning The ISR of SPI is always executed on the core which calls this
* function. Never starve the ISR on this core or the SPI transactions will not
* be handled.
*
* @return
* - ESP_ERR_INVALID_ARG if configuration is invalid
* - ESP_ERR_INVALID_STATE if host already is in use
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan);
/**
* @brief Free a SPI bus
*
* @warning In order for this to succeed, all devices have to be removed first.
*
* @param host SPI peripheral to free
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
* - ESP_OK on success
*/
esp_err_t spi_bus_free(spi_host_device_t host);
/**
* @brief Allocate a device on a SPI bus
*
@@ -439,4 +395,3 @@ int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns);
}
#endif
#endif

View File

@@ -1157,25 +1157,30 @@ esp_err_t touch_pad_filter_start(uint32_t filter_period_ms)
RTC_MODULE_CHECK(filter_period_ms >= portTICK_PERIOD_MS, "Touch pad filter period error", ESP_ERR_INVALID_ARG);
RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE);
esp_err_t ret = ESP_OK;
xSemaphoreTake(rtc_touch_mux, portMAX_DELAY);
if (s_touch_pad_filter == NULL) {
s_touch_pad_filter = (touch_pad_filter_t *) calloc(1, sizeof(touch_pad_filter_t));
if (s_touch_pad_filter == NULL) {
ret = ESP_ERR_NO_MEM;
goto err_no_mem;
}
}
if (s_touch_pad_filter->timer == NULL) {
s_touch_pad_filter->timer = xTimerCreate("filter_tmr", filter_period_ms / portTICK_PERIOD_MS, pdFALSE,
NULL, touch_pad_filter_cb);
if (s_touch_pad_filter->timer == NULL) {
ret = ESP_ERR_NO_MEM;
free(s_touch_pad_filter);
s_touch_pad_filter = NULL;
goto err_no_mem;
}
s_touch_pad_filter->period = filter_period_ms;
}
xSemaphoreGive(rtc_touch_mux);
touch_pad_filter_cb(NULL);
return ret;
return ESP_OK;
err_no_mem:
xSemaphoreGive(rtc_touch_mux);
return ESP_ERR_NO_MEM;
}
esp_err_t touch_pad_filter_stop()

View File

@@ -360,19 +360,39 @@ static inline bool sdio_ringbuf_empty(sdio_ringbuf_t* buf)
}
/**************** End of Ring buffer for SDIO *****************/
static inline void show_ll(buf_desc_t *item)
static inline void show_queue_item(buf_desc_t *item)
{
ESP_EARLY_LOGD(TAG, "=> %p: size: %d(%d), eof: %d, owner: %d", item, item->size, item->length, item->eof, item->owner);
ESP_EARLY_LOGD(TAG, " buf: %p, stqe_next: %p, tqe-prev: %p", item->buf, item->qe.stqe_next, item->te.tqe_prev);
ESP_EARLY_LOGI(TAG, "=> %p: size: %d(%d), eof: %d, owner: %d", item, item->size, item->length, item->eof, item->owner);
ESP_EARLY_LOGI(TAG, " buf: %p, stqe_next: %p, tqe-prev: %p", item->buf, item->qe.stqe_next, item->te.tqe_prev);
}
static void __attribute((unused)) dump_ll(buf_stailq_t *queue)
static void __attribute((unused)) dump_queue(buf_stailq_t *queue)
{
int cnt = 0;
buf_desc_t *item = NULL;
ESP_EARLY_LOGD(TAG, ">>>>> first: %p, last: %p <<<<<", queue->stqh_first, queue->stqh_last);
ESP_EARLY_LOGI(TAG, ">>>>> first: %p, last: %p <<<<<", queue->stqh_first, queue->stqh_last);
STAILQ_FOREACH(item, queue, qe) {
show_ll(item);
cnt++;
show_queue_item(item);
}
ESP_EARLY_LOGI(TAG, "total: %d", cnt);
}
static inline void show_ll(lldesc_t *item)
{
ESP_EARLY_LOGI(TAG, "=> %p: size: %d(%d), eof: %d, owner: %d", item, item->size, item->length, item->eof, item->owner);
ESP_EARLY_LOGI(TAG, " buf: %p, stqe_next: %p", item->buf, item->qe.stqe_next);
}
static void __attribute((unused)) dump_ll(lldesc_t *queue)
{
int cnt = 0;
lldesc_t *item = queue;
while (item != NULL) {
cnt++;
show_ll(item);
item = STAILQ_NEXT(item, qe);
}
ESP_EARLY_LOGI(TAG, "total: %d", cnt);
}
static inline void deinit_context()
@@ -964,7 +984,7 @@ static esp_err_t send_flush_data()
buf_desc_t *last = NULL;
if (context.in_flight) {
buf_desc_t *desc = context.in_flight;
while(desc != NULL) {
while (desc != NULL) {
xQueueSend(context.ret_queue, &desc->arg, portMAX_DELAY);
last = desc;
desc = STAILQ_NEXT(desc, qe);
@@ -975,13 +995,14 @@ static esp_err_t send_flush_data()
context.in_flight_end = NULL;
}
buf_desc_t *head;
esp_err_t ret = sdio_ringbuf_recv(&context.sendbuf, (uint8_t**)&head, NULL, RINGBUF_GET_ALL, 0);
buf_desc_t *head, *tail;
esp_err_t ret = sdio_ringbuf_recv(&context.sendbuf, (uint8_t**)&head, (uint8_t**)&tail, RINGBUF_GET_ALL, 0);
if (ret == ESP_OK) {
buf_desc_t *desc = head;
while(desc != NULL) {
while (1) {
xQueueSend(context.ret_queue, &desc->arg, portMAX_DELAY);
last = desc;
if (desc == tail) break;
desc = STAILQ_NEXT(desc, qe);
}
sdio_ringbuf_return(&context.sendbuf, (uint8_t*)head);
@@ -1162,6 +1183,7 @@ esp_err_t sdio_slave_recv_load_buf(sdio_slave_buf_handle_t handle)
buf_stailq_t *const queue = &context.recv_link_list;
critical_enter_recv();
assert(desc->not_receiving);
TAILQ_REMOVE(&context.recv_reg_list, desc, te);
desc->owner = 1;
desc->not_receiving = 0; //manually remove the prev link (by set not_receiving=0), to indicate this is in the queue
@@ -1253,3 +1275,9 @@ uint8_t* sdio_slave_recv_get_buf(sdio_slave_buf_handle_t handle, size_t *len_o)
if (len_o!= NULL) *len_o= desc->length;
return desc->buf;
}
static void __attribute((unused)) sdio_slave_recv_get_loaded_buffer_num()
{
buf_stailq_t *const queue = &context.recv_link_list;
dump_queue(queue);
}

View File

@@ -26,6 +26,8 @@
#include "sdspi_private.h"
#include "sdspi_crc.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
/// Max number of transactions in flight (used in start_command_write_blocks)

View File

@@ -103,11 +103,6 @@ int spicommon_irqdma_source_for_host(spi_host_device_t host)
return spi_periph_signal[host].irq_dma;
}
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host)
{
return spi_periph_signal[host].hw;
}
static inline uint32_t get_dma_periph(int dma_chan)
{
#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
@@ -137,6 +132,7 @@ bool spicommon_dma_chan_claim (int dma_chan)
spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan);
ret = true;
}
#if CONFIG_IDF_TARGET_ESP32
periph_module_enable(get_dma_periph(dma_chan));
#elif CONFIG_IDF_TARGET_ESP32S2BETA
@@ -393,32 +389,6 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
return ESP_OK;
}
//Find any pin with output muxed to ``func`` and reset it to GPIO
static void reset_func_to_gpio(int func)
{
for (int x = 0; x < GPIO_PIN_COUNT; x++) {
if (GPIO_IS_VALID_GPIO(x) && (READ_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG + (x * 4))&GPIO_FUNC0_OUT_SEL_M) == func) {
gpio_matrix_out(x, SIG_GPIO_OUT_IDX, false, false);
}
}
}
esp_err_t spicommon_bus_free_io(spi_host_device_t host)
{
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spid_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spid_iomux_pin], PIN_FUNC_GPIO);
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiq_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiq_iomux_pin], PIN_FUNC_GPIO);
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiclk_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiclk_iomux_pin], PIN_FUNC_GPIO);
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiwp_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiwp_iomux_pin], PIN_FUNC_GPIO);
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spihd_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spihd_iomux_pin], PIN_FUNC_GPIO);
reset_func_to_gpio(spi_periph_signal[host].spid_out);
reset_func_to_gpio(spi_periph_signal[host].spiq_out);
reset_func_to_gpio(spi_periph_signal[host].spiclk_out);
reset_func_to_gpio(spi_periph_signal[host].spiwp_out);
reset_func_to_gpio(spi_periph_signal[host].spihd_out);
return ESP_OK;
}
esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg)
{
int pin_array[] = {
@@ -459,26 +429,22 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
}
}
void spicommon_cs_free(spi_host_device_t host, int cs_io_num)
{
if (cs_io_num == 0 && REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spics0_iomux_pin], MCU_SEL) == 1) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spics0_iomux_pin], PIN_FUNC_GPIO);
}
reset_func_to_gpio(spi_periph_signal[host].spics_out[cs_io_num]);
}
void spicommon_cs_free_io(int cs_gpio_num)
{
assert(cs_gpio_num>=0 && GPIO_IS_VALID_GPIO(cs_gpio_num));
gpio_reset_pin(cs_gpio_num);
}
//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to.
void IRAM_ATTR spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
bool spicommon_bus_using_iomux(spi_host_device_t host)
{
lldesc_setup_link(dmadesc, data, len, isrx);
}
#define CHECK_IOMUX_PIN(HOST, PIN_NAME) if (GPIO.func_in_sel_cfg[spi_periph_signal[(HOST)].PIN_NAME##_in].sig_in_sel) return false
CHECK_IOMUX_PIN(host, spid);
CHECK_IOMUX_PIN(host, spiq);
CHECK_IOMUX_PIN(host, spiwp);
CHECK_IOMUX_PIN(host, spihd);
return true;
}
/*
Code for workaround for DMA issue in ESP32 v0/v1 silicon
@@ -549,4 +515,4 @@ void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
dmaworkaround_channels_busy[dmachan-1] = 1;
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
#endif
}
}

View File

@@ -314,7 +314,7 @@ cleanup:
free(spihost[host]);
spihost[host] = NULL;
spicommon_periph_free(host);
spicommon_dma_chan_free(dma_chan);
if (dma_chan != 0) spicommon_dma_chan_free(dma_chan);
return ret;
}
@@ -879,7 +879,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de
}
if (send_ptr && isdma && !esp_ptr_dma_capable( send_ptr )) {
//if txbuf in the desc not DMA-capable, malloc a new one
ESP_LOGI( SPI_TAG, "Allocate TX buffer for DMA" );
ESP_LOGD( SPI_TAG, "Allocate TX buffer for DMA" );
uint32_t *temp = heap_caps_malloc((trans_desc->length + 7) / 8, MALLOC_CAP_DMA);
if (temp == NULL) goto clean_up;

View File

@@ -364,12 +364,14 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
}
}
//Disable interrupt before checking to avoid concurrency issue.
esp_intr_disable(host->intr);
//Grab next transaction
r = xQueueReceiveFromISR(host->trans_queue, &trans, &do_yield);
if (!r) {
//No packet waiting. Disable interrupt.
esp_intr_disable(host->intr);
} else {
if (r) {
//enable the interrupt again if there is packet to send
esp_intr_enable(host->intr);
//We have a transaction. Send it.
host->cur_trans = trans;

View File

@@ -1,6 +1,3 @@
set(COMPONENT_SRCDIRS ". param_test")
set(COMPONENT_ADD_INCLUDEDIRS "include param_test/include")
set(COMPONENT_REQUIRES unity test_utils driver nvs_flash)
register_component()
idf_component_register(SRC_DIRS "." "param_test"
INCLUDE_DIRS "include" "param_test/include"
REQUIRES unity test_utils driver nvs_flash)

View File

@@ -616,3 +616,128 @@ TEST_CASE("GPIO drive capability test", "[gpio][ignore]")
drive_capability_set_get(GPIO_OUTPUT_IO, GPIO_DRIVE_CAP_3);
prompt_to_continue("If this test finishes");
}
#if !CONFIG_FREERTOS_UNICORE
void gpio_enable_task(void *param)
{
int gpio_num = (int)param;
TEST_ESP_OK(gpio_intr_enable(gpio_num));
vTaskDelete(NULL);
}
/** Test the GPIO Interrupt Enable API with dual core enabled. The GPIO ISR service routine is registered on one core.
* When the GPIO interrupt on another core is enabled, the GPIO interrupt will be lost.
* First on the core 0, Do the following steps:
* 1. Configure the GPIO18 input_output mode, and enable the rising edge interrupt mode.
* 2. Trigger the GPIO18 interrupt and check if the interrupt responds correctly.
* 3. Disable the GPIO18 interrupt
* Then on the core 1, Do the following steps:
* 1. Enable the GPIO18 interrupt again.
* 2. Trigger the GPIO18 interrupt and check if the interrupt responds correctly.
*
*/
TEST_CASE("GPIO Enable/Disable interrupt on multiple cores", "[gpio][ignore]")
{
const int test_io18 = GPIO_NUM_18;
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
io_conf.pin_bit_mask = (1ULL << test_io18);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 1;
TEST_ESP_OK(gpio_config(&io_conf));
TEST_ESP_OK(gpio_set_level(test_io18, 0));
TEST_ESP_OK(gpio_install_isr_service(0));
TEST_ESP_OK(gpio_isr_handler_add(test_io18, gpio_isr_edge_handler, (void*) test_io18));
vTaskDelay(1000 / portTICK_RATE_MS);
TEST_ESP_OK(gpio_set_level(test_io18, 1));
vTaskDelay(100 / portTICK_RATE_MS);
TEST_ESP_OK(gpio_set_level(test_io18, 0));
vTaskDelay(100 / portTICK_RATE_MS);
TEST_ESP_OK(gpio_intr_disable(test_io18));
TEST_ASSERT(edge_intr_times == 1);
xTaskCreatePinnedToCore(gpio_enable_task, "gpio_enable_task", 1024*4, (void*)test_io18, 8, NULL, (xPortGetCoreID() == 0));
vTaskDelay(1000 / portTICK_RATE_MS);
TEST_ESP_OK(gpio_set_level(test_io18, 1));
vTaskDelay(100 / portTICK_RATE_MS);
TEST_ESP_OK(gpio_set_level(test_io18, 0));
vTaskDelay(100 / portTICK_RATE_MS);
TEST_ESP_OK(gpio_intr_disable(test_io18));
TEST_ESP_OK(gpio_isr_handler_remove(test_io18));
gpio_uninstall_isr_service();
TEST_ASSERT(edge_intr_times == 2);
}
#endif
typedef struct {
int gpio_num;
int isr_cnt;
} gpio_isr_param_t;
static void gpio_isr_handler(void* arg)
{
gpio_isr_param_t *param = (gpio_isr_param_t *)arg;
ets_printf("GPIO[%d] intr, val: %d\n", param->gpio_num, gpio_get_level(param->gpio_num));
param->isr_cnt++;
}
/** The previous GPIO interrupt service routine polls the interrupt raw status register to find the GPIO that triggered the interrupt.
* But this will incorrectly handle the interrupt disabled GPIOs, because the raw interrupt status register can still be set when
* the trigger signal arrives, even if the interrupt is disabled.
* First on the core 0:
* 1. Configure the GPIO18 and GPIO19 input_output mode.
* 2. Enable GPIO18 dual edge triggered interrupt, enable GPIO19 falling edge triggered interrupt.
* 3. Trigger GPIO18 interrupt, than disable the GPIO8 interrupt, and than trigger GPIO18 again(This time will not respond to the interrupt).
* 4. Trigger GPIO19 interrupt.
* If the bug is not fixed, you will see, in the step 4, the interrupt of GPIO18 will also respond.
*/
TEST_CASE("GPIO ISR service test", "[gpio][ignore]")
{
const int test_io18 = GPIO_NUM_18;
const int test_io19 = GPIO_NUM_19;
static gpio_isr_param_t io18_param = {
.gpio_num = GPIO_NUM_18,
.isr_cnt = 0,
};
static gpio_isr_param_t io19_param = {
.gpio_num = GPIO_NUM_19,
.isr_cnt = 0,
};
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
io_conf.pin_bit_mask = (1ULL << test_io18) | (1ULL << test_io19);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 1;
TEST_ESP_OK(gpio_config(&io_conf));
TEST_ESP_OK(gpio_set_level(test_io18, 0));
TEST_ESP_OK(gpio_set_level(test_io19, 0));
TEST_ESP_OK(gpio_install_isr_service(0));
TEST_ESP_OK(gpio_set_intr_type(test_io18, GPIO_INTR_ANYEDGE));
TEST_ESP_OK(gpio_set_intr_type(test_io19, GPIO_INTR_NEGEDGE));
TEST_ESP_OK(gpio_isr_handler_add(test_io18, gpio_isr_handler, (void*)&io18_param));
TEST_ESP_OK(gpio_isr_handler_add(test_io19, gpio_isr_handler, (void*)&io19_param));
printf("Triggering the interrupt of GPIO18\n");
vTaskDelay(1000 / portTICK_RATE_MS);
//Rising edge
TEST_ESP_OK(gpio_set_level(test_io18, 1));
printf("Disable the interrupt of GPIO18");
vTaskDelay(100 / portTICK_RATE_MS);
//Disable GPIO18 interrupt, GPIO18 will not respond to the next falling edge interrupt.
TEST_ESP_OK(gpio_intr_disable(test_io18));
vTaskDelay(100 / portTICK_RATE_MS);
//Falling edge
TEST_ESP_OK(gpio_set_level(test_io18, 0));
printf("Triggering the interrupt of GPIO19\n");
vTaskDelay(100 / portTICK_RATE_MS);
TEST_ESP_OK(gpio_set_level(test_io19, 1));
vTaskDelay(100 / portTICK_RATE_MS);
//Falling edge
TEST_ESP_OK(gpio_set_level(test_io19, 0));
vTaskDelay(100 / portTICK_RATE_MS);
TEST_ESP_OK(gpio_isr_handler_remove(test_io18));
TEST_ESP_OK(gpio_isr_handler_remove(test_io19));
gpio_uninstall_isr_service();
TEST_ASSERT((io18_param.isr_cnt == 1) && (io19_param.isr_cnt == 1));
}

View File

@@ -9,6 +9,7 @@
#include "freertos/task.h"
#include "driver/i2s.h"
#include "unity.h"
#include "math.h"
#define SAMPLE_RATE (36000)
#define SAMPLE_BITS (16)
@@ -18,6 +19,7 @@
#define SLAVE_WS_IO 26
#define DATA_IN_IO 21
#define DATA_OUT_IO 22
#define PERCENT_DIFF 0.0001
/**
* i2s initialize test
@@ -267,3 +269,54 @@ TEST_CASE("I2S memory leaking test", "[i2s]")
vTaskDelay(100 / portTICK_PERIOD_MS);
TEST_ASSERT(initial_size == esp_get_free_heap_size());
}
/*
* The I2S APLL clock variation test used to test the difference between the different sample rates, different bits per sample
* and the APLL clock generate for it. The TEST_CASE passes PERCENT_DIFF variation from the provided sample rate in APLL generated clock
* The percentage difference calculated as (mod((obtained clock rate - desired clock rate)/(desired clock rate))) * 100.
*/
TEST_CASE("I2S APLL clock variation test", "[i2s]")
{
i2s_pin_config_t pin_config = {
.bck_io_num = MASTER_BCK_IO,
.ws_io_num = MASTER_WS_IO,
.data_out_num = DATA_OUT_IO,
.data_in_num = -1
};
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S,
.dma_buf_count = 6,
.dma_buf_len = 60,
.use_apll = true,
.intr_alloc_flags = 0,
};
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config));
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
int initial_size = esp_get_free_heap_size();
uint32_t sample_rate_arr[8] = { 10675, 11025, 16000, 22050, 32000, 44100, 48000, 96000 };
int bits_per_sample_arr[3] = { 16, 24, 32 };
for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) {
for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) {
i2s_config.sample_rate = sample_rate_arr[i];
i2s_config.bits_per_sample = bits_per_sample_arr[j];
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config));
TEST_ASSERT((fabs((i2s_get_clk(I2S_NUM_0) - sample_rate_arr[i]))/(sample_rate_arr[i]))*100 < PERCENT_DIFF);
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
TEST_ASSERT(initial_size == esp_get_free_heap_size());
}
}
vTaskDelay(100 / portTICK_PERIOD_MS);
TEST_ASSERT(initial_size == esp_get_free_heap_size());
}

View File

@@ -36,6 +36,8 @@
#define UART_NUM SOC_UART_NUM
#define UART_NUM SOC_UART_NUM
#define XOFF (char)0x13
#define XON (char)0x11
@@ -596,19 +598,19 @@ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void *), void *arg,
int ret;
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
switch (uart_num) {
case UART_NUM_1:
ret = esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
switch(uart_num) {
case UART_NUM_1:
ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
#if UART_NUM > 2
case UART_NUM_2:
ret = esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
case UART_NUM_2:
ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
#endif
case UART_NUM_0:
default:
ret = esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
case UART_NUM_0:
default:
ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
break;
}
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
return ret;
@@ -640,34 +642,34 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r
UART_CHECK((cts_io_num < 0 || (GPIO_IS_VALID_GPIO(cts_io_num))), "cts_io_num error", ESP_FAIL);
int tx_sig, rx_sig, rts_sig, cts_sig;
switch (uart_num) {
case UART_NUM_0:
tx_sig = U0TXD_OUT_IDX;
rx_sig = U0RXD_IN_IDX;
rts_sig = U0RTS_OUT_IDX;
cts_sig = U0CTS_IN_IDX;
break;
case UART_NUM_1:
tx_sig = U1TXD_OUT_IDX;
rx_sig = U1RXD_IN_IDX;
rts_sig = U1RTS_OUT_IDX;
cts_sig = U1CTS_IN_IDX;
break;
switch(uart_num) {
case UART_NUM_0:
tx_sig = U0TXD_OUT_IDX;
rx_sig = U0RXD_IN_IDX;
rts_sig = U0RTS_OUT_IDX;
cts_sig = U0CTS_IN_IDX;
break;
case UART_NUM_1:
tx_sig = U1TXD_OUT_IDX;
rx_sig = U1RXD_IN_IDX;
rts_sig = U1RTS_OUT_IDX;
cts_sig = U1CTS_IN_IDX;
break;
#if UART_NUM > 2
case UART_NUM_2:
tx_sig = U2TXD_OUT_IDX;
rx_sig = U2RXD_IN_IDX;
rts_sig = U2RTS_OUT_IDX;
cts_sig = U2CTS_IN_IDX;
break;
case UART_NUM_2:
tx_sig = U2TXD_OUT_IDX;
rx_sig = U2RXD_IN_IDX;
rts_sig = U2RTS_OUT_IDX;
cts_sig = U2CTS_IN_IDX;
break;
#endif
case UART_NUM_MAX:
default:
tx_sig = U0TXD_OUT_IDX;
rx_sig = U0RXD_IN_IDX;
rts_sig = U0RTS_OUT_IDX;
cts_sig = U0CTS_IN_IDX;
break;
case UART_NUM_MAX:
default:
tx_sig = U0TXD_OUT_IDX;
rx_sig = U0RXD_IN_IDX;
rts_sig = U0RTS_OUT_IDX;
cts_sig = U0CTS_IN_IDX;
break;
}
if (tx_io_num >= 0) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO);
@@ -735,7 +737,7 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf
} else if (uart_num == UART_NUM_1) {
periph_module_enable(PERIPH_UART1_MODULE);
#if UART_NUM > 2
} else if (uart_num == UART_NUM_2) {
} else if(uart_num == UART_NUM_2) {
periph_module_enable(PERIPH_UART2_MODULE);
#endif
}
@@ -775,10 +777,10 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
#if CONFIG_IDF_TARGET_ESP32
//Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times.
//T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH)
if (UART[uart_num]->conf0.tick_ref_always_on == 0) {
UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT) & UART_RX_TOUT_THRHD_V);
if(UART[uart_num]->conf0.tick_ref_always_on == 0) {
UART[uart_num]->conf1.rx_tout_thrhd = (intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT);
} else {
UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);
UART[uart_num]->conf1.rx_tout_thrhd = intr_conf->rx_timeout_thresh;
}
#elif CONFIG_IDF_TARGET_ESP32S2BETA
UART[uart_num]->mem_conf.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);
@@ -822,14 +824,19 @@ static void uart_rx_intr_handler_default(void *param)
uart_obj_t *p_uart = (uart_obj_t *) param;
uint8_t uart_num = p_uart->uart_num;
uart_dev_t *uart_reg = UART[uart_num];
int rx_fifo_len = uart_reg->status.rxfifo_cnt;
int rx_fifo_len = 0;
uint8_t buf_idx = 0;
uint32_t uart_intr_status = UART[uart_num]->int_st.val;
uint32_t uart_intr_status = 0;
uart_event_t uart_event;
portBASE_TYPE HPTaskAwoken = 0;
static uint8_t pat_flg = 0;
while (uart_intr_status != 0x0) {
buf_idx = 0;
while(1) {
uart_intr_status = uart_reg->int_st.val;
// The `continue statement` may cause the interrupt to loop infinitely
// we exit the interrupt here
if(uart_intr_status == 0) {
break;
}
uart_event.type = UART_EVENT_MAX;
if (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) {
uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M);
@@ -841,15 +848,12 @@ static void uart_rx_intr_handler_default(void *param)
if (p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) {
p_uart->tx_waiting_fifo = false;
xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
} else {
//We don't use TX ring buffer, because the size is zero.
if (p_uart->tx_buf_size == 0) {
continue;
}
int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt;
int tx_fifo_rem = UART_FIFO_LEN - uart_reg->status.txfifo_cnt;
bool en_tx_flg = false;
//We need to put a loop here, in case all the buffer items are very short.
//That would cause a watch_dog reset because empty interrupt happens so often.
@@ -870,10 +874,7 @@ static void uart_rx_intr_handler_default(void *param)
}
//We have saved the data description from the 1st item, return buffer.
vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
} else if (p_uart->tx_ptr == NULL) {
}else if(p_uart->tx_ptr == NULL) {
//Update the TX item pointer, we will need this to return item to buffer.
p_uart->tx_ptr = (uint8_t *) p_uart->tx_head;
en_tx_flg = true;
@@ -904,9 +905,6 @@ static void uart_rx_intr_handler_default(void *param)
if (p_uart->tx_len_cur == 0) {
//Return item to ring buffer.
vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
p_uart->tx_head = NULL;
p_uart->tx_ptr = NULL;
//Sending item done, now we need to send break if there is a record.
@@ -948,12 +946,8 @@ static void uart_rx_intr_handler_default(void *param)
}
if (p_uart->rx_buffer_full_flg == false) {
//We have to read out all data in RX FIFO to clear the interrupt signal
while (buf_idx < rx_fifo_len) {
#if CONFIG_IDF_TARGET_ESP32
p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte;
#elif CONFIG_IDF_TARGET_ESP32S2BETA
p_uart->rx_data_buf[buf_idx++] = READ_PERI_REG(UART_FIFO_AHB_REG(uart_num));
#endif
for(buf_idx = 0; buf_idx < rx_fifo_len; buf_idx++) {
p_uart->rx_data_buf[buf_idx] = uart_reg->fifo.rw_byte;
}
uint8_t pat_chr = uart_reg->at_cmd_char.data;
int pat_num = uart_reg->at_cmd_char.char_num;
@@ -1013,9 +1007,6 @@ static void uart_rx_intr_handler_default(void *param)
p_uart->rx_buffered_len += p_uart->rx_stash_len;
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
}
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
} else {
uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M);
uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M);
@@ -1071,9 +1062,6 @@ static void uart_rx_intr_handler_default(void *param)
p_uart->tx_waiting_brk = 0;
} else {
xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
} else if (uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) {
uart_disable_intr_mask_from_isr(uart_num, UART_TX_BRK_IDLE_DONE_INT_ENA_M);
@@ -1104,9 +1092,6 @@ static void uart_rx_intr_handler_default(void *param)
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
}
xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
} else {
uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/
uart_event.type = UART_EVENT_MAX;
@@ -1116,11 +1101,10 @@ static void uart_rx_intr_handler_default(void *param)
if (pdFALSE == xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken)) {
ESP_EARLY_LOGV(UART_TAG, "UART event queue full");
}
if (HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
uart_intr_status = uart_reg->int_st.val;
}
if(HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
@@ -1137,7 +1121,9 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait)
return ESP_ERR_TIMEOUT;
}
xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, 0);
if (UART[uart_num]->status.txfifo_cnt == 0) {
typeof(UART0.status) status = UART[uart_num]->status;
//Wait txfifo_cnt = 0, and the transmitter state machine is in idle state.
if(status.txfifo_cnt == 0 && status.st_utx_out == 0) {
xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
return ESP_OK;
}
@@ -1552,15 +1538,15 @@ esp_err_t uart_driver_delete(uart_port_t uart_num)
p_uart_obj[uart_num] = NULL;
if (uart_num != CONFIG_ESP_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);
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);
#if UART_NUM > 2
} else if (uart_num == UART_NUM_2) {
periph_module_disable(PERIPH_UART2_MODULE);
} else if(uart_num == UART_NUM_2) {
periph_module_disable(PERIPH_UART2_MODULE);
#endif
}
}
}
return ESP_OK;
}
@@ -1646,6 +1632,8 @@ esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh)
// transmission time of one symbol (~11 bit) on current baudrate
if (tout_thresh > 0) {
#if CONFIG_IDF_TARGET_ESP32
//ESP32 hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times.
//T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH)
if (UART[uart_num]->conf0.tick_ref_always_on == 0) {
UART[uart_num]->conf1.rx_tout_thrhd = ((tout_thresh * UART_TOUT_REF_FACTOR_DEFAULT) & UART_RX_TOUT_THRHD_V);
} else {