mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
spi: esp32s3 bringup for spi
This commit is contained in:
parent
286ccb203e
commit
f7e91ef6c1
@ -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"
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
@ -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);
|
||||
|
||||
@ -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 &&
|
||||
@ -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;
|
||||
}
|
||||
@ -486,6 +519,8 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
||||
|
@ -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";
|
||||
@ -207,5 +205,3 @@ 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
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
@ -1095,5 +1095,3 @@ TEST_CASE("spi_speed","[spi]")
|
||||
master_free_device_bus(spi);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -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)
|
||||
@ -1166,5 +1164,3 @@ spitest_param_set_t mode_conf[] = {
|
||||
TEST_SPI_MASTER_SLAVE(MODE, mode_conf, "")
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -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 );
|
||||
@ -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
|
||||
@ -144,5 +142,3 @@ TEST_CASE("test slave send unaligned","[spi]")
|
||||
}
|
||||
|
||||
#endif // !CONFIG_SPIRAM
|
||||
|
||||
#endif
|
@ -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)
|
||||
{
|
||||
@ -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;
|
||||
|
||||
@ -575,5 +584,3 @@ TEST_CASE("test spi slave hd continuous mode, master too long", "[spi][spi_slv_h
|
||||
}
|
||||
|
||||
#endif //SOC_SPI_SUPPORT_SLAVE_HD_VER2
|
||||
|
||||
#endif
|
||||
|
@ -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
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,80 +134,34 @@ 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_reset_dma(spi_dev_t *hw)
|
||||
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;
|
||||
|
||||
/**
|
||||
* Start RX DMA.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Start TX DMA.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address of the beginning DMA descriptor.
|
||||
*/
|
||||
static inline void spi_ll_txdma_start(spi_dev_t *hw, lldesc_t *addr)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to SPI buffer.
|
||||
*
|
||||
* @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_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen)
|
||||
{
|
||||
for (int x = 0; x < bitlen; x += 32) {
|
||||
//Use memcpy to get around alignment issues for txdata
|
||||
uint32_t word;
|
||||
memcpy(&word, &buffer_to_send[x / 8], 4);
|
||||
hw->data_buf[(x / 32)] = word;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from SPI 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.
|
||||
*/
|
||||
static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen)
|
||||
{
|
||||
for (int x = 0; x < bitlen; x += 32) {
|
||||
//Do a memcpy to get around possible alignment issues in rx_buffer
|
||||
uint32_t word = hw->data_buf[x / 32];
|
||||
int len = bitlen - x;
|
||||
if (len > 32) {
|
||||
len = 32;
|
||||
}
|
||||
memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8);
|
||||
}
|
||||
hw->slave.soft_reset = 1;
|
||||
hw->slave.soft_reset = 0;
|
||||
hw->slave.slave_mode = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -184,19 +169,32 @@ static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, siz
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return true if transaction is done, otherwise false.
|
||||
* @return True if transaction is done, otherwise false.
|
||||
*/
|
||||
static inline bool spi_ll_usr_is_done(spi_dev_t *hw)
|
||||
{
|
||||
return false;
|
||||
return hw->dma_int_raw.trans_done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger start of user-defined transaction.
|
||||
* 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_user_start(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@ -214,50 +212,186 @@ static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the trans_done interrupt.
|
||||
* Reset the slave peripheral before next transaction.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_disable_int(spi_dev_t *hw)
|
||||
static inline void spi_ll_slave_reset(spi_dev_t *hw)
|
||||
{
|
||||
hw->slave.soft_reset = 1;
|
||||
hw->slave.soft_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the trans_done interrupt.
|
||||
* Reset SPI CPU FIFO
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_clear_int_stat(spi_dev_t *hw)
|
||||
static inline void spi_ll_cpu_fifo_reset(spi_dev_t *hw)
|
||||
{
|
||||
hw->dma_int_clr.val = UINT32_MAX;
|
||||
hw->dma_conf.val |= SPI_LL_CPU_FIFO_RST_MASK;
|
||||
hw->dma_conf.val &= ~SPI_LL_CPU_FIFO_RST_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the trans_done interrupt.
|
||||
* Reset SPI DMA FIFO
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_int_stat(spi_dev_t *hw)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the trans_done interrupt.
|
||||
* Clear in fifo full error
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_enable_int(spi_dev_t *hw)
|
||||
static inline void spi_ll_infifo_full_clr(spi_dev_t *hw)
|
||||
{
|
||||
hw->dma_int_clr.infifo_full_err = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set different interrupt types for the slave.
|
||||
* Clear out fifo empty error
|
||||
*
|
||||
* @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)
|
||||
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)
|
||||
{
|
||||
for (int x = 0; x < bitlen; x += 32) {
|
||||
//Use memcpy to get around alignment issues for txdata
|
||||
uint32_t word;
|
||||
memcpy(&word, &buffer_to_send[x / 8], 4);
|
||||
hw->data_buf[(x / 32)] = word;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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)
|
||||
{
|
||||
for (int x = 0; x < bitlen; x += 32) {
|
||||
//Do a memcpy to get around possible alignment issues in rx_buffer
|
||||
uint32_t word = hw->data_buf[x / 32];
|
||||
int len = bitlen - x;
|
||||
if (len > 32) {
|
||||
len = 32;
|
||||
}
|
||||
memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 void spi_ll_read_buffer_byte(spi_dev_t *hw, int byte_id, uint8_t *out_data, int len)
|
||||
{
|
||||
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;
|
||||
|
||||
memcpy(out_data, ((uint8_t *)&word) + offset, copy_len);
|
||||
byte_id += copy_len;
|
||||
out_data += copy_len;
|
||||
len -= copy_len;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
@ -268,7 +402,7 @@ static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_ty
|
||||
*
|
||||
* @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 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)
|
||||
{
|
||||
@ -283,7 +417,7 @@ 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 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)
|
||||
{
|
||||
@ -294,7 +428,7 @@ 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 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)
|
||||
{
|
||||
@ -333,13 +467,35 @@ static inline void spi_ll_master_set_mode(spi_dev_t *hw, uint8_t mode)
|
||||
*/
|
||||
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 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)
|
||||
{
|
||||
@ -352,7 +508,7 @@ 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 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)
|
||||
{
|
||||
@ -397,6 +553,18 @@ 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.
|
||||
*
|
||||
@ -405,9 +573,20 @@ static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_
|
||||
*/
|
||||
static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
@ -417,7 +596,7 @@ 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 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)
|
||||
{
|
||||
@ -429,7 +608,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl
|
||||
*
|
||||
* @param fapb APB clock of the system.
|
||||
* @param pre Pre devider.
|
||||
* @param n main divider.
|
||||
* @param n Main divider.
|
||||
*
|
||||
* @return Frequency of given dividers.
|
||||
*/
|
||||
@ -561,21 +740,6 @@ static inline void spi_ll_set_miso_delay(spi_dev_t *hw, int delay_mode, int dela
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -584,6 +748,7 @@ static inline void spi_ll_set_dummy(spi_dev_t *hw, int dummy_n)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@ -598,22 +763,27 @@ static inline void spi_ll_master_set_cs_hold(spi_dev_t *hw, int hold)
|
||||
*/
|
||||
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 output length (master).
|
||||
* This should be called before master setting MISO(input) length
|
||||
*
|
||||
* @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).
|
||||
*
|
||||
@ -622,38 +792,31 @@ static inline void spi_ll_slave_set_seg_en(spi_dev_t *hw, bool en)
|
||||
*/
|
||||
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 output length (master).
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum input length (slave).
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
* @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 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -694,7 +857,7 @@ static inline void spi_ll_set_addr_bitlen(spi_dev_t *hw, int bitlen)
|
||||
* @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 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)
|
||||
{
|
||||
@ -723,7 +886,7 @@ static inline void spi_ll_set_address(spi_dev_t *hw, uint64_t addr, int addrlen,
|
||||
* @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 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 enable True if RX phase exist, otherwise false.
|
||||
*/
|
||||
static inline void spi_ll_enable_miso(spi_dev_t *hw, int enable)
|
||||
{
|
||||
@ -755,22 +933,13 @@ 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 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.
|
||||
*
|
||||
@ -780,27 +949,125 @@ static inline void spi_ll_slave_reset(spi_dev_t *hw)
|
||||
*/
|
||||
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_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_infifo_full_clr(spi_dev_t *hw)
|
||||
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_dma_rx_enable(spi_dev_t *hw, bool enable)
|
||||
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_outfifo_empty_clr(spi_dev_t *hw)
|
||||
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 void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable)
|
||||
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
|
||||
|
@ -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";
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user