From dceb3452c7e96aa44fe3c26a3a2d958cd0e6f47a Mon Sep 17 00:00:00 2001 From: "Michael (Xiao Xufeng)" Date: Tue, 27 Mar 2018 15:20:15 +0800 Subject: [PATCH 1/3] doc(spi_master): format the documentation of several fields and macros in `spi_master.h` --- components/driver/include/driver/spi_master.h | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/components/driver/include/driver/spi_master.h b/components/driver/include/driver/spi_master.h index 613b8cf74..ba77b9fb2 100644 --- a/components/driver/include/driver/spi_master.h +++ b/components/driver/include/driver/spi_master.h @@ -36,10 +36,10 @@ extern "C" #define SPI_DEVICE_HALFDUPLEX (1<<4) ///< Transmit data before receiving it, instead of simultaneously #define SPI_DEVICE_CLK_AS_CS (1<<5) ///< Output clock on CS line if CS is active /** There are timing issue when reading at high frequency (the frequency is related to whether native pins are used, valid time after slave sees the clock). - * In half-duplex mode, the driver automatically inserts dummy bits before reading phase to fix the timing issue. Set this flag to disable this feature. - * However in full-duplex mode, dummy bits are not allowed to use and no way to prevent reading data from being corrupted. - * Set this flag to confirm that you're going to work with output only, or read without dummy bits at your own risk. - */ + * - In half-duplex mode, the driver automatically inserts dummy bits before reading phase to fix the timing issue. Set this flag to disable this feature. + * - In full-duplex mode, however, the hardware cannot use dummy bits, so there is no way to prevent data being read from getting corrupted. + * Set this flag to confirm that you're going to work with output only, or read without dummy bits at your own risk. + */ #define SPI_DEVICE_NO_DUMMY (1<<6) @@ -79,12 +79,18 @@ typedef struct { */ struct spi_transaction_t { uint32_t flags; ///< Bitwise OR of SPI_TRANS_* flags - uint16_t cmd; ///< Command data, of which the length is set in the ``command_bits`` of spi_device_interface_config_t. - ///< NOTE: this field, used to be "command" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF 3.0. - ///< - Example: write 0x0123 and command_bits=12 to send command 0x12, 0x3_ (in previous version, you may have to write 0x3_12). - uint64_t addr; ///< Address data, of which the length is set in the ``address_bits`` of spi_device_interface_config_t. - ///< NOTE: this field, used to be "address" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF3.0. - ///< - Example: write 0x123400 and address_bits=24 to send address of 0x12, 0x34, 0x00 (in previous version, you may have to write 0x12340000). + uint16_t cmd; /**< Command data, of which the length is set in the ``command_bits`` of spi_device_interface_config_t. + * + * NOTE: this field, used to be "command" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF 3.0. + * + * Example: write 0x0123 and command_bits=12 to send command 0x12, 0x3_ (in previous version, you may have to write 0x3_12). + */ + uint64_t addr; /**< Address data, of which the length is set in the ``address_bits`` of spi_device_interface_config_t. + * + * NOTE: this field, used to be "address" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF3.0. + * + * Example: write 0x123400 and address_bits=24 to send address of 0x12, 0x34, 0x00 (in previous version, you may have to write 0x12340000). + */ size_t length; ///< Total data length, in bits size_t rxlength; ///< Total data length received, should be not greater than ``length`` in full-duplex mode (0 defaults this to the value of ``length``). void *user; ///< User-defined variable. Can be used to store eg transaction ID. From 77629129c0b523c619287b70ce8efcb9f7027da4 Mon Sep 17 00:00:00 2001 From: "Michael (Xiao Xufeng)" Date: Wed, 21 Mar 2018 20:42:45 +0800 Subject: [PATCH 2/3] chore(spi): update the return value of spi init functions --- components/driver/spi_master.c | 34 +++++++++++++++++++++++------- components/driver/spi_slave.c | 38 ++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index f216a2831..0fa5c9b31 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -122,6 +122,8 @@ static void spi_intr(void *arg); esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan) { bool native, spi_chan_claimed, dma_chan_claimed; + esp_err_t ret = ESP_OK; + esp_err_t err; /* ToDo: remove this when we have flash operations cooperating with this */ SPI_CHECK(host!=SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED); @@ -140,17 +142,25 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus } spihost[host]=malloc(sizeof(spi_host_t)); - if (spihost[host]==NULL) goto nomem; + if (spihost[host]==NULL) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } memset(spihost[host], 0, sizeof(spi_host_t)); #ifdef CONFIG_PM_ENABLE - esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master", + err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master", &spihost[host]->pm_lock); if (err != ESP_OK) { - goto nomem; + ret = err; + goto cleanup; } #endif //CONFIG_PM_ENABLE - spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER|SPICOMMON_BUSFLAG_QUAD, &native); + err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER|SPICOMMON_BUSFLAG_QUAD, &native); + if (err != ESP_OK) { + ret = err; + goto cleanup; + } spihost[host]->no_gpio_matrix=native; spihost[host]->dma_chan=dma_chan; @@ -163,9 +173,17 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus spihost[host]->max_transfer_sz = dma_desc_ct*SPI_MAX_DMA_LEN; spihost[host]->dmadesc_tx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA); spihost[host]->dmadesc_rx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA); - if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) goto nomem; + if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } + } + + err = esp_intr_alloc(spicommon_irqsource_for_host(host), ESP_INTR_FLAG_INTRDISABLED, spi_intr, (void*)spihost[host], &spihost[host]->intr); + if (err != ESP_OK) { + ret = err; + goto cleanup; } - esp_intr_alloc(spicommon_irqsource_for_host(host), ESP_INTR_FLAG_INTRDISABLED, spi_intr, (void*)spihost[host], &spihost[host]->intr); spihost[host]->hw=spicommon_hw_for_host(host); spihost[host]->cur_cs = NO_CS; @@ -197,7 +215,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus return ESP_OK; -nomem: +cleanup: if (spihost[host]) { free(spihost[host]->dmadesc_tx); free(spihost[host]->dmadesc_rx); @@ -210,7 +228,7 @@ nomem: free(spihost[host]); spicommon_periph_free(host); spicommon_dma_chan_free(dma_chan); - return ESP_ERR_NO_MEM; + return ret; } esp_err_t spi_bus_free(spi_host_device_t host) diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index c65cb3b52..157829eeb 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -73,6 +73,8 @@ static void IRAM_ATTR spi_intr(void *arg); esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, int dma_chan) { bool native, spi_chan_claimed, dma_chan_claimed; + esp_err_t ret = ESP_OK; + esp_err_t err; //We only support HSPI/VSPI, period. SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG); SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG ); @@ -89,11 +91,18 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b } spihost[host] = malloc(sizeof(spi_slave_t)); - if (spihost[host] == NULL) goto nomem; + 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)); - spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE, &native); + err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE, &native); + if (err!=ESP_OK) { + ret = err; + goto cleanup; + } gpio_set_direction(slave_config->spics_io_num, GPIO_MODE_INPUT); spicommon_cs_initialize(host, slave_config->spics_io_num, 0, native == false); spihost[host]->no_gpio_matrix = native; @@ -105,16 +114,20 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b spihost[host]->max_transfer_sz = dma_desc_ct * SPI_MAX_DMA_LEN; spihost[host]->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA); spihost[host]->dmadesc_rx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA); - if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) goto nomem; + if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } } else { //We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most. spihost[host]->max_transfer_sz = 16 * 4; } #ifdef CONFIG_PM_ENABLE - esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave", + err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave", &spihost[host]->pm_lock); if (err != ESP_OK) { - goto nomem; + ret = err; + goto cleanup; } // Lock APB frequency while SPI slave driver is in use esp_pm_lock_acquire(spihost[host]->pm_lock); @@ -123,9 +136,16 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b //Create queues spihost[host]->trans_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *)); spihost[host]->ret_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *)); - if (!spihost[host]->trans_queue || !spihost[host]->ret_queue) goto nomem; + if (!spihost[host]->trans_queue || !spihost[host]->ret_queue) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } - esp_intr_alloc(spicommon_irqsource_for_host(host), ESP_INTR_FLAG_INTRDISABLED, spi_intr, (void *)spihost[host], &spihost[host]->intr); + err = esp_intr_alloc(spicommon_irqsource_for_host(host), ESP_INTR_FLAG_INTRDISABLED, spi_intr, (void *)spihost[host], &spihost[host]->intr); + if (err != ESP_OK) { + ret = err; + goto cleanup; + } spihost[host]->hw = spicommon_hw_for_host(host); //Configure slave @@ -191,7 +211,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b return ESP_OK; -nomem: +cleanup: if (spihost[host]) { if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue); if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue); @@ -208,7 +228,7 @@ nomem: spihost[host] = NULL; spicommon_periph_free(host); spicommon_dma_chan_free(dma_chan); - return ESP_ERR_NO_MEM; + return ret; } esp_err_t spi_slave_free(spi_host_device_t host) From 45f8bcf3f8b0062599afd9b538d4c1ddac22de51 Mon Sep 17 00:00:00 2001 From: "Michael (Xiao Xufeng)" Date: Wed, 21 Mar 2018 20:42:45 +0800 Subject: [PATCH 3/3] fix(spi): allow using MISO on GPIO34-39 Breaking Changes: arguments of ``spicommon_bus_initialize_io`` are changed. Closes https://github.com/espressif/esp-idf/issues/1736. --- components/driver/include/driver/spi_common.h | 37 ++++- components/driver/spi_common.c | 118 +++++++++----- components/driver/spi_master.c | 17 +- components/driver/spi_slave.c | 10 +- components/driver/test/test_spi_master.c | 152 +++++++++++++++++- 5 files changed, 275 insertions(+), 59 deletions(-) diff --git a/components/driver/include/driver/spi_common.h b/components/driver/include/driver/spi_common.h index 6adcc06a9..9f014d279 100644 --- a/components/driver/include/driver/spi_common.h +++ b/components/driver/include/driver/spi_common.h @@ -58,6 +58,7 @@ typedef struct { int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used. int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used. int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0. + uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags. } spi_bus_config_t; @@ -99,9 +100,17 @@ bool spicommon_dma_chan_claim(int dma_chan); */ bool spicommon_dma_chan_free(int dma_chan); -#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_QUAD (1<<1) ///< Also initialize WP/HD pins, if specified + + +#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_NATIVE_PINS (1<<1) ///< Check using native pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix. +#define SPICOMMON_BUSFLAG_SCLK (1<<2) ///< Check existing of SCLK pin. Or indicates CLK line initialized. +#define SPICOMMON_BUSFLAG_MISO (1<<3) ///< Check existing of MISO pin. Or indicates MISO line initialized. +#define SPICOMMON_BUSFLAG_MOSI (1<<4) ///< Check existing of MOSI pin. Or indicates CLK line initialized. +#define SPICOMMON_BUSFLAG_DUAL (1<<5) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode. +#define SPICOMMON_BUSFLAG_WPHD (1<<6) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized. +#define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode. /** * @brief Connect a SPI peripheral to GPIO pins @@ -113,14 +122,28 @@ bool spicommon_dma_chan_free(int dma_chan); * @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. - * @param flags Combination of SPICOMMON_BUSFLAG_* flags - * @param[out] is_native A value of 'true' will be written to this address if the GPIOs can be - * routed using the IO_mux, 'false' if the GPIO matrix is used. + * @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions: + * - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode + * - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode + * - ``SPICOMMON_BUSFLAG_NATIVE_PINS``: Pins set should match the native pins of the controller. + * - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: + * Make sure SCLK/MISO/MOSI is/are set to a valid GPIO. Also check output capability according to the mode. + * - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable. + * - ``SPICOMMON_BUSFLAG_WPHD`` Make sure WP and HD are set to valid output GPIOs. + * - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``. + * @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address. + * Leave to NULL if not needed. + * - ``SPICOMMON_BUSFLAG_NATIVE_PINS``: The bus is connected to native pins. + * - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: The bus has + * CLK/MISO/MOSI connected. + * - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode. + * - ``SPICOMMON_BUSFLAG_WPHD`` The bus has WP and HD connected. + * - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``. * @return * - ESP_ERR_INVALID_ARG if parameter is invalid * - ESP_OK on success */ -esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, int flags, bool *is_native); +esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, uint32_t flags, uint32_t *flags_o); /** * @brief Free the IO used by a SPI peripheral diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index bd78e9352..4ea94a7c0 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -220,67 +220,113 @@ bool spicommon_dma_chan_free(int dma_chan) /* Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pins. Feed it a host number and a -bus config struct and it'll set up the GPIO matrix and enable the device. It will set is_native to 1 if the bus -config can be done using the IOMUX instead of using the GPIO matrix. +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, int dma_chan, int flags, bool *is_native) +esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, uint32_t flags, uint32_t* flags_o) { bool native = true; - bool use_quad = (flags & SPICOMMON_BUSFLAG_QUAD) != 0; + uint32_t temp_flag=0; + bool quad_pins_exist = true; + //the MISO should be output capable in slave mode, or in DIO/QIO mode. + bool miso_output = !(flags&SPICOMMON_BUSFLAG_MASTER) || flags&SPICOMMON_BUSFLAG_DUAL; + //the MOSI should be output capble in master mode, or in DIO/QIO mode. + bool mosi_output = (flags&SPICOMMON_BUSFLAG_MASTER)!=0 || flags&SPICOMMON_BUSFLAG_DUAL; - SPI_CHECK(bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "spid pin invalid", ESP_ERR_INVALID_ARG); - SPI_CHECK(bus_config->sclk_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->sclk_io_num), "spiclk pin invalid", ESP_ERR_INVALID_ARG); - SPI_CHECK(bus_config->miso_io_num < 0 || GPIO_IS_VALID_GPIO(bus_config->miso_io_num), "spiq pin invalid", ESP_ERR_INVALID_ARG); - if (use_quad) { - SPI_CHECK(bus_config->quadwp_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadwp_io_num), "spiwp pin invalid", ESP_ERR_INVALID_ARG); - SPI_CHECK(bus_config->quadhd_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadhd_io_num), "spihd pin invalid", ESP_ERR_INVALID_ARG); - } - - //Check if the selected pins correspond to the native pins of the peripheral - if (bus_config->mosi_io_num >= 0 && bus_config->mosi_io_num != io_signal[host].spid_native) native = false; - if (bus_config->miso_io_num >= 0 && bus_config->miso_io_num != io_signal[host].spiq_native) native = false; - if (bus_config->sclk_io_num >= 0 && bus_config->sclk_io_num != io_signal[host].spiclk_native) native = false; - if (use_quad) { - if (bus_config->quadwp_io_num >= 0 && bus_config->quadwp_io_num != io_signal[host].spiwp_native) native = false; - if (bus_config->quadhd_io_num >= 0 && bus_config->quadhd_io_num != io_signal[host].spihd_native) native = false; - } - - *is_native = native; - if ( native ) { - ESP_LOGD(SPI_TAG, "SPI%d use native pins.", host ); + //check pins existence and if the selected pins correspond to the native pins of the peripheral + if (bus_config->sclk_io_num>=0) { + temp_flag |= SPICOMMON_BUSFLAG_SCLK; + SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(bus_config->sclk_io_num), "sclk not valid", ESP_ERR_INVALID_ARG); + if (bus_config->sclk_io_num != io_signal[host].spiclk_native) native = false; } else { - ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host ); + SPI_CHECK((flags&SPICOMMON_BUSFLAG_SCLK)==0, "sclk pin required.", ESP_ERR_INVALID_ARG); } + if (bus_config->quadwp_io_num>=0) { + SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadwp_io_num), "spiwp not valid", ESP_ERR_INVALID_ARG); + if (bus_config->quadwp_io_num != io_signal[host].spiwp_native) native = false; + } else { + quad_pins_exist = false; + SPI_CHECK((flags&SPICOMMON_BUSFLAG_WPHD)==0, "spiwp pin required.", ESP_ERR_INVALID_ARG); + } + if (bus_config->quadhd_io_num>=0) { + SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadhd_io_num), "spihd not valid", ESP_ERR_INVALID_ARG); + if (bus_config->quadhd_io_num != io_signal[host].spihd_native) native = false; + } else { + quad_pins_exist = false; + SPI_CHECK((flags&SPICOMMON_BUSFLAG_WPHD)==0, "spihd pin required.", ESP_ERR_INVALID_ARG); + } + if (bus_config->mosi_io_num >= 0) { + temp_flag |= SPICOMMON_BUSFLAG_MOSI; + if (mosi_output) { + SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "mosi not valid", ESP_ERR_INVALID_ARG); + } else { + SPI_CHECK(GPIO_IS_VALID_GPIO(bus_config->mosi_io_num), "mosi not valid", ESP_ERR_INVALID_ARG); + } + if (bus_config->mosi_io_num != io_signal[host].spid_native) native = false; + } else { + SPI_CHECK((flags&SPICOMMON_BUSFLAG_MOSI)==0, "mosi pin required.", ESP_ERR_INVALID_ARG); + } + if (bus_config->miso_io_num>=0) { + temp_flag |= SPICOMMON_BUSFLAG_MISO; + if (miso_output) { + SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(bus_config->miso_io_num), "miso not valid", ESP_ERR_INVALID_ARG); + } else { + SPI_CHECK(GPIO_IS_VALID_GPIO(bus_config->miso_io_num), "miso not valid", ESP_ERR_INVALID_ARG); + } + if (bus_config->miso_io_num != io_signal[host].spiq_native) native = false; + } else { + SPI_CHECK((flags&SPICOMMON_BUSFLAG_MISO)==0, "miso pin required.", ESP_ERR_INVALID_ARG); + } + //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)) && + (bus_config->miso_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->miso_io_num)) ) { + temp_flag |= SPICOMMON_BUSFLAG_DUAL; + } + //set flags for QUAD mode according to the existence of wp and hd + if (quad_pins_exist) temp_flag |= SPICOMMON_BUSFLAG_WPHD; + //check native pins if required. + SPI_CHECK((flags&SPICOMMON_BUSFLAG_NATIVE_PINS)==0 || native, "not using native pins", ESP_ERR_INVALID_ARG); if (native) { //All SPI native 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 native pins.", host ); if (bus_config->mosi_io_num >= 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], 1); if (bus_config->miso_io_num >= 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], 1); - if (use_quad && bus_config->quadwp_io_num >= 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], 1); - if (use_quad && bus_config->quadhd_io_num >= 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], 1); + if (bus_config->quadwp_io_num >= 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], 1); + if (bus_config->quadhd_io_num >= 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], 1); if (bus_config->sclk_io_num >= 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], 1); + temp_flag |= SPICOMMON_BUSFLAG_NATIVE_PINS; } else { - //Use GPIO + //Use GPIO matrix + ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host ); if (bus_config->mosi_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], PIN_FUNC_GPIO); - gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT_OUTPUT); - gpio_matrix_out(bus_config->mosi_io_num, io_signal[host].spid_out, false, false); + if (mosi_output) { + gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT_OUTPUT); + gpio_matrix_out(bus_config->mosi_io_num, io_signal[host].spid_out, false, false); + } else { + gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT); + } gpio_matrix_in(bus_config->mosi_io_num, io_signal[host].spid_in, false); } if (bus_config->miso_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], PIN_FUNC_GPIO); - gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT_OUTPUT); - gpio_matrix_out(bus_config->miso_io_num, io_signal[host].spiq_out, false, false); - gpio_matrix_in(bus_config->miso_io_num, io_signal[host].spiq_in, false); + if (miso_output) { + gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT_OUTPUT); + gpio_matrix_out(bus_config->miso_io_num, io_signal[host].spiq_out, false, false); + } else { + gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT); + } + gpio_matrix_in(bus_config->miso_io_num, io_signal[host].spiq_in, false); } - if (use_quad && bus_config->quadwp_io_num >= 0) { + if (bus_config->quadwp_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], PIN_FUNC_GPIO); gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_INPUT_OUTPUT); gpio_matrix_out(bus_config->quadwp_io_num, io_signal[host].spiwp_out, false, false); gpio_matrix_in(bus_config->quadwp_io_num, io_signal[host].spiwp_in, false); } - if (use_quad && bus_config->quadhd_io_num >= 0) { + if (bus_config->quadhd_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], PIN_FUNC_GPIO); gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_INPUT_OUTPUT); gpio_matrix_out(bus_config->quadhd_io_num, io_signal[host].spihd_out, false, false); @@ -297,6 +343,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf //Select DMA channel. DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2)); + if (flags_o) *flags_o = temp_flag; return ESP_OK; } @@ -311,7 +358,6 @@ static void reset_func_to_gpio(int func) } } - esp_err_t spicommon_bus_free_io(spi_host_device_t host) { if (REG_GET_FIELD(GPIO_PIN_MUX_REG[io_signal[host].spid_native], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[io_signal[host].spid_native], PIN_FUNC_GPIO); diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 0fa5c9b31..4e6a51a5e 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -84,7 +84,7 @@ typedef struct { int prev_cs; lldesc_t *dmadesc_tx; lldesc_t *dmadesc_rx; - bool no_gpio_matrix; + uint32_t flags; int dma_chan; int max_transfer_sz; #ifdef CONFIG_PM_ENABLE @@ -121,7 +121,7 @@ static void spi_intr(void *arg); esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan) { - bool native, spi_chan_claimed, dma_chan_claimed; + bool spi_chan_claimed, dma_chan_claimed; esp_err_t ret = ESP_OK; esp_err_t err; /* ToDo: remove this when we have flash operations cooperating with this */ @@ -155,14 +155,13 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus goto cleanup; } #endif //CONFIG_PM_ENABLE - - err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER|SPICOMMON_BUSFLAG_QUAD, &native); + + err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER|bus_config->flags, &spihost[host]->flags); if (err != ESP_OK) { ret = err; goto cleanup; } - spihost[host]->no_gpio_matrix=native; - + spihost[host]->dma_chan=dma_chan; if (dma_chan == 0) { spihost[host]->max_transfer_sz = 32; @@ -294,7 +293,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_ //Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections. duty_cycle = (dev_config->duty_cycle_pos==0? 128: dev_config->duty_cycle_pos); eff_clk = spi_cal_clock(apbclk, dev_config->clock_speed_hz, duty_cycle, (uint32_t*)&clk_reg); - uint32_t dummy_limit = spi_dummy_limit(!spihost[host]->no_gpio_matrix); + uint32_t dummy_limit = spi_dummy_limit(!(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS)); SPI_CHECK( dev_config->flags & SPI_DEVICE_HALFDUPLEX || (eff_clk/1000/1000) < (dummy_limit/1000/1000) || dev_config->flags & SPI_DEVICE_NO_DUMMY, "When GPIO matrix is used in full-duplex mode at frequency > 26MHz, device cannot read correct data.\n\ @@ -327,7 +326,7 @@ Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output dat //Set CS pin, CS options if (dev_config->spics_io_num >= 0) { gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT); - spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, spihost[host]->no_gpio_matrix == false); + spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, !(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS)); } if (dev_config->flags&SPI_DEVICE_CLK_AS_CS) { spihost[host]->hw->pin.master_ck_sel |= (1<no_gpio_matrix) { + if ((host->flags&SPICOMMON_BUSFLAG_NATIVE_PINS)!=0) { if (effclk >= apbclk/2) { nodelay=1; } diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index 157829eeb..7ee2222e2 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -56,7 +56,7 @@ typedef struct { spi_slave_transaction_t *cur_trans; lldesc_t *dmadesc_tx; lldesc_t *dmadesc_rx; - bool no_gpio_matrix; + uint32_t flags; int max_transfer_sz; QueueHandle_t trans_queue; QueueHandle_t ret_queue; @@ -72,7 +72,7 @@ static void IRAM_ATTR spi_intr(void *arg); esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, int dma_chan) { - bool native, spi_chan_claimed, dma_chan_claimed; + bool spi_chan_claimed, dma_chan_claimed; esp_err_t ret = ESP_OK; esp_err_t err; //We only support HSPI/VSPI, period. @@ -98,14 +98,13 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b memset(spihost[host], 0, sizeof(spi_slave_t)); memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t)); - err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE, &native); + err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE|bus_config->flags, &spihost[host]->flags); if (err!=ESP_OK) { ret = err; goto cleanup; } gpio_set_direction(slave_config->spics_io_num, GPIO_MODE_INPUT); - spicommon_cs_initialize(host, slave_config->spics_io_num, 0, native == false); - spihost[host]->no_gpio_matrix = native; + spicommon_cs_initialize(host, slave_config->spics_io_num, 0, !(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS)); spihost[host]->dma_chan = dma_chan; if (dma_chan != 0) { //See how many dma descriptors we need and allocate them @@ -186,7 +185,6 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b spihost[host]->hw->ctrl2.miso_delay_mode = nodelay ? 0 : 2; } - //Reset DMA spihost[host]->hw->dma_conf.val |= SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST; spihost[host]->hw->dma_out_link.start = 0; diff --git a/components/driver/test/test_spi_master.c b/components/driver/test/test_spi_master.c index 2744ac564..da6d5a596 100644 --- a/components/driver/test/test_spi_master.c +++ b/components/driver/test/test_spi_master.c @@ -231,7 +231,7 @@ TEST_CASE("SPI Master test, interaction of multiple devs", "[spi][ignore]") { .clock_speed_hz=1000000, .duty_cycle_pos=128, .mode=0, - .spics_io_num=23, + .spics_io_num=23, .queue_size=3, }; spi_device_handle_t handle1=setup_spi_bus(80000, true); @@ -263,6 +263,156 @@ TEST_CASE("SPI Master test, interaction of multiple devs", "[spi][ignore]") { destroy_spi_bus(handle1); } +#define NATIVE_SCLK 14 +#define NATIVE_MISO 12 +#define NATIVE_MOSI 13 +#define NATIVE_WP 2 +#define NATIVE_HD 4 + +TEST_CASE("spi bus setting with different pin configs", "[spi]") +{ + spi_bus_config_t cfg; + uint32_t flags_o; + uint32_t flags_expected; + + ESP_LOGI(TAG, "test 6 native output pins..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_NATIVE_PINS | SPICOMMON_BUSFLAG_QUAD; + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + + ESP_LOGI(TAG, "test 4 native output pins..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_NATIVE_PINS | SPICOMMON_BUSFLAG_DUAL; + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = -1, .quadwp_io_num = -1, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + + ESP_LOGI(TAG, "test 6 output pins..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_QUAD; + //swap MOSI and MISO + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MISO, .miso_io_num = NATIVE_MOSI, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + + ESP_LOGI(TAG, "test 4 output pins..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_DUAL; + //swap MOSI and MISO + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MISO, .miso_io_num = NATIVE_MOSI, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = -1, .quadwp_io_num = -1, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + + ESP_LOGI(TAG, "test master 5 output pins and MOSI on input-only pin..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_WPHD; + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = 34, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + + ESP_LOGI(TAG, "test slave 5 output pins and MISO on input-only pin..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_WPHD; + cfg = (spi_bus_config_t){.mosi_io_num = 34, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + + ESP_LOGI(TAG, "test master 3 output pins and MOSI on input-only pin..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO; + + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = 34, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = -1, .quadwp_io_num = -1, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + + ESP_LOGI(TAG, "test slave 3 output pins and MISO on input-only pin..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO; + cfg = (spi_bus_config_t){.mosi_io_num = 34, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = -1, .quadwp_io_num = -1, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ESP_OK(spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o ); + + ESP_LOGI(TAG, "check native flag for 6 output pins..."); + flags_expected = SPICOMMON_BUSFLAG_NATIVE_PINS; + //swap MOSI and MISO + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MISO, .miso_io_num = NATIVE_MOSI, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + + ESP_LOGI(TAG, "check native flag for 4 output pins..."); + flags_expected = SPICOMMON_BUSFLAG_NATIVE_PINS; + //swap MOSI and MISO + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MISO, .miso_io_num = NATIVE_MOSI, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = -1, .quadwp_io_num = -1, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + + ESP_LOGI(TAG, "check dual flag for master 5 output pins and MISO/MOSI on input-only pin..."); + flags_expected = SPICOMMON_BUSFLAG_DUAL; + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = 34, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + cfg = (spi_bus_config_t){.mosi_io_num = 34, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + + ESP_LOGI(TAG, "check dual flag for master 3 output pins and MISO/MOSI on input-only pin..."); + flags_expected = SPICOMMON_BUSFLAG_DUAL; + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = 34, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = -1, .quadwp_io_num = -1, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + cfg = (spi_bus_config_t){.mosi_io_num = 34, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = -1, .quadwp_io_num = -1, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + + ESP_LOGI(TAG, "check sclk flag..."); + flags_expected = SPICOMMON_BUSFLAG_SCLK; + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = NATIVE_MISO, .sclk_io_num = -1, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + + ESP_LOGI(TAG, "check mosi flag..."); + flags_expected = SPICOMMON_BUSFLAG_MOSI; + cfg = (spi_bus_config_t){.mosi_io_num = -1, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + + ESP_LOGI(TAG, "check miso flag..."); + flags_expected = SPICOMMON_BUSFLAG_MISO; + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = -1, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + + ESP_LOGI(TAG, "check quad flag..."); + flags_expected = SPICOMMON_BUSFLAG_QUAD; + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = -1, .quadwp_io_num = NATIVE_WP, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); + cfg = (spi_bus_config_t){.mosi_io_num = NATIVE_MOSI, .miso_io_num = NATIVE_MISO, .sclk_io_num = NATIVE_SCLK, .quadhd_io_num = NATIVE_HD, .quadwp_io_num = -1, + .max_transfer_sz = 8, .flags = flags_expected}; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(HSPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o)); +} + TEST_CASE("SPI Master no response when switch from host1 (HSPI) to host2 (VSPI)", "[spi]") { //spi config