Merge branch 'feature/fast_gpio_c3' into 'master'

fast gpio support on esp32-c3

Closes IDF-3783

See merge request espressif/esp-idf!14986
This commit is contained in:
morris 2021-09-14 06:09:34 +00:00
commit 502e132e5d
14 changed files with 206 additions and 30 deletions

View File

@ -67,6 +67,7 @@ if(IDF_TARGET STREQUAL "esp32c3")
list(APPEND srcs "gdma.c"
"spi_slave_hd.c"
"adc_common.c"
"dedic_gpio.c"
"usb_serial_jtag.c"
"esp32c3/adc.c"
"esp32c3/adc2_init_cal.c"
@ -77,6 +78,7 @@ if(IDF_TARGET STREQUAL "esp32h2")
list(APPEND srcs "gdma.c"
"spi_slave_hd.c"
"adc_common.c"
"dedic_gpio.c"
"esp32h2/adc.c"
"esp32h2/adc2_init_cal.c"
"esp32h2/rtc_tempsensor.c")

View File

@ -63,8 +63,8 @@ struct dedic_gpio_bundle_t {
uint32_t in_mask; // mask of input channels in the bank
uint32_t out_offset; // offset in the bank (seen from output channel)
uint32_t in_offset; // offset in the bank (seen from input channel)
size_t nr_gpio; // number of GPIOs in the gpio_array
int gpio_array[]; // array of GPIO numbers (configured by user)
size_t nr_gpio; // number of GPIOs in the gpio_array
int gpio_array[]; // array of GPIO numbers (configured by user)
};
static esp_err_t dedic_gpio_build_platform(uint32_t core_id)
@ -80,8 +80,10 @@ static esp_err_t dedic_gpio_build_platform(uint32_t core_id)
s_platform[core_id]->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
#if SOC_DEDIC_GPIO_ALLOW_REG_ACCESS
s_platform[core_id]->dev = &DEDIC_GPIO;
#endif
#endif // SOC_DEDIC_GPIO_ALLOW_REG_ACCESS
#if !SOC_DEDIC_PERIPH_AUTO_ENABLE
periph_module_enable(dedic_gpio_periph_signals.module); // enable APB clock to peripheral
#endif // !SOC_DEDIC_PERIPH_AUTO_ENABLE
}
}
_lock_release(&s_platform_mutexlock[core_id]);
@ -102,7 +104,9 @@ static void dedic_gpio_break_platform(uint32_t core_id)
if (s_platform[core_id]) {
free(s_platform[core_id]);
s_platform[core_id] = NULL;
#if !SOC_DEDIC_PERIPH_AUTO_ENABLE
periph_module_disable(dedic_gpio_periph_signals.module); // disable module if no GPIO channel is being used
#endif // !SOC_DEDIC_PERIPH_AUTO_ENABLE
}
_lock_release(&s_platform_mutexlock[core_id]);
}
@ -263,6 +267,9 @@ esp_err_t dedic_gpio_new_bundle(const dedic_gpio_bundle_config_t *config, dedic_
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->gpio_array[i]], PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(config->gpio_array[i], dedic_gpio_periph_signals.cores[core_id].out_sig_per_channel[out_offset + i], config->flags.out_invert, false);
}
#if !SOC_DEDIC_GPIO_OUT_AUTO_ENABLE
cpu_ll_enable_dedic_gpio_output(s_platform[core_id]->out_occupied_mask);
#endif // !SOC_DEDIC_GPIO_OUT_AUTO_ENABLE
}
// it's safe to initialize bundle members without locks here
@ -340,14 +347,14 @@ err:
void dedic_gpio_bundle_write(dedic_gpio_bundle_handle_t bundle, uint32_t mask, uint32_t value)
{
// For performace reasons, we don't want to check the validation of parameters here
// For performance reasons, we don't want to check the validation of parameters here
// Even didn't check if we're working on the correct CPU core (i.e. bundle->core_id == current core_id)
cpu_ll_write_dedic_gpio_mask(bundle->out_mask & (mask << bundle->out_offset), value << bundle->out_offset);
}
uint32_t dedic_gpio_bundle_read_out(dedic_gpio_bundle_handle_t bundle)
{
// For performace reasons, we don't want to check the validation of parameters here
// For performance reasons, we don't want to check the validation of parameters here
// Even didn't check if we're working on the correct CPU core (i.e. bundle->core_id == current core_id)
uint32_t value = cpu_ll_read_dedic_gpio_out();
return (value & bundle->out_mask) >> (bundle->out_offset);
@ -355,7 +362,7 @@ uint32_t dedic_gpio_bundle_read_out(dedic_gpio_bundle_handle_t bundle)
uint32_t dedic_gpio_bundle_read_in(dedic_gpio_bundle_handle_t bundle)
{
// For performace reasons, we don't want to check the validation of parameters here
// For performance reasons, we don't want to check the validation of parameters here
// Even didn't check if we're working on the correct CPU core (i.e. bundle->core_id == current core_id)
uint32_t value = cpu_ll_read_dedic_gpio_in();
return (value & bundle->in_mask) >> (bundle->in_offset);

View File

@ -28,6 +28,11 @@
#define CSR_PCMR_MACHINE 0x7e1
#define CSR_PCCR_MACHINE 0x7e2
/*fast gpio*/
#define CSR_GPIO_OEN_USER 0x803
#define CSR_GPIO_IN_USER 0x804
#define CSR_GPIO_OUT_USER 0x805
#ifdef __cplusplus
extern "C" {
#endif
@ -163,6 +168,34 @@ static inline void cpu_ll_waiti(void)
asm volatile ("wfi\n");
}
static inline void cpu_ll_enable_dedic_gpio_output(uint32_t mask)
{
RV_WRITE_CSR(CSR_GPIO_OEN_USER, mask);
}
static inline void cpu_ll_write_dedic_gpio_all(uint32_t value)
{
RV_WRITE_CSR(CSR_GPIO_OUT_USER, value);
}
static inline uint32_t cpu_ll_read_dedic_gpio_in(void)
{
uint32_t value = RV_READ_CSR(CSR_GPIO_IN_USER);
return value;
}
static inline uint32_t cpu_ll_read_dedic_gpio_out(void)
{
uint32_t value = RV_READ_CSR(CSR_GPIO_OUT_USER);
return value;
}
static inline void cpu_ll_write_dedic_gpio_mask(uint32_t mask, uint32_t value)
{
RV_SET_CSR(CSR_GPIO_OUT_USER, mask & value);
RV_CLEAR_CSR(CSR_GPIO_OUT_USER, mask & ~(value));
}
#ifdef __cplusplus
}
#endif

View File

@ -26,6 +26,11 @@
#define CSR_PCMR_MACHINE 0x7e1
#define CSR_PCCR_MACHINE 0x7e2
/*fast gpio*/
#define CSR_GPIO_OEN_USER 0x803
#define CSR_GPIO_IN_USER 0x804
#define CSR_GPIO_OUT_USER 0x805
#ifdef __cplusplus
extern "C" {
#endif
@ -156,6 +161,34 @@ static inline void cpu_ll_waiti(void)
asm volatile ("wfi\n");
}
static inline void cpu_ll_enable_dedic_gpio_output(uint32_t mask)
{
RV_WRITE_CSR(CSR_GPIO_OEN_USER, mask);
}
static inline void cpu_ll_write_dedic_gpio_all(uint32_t value)
{
RV_WRITE_CSR(CSR_GPIO_OUT_USER, value);
}
static inline uint32_t cpu_ll_read_dedic_gpio_in(void)
{
uint32_t value = RV_READ_CSR(CSR_GPIO_IN_USER);
return value;
}
static inline uint32_t cpu_ll_read_dedic_gpio_out(void)
{
uint32_t value = RV_READ_CSR(CSR_GPIO_OUT_USER);
return value;
}
static inline void cpu_ll_write_dedic_gpio_mask(uint32_t mask, uint32_t value)
{
RV_SET_CSR(CSR_GPIO_OUT_USER, mask & value);
RV_CLEAR_CSR(CSR_GPIO_OUT_USER, mask & ~(value));
}
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,6 @@
set(srcs
"adc_periph.c"
"dedic_gpio_periph.c"
"gdma_periph.c"
"gpio_periph.c"
"interrupts.c"

View File

@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/gpio_sig_map.h"
#include "soc/dedic_gpio_periph.h"
const dedic_gpio_signal_conn_t dedic_gpio_periph_signals = {
.module = -1,
.irq = -1,
.cores = {
[0] = {
.in_sig_per_channel = {
[0] = CPU_GPIO_IN0_IDX,
[1] = CPU_GPIO_IN1_IDX,
[2] = CPU_GPIO_IN2_IDX,
[3] = CPU_GPIO_IN3_IDX,
[4] = CPU_GPIO_IN4_IDX,
[5] = CPU_GPIO_IN5_IDX,
[6] = CPU_GPIO_IN6_IDX,
[7] = CPU_GPIO_IN7_IDX,
},
.out_sig_per_channel = {
[0] = CPU_GPIO_OUT0_IDX,
[1] = CPU_GPIO_OUT1_IDX,
[2] = CPU_GPIO_OUT2_IDX,
[3] = CPU_GPIO_OUT3_IDX,
[4] = CPU_GPIO_OUT4_IDX,
[5] = CPU_GPIO_OUT5_IDX,
[6] = CPU_GPIO_OUT6_IDX,
[7] = CPU_GPIO_OUT7_IDX,
}
},
},
};

View File

@ -53,26 +53,26 @@
#define GPIO_WLAN_PRIO_IDX 18
#define GPIO_BT_ACTIVE_IDX 19
#define GPIO_WLAN_ACTIVE_IDX 19
#define BB_DIAG0_IDX 20
#define BB_DIAG1_IDX 21
#define BB_DIAG2_IDX 22
#define BB_DIAG3_IDX 23
#define BB_DIAG4_IDX 24
#define BB_DIAG5_IDX 25
#define BB_DIAG6_IDX 26
#define BB_DIAG7_IDX 27
#define BB_DIAG8_IDX 28
#define BB_DIAG9_IDX 29
#define BB_DIAG10_IDX 30
#define BB_DIAG11_IDX 31
#define BB_DIAG12_IDX 32
#define BB_DIAG13_IDX 33
#define BB_DIAG14_IDX 34
#define BB_DIAG15_IDX 35
#define BB_DIAG16_IDX 36
#define BB_DIAG17_IDX 37
#define BB_DIAG18_IDX 38
#define BB_DIAG19_IDX 39
#define CPU_GPIO_IN0_IDX 28
#define CPU_GPIO_OUT0_IDX 28
#define CPU_GPIO_IN1_IDX 29
#define CPU_GPIO_OUT1_IDX 29
#define CPU_GPIO_IN2_IDX 30
#define CPU_GPIO_OUT2_IDX 30
#define CPU_GPIO_IN3_IDX 31
#define CPU_GPIO_OUT3_IDX 31
#define CPU_GPIO_IN4_IDX 32
#define CPU_GPIO_OUT4_IDX 32
#define CPU_GPIO_IN5_IDX 33
#define CPU_GPIO_OUT5_IDX 33
#define CPU_GPIO_IN6_IDX 34
#define CPU_GPIO_OUT6_IDX 34
#define CPU_GPIO_IN7_IDX 35
#define CPU_GPIO_OUT7_IDX 35
#define USB_JTAG_TCK_OUT_IDX 36
#define USB_JTAG_TMS_OUT_IDX 37
#define USB_JTAG_TDI_OUT_IDX 38
#define USB_JTAG_TDO_OUT_IDX 39
#define USB_EXTPHY_VP_IDX 40
#define USB_EXTPHY_OEN_IDX 40
#define USB_EXTPHY_VM_IDX 41
@ -179,6 +179,7 @@
#define CLK_OUT_OUT2_IDX 124
#define CLK_OUT_OUT3_IDX 125
#define SPICS1_OUT_IDX 126
#define USB_JTAG_TRST_OUT_IDX 127
#define SIG_GPIO_OUT_IDX 128
#define GPIO_MAP_DATE_IDX 0x2006130
#endif /* _SOC_GPIO_SIG_MAP_H_ */

View File

@ -6,6 +6,7 @@
#pragma once
#define SOC_CPU_CORES_NUM 1
#define SOC_DEDICATED_GPIO_SUPPORTED 1
#define SOC_GDMA_SUPPORTED 1
#define SOC_TWAI_SUPPORTED 1
#define SOC_BT_SUPPORTED 1
@ -97,6 +98,11 @@
// Support to configure sleep status
#define SOC_GPIO_SUPPORT_SLP_SWITCH (1)
/*-------------------------- Dedicated GPIO CAPS -----------------------------*/
#define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */
#define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */
#define SOC_DEDIC_PERIPH_AUTO_ENABLE (1) /*!< The dedicated GPIO peripheral is enabled automatically */
/*-------------------------- I2C CAPS ----------------------------------------*/
// ESP32-C3 have 2 I2C.
#define SOC_I2C_NUM (1)

View File

@ -1,5 +1,6 @@
set(srcs
"adc_periph.c"
"dedic_gpio_periph.c"
"gdma_periph.c"
"gpio_periph.c"
"interrupts.c"

View File

@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/gpio_sig_map.h"
#include "soc/dedic_gpio_periph.h"
const dedic_gpio_signal_conn_t dedic_gpio_periph_signals = {
.module = -1,
.irq = -1,
.cores = {
[0] = {
.in_sig_per_channel = {
[0] = CPU_GPIO_IN0_IDX,
[1] = CPU_GPIO_IN1_IDX,
[2] = CPU_GPIO_IN2_IDX,
[3] = CPU_GPIO_IN3_IDX,
[4] = CPU_GPIO_IN4_IDX,
[5] = CPU_GPIO_IN5_IDX,
[6] = CPU_GPIO_IN6_IDX,
[7] = CPU_GPIO_IN7_IDX,
},
.out_sig_per_channel = {
[0] = CPU_GPIO_OUT0_IDX,
[1] = CPU_GPIO_OUT1_IDX,
[2] = CPU_GPIO_OUT2_IDX,
[3] = CPU_GPIO_OUT3_IDX,
[4] = CPU_GPIO_OUT4_IDX,
[5] = CPU_GPIO_OUT5_IDX,
[6] = CPU_GPIO_OUT6_IDX,
[7] = CPU_GPIO_OUT7_IDX,
}
},
},
};

View File

@ -6,6 +6,7 @@
#pragma once
#define SOC_CPU_CORES_NUM 1
#define SOC_DEDICATED_GPIO_SUPPORTED 1
#define SOC_GDMA_SUPPORTED 1
#define SOC_TWAI_SUPPORTED 1
#define SOC_BT_SUPPORTED 1
@ -92,6 +93,11 @@
// Support to configure sleep status
#define SOC_GPIO_SUPPORT_SLP_SWITCH (1)
/*-------------------------- Dedicated GPIO CAPS -----------------------------*/
#define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */
#define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */
#define SOC_DEDIC_PERIPH_AUTO_ENABLE (1) /*!< The dedicated GPIO peripheral is enabled automatically */
/*-------------------------- I2C CAPS ----------------------------------------*/
// ESP32-C3 have 2 I2C.
#define SOC_I2C_NUM (1)

View File

@ -120,6 +120,7 @@
#define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */
#define SOC_DEDIC_GPIO_ALLOW_REG_ACCESS (1) /*!< Allow access dedicated GPIO channel by register */
#define SOC_DEDIC_GPIO_HAS_INTERRUPT (1) /*!< Dedicated GPIO has its own interrupt source */
#define SOC_DEDIC_GPIO_OUT_AUTO_ENABLE (1) /*!< Dedicated GPIO output attribution is enabled automatically */
/*-------------------------- I2C CAPS ----------------------------------------*/
// ESP32-S2 have 2 I2C.

View File

@ -75,6 +75,7 @@
/*-------------------------- Dedicated GPIO CAPS -----------------------------*/
#define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */
#define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */
#define SOC_DEDIC_GPIO_OUT_AUTO_ENABLE (1) /*!< Dedicated GPIO output attribution is enabled automatically */
/*-------------------------- I2C CAPS ----------------------------------------*/
#include "i2c_caps.h"

View File

@ -4,7 +4,7 @@ Dedicated GPIO
Overview
--------
The dedicated GPIO is designed for CPU interaction with GPIO matrix and IO MUX. Any GPIO that is configured as "dedicated" can be access by CPU instructions directly, which makes it easy to achieve a high GPIO flip speed, and simulate serial/parallel interface in a bit-banging way.
The dedicated GPIO is designed for CPU interaction with GPIO matrix and IO MUX. Any GPIO that is configured as "dedicated" can be access by CPU instructions directly, which makes it easy to achieve a high GPIO flip speed, and simulate serial/parallel interface in a bit-banging way. As toggling a GPIO in this "CPU Dedicated" way costs few overhead, it would be great for cases like performance measurement using an oscilloscope.
Create/Destroy GPIO Bundle
@ -75,7 +75,7 @@ GPIO Bundle Operations
.. note::
The functions above just wrap the customized instructions defined for {IDF_TARGET_NAME}, for the details of those instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__].
.. only:: esp32s2
.. only:: SOC_DEDIC_GPIO_HAS_INTERRUPT
Interrupt Handling
------------------
@ -112,11 +112,21 @@ For advanced users, they can always manipulate the GPIOs by writing assembly cod
1. Allocate a GPIO bundle: :cpp:func:`dedic_gpio_new_bundle`
2. Query the mask occupied by that bundle: :cpp:func:`dedic_gpio_get_out_mask` or/and :cpp:func:`dedic_gpio_get_in_mask`
3. Call CPU LL apis (e.g. `cpu_ll_write_dedic_gpio_mask`) or write assembly code with that mask
4. The fasted way of toggling IO is to use the dedicated "set/clear" instructions:
For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__].
+----------+---------------------------+---------------------------+------------------------------------------------------------------------+
| CPU Arch | Set bits of GPIO | Clear bits of GPIO | Remarks |
+==========+===========================+===========================+========================================================================+
| Xtensa | set_bit_gpio_out imm[7:0] | clr_bit_gpio_out imm[7:0] | immediate value width depends on the number of dedicated GPIO channels |
+----------+---------------------------+---------------------------+------------------------------------------------------------------------+
| RISC-V | csrrsi rd, csr, imm[4:0] | csrrci rd, csr, imm[4:0] | can only control the lowest 4 GPIO channels |
+----------+---------------------------+---------------------------+------------------------------------------------------------------------+
For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__]. The supported dedicated CPU instructions are also wrapped inside `soc/cpu_ll.h` as helper inline functions.
.. note::
Writing assembly code in application could make your code hard to port between targets, because those customized instructions are not guaranteed to remain the same format in different targets.
Writing assembly code in application could make your code hard to port between targets, because those customized instructions are not guaranteed to remain the same format on different targets.
Application Example