From f7e91ef6c15a5de664709b5ddf8824fd695e305a Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 8 Sep 2020 17:05:49 +0800 Subject: [PATCH] spi: esp32s3 bringup for spi --- components/driver/CMakeLists.txt | 5 + .../include/driver/spi_common_internal.h | 8 + components/driver/spi_common.c | 55 +- components/driver/spi_master.c | 4 +- components/driver/spi_slave.c | 2 + components/driver/spi_slave_hd.c | 2 + .../test/include/test/test_common_spi.h | 3 +- components/driver/test/test_common_spi.c | 6 +- components/driver/test/test_spi_bus_lock.c | 8 +- components/driver/test/test_spi_master.c | 10 +- components/driver/test/test_spi_param.c | 14 +- components/driver/test/test_spi_slave.c | 12 +- components/driver/test/test_spi_slave_hd.c | 41 +- .../include/essl_spi/esp32s3_defs.h | 38 + components/hal/CMakeLists.txt | 1 + components/hal/esp32/include/hal/spi_ll.h | 14 +- components/hal/esp32s2/include/hal/spi_ll.h | 14 +- components/hal/esp32s3/include/hal/spi_ll.h | 695 ++++++++++++------ components/hal/spi_hal.c | 18 +- components/hal/spi_hal_iram.c | 14 +- components/hal/spi_slave_hal.c | 18 +- components/hal/spi_slave_hal_iram.c | 18 +- components/hal/spi_slave_hd_hal.c | 11 +- .../soc/soc/esp32s3/include/soc/gdma_struct.h | 2 + .../soc/soc/esp32s3/include/soc/spi_caps.h | 3 +- .../soc/soc/esp32s3/include/soc/spi_struct.h | 2 +- 26 files changed, 675 insertions(+), 343 deletions(-) create mode 100644 components/esp_serial_slave_link/include/essl_spi/esp32s3_defs.h diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 40f5082388..5e6912e77d 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -49,6 +49,11 @@ if(${target} STREQUAL "esp32s2") list(APPEND includes "esp32s2/include") endif() +if(${target} STREQUAL "esp32s3") + list(APPEND srcs "spi_slave_hd.c" + ) +endif() + idf_component_register(SRCS "${srcs}" INCLUDE_DIRS ${includes} PRIV_INCLUDE_DIRS "include/driver" diff --git a/components/driver/include/driver/spi_common_internal.h b/components/driver/include/driver/spi_common_internal.h index 48b00166e6..51c7e01f2e 100644 --- a/components/driver/include/driver/spi_common_internal.h +++ b/components/driver/include/driver/spi_common_internal.h @@ -150,6 +150,14 @@ bool spicommon_dma_chan_in_use(int dma_chan); */ bool spicommon_dma_chan_free(int dma_chan); +/** + * @brief Connect SPI and DMA peripherals + * + * @param host SPI peripheral + * @param dma_chan DMA channel + */ +void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan); + /** * @brief Connect a SPI peripheral to GPIO pins * diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index 59280896bd..32b30b69a8 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -22,6 +22,7 @@ #include "esp_log.h" #include "esp_err.h" #include "soc/soc.h" +#include "soc/soc_caps.h" #include "soc/dport_reg.h" #include "soc/lldesc.h" #include "driver/gpio.h" @@ -32,6 +33,15 @@ #include "hal/spi_hal.h" #include "esp_rom_gpio.h" +//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. +#if SOC_GDMA_SUPPORTED +#include "hal/gdma_ll.h" + +#define spi_dma_set_rx_channel_priority(gdma_chan, priority) gdma_ll_rx_set_priority(&GDMA, gdma_chan, priority); +#define spi_dma_set_tx_channel_priority(gdma_chan, priority) gdma_ll_tx_set_priority(&GDMA, gdma_chan, priority); +#define spi_dma_connect_rx_channel_to_periph(gdma_chan, periph_id) gdma_ll_rx_connect_to_periph(&GDMA, gdma_chan, periph_id); +#define spi_dma_connect_tx_channel_to_periph(gdma_chan, periph_id) gdma_ll_tx_connect_to_periph(&GDMA, gdma_chan, periph_id); +#endif static const char *SPI_TAG = "spi"; @@ -114,7 +124,6 @@ bool spicommon_periph_free(spi_host_device_t host) return ret; } - int spicommon_irqsource_for_host(spi_host_device_t host) { return spi_periph_signal[host].irq; @@ -143,7 +152,7 @@ static inline uint32_t get_dma_periph(int dma_chan) #endif } -bool spicommon_dma_chan_claim (int dma_chan) +bool spicommon_dma_chan_claim(int dma_chan) { bool ret = false; assert(dma_chan >= 1 && dma_chan <= SOC_SPI_DMA_CHAN_NUM); @@ -163,6 +172,8 @@ bool spicommon_dma_chan_claim (int dma_chan) } else if (dma_chan==2) { periph_module_enable(PERIPH_SPI3_DMA_MODULE); } +#elif SOC_GDMA_SUPPORTED + periph_module_enable(PERIPH_GDMA_MODULE); #endif portEXIT_CRITICAL(&spi_dma_spinlock); @@ -171,7 +182,7 @@ bool spicommon_dma_chan_claim (int dma_chan) bool spicommon_dma_chan_in_use(int dma_chan) { - assert(dma_chan==1 || dma_chan == 2); + assert(dma_chan ==1 || dma_chan == 2); return spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan); } @@ -193,12 +204,39 @@ bool spicommon_dma_chan_free(int dma_chan) } else if (dma_chan==2) { periph_module_disable(PERIPH_SPI3_DMA_MODULE); } +#elif SOC_GDMA_SUPPORTED + periph_module_disable(PERIPH_GDMA_MODULE); #endif portEXIT_CRITICAL(&spi_dma_spinlock); return true; } +void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan) +{ +#if CONFIG_IDF_TARGET_ESP32 + DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2)); +#elif CONFIG_IDF_TARGET_ESP32S2 + //On ESP32S2, each SPI controller has its own DMA channel. So there is no need to connect them. +#elif SOC_GDMA_SUPPORTED + int gdma_chan, periph_id; + if (dma_chan == 1) { + gdma_chan = SOC_GDMA_SPI2_DMA_CHANNEL; + periph_id = GDMA_LL_TRIG_SRC_SPI2; + } else if (dma_chan == 2) { + gdma_chan = SOC_GDMA_SPI3_DMA_CHANNEL; + periph_id = GDMA_LL_TRIG_SRC_SPI3; + } else { + abort(); + } + + spi_dma_connect_rx_channel_to_periph(gdma_chan, periph_id); + spi_dma_connect_tx_channel_to_periph(gdma_chan, periph_id); + spi_dma_set_rx_channel_priority(gdma_chan, 1); + spi_dma_set_tx_channel_priority(gdma_chan, 1); +#endif +} + static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config) { if (bus_config->sclk_io_num>=0 && @@ -222,7 +260,7 @@ 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, uint32_t flags, uint32_t* flags_o) { - uint32_t temp_flag=0; + uint32_t temp_flag = 0; bool miso_need_output; bool mosi_need_output; @@ -378,11 +416,6 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf } } - //Select DMA channel. -#if CONFIG_IDF_TARGET_ESP32 - DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2)); -#endif - if (flags_o) *flags_o = temp_flag; return ESP_OK; } @@ -481,11 +514,13 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * SPI_CHECK(spi_chan_claimed, "host_id already in use", ESP_ERR_INVALID_STATE); if (dma_chan != 0) { - bool dma_chan_claimed=spicommon_dma_chan_claim(dma_chan); + bool dma_chan_claimed = spicommon_dma_chan_claim(dma_chan); if (!dma_chan_claimed) { spicommon_periph_free(host_id); SPI_CHECK(false, "dma channel already in use", ESP_ERR_INVALID_STATE); } + + spicommon_connect_spi_and_dma(host_id, dma_chan); } //clean and initialize the context diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index c0caa3a3d4..8c0d7d143f 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -693,6 +693,8 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && !is_half_duplex), "incompatible iface params", ESP_ERR_INVALID_ARG); #ifdef CONFIG_IDF_TARGET_ESP32 SPI_CHECK(!is_half_duplex || bus_attr->dma_chan == 0 || !rx_enabled || !tx_enabled, "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG ); +#elif CONFIG_IDF_TARGET_ESP32S3 + SPI_CHECK(!is_half_duplex || !tx_enabled || !rx_enabled, "SPI half duplex mode is not supported when both MOSI and MISO phases are enabled.", ESP_ERR_INVALID_ARG); #endif //MOSI phase is skipped only when both tx_buffer and SPI_TRANS_USE_TXDATA are not set. SPI_CHECK(trans_desc->length != 0 || !tx_enabled, "trans tx_buffer should be NULL and SPI_TRANS_USE_TXDATA should be cleared to skip MOSI phase.", ESP_ERR_INVALID_ARG); @@ -706,7 +708,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl } //Dummy phase is not available when both data out and in are enabled, regardless of FD or HD mode. SPI_CHECK(!tx_enabled || !rx_enabled || !dummy_enabled || !extra_dummy_enabled, "Dummy phase is not available when both data out and in are enabled", ESP_ERR_INVALID_ARG); - + return ESP_OK; } diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index 7e1882c3d0..9bf15965d7 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -137,6 +137,8 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b spicommon_periph_free( host ); SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE); } + + spicommon_connect_spi_and_dma(host, dma_chan); } spihost[host] = malloc(sizeof(spi_slave_t)); diff --git a/components/driver/spi_slave_hd.c b/components/driver/spi_slave_hd.c index c182e7983e..f7fab57dd0 100644 --- a/components/driver/spi_slave_hd.c +++ b/components/driver/spi_slave_hd.c @@ -77,6 +77,8 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b spicommon_periph_free(host_id); SPIHD_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE); } + + spicommon_connect_spi_and_dma(host_id, config->dma_chan); } spi_slave_hd_slot_t* host = malloc(sizeof(spi_slave_hd_slot_t)); diff --git a/components/driver/test/include/test/test_common_spi.h b/components/driver/test/include/test/test_common_spi.h index 631cada52b..f2cf965265 100644 --- a/components/driver/test/include/test/test_common_spi.h +++ b/components/driver/test/include/test/test_common_spi.h @@ -49,7 +49,7 @@ #define ESP_SPI_SLAVE_TV (12.5*3.5) #define WIRE_DELAY 12.5 -#elif CONFIG_IDF_TARGET_ESP32S2 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #define TEST_SPI_HOST FSPI_HOST #define TEST_SLAVE_HOST HSPI_HOST @@ -58,6 +58,7 @@ #define PIN_NUM_MOSI FSPI_IOMUX_PIN_NUM_MOSI #define PIN_NUM_CLK FSPI_IOMUX_PIN_NUM_CLK #define PIN_NUM_CS FSPI_IOMUX_PIN_NUM_CS + #define PIN_NUM_WP FSPI_IOMUX_PIN_NUM_WP #define PIN_NUM_HD FSPI_IOMUX_PIN_NUM_HD diff --git a/components/driver/test/test_common_spi.c b/components/driver/test/test_common_spi.c index 07ca8c7584..59bfc49e3e 100644 --- a/components/driver/test/test_common_spi.c +++ b/components/driver/test/test_common_spi.c @@ -3,8 +3,6 @@ #include "esp_log.h" #include "driver/gpio.h" -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3) - int test_freq_default[]=TEST_FREQ_DEFAULT(); const char MASTER_TAG[] = "test_master"; @@ -206,6 +204,4 @@ void spitest_gpio_output_sel(uint32_t gpio_num, int func, uint32_t signal_idx) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], func); GPIO.func_out_sel_cfg[gpio_num].func_sel=signal_idx; -} - -#endif +} \ No newline at end of file diff --git a/components/driver/test/test_spi_bus_lock.c b/components/driver/test/test_spi_bus_lock.c index 0e41c63a2d..855c834b8c 100644 --- a/components/driver/test/test_spi_bus_lock.c +++ b/components/driver/test/test_spi_bus_lock.c @@ -18,7 +18,7 @@ #define TEST_BUS_PIN_NUM_WP VSPI_IOMUX_PIN_NUM_WP #define TEST_BUS_PIN_NUM_HD VSPI_IOMUX_PIN_NUM_HD -#elif CONFIG_IDF_TARGET_ESP32S2 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #define TEST_BUS_PIN_NUM_MISO FSPI_IOMUX_PIN_NUM_MISO #define TEST_BUS_PIN_NUM_MOSI FSPI_IOMUX_PIN_NUM_MOSI #define TEST_BUS_PIN_NUM_CLK FSPI_IOMUX_PIN_NUM_CLK @@ -256,9 +256,9 @@ static void test_bus_lock(bool test_flash) } ESP_LOGI(TAG, "Start testing..."); - xTaskCreate( spi_task1, "task1", 2048, &context1, 0, &task1 ); - xTaskCreate( spi_task2, "task2", 2048, &context2, 0, &task2 ); - xTaskCreate( spi_task3, "task3", 2048, &context3, 0, &task3 ); + xTaskCreate( spi_task1, "task1", 4096, &context1, 0, &task1 ); + xTaskCreate( spi_task2, "task2", 4096, &context2, 0, &task2 ); + xTaskCreate( spi_task3, "task3", 4096, &context3, 0, &task3 ); if (test_flash) { xTaskCreate( spi_task4, "task4", 2048, &context4, 0, &task4 ); } else { diff --git a/components/driver/test/test_spi_master.c b/components/driver/test/test_spi_master.c index ccc6270190..6a8ba2b5e7 100644 --- a/components/driver/test/test_spi_master.c +++ b/components/driver/test/test_spi_master.c @@ -26,8 +26,6 @@ #include "soc/soc_memory_layout.h" #include "driver/spi_common_internal.h" -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3) - const static char TAG[] = "test_spi"; static void check_spi_pre_n_for(int clk, int pre, int n) @@ -757,7 +755,7 @@ void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first) int addr_bits = #ifdef CONFIG_IDF_TARGET_ESP32 56-8*i; -#elif CONFIG_IDF_TARGET_ESP32S2 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 //ESP32S2 only supportes up to 32 bits address 28-4*i; #endif @@ -957,6 +955,8 @@ TEST_CASE("SPI master variable dummy test", "[spi]") #define GET_US_BY_CCOUNT(t) ((double)t/CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) #elif CONFIG_IDF_TARGET_ESP32S2 #define GET_US_BY_CCOUNT(t) ((double)t/CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ) +#elif CONFIG_IDF_TARGET_ESP32S3 +#define GET_US_BY_CCOUNT(t) ((double)t/CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ) #endif static void speed_setup(spi_device_handle_t* spi, bool use_dma) @@ -1094,6 +1094,4 @@ TEST_CASE("spi_speed","[spi]") spi_device_release_bus(spi); master_free_device_bus(spi); } -#endif - -#endif +#endif \ No newline at end of file diff --git a/components/driver/test/test_spi_param.c b/components/driver/test/test_spi_param.c index 68fb60c054..02e20e867c 100644 --- a/components/driver/test/test_spi_param.c +++ b/components/driver/test/test_spi_param.c @@ -6,8 +6,6 @@ #include "test/test_common_spi.h" #include "sdkconfig.h" -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3) - #ifndef MIN #define MIN(a, b)((a) > (b)? (b): (a)) #endif @@ -224,7 +222,7 @@ static void local_test_loop(const void* arg1, void* arg2) //TODO: esp32s2 has better timing performance static spitest_param_set_t timing_pgroup[] = { //signals are not fed to peripherals through iomux if the functions are not selected to iomux -#if !DISABLED_FOR_TARGETS(ESP32S2) +#if !DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) { .pset_name = "FULL_DUP, MASTER IOMUX", .freq_limit = ESP_SPI_SLAVE_MAX_FREQ_SYNC, .master_limit = SPI_MASTER_FREQ_13M, @@ -251,7 +249,7 @@ static spitest_param_set_t timing_pgroup[] = { .slave_tv_ns = TV_INT_CONNECT_GPIO, }, //signals are not fed to peripherals through iomux if the functions are not selected to iomux -#if !DISABLED_FOR_TARGETS(ESP32S2) +#if !DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) { .pset_name = "MISO_DUP, MASTER IOMUX", .freq_limit = ESP_SPI_SLAVE_MAX_FREQ_SYNC, .master_limit = ESP_SPI_SLAVE_MAX_FREQ_SYNC, @@ -278,7 +276,7 @@ static spitest_param_set_t timing_pgroup[] = { .slave_tv_ns = TV_INT_CONNECT_GPIO, }, //signals are not fed to peripherals through iomux if the functions are not selected to iomux -#if !DISABLED_FOR_TARGETS(ESP32S2) +#if !DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) { .pset_name = "MOSI_DUP, MASTER IOMUX", .freq_limit = ESP_SPI_SLAVE_MAX_FREQ_SYNC, //.freq_limit = ESP_SPI_SLAVE_MAX_READ_FREQ, //ESP_SPI_SLAVE_MAX_FREQ_SYNC, @@ -615,7 +613,7 @@ TEST_CASE("Slave receive correct data", "[spi]") } } -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2) +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3) //These tests are ESP32 only due to lack of runners /******************************************************************************** * Test By Master & Slave (2 boards) @@ -1165,6 +1163,4 @@ spitest_param_set_t mode_conf[] = { }; TEST_SPI_MASTER_SLAVE(MODE, mode_conf, "") -#endif - -#endif +#endif \ No newline at end of file diff --git a/components/driver/test/test_spi_slave.c b/components/driver/test/test_spi_slave.c index 925b7f0a8e..c23086c9a1 100644 --- a/components/driver/test/test_spi_slave.c +++ b/components/driver/test/test_spi_slave.c @@ -12,15 +12,13 @@ #include "test/test_common_spi.h" #include "esp_rom_gpio.h" -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3) - #ifndef CONFIG_SPIRAM //This test should be removed once the timing test is merged. - #define MASTER_SEND {0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43} #define SLAVE_SEND { 0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 } + static inline void int_connect( uint32_t gpio, uint32_t sigo, uint32_t sigi ) { esp_rom_gpio_connect_out_signal( gpio, sigo, false, false ); @@ -92,7 +90,7 @@ TEST_CASE("test slave send unaligned","[spi]") //do internal connection int_connect( PIN_NUM_MOSI, spi_periph_signal[TEST_SPI_HOST].spid_out, spi_periph_signal[TEST_SLAVE_HOST].spiq_in ); - int_connect( PIN_NUM_MISO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out, spi_periph_signal[TEST_SPI_HOST].spid_in ); + int_connect( PIN_NUM_MISO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out, spi_periph_signal[TEST_SPI_HOST].spid_in ); int_connect( PIN_NUM_CS, spi_periph_signal[TEST_SPI_HOST].spics_out[0], spi_periph_signal[TEST_SLAVE_HOST].spics_in ); int_connect( PIN_NUM_CLK, spi_periph_signal[TEST_SPI_HOST].spiclk_out, spi_periph_signal[TEST_SLAVE_HOST].spiclk_in ); @@ -104,6 +102,7 @@ TEST_CASE("test slave send unaligned","[spi]") slave_t.length=8*32; slave_t.tx_buffer=slave_txbuf+i; slave_t.rx_buffer=slave_rxbuf; + TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_t, portMAX_DELAY)); //send @@ -127,7 +126,6 @@ TEST_CASE("test slave send unaligned","[spi]") TEST_ASSERT_EQUAL_HEX8_ARRAY( t.tx_buffer, slave_t.rx_buffer, t.length/8 ); TEST_ASSERT_EQUAL_HEX8_ARRAY( slave_t.tx_buffer, t.rx_buffer, t.length/8 ); - TEST_ASSERT_EQUAL( t.length, slave_t.trans_len ); //clean @@ -143,6 +141,4 @@ TEST_CASE("test slave send unaligned","[spi]") ESP_LOGI(MASTER_TAG, "test passed."); } -#endif // !CONFIG_SPIRAM - -#endif \ No newline at end of file +#endif // !CONFIG_SPIRAM \ No newline at end of file diff --git a/components/driver/test/test_spi_slave_hd.c b/components/driver/test/test_spi_slave_hd.c index e978841e4c..6f4b823dd5 100644 --- a/components/driver/test/test_spi_slave_hd.c +++ b/components/driver/test/test_spi_slave_hd.c @@ -13,12 +13,10 @@ #if SOC_SPI_SUPPORT_SLAVE_HD_VER2 #include "driver/spi_slave_hd.h" - +#include "esp_rom_gpio.h" #include "unity.h" #include "test/test_common_spi.h" -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3) - #define TEST_DMA_MAX_SIZE 14000 #define TEST_BUFFER_SIZE 256 ///< buffer size of each wrdma buffer in fifo mode #define TEST_SEG_SIZE 25 @@ -72,6 +70,21 @@ static uint32_t get_hd_flags(void) } } +void config_single_board_test_pin(void) +{ + esp_rom_gpio_connect_out_signal(PIN_NUM_MOSI, spi_periph_signal[TEST_SPI_HOST].spid_out, 0, 0); + esp_rom_gpio_connect_in_signal(PIN_NUM_MOSI, spi_periph_signal[TEST_SLAVE_HOST].spid_in, 0); + + esp_rom_gpio_connect_out_signal(PIN_NUM_MISO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out, 0, 0); + esp_rom_gpio_connect_in_signal(PIN_NUM_MISO, spi_periph_signal[TEST_SPI_HOST].spiq_in, 0); + + esp_rom_gpio_connect_out_signal(PIN_NUM_CS, spi_periph_signal[TEST_SPI_HOST].spics_out[0], 0, 0); + esp_rom_gpio_connect_in_signal(PIN_NUM_CS, spi_periph_signal[TEST_SLAVE_HOST].spics_in, 0); + + esp_rom_gpio_connect_out_signal(PIN_NUM_CLK, spi_periph_signal[TEST_SPI_HOST].spiclk_out, 0, 0); + esp_rom_gpio_connect_in_signal(PIN_NUM_CLK, spi_periph_signal[TEST_SLAVE_HOST].spiclk_in, 0); +} + static void init_master_hd(spi_device_handle_t* spi, const spitest_param_set_t* config, int freq) { spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG(); @@ -196,10 +209,8 @@ static void test_hd_start(spi_device_handle_t *spi, int freq, const spitest_para }; init_slave_hd(cfg->mode, &callback); - spitest_gpio_output_sel(PIN_NUM_MOSI, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out); - spitest_gpio_output_sel(PIN_NUM_MISO, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out); - spitest_gpio_output_sel(PIN_NUM_CS, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spics_out[0]); - spitest_gpio_output_sel(PIN_NUM_CLK, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spiclk_out); + //when test with single board via same set of mosi, miso, clk and cs pins. + config_single_board_test_pin(); wait_wrbuf_sig(ctx, 0); wait_rdbuf_sig(ctx, 0); @@ -232,7 +243,7 @@ static void test_hd_start(spi_device_handle_t *spi, int freq, const spitest_para } -#define REG_REGION_SIZE 4*18 +#define REG_REGION_SIZE SOC_SPI_MAXIMUM_BUFFER_SIZE void check_no_signal(testhd_context_t* context) { @@ -358,8 +369,8 @@ static void test_hd_loop(const void* arg1, void* arg2) wait_rdbuf_sig(context, portMAX_DELAY); ESP_LOGI("mem", "pos: %d, len: %d", pos, len); - //ESP_LOG_BUFFER_HEX("recv_buffer", recv_buffer, len); - //ESP_LOG_BUFFER_HEX("mem", &mem_ptr[pos], len); + // ESP_LOG_BUFFER_HEX("recv_buffer", recv_buffer, len); + // ESP_LOG_BUFFER_HEX("mem", &mem_ptr[pos], len); TEST_ASSERT_EQUAL_HEX8_ARRAY(&mem_ptr[pos], recv_buffer, len); } @@ -490,10 +501,8 @@ TEST_CASE("test spi slave hd continuous mode, master too long", "[spi][spi_slv_h //no callback needed init_slave_hd(cfg->mode, NULL); - spitest_gpio_output_sel(PIN_NUM_MOSI, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out); - spitest_gpio_output_sel(PIN_NUM_MISO, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out); - spitest_gpio_output_sel(PIN_NUM_CS, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spics_out[0]); - spitest_gpio_output_sel(PIN_NUM_CLK, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spiclk_out); + //Use GPIO matrix to connect signal of master and slave via same set of pins on one board. + config_single_board_test_pin(); const int send_buf_size = 1024; @@ -574,6 +583,4 @@ TEST_CASE("test spi slave hd continuous mode, master too long", "[spi][spi_slv_h master_free_device_bus(spi); } -#endif //SOC_SPI_SUPPORT_SLAVE_HD_VER2 - -#endif +#endif //SOC_SPI_SUPPORT_SLAVE_HD_VER2 \ No newline at end of file diff --git a/components/esp_serial_slave_link/include/essl_spi/esp32s3_defs.h b/components/esp_serial_slave_link/include/essl_spi/esp32s3_defs.h new file mode 100644 index 0000000000..1de97d642b --- /dev/null +++ b/components/esp_serial_slave_link/include/essl_spi/esp32s3_defs.h @@ -0,0 +1,38 @@ +// Copyright 2010-2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#pragma once + +// NOTE: From the view of master +#define CMD_HD_WRBUF_REG 0x01 +#define CMD_HD_RDBUF_REG 0x02 +#define CMD_HD_WRDMA_REG 0x03 +#define CMD_HD_RDDMA_REG 0x04 + +#define CMD_HD_ONEBIT_MODE 0x00 +#define CMD_HD_DOUT_MODE 0x10 +#define CMD_HD_QOUT_MODE 0x20 +#define CMD_HD_DIO_MODE 0x50 +#define CMD_HD_QIO_MODE 0xA0 + +#define CMD_HD_SEG_END_REG 0x05 +#define CMD_HD_EN_QPI_REG 0x06 +#define CMD_HD_WR_END_REG 0x07 +#define CMD_HD_INT0_REG 0x08 +#define CMD_HD_INT1_REG 0x09 +#define CMD_HD_INT2_REG 0x0A +#define CMD_HD_EX_QPI_REG 0xDD + +#define SPI_SLAVE_HD_BUFFER_SIZE 64 \ No newline at end of file diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 27db8c6f24..be693fe318 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -64,6 +64,7 @@ if(NOT BOOTLOADER_BUILD) if(${target} STREQUAL "esp32s3") list(APPEND srcs "spi_flash_hal_gpspi.c" + "spi_slave_hd_hal.c" "esp32s3/brownout_hal.c" "esp32s3/systimer_hal.c" "esp32s3/touch_sensor_hal.c") diff --git a/components/hal/esp32/include/hal/spi_ll.h b/components/hal/esp32/include/hal/spi_ll.h index dd2b1d467c..9c410d3de3 100644 --- a/components/hal/esp32/include/hal/spi_ll.h +++ b/components/hal/esp32/include/hal/spi_ll.h @@ -121,11 +121,21 @@ static inline bool spi_ll_usr_is_done(spi_dev_t *hw) } /** - * Trigger start of user-defined transaction. + * Trigger start of user-defined transaction for master. * * @param hw Beginning address of the peripheral registers. */ -static inline void spi_ll_user_start(spi_dev_t *hw) +static inline void spi_ll_master_user_start(spi_dev_t *hw) +{ + hw->cmd.usr = 1; +} + +/** + * Trigger start of user-defined transaction for slave. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_user_start(spi_dev_t *hw) { hw->cmd.usr = 1; } diff --git a/components/hal/esp32s2/include/hal/spi_ll.h b/components/hal/esp32s2/include/hal/spi_ll.h index 0506ed6b72..e05b3ef0c9 100644 --- a/components/hal/esp32s2/include/hal/spi_ll.h +++ b/components/hal/esp32s2/include/hal/spi_ll.h @@ -166,11 +166,21 @@ static inline bool spi_ll_usr_is_done(spi_dev_t *hw) } /** - * Trigger start of user-defined transaction. + * Trigger start of user-defined transaction for master. * * @param hw Beginning address of the peripheral registers. */ -static inline void spi_ll_user_start(spi_dev_t *hw) +static inline void spi_ll_master_user_start(spi_dev_t *hw) +{ + hw->cmd.usr = 1; +} + +/** + * Trigger start of user-defined transaction for slave. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_user_start(spi_dev_t *hw) { hw->cmd.usr = 1; } diff --git a/components/hal/esp32s3/include/hal/spi_ll.h b/components/hal/esp32s3/include/hal/spi_ll.h index c9be4dfd47..3cd81b3e97 100644 --- a/components/hal/esp32s3/include/hal/spi_ll.h +++ b/components/hal/esp32s3/include/hal/spi_ll.h @@ -28,13 +28,18 @@ #include "esp_types.h" #include "soc/spi_periph.h" #include "esp32s3/rom/lldesc.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif /// Registers to reset during initialization. Don't use in app. -#define SPI_LL_RST_MASK (SPI_DMA_AFIFO_RST | SPI_BUF_AFIFO_RST | SPI_RX_AFIFO_RST) +#define SPI_LL_CPU_FIFO_RST_MASK (SPI_BUF_AFIFO_RST | SPI_RX_AFIFO_RST) +/// Registers to reset during initialization. Don't use in app. +#define SPI_LL_DMA_FIFO_RST_MASK (SPI_DMA_AFIFO_RST | SPI_RX_AFIFO_RST) + + /// Interrupt not used. Don't use in app. #define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA) /// Swap the bit order to its correct place to send @@ -59,12 +64,29 @@ typedef enum { SPI_LL_IO_MODE_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases } spi_ll_io_mode_t; -/// Interrupt type for different working pattern +// Type definition of all supported interrupts typedef enum { - SPI_LL_INT_TYPE_NORMAL = 0, ///< Typical pattern, only wait for trans done - SPI_LL_INT_TYPE_SEG = 1, ///< Wait for DMA signals -} spi_ll_slave_intr_type; + SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done + SPI_LL_INTR_RDBUF = BIT(6), ///< Has received RDBUF command. Only available in slave HD. + SPI_LL_INTR_WRBUF = BIT(7), ///< Has received WRBUF command. Only available in slave HD. + SPI_LL_INTR_RDDMA = BIT(8), ///< Has received RDDMA command. Only available in slave HD. + SPI_LL_INTR_WRDMA = BIT(9), ///< Has received WRDMA command. Only available in slave HD. + SPI_LL_INTR_WR_DONE = BIT(10), ///< Has received WR_DONE command. Only available in slave HD. + SPI_LL_INTR_CMD8 = BIT(11), ///< Has received CMD8 command. Only available in slave HD. + SPI_LL_INTR_CMD9 = BIT(12), ///< Has received CMD9 command. Only available in slave HD. + SPI_LL_INTR_CMDA = BIT(13), ///< Has received CMDA command. Only available in slave HD. + SPI_LL_INTR_SEG_DONE = BIT(14), +} spi_ll_intr_t; +FLAG_ATTR(spi_ll_intr_t) +// Flags for conditions under which the transaction length should be recorded +typedef enum { + SPI_LL_TRANS_LEN_COND_WRBUF = BIT(0), ///< WRBUF length will be recorded + SPI_LL_TRANS_LEN_COND_RDBUF = BIT(1), ///< RDBUF length will be recorded + SPI_LL_TRANS_LEN_COND_WRDMA = BIT(2), ///< WRDMA length will be recorded + SPI_LL_TRANS_LEN_COND_RDDMA = BIT(3), ///< RDDMA length will be recorded +} spi_ll_trans_len_cond_t; +FLAG_ATTR(spi_ll_trans_len_cond_t) /*------------------------------------------------------------------------------ * Control @@ -76,17 +98,26 @@ typedef enum { */ static inline void spi_ll_master_init(spi_dev_t *hw) { - //Reset DMA - hw->dma_conf.val |= SPI_LL_RST_MASK; - hw->dma_conf.val &= ~SPI_LL_RST_MASK; + //Reset timing + hw->user1.cs_setup_time = 0; + hw->user1.cs_hold_time = 0; //use all 64 bytes of the buffer hw->user.usr_miso_highpart = 0; hw->user.usr_mosi_highpart = 0; //Disable unneeded ints - hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK; + hw->slave.val = 0; + hw->user.val = 0; + hw->clk_gate.clk_en = 1; + hw->clk_gate.mst_clk_active = 1; + hw->clk_gate.mst_clk_sel = 1; + + hw->dma_conf.val = 0; + hw->dma_conf.tx_seg_trans_clr_en = 1; + hw->dma_conf.rx_seg_trans_clr_en = 1; + hw->dma_conf.dma_seg_trans_en = 0; } /** @@ -103,51 +134,181 @@ static inline void spi_ll_slave_init(spi_dev_t *hw) hw->user.doutdin = 1; //we only support full duplex hw->user.sio = 0; hw->slave.slave_mode = 1; - hw->dma_conf.val &= ~SPI_LL_RST_MASK; + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; //use all 64 bytes of the buffer hw->user.usr_miso_highpart = 0; hw->user.usr_mosi_highpart = 0; + hw->dma_conf.dma_seg_trans_en = 0; + //Disable unneeded ints hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK; - hw->dma_int_ena.val = 0; } /** - * Reset TX and RX DMAs. + * Initialize SPI peripheral (slave half duplex mode) + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_slave_hd_init(spi_dev_t *hw) +{ + hw->clock.val = 0; + hw->user.val = 0; + hw->ctrl.val = 0; + hw->user.doutdin = 0; + hw->user.sio = 0; + + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; + hw->slave.slave_mode = 1; +} + +/** + * Check whether user-defined transaction is done. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if transaction is done, otherwise false. + */ +static inline bool spi_ll_usr_is_done(spi_dev_t *hw) +{ + return hw->dma_int_raw.trans_done; +} + +/** + * Trigger start of user-defined transaction for master. + * The synchronization between two clock domains is required in ESP32-S3 * * @param hw Beginning address of the peripheral registers. */ -static inline void spi_ll_reset_dma(spi_dev_t *hw) +static inline void spi_ll_master_user_start(spi_dev_t *hw) { + hw->cmd.update = 1; + while (hw->cmd.update); + hw->cmd.usr = 1; } /** - * Start RX DMA. + * Trigger start of user-defined transaction for slave. * * @param hw Beginning address of the peripheral registers. - * @param addr Address of the beginning DMA descriptor. */ -static inline void spi_ll_rxdma_start(spi_dev_t *hw, lldesc_t *addr) +static inline void spi_ll_slave_user_start(spi_dev_t *hw) { + hw->cmd.usr = 1; } /** - * Start TX DMA. + * Get current running command bit-mask. (Preview) * * @param hw Beginning address of the peripheral registers. - * @param addr Address of the beginning DMA descriptor. + * + * @return Bitmask of running command, see ``SPI_CMD_REG``. 0 if no in-flight command. */ -static inline void spi_ll_txdma_start(spi_dev_t *hw, lldesc_t *addr) +static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw) { + return hw->cmd.val; } /** - * Write to SPI buffer. + * Reset the slave peripheral before next transaction. * * @param hw Beginning address of the peripheral registers. - * @param buffer_to_send Data address to copy to the buffer. - * @param bitlen Length to copy, in bits. + */ +static inline void spi_ll_slave_reset(spi_dev_t *hw) +{ + hw->slave.soft_reset = 1; + hw->slave.soft_reset = 0; +} + +/** + * Reset SPI CPU FIFO + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_cpu_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.val |= SPI_LL_CPU_FIFO_RST_MASK; + hw->dma_conf.val &= ~SPI_LL_CPU_FIFO_RST_MASK; +} + +/** + * Reset SPI DMA FIFO + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_dma_fifo_reset(spi_dev_t *hw) +{ + hw->dma_conf.val |= SPI_LL_DMA_FIFO_RST_MASK; + hw->dma_conf.val &= ~SPI_LL_DMA_FIFO_RST_MASK; +} + +/** + * Clear in fifo full error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_infifo_full_clr(spi_dev_t *hw) +{ + hw->dma_int_clr.infifo_full_err = 1; +} + +/** + * Clear out fifo empty error + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw) +{ + hw->dma_int_clr.outfifo_empty_err = 1; +} + +/*------------------------------------------------------------------------------ + * DMA + *----------------------------------------------------------------------------*/ +/** + * Enable/Disable RX DMA (Peripherals->DMA->RAM) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.dma_rx_ena = enable; +} + +/** + * Enable/Disable TX DMA (RAM->DMA->Peripherals) + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: enable; 2: disable + */ +static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.dma_tx_ena = enable; +} + +/** + * Configuration of RX DMA EOF interrupt generation way + * + * @param hw Beginning address of the peripheral registers. + * @param enable 1: spi_dma_inlink_eof is set when the number of dma pushed data bytes is equal to the value of spi_slv/mst_dma_rd_bytelen[19:0] in spi dma transition. 0: spi_dma_inlink_eof is set by spi_trans_done in non-seg-trans or spi_dma_seg_trans_done in seg-trans. + */ +static inline void spi_ll_dma_set_rx_eof_generation(spi_dev_t *hw, bool enable) +{ + hw->dma_conf.rx_eof_en = enable; +} + +/*------------------------------------------------------------------------------ + * Buffer + *----------------------------------------------------------------------------*/ +/** + * Write to SPI hardware data buffer. + * + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_send Address of the data to be written to the hardware data buffer. + * @param bitlen Length to write, in bits. */ static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen) { @@ -160,11 +321,42 @@ static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_s } /** - * Read from SPI buffer. + * Write to SPI hardware data buffer by buffer ID (address) + * + * @param hw Beginning address of the peripheral registers + * @param byte_id Start ID (address) of the hardware buffer to be written + * @param data Address of the data to be written to the hardware data buffer. + * @param len Length to write, in bytes. + */ +static inline void spi_ll_write_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *data, int len) +{ + assert(byte_id+len <= 64); + assert(len > 0); + assert(byte_id >= 0); + + while (len > 0) { + uint32_t word; + int offset = byte_id % 4; + int copy_len = 4 - offset; + if (copy_len > len) copy_len = len; + + //read-modify-write + if (copy_len != 4) word = hw->data_buf[byte_id / 4]; //read + memcpy(((uint8_t *)&word) + offset, data, copy_len); //modify + hw->data_buf[byte_id / 4] = word; //write + + data += copy_len; + byte_id += copy_len; + len -= copy_len; + } +} + +/** + * Read from SPI hardware data buffer. * - * @param hw Beginning address of the peripheral registers. - * @param buffer_to_rcv Address to copy buffer data to. - * @param bitlen Length to copy, in bits. + * @param hw Beginning address of the peripheral registers. + * @param buffer_to_rcv Address of a buffer to read data from hardware data buffer + * @param bitlen Length to read, in bits. */ static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen) { @@ -180,84 +372,26 @@ static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, siz } /** - * Check whether user-defined transaction is done. - * - * @param hw Beginning address of the peripheral registers. - * - * @return true if transaction is done, otherwise false. + * Read from SPI hardware data buffer by buffer ID (address) + * + * @param hw Beginning address of the peripheral registers + * @param byte_id Start ID (address) of the hardware buffer to be read + * @param data Address of a buffer to read data from hardware data buffer + * @param len Length to read, in bytes. */ -static inline bool spi_ll_usr_is_done(spi_dev_t *hw) +static inline void spi_ll_read_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *out_data, int len) { - return false; -} + while (len > 0) { + uint32_t word = hw->data_buf[byte_id / 4]; + int offset = byte_id % 4; + int copy_len = 4 - offset; + if (copy_len > len) copy_len = len; -/** - * Trigger start of user-defined transaction. - * - * @param hw Beginning address of the peripheral registers. - */ -static inline void spi_ll_user_start(spi_dev_t *hw) -{ - hw->cmd.usr = 1; -} - -/** - * Get current running command bit-mask. (Preview) - * - * @param hw Beginning address of the peripheral registers. - * - * @return Bitmask of running command, see ``SPI_CMD_REG``. 0 if no in-flight command. - */ -static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw) -{ - return hw->cmd.val; -} - -/** - * Disable the trans_done interrupt. - * - * @param hw Beginning address of the peripheral registers. - */ -static inline void spi_ll_disable_int(spi_dev_t *hw) -{ -} - -/** - * Clear the trans_done interrupt. - * - * @param hw Beginning address of the peripheral registers. - */ -static inline void spi_ll_clear_int_stat(spi_dev_t *hw) -{ - hw->dma_int_clr.val = UINT32_MAX; -} - -/** - * Set the trans_done interrupt. - * - * @param hw Beginning address of the peripheral registers. - */ -static inline void spi_ll_set_int_stat(spi_dev_t *hw) -{ -} - -/** - * Enable the trans_done interrupt. - * - * @param hw Beginning address of the peripheral registers. - */ -static inline void spi_ll_enable_int(spi_dev_t *hw) -{ -} - -/** - * Set different interrupt types for the slave. - * - * @param hw Beginning address of the peripheral registers. - * @param int_type Interrupt type - */ -static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_type int_type) -{ + memcpy(out_data, ((uint8_t *)&word) + offset, copy_len); + byte_id += copy_len; + out_data += copy_len; + len -= copy_len; + } } /*------------------------------------------------------------------------------ @@ -266,9 +400,9 @@ static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_ty /** * Enable/disable the postive-cs feature. * - * @param hw Beginning address of the peripheral registers. - * @param cs One of the CS (0-2) to enable/disable the feature. - * @param pos_cs true to enable the feature, otherwise disable (default). + * @param hw Beginning address of the peripheral registers. + * @param cs One of the CS (0-2) to enable/disable the feature. + * @param pos_cs True to enable the feature, otherwise disable (default). */ static inline void spi_ll_master_set_pos_cs(spi_dev_t *hw, int cs, uint32_t pos_cs) { @@ -282,8 +416,8 @@ static inline void spi_ll_master_set_pos_cs(spi_dev_t *hw, int cs, uint32_t pos_ /** * Enable/disable the LSBFIRST feature for TX data. * - * @param hw Beginning address of the peripheral registers. - * @param lsbfirst true if LSB of TX data to be sent first, otherwise MSB is sent first (default). + * @param hw Beginning address of the peripheral registers. + * @param lsbfirst True if LSB of TX data to be sent first, otherwise MSB is sent first (default). */ static inline void spi_ll_set_tx_lsbfirst(spi_dev_t *hw, bool lsbfirst) { @@ -293,8 +427,8 @@ static inline void spi_ll_set_tx_lsbfirst(spi_dev_t *hw, bool lsbfirst) /** * Enable/disable the LSBFIRST feature for RX data. * - * @param hw Beginning address of the peripheral registers. - * @param lsbfirst true if first bit received as LSB, otherwise as MSB (default). + * @param hw Beginning address of the peripheral registers. + * @param lsbfirst True if first bit received as LSB, otherwise as MSB (default). */ static inline void spi_ll_set_rx_lsbfirst(spi_dev_t *hw, bool lsbfirst) { @@ -304,7 +438,7 @@ static inline void spi_ll_set_rx_lsbfirst(spi_dev_t *hw, bool lsbfirst) /** * Set SPI mode for the peripheral as master. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param mode SPI mode to work at, 0-3. */ static inline void spi_ll_master_set_mode(spi_dev_t *hw, uint8_t mode) @@ -328,18 +462,40 @@ static inline void spi_ll_master_set_mode(spi_dev_t *hw, uint8_t mode) /** * Set SPI mode for the peripheral as slave. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param mode SPI mode to work at, 0-3. */ static inline void spi_ll_slave_set_mode(spi_dev_t *hw, const int mode, bool dma_used) { + if (mode == 0) { + hw->misc.ck_idle_edge = 0; + hw->user.rsck_i_edge = 0; + hw->user.tsck_i_edge = 0; + hw->slave.clk_mode_13 = 0; + } else if (mode == 1) { + hw->misc.ck_idle_edge = 0; + hw->user.rsck_i_edge = 1; + hw->user.tsck_i_edge = 1; + hw->slave.clk_mode_13 = 1; + } else if (mode == 2) { + hw->misc.ck_idle_edge = 1; + hw->user.rsck_i_edge = 1; + hw->user.tsck_i_edge = 1; + hw->slave.clk_mode_13 = 0; + } else if (mode == 3) { + hw->misc.ck_idle_edge = 1; + hw->user.rsck_i_edge = 0; + hw->user.tsck_i_edge = 0; + hw->slave.clk_mode_13 = 1; + } + hw->slave.rsck_data_out = 0; } /** * Set SPI to work in full duplex or half duplex mode. * - * @param hw Beginning address of the peripheral registers. - * @param half_duplex true to work in half duplex mode, otherwise in full duplex mode. + * @param hw Beginning address of the peripheral registers. + * @param half_duplex True to work in half duplex mode, otherwise in full duplex mode. */ static inline void spi_ll_set_half_duplex(spi_dev_t *hw, bool half_duplex) { @@ -351,8 +507,8 @@ static inline void spi_ll_set_half_duplex(spi_dev_t *hw, bool half_duplex) * * SIO is a mode which MOSI and MISO share a line. The device MUST work in half-duplexmode. * - * @param hw Beginning address of the peripheral registers. - * @param sio_mode true to work in SIO mode, otherwise false. + * @param hw Beginning address of the peripheral registers. + * @param sio_mode True to work in SIO mode, otherwise false. */ static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode) { @@ -362,7 +518,7 @@ static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode) /** * Configure the io mode for the master to work at. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param io_mode IO mode to work at, see ``spi_ll_io_mode_t``. */ static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_mode) @@ -397,17 +553,40 @@ static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_ } } +/** + * Set the SPI slave to work in segment transaction mode + * + * @param hw Beginning address of the peripheral registers. + * @param seg_trans True to work in seg mode, otherwise false. + */ +static inline void spi_ll_slave_set_seg_mode(spi_dev_t *hw, bool seg_trans) +{ + hw->dma_conf.dma_seg_trans_en = seg_trans; + hw->dma_conf.rx_eof_en = seg_trans; +} + /** * Select one of the CS to use in current transaction. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param cs_id The cs to use, 0-2, otherwise none of them is used. */ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) { - hw->misc.cs0_dis = (cs_id == 0) ? 0 : 1; - hw->misc.cs1_dis = (cs_id == 1) ? 0 : 1; - hw->misc.cs2_dis = (cs_id == 2) ? 0 : 1; + if (hw == &GPSPI2) { + hw->misc.cs0_dis = (cs_id == 0) ? 0 : 1; + hw->misc.cs1_dis = (cs_id == 1) ? 0 : 1; + hw->misc.cs2_dis = (cs_id == 2) ? 0 : 1; + hw->misc.cs3_dis = (cs_id == 3) ? 0 : 1; + hw->misc.cs4_dis = (cs_id == 4) ? 0 : 1; + hw->misc.cs5_dis = (cs_id == 5) ? 0 : 1; + } + + if (hw == &GPSPI3) { + hw->misc.cs0_dis = (cs_id == 0) ? 0 : 1; + hw->misc.cs1_dis = (cs_id == 1) ? 0 : 1; + hw->misc.cs2_dis = (cs_id == 2) ? 0 : 1; + } } /*------------------------------------------------------------------------------ @@ -416,8 +595,8 @@ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) /** * Set the clock for master by stored value. * - * @param hw Beginning address of the peripheral registers. - * @param val stored clock configuration calculated before (by ``spi_ll_cal_clock``). + * @param hw Beginning address of the peripheral registers. + * @param val Stored clock configuration calculated before (by ``spi_ll_cal_clock``). */ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_clock_val_t *val) { @@ -428,10 +607,10 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl * Get the frequency of given dividers. Don't use in app. * * @param fapb APB clock of the system. - * @param pre Pre devider. - * @param n main divider. + * @param pre Pre devider. + * @param n Main divider. * - * @return Frequency of given dividers. + * @return Frequency of given dividers. */ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n) { @@ -441,12 +620,12 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n) /** * Calculate the nearest frequency avaliable for master. * - * @param fapb APB clock of the system. - * @param hz Frequncy desired. + * @param fapb APB clock of the system. + * @param hz Frequncy desired. * @param duty_cycle Duty cycle desired. - * @param out_reg Output address to store the calculated clock configurations for the return frequency. + * @param out_reg Output address to store the calculated clock configurations for the return frequency. * - * @return Actual (nearest) frequency. + * @return Actual (nearest) frequency. */ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg) { @@ -520,12 +699,12 @@ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ * configure the clock by stored value when used by * ``spi_ll_msater_set_clock_by_reg``. * - * @param hw Beginning address of the peripheral registers. - * @param fapb APB clock of the system. - * @param hz Frequncy desired. + * @param hw Beginning address of the peripheral registers. + * @param fapb APB clock of the system. + * @param hz Frequncy desired. * @param duty_cycle Duty cycle desired. * - * @return Actual frequency that is used. + * @return Actual frequency that is used. */ static inline int spi_ll_master_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) { @@ -540,9 +719,9 @@ static inline int spi_ll_master_set_clock(spi_dev_t *hw, int fapb, int hz, int d * * The delay mode/num is a Espressif conception, may change in the new chips. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param delay_mode Delay mode, see TRM. - * @param delay_num APB clocks to delay. + * @param delay_num APB clocks to delay. */ static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int delay_num) { @@ -553,37 +732,23 @@ static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int dela * * The delay mode/num is a Espressif conception, may change in the new chips. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param delay_mode Delay mode, see TRM. - * @param delay_num APB clocks to delay. + * @param delay_num APB clocks to delay. */ static inline void spi_ll_set_miso_delay(spi_dev_t *hw, int delay_mode, int delay_num) { } -/** - * Set dummy clocks to output before RX phase (master), or clocks to skip - * before the data phase and after the address phase (slave). - * - * Note this phase is also used to compensate RX timing in half duplex mode. - * - * @param hw Beginning address of the peripheral registers. - * @param dummy_n Dummy cycles used. 0 to disable the dummy phase. - */ -static inline void spi_ll_set_dummy(spi_dev_t *hw, int dummy_n) -{ - hw->user.usr_dummy = dummy_n ? 1 : 0; - hw->user1.usr_dummy_cyclelen = dummy_n - 1; -} - /** * Set the delay of SPI clocks before the CS inactive edge after the last SPI clock. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param hold Delay of SPI clocks after the last clock, 0 to disable the hold phase. */ static inline void spi_ll_master_set_cs_hold(spi_dev_t *hw, int hold) { + hw->user1.cs_hold_time = hold - 1; hw->user.cs_hold = hold ? 1 : 0; } @@ -593,67 +758,65 @@ static inline void spi_ll_master_set_cs_hold(spi_dev_t *hw, int hold) * Note ESP32 doesn't support to use this feature when command/address phases * are used in full duplex mode. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param setup Delay of SPI clocks after the CS active edge, 0 to disable the setup phase. */ static inline void spi_ll_master_set_cs_setup(spi_dev_t *hw, uint8_t setup) { -} - -/** - * Enable/disable the segment transfer feature for the slave. - * - * @param hw Beginning address of the peripheral registers. - * @param en true to enable, false to disable. - */ -static inline void spi_ll_slave_set_seg_en(spi_dev_t *hw, bool en) -{ - hw->dma_conf.dma_seg_trans_en = en; + hw->user1.cs_setup_time = setup - 1; + hw->user.cs_setup = setup ? 1 : 0; } /*------------------------------------------------------------------------------ * Configs: data *----------------------------------------------------------------------------*/ -/** - * Set the input length (master). - * - * @param hw Beginning address of the peripheral registers. - * @param bitlen input length, in bits. - */ -static inline void spi_ll_set_miso_bitlen(spi_dev_t *hw, size_t bitlen) -{ -} - /** * Set the output length (master). + * This should be called before master setting MISO(input) length * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param bitlen output length, in bits. */ static inline void spi_ll_set_mosi_bitlen(spi_dev_t *hw, size_t bitlen) { + if (bitlen > 0) { + hw->ms_dlen.ms_data_bitlen = bitlen - 1; + } +} + +/** + * Set the input length (master). + * + * @param hw Beginning address of the peripheral registers. + * @param bitlen input length, in bits. + */ +static inline void spi_ll_set_miso_bitlen(spi_dev_t *hw, size_t bitlen) +{ + if (bitlen > 0) { + hw->ms_dlen.ms_data_bitlen = bitlen - 1; + } } /** * Set the maximum input length (slave). * - * @param hw Beginning address of the peripheral registers. - * @param bitlen input length, in bits. + * @param hw Beginning address of the peripheral registers. + * @param bitlen Input length, in bits. */ static inline void spi_ll_slave_set_rx_bitlen(spi_dev_t *hw, size_t bitlen) { - spi_ll_set_miso_bitlen(hw, bitlen); + spi_ll_set_mosi_bitlen(hw, bitlen); } /** * Set the maximum output length (slave). * - * @param hw Beginning address of the peripheral registers. - * @param bitlen output length, in bits. + * @param hw Beginning address of the peripheral registers. + * @param bitlen Output length, in bits. */ static inline void spi_ll_slave_set_tx_bitlen(spi_dev_t *hw, size_t bitlen) { - spi_ll_set_miso_bitlen(hw, bitlen); + spi_ll_set_mosi_bitlen(hw, bitlen); } /** @@ -662,7 +825,7 @@ static inline void spi_ll_slave_set_tx_bitlen(spi_dev_t *hw, size_t bitlen) * When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit * command phases takes 4 cycles in 4-bit mode. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param bitlen Length of command phase, in bits. 0 to disable the command phase. */ static inline void spi_ll_set_command_bitlen(spi_dev_t *hw, int bitlen) @@ -677,7 +840,7 @@ static inline void spi_ll_set_command_bitlen(spi_dev_t *hw, int bitlen) * When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit * address phases takes 4 cycles in 4-bit mode. * - * @param hw Beginning address of the peripheral registers. + * @param hw Beginning address of the peripheral registers. * @param bitlen Length of address phase, in bits. 0 to disable the address phase. */ static inline void spi_ll_set_addr_bitlen(spi_dev_t *hw, int bitlen) @@ -691,10 +854,10 @@ static inline void spi_ll_set_addr_bitlen(spi_dev_t *hw, int bitlen) * * The length and lsbfirst is required to shift and swap the address to the right place. * - * @param hw Beginning address of the peripheral registers. - * @param address Address to set - * @param addrlen Length of the address phase - * @param lsbfirst whether the LSB first feature is enabled. + * @param hw Beginning address of the peripheral registers. + * @param address Address to set + * @param addrlen Length of the address phase + * @param lsbfirst Whether the LSB first feature is enabled. */ static inline void spi_ll_set_address(spi_dev_t *hw, uint64_t addr, int addrlen, uint32_t lsbfirst) { @@ -720,10 +883,10 @@ static inline void spi_ll_set_address(spi_dev_t *hw, uint64_t addr, int addrlen, * * The length and lsbfirst is required to shift and swap the command to the right place. * - * @param hw Beginning command of the peripheral registers. - * @param command Command to set - * @param addrlen Length of the command phase - * @param lsbfirst whether the LSB first feature is enabled. + * @param hw Beginning command of the peripheral registers. + * @param command Command to set + * @param addrlen Length of the command phase + * @param lsbfirst Whether the LSB first feature is enabled. */ static inline void spi_ll_set_command(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst) { @@ -740,11 +903,26 @@ static inline void spi_ll_set_command(spi_dev_t *hw, uint16_t cmd, int cmdlen, b } } +/** + * Set dummy clocks to output before RX phase (master), or clocks to skip + * before the data phase and after the address phase (slave). + * + * Note this phase is also used to compensate RX timing in half duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * @param dummy_n Dummy cycles used. 0 to disable the dummy phase. + */ +static inline void spi_ll_set_dummy(spi_dev_t *hw, int dummy_n) +{ + hw->user.usr_dummy = dummy_n ? 1 : 0; + hw->user1.usr_dummy_cyclelen = dummy_n - 1; +} + /** * Enable/disable the RX data phase. * - * @param hw Beginning address of the peripheral registers. - * @param enable true if RX phase exist, otherwise false. + * @param hw Beginning address of the peripheral registers. + * @param enable True if RX phase exist, otherwise false. */ static inline void spi_ll_enable_miso(spi_dev_t *hw, int enable) { @@ -754,53 +932,142 @@ static inline void spi_ll_enable_miso(spi_dev_t *hw, int enable) /** * Enable/disable the TX data phase. * - * @param hw Beginning address of the peripheral registers. - * @param enable true if TX phase exist, otherwise false. + * @param hw Beginning address of the peripheral registers. + * @param enable True if TX phase exist, otherwise false. */ static inline void spi_ll_enable_mosi(spi_dev_t *hw, int enable) { hw->user.usr_mosi = enable; } -/** - * Reset the slave peripheral before next transaction. - * - * @param hw Beginning address of the peripheral registers. - */ -static inline void spi_ll_slave_reset(spi_dev_t *hw) -{ -} - /** * Get the received bit length of the slave. * * @param hw Beginning address of the peripheral registers. * - * @return Received bits of the slave. + * @return Received bits of the slave. */ static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw) { - return 0; + return hw->slave1.data_bitlen; } -static inline void spi_ll_dma_fifo_reset(spi_dev_t *hw) -{ -} +/*------------------------------------------------------------------------------ + * Interrupts + *----------------------------------------------------------------------------*/ +//helper macros to generate code for each interrupts +#define FOR_EACH_ITEM(op, list) do { list(op) } while(0) +#define INTR_LIST(item) \ + item(SPI_LL_INTR_TRANS_DONE, dma_int_ena.trans_done, dma_int_raw.trans_done, dma_int_clr.trans_done=1) \ + item(SPI_LL_INTR_RDBUF, dma_int_ena.rd_buf_done, dma_int_raw.rd_buf_done, dma_int_clr.rd_buf_done=1) \ + item(SPI_LL_INTR_WRBUF, dma_int_ena.wr_buf_done, dma_int_raw.wr_buf_done, dma_int_clr.wr_buf_done=1) \ + item(SPI_LL_INTR_RDDMA, dma_int_ena.rd_dma_done, dma_int_raw.rd_dma_done, dma_int_clr.rd_dma_done=1) \ + item(SPI_LL_INTR_WRDMA, dma_int_ena.wr_dma_done, dma_int_raw.wr_dma_done, dma_int_clr.wr_dma_done=1) \ + item(SPI_LL_INTR_SEG_DONE, dma_int_ena.dma_seg_trans_done, dma_int_raw.dma_seg_trans_done, dma_int_clr.dma_seg_trans_done=1) \ + item(SPI_LL_INTR_WR_DONE, dma_int_ena.cmd7, dma_int_raw.cmd7, dma_int_clr.cmd7=1) \ + item(SPI_LL_INTR_CMD8, dma_int_ena.cmd8, dma_int_raw.cmd8, dma_int_clr.cmd8=1) \ + item(SPI_LL_INTR_CMD9, dma_int_ena.cmd9, dma_int_raw.cmd9, dma_int_clr.cmd9=1) \ + item(SPI_LL_INTR_CMDA, dma_int_ena.cmda, dma_int_raw.cmda, dma_int_clr.cmda=1) -static inline void spi_ll_infifo_full_clr(spi_dev_t *hw) + +static inline void spi_ll_enable_intr(spi_dev_t* hw, spi_ll_intr_t intr_mask) { +#define ENA_INTR(intr_bit, en_reg, ...) if (intr_mask & (intr_bit)) hw->en_reg = 1; + FOR_EACH_ITEM(ENA_INTR, INTR_LIST); +#undef ENA_INTR } -static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable) +static inline void spi_ll_disable_intr(spi_dev_t* hw, spi_ll_intr_t intr_mask) { +#define DIS_INTR(intr_bit, en_reg, ...) if (intr_mask & (intr_bit)) hw->en_reg = 0; + FOR_EACH_ITEM(DIS_INTR, INTR_LIST); +#undef DIS_INTR } -static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw) +static inline void spi_ll_set_intr(spi_dev_t* hw, spi_ll_intr_t intr_mask) { +#define SET_INTR(intr_bit, _, st_reg, ...) if (intr_mask & (intr_bit)) hw->st_reg = 1; + FOR_EACH_ITEM(SET_INTR, INTR_LIST); +#undef SET_INTR } -static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) +static inline void spi_ll_clear_intr(spi_dev_t* hw, spi_ll_intr_t intr_mask) { +#define CLR_INTR(intr_bit, _, __, clr_op) if (intr_mask & (intr_bit)) hw->clr_op; + FOR_EACH_ITEM(CLR_INTR, INTR_LIST); +#undef CLR_INTR +} + +static inline bool spi_ll_get_intr(spi_dev_t* hw, spi_ll_intr_t intr_mask) +{ +#define GET_INTR(intr_bit, _, st_reg, ...) if (intr_mask & (intr_bit) && hw->st_reg) return true; + FOR_EACH_ITEM(GET_INTR, INTR_LIST); + return false; +#undef GET_INTR +} + +#undef FOR_EACH_ITEM +#undef INTR_LIST + +/** + * Disable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_disable_int(spi_dev_t *hw) +{ + hw->dma_int_ena.trans_done = 0; +} + +/** + * Clear the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_clear_int_stat(spi_dev_t *hw) +{ + hw->dma_int_raw.trans_done = 0; +} + +/** + * Set the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_set_int_stat(spi_dev_t *hw) +{ + hw->dma_int_raw.trans_done = 1; +} + +/** + * Enable the trans_done interrupt. + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_enable_int(spi_dev_t *hw) +{ + hw->dma_int_ena.trans_done = 1; +} + +/*------------------------------------------------------------------------------ + * Slave HD + *----------------------------------------------------------------------------*/ +static inline void spi_ll_slave_hd_set_len_cond(spi_dev_t* hw, spi_ll_trans_len_cond_t cond_mask) +{ + hw->slave.rdbuf_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_RDBUF) ? 1 : 0; + hw->slave.wrbuf_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_WRBUF) ? 1 : 0; + hw->slave.rddma_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_RDDMA) ? 1 : 0; + hw->slave.wrdma_bitlen_en = (cond_mask & SPI_LL_TRANS_LEN_COND_WRDMA) ? 1 : 0; +} + +static inline int spi_ll_slave_get_rx_byte_len(spi_dev_t* hw) +{ + return hw->slave1.data_bitlen / 8; +} + +static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t* hw) +{ + return hw->slave1.last_addr; } #undef SPI_LL_RST_MASK @@ -808,4 +1075,4 @@ static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable) #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/components/hal/spi_hal.c b/components/hal/spi_hal.c index 80fe3e842b..74e33e271e 100644 --- a/components/hal/spi_hal.c +++ b/components/hal/spi_hal.c @@ -17,31 +17,17 @@ #include "hal/spi_hal.h" #include "soc/soc_caps.h" +//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. #if SOC_GDMA_SUPPORTED #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" -#define spi_dma_ll_rx_reset(dev) gdma_ll_rx_reset_channel(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL) -#define spi_dma_ll_tx_reset(dev) gdma_ll_tx_reset_channel(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL); #define spi_dma_ll_rx_enable_burst_data(dev, enable) gdma_ll_rx_enable_data_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); #define spi_dma_ll_tx_enable_burst_data(dev, enable) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); #define spi_dma_ll_rx_enable_burst_desc(dev, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); #define spi_dma_ll_tx_enable_burst_desc(dev, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_set_rx_channel_priority(dev, priority) gdma_ll_rx_set_priority(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, priority); -#define spi_dma_set_tx_channel_priority(dev, priority) gdma_ll_tx_set_priority(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, priority); #define spi_dma_enable_out_auto_wrback(dev, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); #define spi_dma_set_out_eof_generation(dev, enable) gdma_ll_tx_set_eof_mode(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_connect_rx_channel_to_periph(dev, periph_id) gdma_ll_rx_connect_to_periph(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, periph_id); -#define spi_dma_connect_tx_channel_to_periph(dev, periph_id) gdma_ll_tx_connect_to_periph(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, periph_id); -#define spi_dma_ll_rx_start(dev, addr) do {\ - gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_rx_start(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL);\ - } while (0) -#define spi_dma_ll_tx_start(dev, addr) do {\ - gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_tx_start(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL);\ - } while (0) - #endif static const char SPI_HAL_TAG[] = "spi_hal"; @@ -169,4 +155,4 @@ int spi_hal_get_freq_limit(bool gpio_is_used, int input_delay_ns) } return APB_CLK_FREQ / (delay_apb_n + 1); -} \ No newline at end of file +} diff --git a/components/hal/spi_hal_iram.c b/components/hal/spi_hal_iram.c index e45206114d..20c05598fc 100644 --- a/components/hal/spi_hal_iram.c +++ b/components/hal/spi_hal_iram.c @@ -18,22 +18,13 @@ #include "hal/spi_hal.h" #include "soc/soc_caps.h" +//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. #if SOC_GDMA_SUPPORTED #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" #define spi_dma_ll_rx_reset(dev) gdma_ll_rx_reset_channel(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL) #define spi_dma_ll_tx_reset(dev) gdma_ll_tx_reset_channel(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL); -#define spi_dma_ll_rx_enable_burst_data(dev, enable) gdma_ll_rx_enable_data_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_data(dev, enable) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_ll_rx_enable_burst_desc(dev, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_desc(dev, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_set_rx_channel_priority(dev, priority) gdma_ll_rx_set_priority(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, priority); -#define spi_dma_set_tx_channel_priority(dev, priority) gdma_ll_tx_set_priority(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, priority); -#define spi_dma_enable_out_auto_wrback(dev, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_set_out_eof_generation(dev, enable) gdma_ll_tx_set_eof_mode(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, enable); -#define spi_dma_connect_rx_channel_to_periph(dev, periph_id) gdma_ll_rx_connect_to_periph(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, periph_id); -#define spi_dma_connect_tx_channel_to_periph(dev, periph_id) gdma_ll_tx_connect_to_periph(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, periph_id); #define spi_dma_ll_rx_start(dev, addr) do {\ gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, (uint32_t)addr);\ gdma_ll_rx_start(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL);\ @@ -42,7 +33,6 @@ gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL, (uint32_t)addr);\ gdma_ll_tx_start(&GDMA, SOC_GDMA_SPI2_DMA_CHANNEL);\ } while (0) - #endif void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev) @@ -196,7 +186,7 @@ void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *de void spi_hal_user_start(const spi_hal_context_t *hal) { - spi_ll_user_start(hal->hw); + spi_ll_master_user_start(hal->hw); } bool spi_hal_usr_is_done(const spi_hal_context_t *hal) diff --git a/components/hal/spi_slave_hal.c b/components/hal/spi_slave_hal.c index b6a2e7dffb..37e9946ac0 100644 --- a/components/hal/spi_slave_hal.c +++ b/components/hal/spi_slave_hal.c @@ -2,31 +2,17 @@ #include "hal/spi_ll.h" #include "soc/soc_caps.h" +//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. #if SOC_GDMA_SUPPORTED #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" -#define spi_dma_ll_rx_reset(dev) gdma_ll_rx_reset_channel(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL) -#define spi_dma_ll_tx_reset(dev) gdma_ll_tx_reset_channel(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL); #define spi_dma_ll_rx_enable_burst_data(dev, enable) gdma_ll_rx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); #define spi_dma_ll_tx_enable_burst_data(dev, enable) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); #define spi_dma_ll_rx_enable_burst_desc(dev, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); #define spi_dma_ll_tx_enable_burst_desc(dev, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_set_rx_channel_priority(dev, priority) gdma_ll_rx_set_priority(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, priority); -#define spi_dma_set_tx_channel_priority(dev, priority) gdma_ll_tx_set_priority(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, priority); #define spi_dma_enable_out_auto_wrback(dev, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); #define spi_dma_set_out_eof_generation(dev, enable) gdma_ll_tx_set_eof_mode(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_connect_rx_channel_to_periph(dev, periph_id) gdma_ll_rx_connect_to_periph(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, periph_id); -#define spi_dma_connect_tx_channel_to_periph(dev, periph_id) gdma_ll_tx_connect_to_periph(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, periph_id); -#define spi_dma_ll_rx_start(dev, addr) do {\ - gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_rx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ - } while (0) -#define spi_dma_ll_tx_start(dev, addr) do {\ - gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ - gdma_ll_tx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ - } while (0) - #endif static void s_spi_slave_hal_dma_init_config(const spi_slave_hal_context_t *hal) @@ -65,4 +51,4 @@ void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal) void spi_slave_hal_deinit(spi_slave_hal_context_t *hal) { -} \ No newline at end of file +} diff --git a/components/hal/spi_slave_hal_iram.c b/components/hal/spi_slave_hal_iram.c index bb44d40410..587bb5de4f 100644 --- a/components/hal/spi_slave_hal_iram.c +++ b/components/hal/spi_slave_hal_iram.c @@ -2,22 +2,13 @@ #include "hal/spi_ll.h" #include "soc/soc_caps.h" +//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. #if SOC_GDMA_SUPPORTED #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" #define spi_dma_ll_rx_reset(dev) gdma_ll_rx_reset_channel(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL) #define spi_dma_ll_tx_reset(dev) gdma_ll_tx_reset_channel(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL); -#define spi_dma_ll_rx_enable_burst_data(dev, enable) gdma_ll_rx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_data(dev, enable) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_rx_enable_burst_desc(dev, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_ll_tx_enable_burst_desc(dev, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_set_rx_channel_priority(dev, priority) gdma_ll_rx_set_priority(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, priority); -#define spi_dma_set_tx_channel_priority(dev, priority) gdma_ll_tx_set_priority(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, priority); -#define spi_dma_enable_out_auto_wrback(dev, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_set_out_eof_generation(dev, enable) gdma_ll_tx_set_eof_mode(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_connect_rx_channel_to_periph(dev, periph_id) gdma_ll_rx_connect_to_periph(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, periph_id); -#define spi_dma_connect_tx_channel_to_periph(dev, periph_id) gdma_ll_tx_connect_to_periph(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, periph_id); #define spi_dma_ll_rx_start(dev, addr) do {\ gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ gdma_ll_rx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ @@ -26,7 +17,6 @@ gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ gdma_ll_tx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ } while (0) - #endif bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal) @@ -37,7 +27,7 @@ bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal) void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal) { spi_ll_clear_int_stat(hal->hw); //clear int bit - spi_ll_user_start(hal->hw); + spi_ll_slave_user_start(hal->hw); } void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal) @@ -74,6 +64,8 @@ void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal) spi_ll_slave_reset(hal->hw); spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen); } + + spi_ll_cpu_fifo_reset(hal->hw); } spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen); @@ -118,4 +110,4 @@ bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal) } } return ret; -} \ No newline at end of file +} diff --git a/components/hal/spi_slave_hd_hal.c b/components/hal/spi_slave_hd_hal.c index ac17c3c51b..20ae6efe8c 100644 --- a/components/hal/spi_slave_hd_hal.c +++ b/components/hal/spi_slave_hd_hal.c @@ -24,6 +24,7 @@ #include "hal/spi_slave_hd_hal.h" #include "soc/soc_caps.h" +//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros. #if SOC_GDMA_SUPPORTED #include "soc/gdma_struct.h" #include "hal/gdma_ll.h" @@ -34,12 +35,8 @@ #define spi_dma_ll_tx_enable_burst_data(dev, enable) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); #define spi_dma_ll_rx_enable_burst_desc(dev, enable) gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); #define spi_dma_ll_tx_enable_burst_desc(dev, enable) gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_set_rx_channel_priority(dev, priority) gdma_ll_rx_set_priority(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, priority); -#define spi_dma_set_tx_channel_priority(dev, priority) gdma_ll_tx_set_priority(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, priority); #define spi_dma_enable_out_auto_wrback(dev, enable) gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); #define spi_dma_set_out_eof_generation(dev, enable) gdma_ll_tx_set_eof_mode(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, enable); -#define spi_dma_connect_rx_channel_to_periph(dev, periph_id) gdma_ll_rx_connect_to_periph(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, periph_id); -#define spi_dma_connect_tx_channel_to_periph(dev, periph_id) gdma_ll_tx_connect_to_periph(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, periph_id); #define spi_dma_ll_rx_start(dev, addr) do {\ gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ gdma_ll_rx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ @@ -48,7 +45,6 @@ gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL, (uint32_t)addr);\ gdma_ll_tx_start(&GDMA, SOC_GDMA_SPI3_DMA_CHANNEL);\ } while (0) - #endif static void s_spi_slave_hd_hal_dma_init_config(const spi_slave_hd_hal_context_t *hal) @@ -110,10 +106,13 @@ void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, s { lldesc_setup_link(hal->dmadesc_rx, out_buf, len, true); + spi_ll_dma_fifo_reset(hal->dev); spi_dma_ll_rx_reset(hal->dma_in); + spi_ll_slave_reset(hal->dev); spi_ll_infifo_full_clr(hal->dev); spi_ll_clear_intr(hal->dev, SPI_LL_INTR_WR_DONE); + spi_ll_slave_set_rx_bitlen(hal->dev, len * 8); spi_ll_dma_rx_enable(hal->dev, 1); spi_dma_ll_rx_start(hal->dma_in, &hal->dmadesc_rx[0]); } @@ -122,7 +121,9 @@ void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size { lldesc_setup_link(hal->dmadesc_tx, data, len, false); + spi_ll_dma_fifo_reset(hal->dev); spi_dma_ll_tx_reset(hal->dma_out); + spi_ll_slave_reset(hal->dev); spi_ll_outfifo_empty_clr(hal->dev); spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD8); diff --git a/components/soc/soc/esp32s3/include/soc/gdma_struct.h b/components/soc/soc/esp32s3/include/soc/gdma_struct.h index 16f8326298..c2a76bf3ef 100644 --- a/components/soc/soc/esp32s3/include/soc/gdma_struct.h +++ b/components/soc/soc/esp32s3/include/soc/gdma_struct.h @@ -315,6 +315,8 @@ typedef volatile struct { uint32_t date; /*register version.*/ } gdma_dev_t; +_Static_assert(sizeof(gdma_dev_t) == 0x244, "incorrect size of gdma_dev_t."); + extern gdma_dev_t GDMA; #ifdef __cplusplus diff --git a/components/soc/soc/esp32s3/include/soc/spi_caps.h b/components/soc/soc/esp32s3/include/soc/spi_caps.h index 12eb1b561d..740b3e8bfb 100644 --- a/components/soc/soc/esp32s3/include/soc/spi_caps.h +++ b/components/soc/soc/esp32s3/include/soc/spi_caps.h @@ -18,12 +18,13 @@ #define SOC_SPI_DMA_CHAN_NUM 3 #define SOC_SPI_PERIPH_CS_NUM(i) 3 -#define SOC_SPI_MAXIMUM_BUFFER_SIZE 72 +#define SOC_SPI_MAXIMUM_BUFFER_SIZE 64 #define SOC_SPI_SUPPORT_DDRCLK 1 #define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1 #define SOC_SPI_SUPPORT_CD_SIG 1 #define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1 +#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1 // Peripheral supports DIO, DOUT, QIO, or QOUT #define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_dev) (!((void*)spi_dev == (void*)&GPSPI3)) diff --git a/components/soc/soc/esp32s3/include/soc/spi_struct.h b/components/soc/soc/esp32s3/include/soc/spi_struct.h index 19731ff8fc..057ebd999e 100644 --- a/components/soc/soc/esp32s3/include/soc/spi_struct.h +++ b/components/soc/soc/esp32s3/include/soc/spi_struct.h @@ -341,7 +341,7 @@ typedef volatile struct { uint32_t reserved_8c; uint32_t reserved_90; uint32_t reserved_94; - uint32_t data_buf[18]; /*data buffer*/ + uint32_t data_buf[16]; /*data buffer*/ uint32_t reserved_d8; uint32_t reserved_dc; union {