mirror of
https://github.com/espressif/esp-idf.git
synced 2025-11-03 00:21:44 +01:00
Merge branch 'master' into feature/esp32s2beta_update
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user