mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-20 18:01:44 +00:00
feat(driver_spi): support gpio reserved check
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_private/gpio.h"
|
||||
#include "esp_private/esp_gpio_reserve.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/spi_common_internal.h"
|
||||
#include "esp_private/spi_share_hw_ctrl.h"
|
||||
@@ -24,7 +25,6 @@
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#include "esp_dma_utils.h"
|
||||
#include "hal/spi_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "soc/dport_reg.h"
|
||||
#endif
|
||||
@@ -41,9 +41,9 @@
|
||||
#define SPI_COMMON_MALLOC_CAPS (MALLOC_CAP_DEFAULT)
|
||||
#endif
|
||||
|
||||
static const char *SPI_TAG = "spi";
|
||||
static const char *SPI_TAG = "spi_common";
|
||||
|
||||
#define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE(a, ret_val, SPI_TAG, str)
|
||||
#define SPI_CHECK(a, str, ret_val, ...) ESP_RETURN_ON_FALSE(a, ret_val, SPI_TAG, str, ##__VA_ARGS__)
|
||||
#define SPI_CHECK_PIN(pin_num, pin_name, check_output) if (check_output) { \
|
||||
SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(pin_num), pin_name" not valid", ESP_ERR_INVALID_ARG); \
|
||||
} else { \
|
||||
@@ -56,8 +56,6 @@ static const char *SPI_TAG = "spi";
|
||||
}, \
|
||||
}
|
||||
|
||||
#define FUNC_GPIO PIN_FUNC_GPIO
|
||||
|
||||
typedef struct {
|
||||
int host_id;
|
||||
_lock_t mutex; // mutex for controller
|
||||
@@ -80,6 +78,29 @@ static __attribute__((constructor)) void spi_bus_lock_init_main_bus(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t spicommon_bus_alloc(spi_host_device_t host_id, const char *name)
|
||||
{
|
||||
SPI_CHECK(spicommon_periph_claim(host_id, name), "host already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
spicommon_bus_context_t *ctx = heap_caps_calloc(1, sizeof(spicommon_bus_context_t), SPI_COMMON_MALLOC_CAPS);
|
||||
if (!ctx) {
|
||||
spicommon_periph_free(host_id);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
ctx->host_id = host_id;
|
||||
bus_ctx[host_id] = ctx;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spicommon_bus_free(spi_host_device_t host_id)
|
||||
{
|
||||
assert(bus_ctx[host_id]);
|
||||
spicommon_periph_free(host_id);
|
||||
free(bus_ctx[host_id]);
|
||||
bus_ctx[host_id] = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
//NOTE!! If both A and B are not defined, '#if (A==B)' is true, because GCC use 0 stand for undefined symbol
|
||||
#if defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI)
|
||||
@@ -454,8 +475,8 @@ static void bus_iomux_pins_set_oct(spi_host_device_t host, const spi_bus_config_
|
||||
bus_config->sclk_io_num, bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num
|
||||
};
|
||||
int io_signals[] = {spi_periph_signal[host].spid_in, spi_periph_signal[host].spiq_in, spi_periph_signal[host].spiwp_in,
|
||||
spi_periph_signal[host].spihd_in, spi_periph_signal[host].spiclk_in, spi_periph_signal[host].spid4_out,
|
||||
spi_periph_signal[host].spid5_out, spi_periph_signal[host].spid6_out, spi_periph_signal[host].spid7_out
|
||||
spi_periph_signal[host].spihd_in, spi_periph_signal[host].spiclk_in, spi_periph_signal[host].spid4_in,
|
||||
spi_periph_signal[host].spid5_in, spi_periph_signal[host].spid6_in, spi_periph_signal[host].spid7_in
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(io_nums) / sizeof(io_nums[0]); i++) {
|
||||
if (io_nums[i] > 0) {
|
||||
@@ -491,15 +512,28 @@ static void bus_iomux_pins_set_quad(spi_host_device_t host, const spi_bus_config
|
||||
}
|
||||
}
|
||||
|
||||
static void bus_iomux_pins_set(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
// check if the GPIO is already used by others
|
||||
static void s_spi_common_gpio_check_reserve(gpio_num_t gpio_num)
|
||||
{
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if ((bus_config->flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
|
||||
bus_iomux_pins_set_oct(host, bus_config);
|
||||
return;
|
||||
uint64_t orig_occupied_map = esp_gpio_reserve(BIT64(gpio_num));
|
||||
if (orig_occupied_map & BIT64(gpio_num)) {
|
||||
ESP_LOGW(SPI_TAG, "GPIO %d is conflict with others and be overwritten", gpio_num);
|
||||
}
|
||||
#endif
|
||||
bus_iomux_pins_set_quad(host, bus_config);
|
||||
}
|
||||
|
||||
static void s_spi_common_bus_via_gpio(gpio_num_t gpio_num, int in_sig, int out_sig, uint64_t *io_mask)
|
||||
{
|
||||
if (in_sig != -1) {
|
||||
gpio_input_enable(gpio_num);
|
||||
esp_rom_gpio_connect_in_signal(gpio_num, in_sig, false);
|
||||
}
|
||||
if (out_sig != -1) {
|
||||
// For gpio_matrix, reserve output pins, see 'esp_gpio_reserve.h'
|
||||
*io_mask |= BIT64(gpio_num);
|
||||
s_spi_common_gpio_check_reserve(gpio_num);
|
||||
esp_rom_gpio_connect_out_signal(gpio_num, out_sig, false, false);
|
||||
}
|
||||
gpio_func_sel(gpio_num, PIN_FUNC_GPIO);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -507,7 +541,7 @@ Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pi
|
||||
bus config struct and it'll set up the GPIO matrix and enable the device. If a pin is set to non-negative value,
|
||||
it should be able to be initialized.
|
||||
*/
|
||||
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t* flags_o)
|
||||
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t* flags_o, uint64_t *io_reserved)
|
||||
{
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
// In the driver of previous version, spi data4 ~ spi data7 are not in spi_bus_config_t struct. So the new-added pins come as 0
|
||||
@@ -521,55 +555,33 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
|
||||
uint32_t temp_flag = 0;
|
||||
|
||||
bool miso_need_output;
|
||||
bool mosi_need_output;
|
||||
bool sclk_need_output;
|
||||
if ((flags & SPICOMMON_BUSFLAG_MASTER) != 0) {
|
||||
//initial for master
|
||||
miso_need_output = ((flags & SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
|
||||
mosi_need_output = true;
|
||||
sclk_need_output = true;
|
||||
} else {
|
||||
//initial for slave
|
||||
miso_need_output = true;
|
||||
mosi_need_output = ((flags & SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
|
||||
sclk_need_output = false;
|
||||
}
|
||||
|
||||
const bool wp_need_output = true;
|
||||
const bool hd_need_output = true;
|
||||
|
||||
uint64_t gpio_reserv = 0;
|
||||
//check pin capabilities
|
||||
if (bus_config->sclk_io_num >= 0) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_SCLK;
|
||||
SPI_CHECK_PIN(bus_config->sclk_io_num, "sclk", sclk_need_output);
|
||||
SPI_CHECK_PIN(bus_config->sclk_io_num, "sclk", (flags & SPICOMMON_BUSFLAG_MASTER));
|
||||
}
|
||||
if (bus_config->quadwp_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->quadwp_io_num, "wp", wp_need_output);
|
||||
SPI_CHECK_PIN(bus_config->quadwp_io_num, "wp", true);
|
||||
}
|
||||
if (bus_config->quadhd_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->quadhd_io_num, "hd", hd_need_output);
|
||||
SPI_CHECK_PIN(bus_config->quadhd_io_num, "hd", true);
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
const bool io4_need_output = true;
|
||||
const bool io5_need_output = true;
|
||||
const bool io6_need_output = true;
|
||||
const bool io7_need_output = true;
|
||||
// set flags for OCTAL mode according to the existence of spi data4 ~ spi data7
|
||||
if (io4_7_enabled) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_IO4_IO7;
|
||||
if (bus_config->data4_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data4_io_num, "spi data4", io4_need_output);
|
||||
SPI_CHECK_PIN(bus_config->data4_io_num, "spi data4", true);
|
||||
}
|
||||
if (bus_config->data5_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data5_io_num, "spi data5", io5_need_output);
|
||||
SPI_CHECK_PIN(bus_config->data5_io_num, "spi data5", true);
|
||||
}
|
||||
if (bus_config->data6_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data6_io_num, "spi data6", io6_need_output);
|
||||
SPI_CHECK_PIN(bus_config->data6_io_num, "spi data6", true);
|
||||
}
|
||||
if (bus_config->data7_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data7_io_num, "spi data7", io7_need_output);
|
||||
SPI_CHECK_PIN(bus_config->data7_io_num, "spi data7", true);
|
||||
}
|
||||
}
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
@@ -580,11 +592,11 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
}
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_MOSI;
|
||||
SPI_CHECK_PIN(bus_config->mosi_io_num, "mosi", mosi_need_output);
|
||||
SPI_CHECK_PIN(bus_config->mosi_io_num, "mosi", (flags & SPICOMMON_BUSFLAG_MASTER) || (temp_flag & SPICOMMON_BUSFLAG_DUAL));
|
||||
}
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_MISO;
|
||||
SPI_CHECK_PIN(bus_config->miso_io_num, "miso", miso_need_output);
|
||||
SPI_CHECK_PIN(bus_config->miso_io_num, "miso", !(flags & SPICOMMON_BUSFLAG_MASTER) || (temp_flag & SPICOMMON_BUSFLAG_DUAL));
|
||||
}
|
||||
//set flags for DUAL mode according to output-capability of MOSI and MISO pins.
|
||||
if ((bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num)) &&
|
||||
@@ -629,91 +641,64 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
ESP_LOGE(SPI_TAG, "spi data4 ~ spi data7 are required.");
|
||||
}
|
||||
#endif
|
||||
SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(false, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
|
||||
}
|
||||
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use %s.", host + 1, use_iomux ? "iomux pins" : "gpio matrix");
|
||||
if (use_iomux) {
|
||||
//All SPI iomux pin selections resolve to 1, so we put that here instead of trying to figure
|
||||
//out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host + 1);
|
||||
bus_iomux_pins_set(host, bus_config);
|
||||
//out which PIN_FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
|
||||
for (uint8_t i = 0; i < sizeof(bus_config->iocfg) / sizeof(bus_config->iocfg[0]); i++) {
|
||||
if (!(flags & SPICOMMON_BUSFLAG_OCTAL) && (i >= 4)) {
|
||||
break;
|
||||
}
|
||||
// For iomux, reserve all configured pins
|
||||
if (GPIO_IS_VALID_GPIO(bus_config->iocfg[i])) {
|
||||
gpio_reserv |= BIT64(bus_config->iocfg[i]);
|
||||
s_spi_common_gpio_check_reserve(bus_config->iocfg[i]);
|
||||
}
|
||||
}
|
||||
bus_iomux_pins_set_quad(host, bus_config);
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (flags & SPICOMMON_BUSFLAG_OCTAL) {
|
||||
bus_iomux_pins_set_oct(host, bus_config);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//Use GPIO matrix
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host + 1);
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
if (mosi_need_output || (temp_flag & SPICOMMON_BUSFLAG_DUAL)) {
|
||||
gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_out, false, false);
|
||||
} else {
|
||||
gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT);
|
||||
}
|
||||
esp_rom_gpio_connect_in_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_in, false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->mosi_io_num]);
|
||||
#endif
|
||||
gpio_func_sel(bus_config->mosi_io_num, FUNC_GPIO);
|
||||
int in_sig = (!(flags & SPICOMMON_BUSFLAG_MASTER) || (temp_flag & SPICOMMON_BUSFLAG_DUAL)) ? spi_periph_signal[host].spid_in : -1;
|
||||
int out_sig = ((flags & SPICOMMON_BUSFLAG_MASTER) || (temp_flag & SPICOMMON_BUSFLAG_DUAL)) ? spi_periph_signal[host].spid_out : -1;
|
||||
s_spi_common_bus_via_gpio(bus_config->mosi_io_num, in_sig, out_sig, &gpio_reserv);
|
||||
}
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
if (miso_need_output || (temp_flag & SPICOMMON_BUSFLAG_DUAL)) {
|
||||
gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_out, false, false);
|
||||
} else {
|
||||
gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT);
|
||||
}
|
||||
esp_rom_gpio_connect_in_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_in, false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->miso_io_num]);
|
||||
#endif
|
||||
gpio_func_sel(bus_config->miso_io_num, FUNC_GPIO);
|
||||
}
|
||||
if (bus_config->quadwp_io_num >= 0) {
|
||||
gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_out, false, false);
|
||||
esp_rom_gpio_connect_in_signal(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in, false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num]);
|
||||
#endif
|
||||
gpio_func_sel(bus_config->quadwp_io_num, FUNC_GPIO);
|
||||
}
|
||||
if (bus_config->quadhd_io_num >= 0) {
|
||||
gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_out, false, false);
|
||||
esp_rom_gpio_connect_in_signal(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in, false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num]);
|
||||
#endif
|
||||
gpio_func_sel(bus_config->quadhd_io_num, FUNC_GPIO);
|
||||
int in_sig = ((flags & SPICOMMON_BUSFLAG_MASTER) || (temp_flag & SPICOMMON_BUSFLAG_DUAL)) ? spi_periph_signal[host].spiq_in : -1;
|
||||
int out_sig = (!(flags & SPICOMMON_BUSFLAG_MASTER) || (temp_flag & SPICOMMON_BUSFLAG_DUAL)) ? spi_periph_signal[host].spiq_out : -1;
|
||||
s_spi_common_bus_via_gpio(bus_config->miso_io_num, in_sig, out_sig, &gpio_reserv);
|
||||
}
|
||||
if (bus_config->sclk_io_num >= 0) {
|
||||
if (sclk_need_output) {
|
||||
gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_out, false, false);
|
||||
} else {
|
||||
gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_INPUT);
|
||||
}
|
||||
esp_rom_gpio_connect_in_signal(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in, false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->sclk_io_num]);
|
||||
#endif
|
||||
gpio_func_sel(bus_config->sclk_io_num, FUNC_GPIO);
|
||||
int in_sig = (flags & SPICOMMON_BUSFLAG_MASTER) ? -1 : spi_periph_signal[host].spiclk_in;
|
||||
int out_sig = (flags & SPICOMMON_BUSFLAG_MASTER) ? spi_periph_signal[host].spiclk_out : -1;
|
||||
s_spi_common_bus_via_gpio(bus_config->sclk_io_num, in_sig, out_sig, &gpio_reserv);
|
||||
}
|
||||
if (bus_config->quadwp_io_num >= 0) {
|
||||
s_spi_common_bus_via_gpio(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in, spi_periph_signal[host].spiwp_out, &gpio_reserv);
|
||||
}
|
||||
if (bus_config->quadhd_io_num >= 0) {
|
||||
s_spi_common_bus_via_gpio(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in, spi_periph_signal[host].spihd_out, &gpio_reserv);
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if ((flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
|
||||
if (flags & SPICOMMON_BUSFLAG_OCTAL) {
|
||||
int io_nums[] = {bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
|
||||
uint8_t io_signals[4][2] = {{spi_periph_signal[host].spid4_out, spi_periph_signal[host].spid4_in},
|
||||
uint8_t io_signals[4][2] = {
|
||||
{spi_periph_signal[host].spid4_out, spi_periph_signal[host].spid4_in},
|
||||
{spi_periph_signal[host].spid5_out, spi_periph_signal[host].spid5_in},
|
||||
{spi_periph_signal[host].spid6_out, spi_periph_signal[host].spid6_in},
|
||||
{spi_periph_signal[host].spid7_out, spi_periph_signal[host].spid7_in}
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(io_nums) / sizeof(io_nums[0]); i++) {
|
||||
if (io_nums[i] >= 0) {
|
||||
gpio_set_direction(io_nums[i], GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(io_nums[i], io_signals[i][0], false, false);
|
||||
esp_rom_gpio_connect_in_signal(io_nums[i], io_signals[i][1], false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_nums[i]]);
|
||||
#endif
|
||||
gpio_func_sel(io_nums[i], FUNC_GPIO);
|
||||
s_spi_common_bus_via_gpio(io_nums[i], io_signals[i][1], io_signals[i][0], &gpio_reserv);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -723,64 +708,64 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
if (flags_o) {
|
||||
*flags_o = temp_flag;
|
||||
}
|
||||
if (io_reserved) {
|
||||
*io_reserved |= gpio_reserv;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg)
|
||||
esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg, uint64_t *io_reserved)
|
||||
{
|
||||
int pin_array[] = {
|
||||
bus_cfg->mosi_io_num,
|
||||
bus_cfg->miso_io_num,
|
||||
bus_cfg->sclk_io_num,
|
||||
bus_cfg->quadwp_io_num,
|
||||
bus_cfg->quadhd_io_num,
|
||||
};
|
||||
for (int i = 0; i < sizeof(pin_array) / sizeof(int); i ++) {
|
||||
const int io = pin_array[i];
|
||||
if (GPIO_IS_VALID_GPIO(io)) {
|
||||
gpio_reset_pin(io);
|
||||
for (uint8_t i = 0; i < sizeof(bus_cfg->iocfg) / sizeof(bus_cfg->iocfg[0]); i++) {
|
||||
#if !SOC_SPI_SUPPORT_OCT
|
||||
if (i > 4) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (GPIO_IS_VALID_GPIO(bus_cfg->iocfg[i]) && (*io_reserved & BIT64(bus_cfg->iocfg[i]))) {
|
||||
*io_reserved &= ~BIT64(bus_cfg->iocfg[i]);
|
||||
gpio_output_disable(bus_cfg->iocfg[i]);
|
||||
esp_gpio_revoke(BIT64(bus_cfg->iocfg[i]));
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix)
|
||||
void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_id, int force_gpio_matrix, uint64_t *io_reserved)
|
||||
{
|
||||
if (!force_gpio_matrix && cs_io_num == spi_periph_signal[host].spics0_iomux_pin && cs_num == 0) {
|
||||
uint64_t out_mask = 0;
|
||||
if (!force_gpio_matrix && cs_io_num == spi_periph_signal[host].spics0_iomux_pin && cs_id == 0) {
|
||||
out_mask |= BIT64(cs_io_num);
|
||||
s_spi_common_gpio_check_reserve(cs_io_num);
|
||||
//The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
|
||||
gpio_iomux_input(cs_io_num, spi_periph_signal[host].func, spi_periph_signal[host].spics_in);
|
||||
gpio_iomux_output(cs_io_num, spi_periph_signal[host].func);
|
||||
} else {
|
||||
//Use GPIO matrix
|
||||
if (GPIO_IS_VALID_OUTPUT_GPIO(cs_io_num)) {
|
||||
gpio_set_direction(cs_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(cs_io_num, spi_periph_signal[host].spics_out[cs_num], false, false);
|
||||
} else {
|
||||
gpio_set_direction(cs_io_num, GPIO_MODE_INPUT);
|
||||
out_mask |= BIT64(cs_io_num);
|
||||
s_spi_common_gpio_check_reserve(cs_io_num);
|
||||
esp_rom_gpio_connect_out_signal(cs_io_num, spi_periph_signal[host].spics_out[cs_id], false, false);
|
||||
}
|
||||
if (cs_num == 0) {
|
||||
// cs_id 0 is always used by slave for input
|
||||
if (cs_id == 0) {
|
||||
gpio_input_enable(cs_io_num);
|
||||
esp_rom_gpio_connect_in_signal(cs_io_num, spi_periph_signal[host].spics_in, false);
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[cs_io_num]);
|
||||
#endif
|
||||
gpio_func_sel(cs_io_num, FUNC_GPIO);
|
||||
gpio_func_sel(cs_io_num, PIN_FUNC_GPIO);
|
||||
}
|
||||
if (io_reserved) {
|
||||
*io_reserved |= out_mask;
|
||||
}
|
||||
}
|
||||
|
||||
void spicommon_cs_free_io(int cs_gpio_num)
|
||||
void spicommon_cs_free_io(int cs_gpio_num, uint64_t *io_reserved)
|
||||
{
|
||||
assert(GPIO_IS_VALID_GPIO(cs_gpio_num));
|
||||
gpio_reset_pin(cs_gpio_num);
|
||||
}
|
||||
|
||||
bool spicommon_bus_using_iomux(spi_host_device_t host)
|
||||
{
|
||||
CHECK_IOMUX_PIN(host, spid);
|
||||
CHECK_IOMUX_PIN(host, spiq);
|
||||
CHECK_IOMUX_PIN(host, spiwp);
|
||||
CHECK_IOMUX_PIN(host, spihd);
|
||||
return true;
|
||||
if (GPIO_IS_VALID_GPIO(cs_gpio_num) && (*io_reserved & BIT64(cs_gpio_num))) {
|
||||
*io_reserved &= ~BIT64(cs_gpio_num);
|
||||
gpio_output_disable(cs_gpio_num);
|
||||
esp_gpio_revoke(BIT64(cs_gpio_num));
|
||||
}
|
||||
}
|
||||
|
||||
spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id)
|
||||
@@ -802,9 +787,6 @@ static esp_err_t s_bus_create_sleep_retention_cb(void *arg)
|
||||
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
spicommon_bus_context_t *ctx = NULL;
|
||||
spi_bus_attr_t *bus_attr = NULL;
|
||||
|
||||
SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(bus_ctx[host_id] == NULL, "SPI bus already initialized.", ESP_ERR_INVALID_STATE);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
@@ -822,18 +804,9 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
|
||||
SPI_CHECK((bus_config->data_io_default_level == 0), "no support changing io default level ", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
|
||||
bool spi_chan_claimed = spicommon_periph_claim(host_id, "spi master");
|
||||
SPI_CHECK(spi_chan_claimed, "host_id already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
//clean and initialize the context
|
||||
ctx = (spicommon_bus_context_t *)heap_caps_calloc(1, sizeof(spicommon_bus_context_t), SPI_COMMON_MALLOC_CAPS);
|
||||
if (!ctx) {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
bus_ctx[host_id] = ctx;
|
||||
ctx->host_id = host_id;
|
||||
bus_attr = &ctx->bus_attr;
|
||||
ESP_RETURN_ON_ERROR(spicommon_bus_alloc(host_id, "spi master"), SPI_TAG, "alloc host failed");
|
||||
spi_bus_attr_t *bus_attr = (spi_bus_attr_t *)spi_bus_get_attr(host_id);
|
||||
spicommon_bus_context_t *ctx = __containerof(bus_attr, spicommon_bus_context_t, bus_attr);
|
||||
bus_attr->bus_cfg = *bus_config;
|
||||
|
||||
if (dma_chan != SPI_DMA_DISABLED) {
|
||||
@@ -908,7 +881,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
err = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags);
|
||||
err = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags, &bus_attr->gpio_reserve);
|
||||
if (err != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -930,9 +903,7 @@ cleanup:
|
||||
ctx->dma_ctx = NULL;
|
||||
}
|
||||
}
|
||||
spicommon_periph_free(host_id);
|
||||
free(bus_ctx[host_id]);
|
||||
bus_ctx[host_id] = NULL;
|
||||
spicommon_bus_free(host_id);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -979,7 +950,7 @@ esp_err_t spi_bus_free(spi_host_device_t host_id)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
spicommon_bus_free_io_cfg(&bus_attr->bus_cfg);
|
||||
spicommon_bus_free_io_cfg(&bus_attr->bus_cfg, &bus_attr->gpio_reserve);
|
||||
|
||||
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
const periph_retention_module_t retention_id = spi_reg_retention_info[host_id - 1].module_id;
|
||||
@@ -1006,9 +977,7 @@ esp_err_t spi_bus_free(spi_host_device_t host_id)
|
||||
spicommon_dma_chan_free(ctx->dma_ctx);
|
||||
ctx->dma_ctx = NULL;
|
||||
}
|
||||
spicommon_periph_free(host_id);
|
||||
free(ctx);
|
||||
bus_ctx[host_id] = NULL;
|
||||
spicommon_bus_free(host_id);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@@ -527,7 +527,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
||||
|
||||
//Set CS pin, CS options
|
||||
if (dev_config->spics_io_num >= 0) {
|
||||
spicommon_cs_initialize(host_id, dev_config->spics_io_num, freecs, use_gpio);
|
||||
spicommon_cs_initialize(host_id, dev_config->spics_io_num, freecs, use_gpio, (uint64_t *)&bus_attr->gpio_reserve);
|
||||
}
|
||||
|
||||
//save a pointer to device in spi_host_t
|
||||
@@ -605,8 +605,9 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
|
||||
|
||||
//return
|
||||
int spics_io_num = handle->cfg.spics_io_num;
|
||||
const spi_bus_attr_t* bus_attr = handle->host->bus_attr;
|
||||
if (spics_io_num >= 0) {
|
||||
spicommon_cs_free_io(spics_io_num);
|
||||
spicommon_cs_free_io(spics_io_num, (uint64_t *)&bus_attr->gpio_reserve);
|
||||
}
|
||||
|
||||
//Kill queues
|
||||
|
@@ -61,6 +61,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
int id;
|
||||
_Atomic spi_bus_fsm_t fsm;
|
||||
uint64_t gpio_reserve;
|
||||
spi_bus_config_t bus_config;
|
||||
spi_dma_ctx_t *dma_ctx;
|
||||
spi_slave_interface_config_t cfg;
|
||||
@@ -145,7 +146,6 @@ static esp_err_t s_spi_create_sleep_retention_cb(void *arg)
|
||||
|
||||
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, spi_dma_chan_t dma_chan)
|
||||
{
|
||||
bool spi_chan_claimed;
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_err_t err;
|
||||
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
@@ -167,16 +167,13 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
SPI_CHECK(slave_config->post_trans_cb != NULL, "use feature flag 'SPI_SLAVE_NO_RETURN_RESULT' but no post_trans_cb function sets", ESP_ERR_INVALID_ARG);
|
||||
}
|
||||
|
||||
spi_chan_claimed = spicommon_periph_claim(host, "spi slave");
|
||||
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
SPI_CHECK(spicommon_periph_claim(host, "spi slave"), "host already in use", ESP_ERR_INVALID_STATE);
|
||||
// spi_slave_t contains atomic variable, memory must be allocated from internal memory
|
||||
spihost[host] = heap_caps_malloc(sizeof(spi_slave_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
spihost[host] = heap_caps_calloc(1, sizeof(spi_slave_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
if (spihost[host] == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
memset(spihost[host], 0, sizeof(spi_slave_t));
|
||||
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
|
||||
memcpy(&spihost[host]->bus_config, bus_config, sizeof(spi_bus_config_t));
|
||||
spihost[host]->id = host;
|
||||
@@ -210,13 +207,13 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
spihost[host]->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
err = spicommon_bus_initialize_io(host, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &spihost[host]->flags);
|
||||
err = spicommon_bus_initialize_io(host, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &spihost[host]->flags, &spihost[host]->gpio_reserve);
|
||||
if (err != ESP_OK) {
|
||||
ret = err;
|
||||
goto cleanup;
|
||||
}
|
||||
if (slave_config->spics_io_num >= 0) {
|
||||
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, !bus_is_iomux(spihost[host]));
|
||||
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, !bus_is_iomux(spihost[host]), &spihost[host]->gpio_reserve);
|
||||
// check and save where cs line really route through
|
||||
spihost[host]->cs_iomux = (slave_config->spics_io_num == spi_periph_signal[host].spics0_iomux_pin) && bus_is_iomux(spihost[host]);
|
||||
spihost[host]->cs_in_signal = spi_periph_signal[host].spics_in;
|
||||
@@ -334,7 +331,10 @@ esp_err_t spi_slave_free(spi_host_device_t host)
|
||||
free(spihost[host]->dma_ctx->dmadesc_rx);
|
||||
spicommon_dma_chan_free(spihost[host]->dma_ctx);
|
||||
}
|
||||
spicommon_bus_free_io_cfg(&spihost[host]->bus_config);
|
||||
spicommon_bus_free_io_cfg(&spihost[host]->bus_config, &spihost[host]->gpio_reserve);
|
||||
if (spihost[host]->cfg.spics_io_num >= 0) {
|
||||
spicommon_cs_free_io(spihost[host]->cfg.spics_io_num, &spihost[host]->gpio_reserve);
|
||||
}
|
||||
esp_intr_free(spihost[host]->intr);
|
||||
|
||||
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
|
@@ -44,6 +44,9 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
spi_host_device_t host_id;
|
||||
spi_bus_config_t bus_config;
|
||||
int cs_io_num;
|
||||
uint64_t gpio_reserve;
|
||||
_Atomic spi_bus_fsm_t fsm;
|
||||
spi_dma_ctx_t *dma_ctx;
|
||||
uint16_t internal_mem_align_size;
|
||||
@@ -100,7 +103,6 @@ static esp_err_t s_spi_create_sleep_retention_cb(void *arg)
|
||||
|
||||
esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config, const spi_slave_hd_slot_config_t *config)
|
||||
{
|
||||
bool spi_chan_claimed;
|
||||
bool append_mode = (config->flags & SPI_SLAVE_HD_APPEND_MODE);
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
@@ -115,9 +117,8 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
||||
SPIHD_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
|
||||
spi_chan_claimed = spicommon_periph_claim(host_id, "slave_hd");
|
||||
SPIHD_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
SPIHD_CHECK(spicommon_periph_claim(host_id, "slave_hd"), "host already in use", ESP_ERR_INVALID_STATE);
|
||||
// spi_slave_hd_slot_t contains atomic variable, memory must be allocated from internal memory
|
||||
spi_slave_hd_slot_t *host = heap_caps_calloc(1, sizeof(spi_slave_hd_slot_t), MALLOC_CAP_INTERNAL);
|
||||
if (host == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
@@ -128,6 +129,8 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
||||
host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
host->append_mode = append_mode;
|
||||
atomic_store(&host->fsm, SPI_BUS_FSM_ENABLED);
|
||||
memcpy(&host->bus_config, bus_config, sizeof(spi_bus_config_t));
|
||||
host->cs_io_num = config->spics_io_num;
|
||||
|
||||
ret = spicommon_dma_chan_alloc(host_id, config->dma_chan, &host->dma_ctx);
|
||||
if (ret != ESP_OK) {
|
||||
@@ -169,12 +172,11 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
||||
host->internal_mem_align_size = 4;
|
||||
#endif
|
||||
|
||||
ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags);
|
||||
ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags, &host->gpio_reserve);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
gpio_set_direction(config->spics_io_num, GPIO_MODE_INPUT);
|
||||
spicommon_cs_initialize(host_id, config->spics_io_num, 0, !(bus_config->flags & SPICOMMON_BUSFLAG_NATIVE_PINS));
|
||||
spicommon_cs_initialize(host_id, config->spics_io_num, 0, !(bus_config->flags & SPICOMMON_BUSFLAG_NATIVE_PINS), &host->gpio_reserve);
|
||||
|
||||
spi_slave_hd_hal_config_t hal_config = {
|
||||
.host_id = host_id,
|
||||
@@ -347,6 +349,8 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
|
||||
}
|
||||
#endif
|
||||
|
||||
spicommon_bus_free_io_cfg(&host->bus_config, &host->gpio_reserve);
|
||||
spicommon_cs_free_io(host->cs_io_num, &host->gpio_reserve);
|
||||
spicommon_periph_free(host_id);
|
||||
free(host->dma_ctx->dmadesc_tx);
|
||||
free(host->dma_ctx->dmadesc_rx);
|
||||
|
Reference in New Issue
Block a user