mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 20:54:32 +02:00
Merge branch 'feature/spi_dma_hal_ll_refactor' into 'master'
spi: refactor DMA ll layer functions Closes IDFGH-3538 and IDFGH-2555 See merge request espressif/esp-idf!9929
This commit is contained in:
@@ -144,7 +144,7 @@ typedef struct {
|
|||||||
int id;
|
int id;
|
||||||
spi_device_t* device[DEV_NUM_MAX];
|
spi_device_t* device[DEV_NUM_MAX];
|
||||||
intr_handle_t intr;
|
intr_handle_t intr;
|
||||||
spi_hal_context_t hal;
|
spi_hal_context_t hal;
|
||||||
spi_trans_priv_t cur_trans_buf;
|
spi_trans_priv_t cur_trans_buf;
|
||||||
int cur_cs; //current device doing transaction
|
int cur_cs; //current device doing transaction
|
||||||
const spi_bus_attr_t* bus_attr;
|
const spi_bus_attr_t* bus_attr;
|
||||||
@@ -164,9 +164,8 @@ struct spi_device_t {
|
|||||||
QueueHandle_t trans_queue;
|
QueueHandle_t trans_queue;
|
||||||
QueueHandle_t ret_queue;
|
QueueHandle_t ret_queue;
|
||||||
spi_device_interface_config_t cfg;
|
spi_device_interface_config_t cfg;
|
||||||
spi_hal_timing_conf_t timing_conf;
|
spi_hal_dev_config_t hal_dev;
|
||||||
spi_host_t *host;
|
spi_host_t *host;
|
||||||
|
|
||||||
spi_bus_lock_dev_handle_t dev_lock;
|
spi_bus_lock_dev_handle_t dev_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -230,11 +229,18 @@ static esp_err_t spi_master_init_driver(spi_host_device_t host_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_hal_init(&host->hal, host_id);
|
//assign the SPI, RX DMA and TX DMA peripheral registers beginning address
|
||||||
|
spi_hal_dma_config_t hal_dma_config = {
|
||||||
|
//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. Pass the registers of SPI peripheral to control it.
|
||||||
|
.dma_in = SPI_LL_GET_HW(host_id),
|
||||||
|
.dma_out = SPI_LL_GET_HW(host_id),
|
||||||
|
.dmadesc_tx = bus_attr->dmadesc_tx,
|
||||||
|
.dmadesc_rx = bus_attr->dmadesc_rx,
|
||||||
|
.dmadesc_n = bus_attr->dma_desc_num
|
||||||
|
};
|
||||||
|
|
||||||
|
spi_hal_init(&host->hal, host_id, &hal_dma_config);
|
||||||
host->hal.dma_enabled = (bus_attr->dma_chan != 0);
|
host->hal.dma_enabled = (bus_attr->dma_chan != 0);
|
||||||
host->hal.dmadesc_tx = bus_attr->dmadesc_tx;
|
|
||||||
host->hal.dmadesc_rx = bus_attr->dmadesc_rx;
|
|
||||||
host->hal.dmadesc_n = bus_attr->dma_desc_num;
|
|
||||||
|
|
||||||
if (host_id != SPI1_HOST) {
|
if (host_id != SPI1_HOST) {
|
||||||
//SPI1 attributes are already initialized at start up.
|
//SPI1 attributes are already initialized at start up.
|
||||||
@@ -293,7 +299,6 @@ void spi_get_timing(bool gpio_is_used, int input_delay_ns, int eff_clk, int* dum
|
|||||||
int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns)
|
int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns)
|
||||||
{
|
{
|
||||||
return spi_hal_get_freq_limit(gpio_is_used, input_delay_ns);
|
return spi_hal_get_freq_limit(gpio_is_used, input_delay_ns);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -302,7 +307,6 @@ int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns)
|
|||||||
*/
|
*/
|
||||||
esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interface_config_t *dev_config, spi_device_handle_t *handle)
|
esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interface_config_t *dev_config, spi_device_handle_t *handle)
|
||||||
{
|
{
|
||||||
int duty_cycle;
|
|
||||||
spi_device_t *dev = NULL;
|
spi_device_t *dev = NULL;
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
|
|
||||||
@@ -339,33 +343,32 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
|||||||
int freecs = spi_bus_lock_get_dev_id(dev_handle);
|
int freecs = spi_bus_lock_get_dev_id(dev_handle);
|
||||||
SPI_CHECK(freecs != -1, "no free cs pins for the host", ESP_ERR_NOT_FOUND);
|
SPI_CHECK(freecs != -1, "no free cs pins for the host", ESP_ERR_NOT_FOUND);
|
||||||
|
|
||||||
duty_cycle = (dev_config->duty_cycle_pos==0) ? 128 : dev_config->duty_cycle_pos;
|
//input parameters to calculate timing configuration
|
||||||
|
int half_duplex = dev_config->flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0;
|
||||||
|
int no_compensate = dev_config->flags & SPI_DEVICE_NO_DUMMY ? 1 : 0;
|
||||||
|
int duty_cycle = (dev_config->duty_cycle_pos==0) ? 128 : dev_config->duty_cycle_pos;
|
||||||
|
int use_gpio = !(bus_attr->flags & SPICOMMON_BUSFLAG_IOMUX_PINS);
|
||||||
|
spi_hal_timing_param_t timing_param = {
|
||||||
|
.half_duplex = half_duplex,
|
||||||
|
.no_compensate = no_compensate,
|
||||||
|
.clock_speed_hz = dev_config->clock_speed_hz,
|
||||||
|
.duty_cycle = duty_cycle,
|
||||||
|
.input_delay_ns = dev_config->input_delay_ns,
|
||||||
|
.use_gpio = use_gpio
|
||||||
|
};
|
||||||
|
|
||||||
|
//output values of timing configuration
|
||||||
|
spi_hal_timing_conf_t temp_timing_conf;
|
||||||
int freq;
|
int freq;
|
||||||
spi_hal_context_t *hal = &(host->hal);
|
esp_err_t ret = spi_hal_cal_clock_conf(&timing_param, &freq, &temp_timing_conf);
|
||||||
hal->half_duplex = dev_config->flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0;
|
|
||||||
#ifdef SOC_SPI_SUPPORT_AS_CS
|
|
||||||
hal->as_cs = dev_config->flags & SPI_DEVICE_CLK_AS_CS ? 1 : 0;
|
|
||||||
#endif
|
|
||||||
hal->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0;
|
|
||||||
hal->no_compensate = dev_config->flags & SPI_DEVICE_NO_DUMMY ? 1 : 0;
|
|
||||||
|
|
||||||
spi_hal_timing_conf_t temp_timing_conf;
|
|
||||||
|
|
||||||
esp_err_t ret = spi_hal_cal_clock_conf(hal, dev_config->clock_speed_hz, duty_cycle,
|
|
||||||
!(bus_attr->flags & SPICOMMON_BUSFLAG_IOMUX_PINS),
|
|
||||||
dev_config->input_delay_ns, &freq,
|
|
||||||
&temp_timing_conf);
|
|
||||||
|
|
||||||
SPI_CHECK(ret==ESP_OK, "assigned clock speed not supported", ret);
|
SPI_CHECK(ret==ESP_OK, "assigned clock speed not supported", ret);
|
||||||
|
|
||||||
//Allocate memory for device
|
//Allocate memory for device
|
||||||
dev=malloc(sizeof(spi_device_t));
|
dev = malloc(sizeof(spi_device_t));
|
||||||
if (dev==NULL) goto nomem;
|
if (dev == NULL) goto nomem;
|
||||||
memset(dev, 0, sizeof(spi_device_t));
|
memset(dev, 0, sizeof(spi_device_t));
|
||||||
host->device[freecs] = dev;
|
|
||||||
dev->id = freecs;
|
dev->id = freecs;
|
||||||
dev->timing_conf = temp_timing_conf;
|
|
||||||
dev->dev_lock = dev_handle;
|
dev->dev_lock = dev_handle;
|
||||||
|
|
||||||
//Allocate queues, set defaults
|
//Allocate queues, set defaults
|
||||||
@@ -375,8 +378,6 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
|||||||
goto nomem;
|
goto nomem;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->host= host;
|
|
||||||
|
|
||||||
//We want to save a copy of the dev config in the dev struct.
|
//We want to save a copy of the dev config in the dev struct.
|
||||||
memcpy(&dev->cfg, dev_config, sizeof(spi_device_interface_config_t));
|
memcpy(&dev->cfg, dev_config, sizeof(spi_device_interface_config_t));
|
||||||
dev->cfg.duty_cycle_pos = duty_cycle;
|
dev->cfg.duty_cycle_pos = duty_cycle;
|
||||||
@@ -384,10 +385,37 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
|||||||
|
|
||||||
//Set CS pin, CS options
|
//Set CS pin, CS options
|
||||||
if (dev_config->spics_io_num >= 0) {
|
if (dev_config->spics_io_num >= 0) {
|
||||||
spicommon_cs_initialize(host_id, dev_config->spics_io_num, freecs, !(bus_attr->flags & SPICOMMON_BUSFLAG_IOMUX_PINS));
|
spicommon_cs_initialize(host_id, dev_config->spics_io_num, freecs, use_gpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
*handle=dev;
|
//save a pointer to device in spi_host_t
|
||||||
|
host->device[freecs] = dev;
|
||||||
|
//save a pointer to host in spi_device_t
|
||||||
|
dev->host= host;
|
||||||
|
|
||||||
|
//initialise the device specific configuration
|
||||||
|
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
|
||||||
|
hal_dev->mode = dev_config->mode;
|
||||||
|
hal_dev->cs_setup = dev_config->cs_ena_pretrans;
|
||||||
|
hal_dev->cs_hold = dev_config->cs_ena_posttrans;
|
||||||
|
//set hold_time to 0 will not actually append delay to CS
|
||||||
|
//set it to 1 since we do need at least one clock of hold time in most cases
|
||||||
|
if (hal_dev->cs_hold == 0) {
|
||||||
|
hal_dev->cs_hold = 1;
|
||||||
|
}
|
||||||
|
hal_dev->cs_pin_id = dev->id;
|
||||||
|
hal_dev->timing_conf = temp_timing_conf;
|
||||||
|
hal_dev->sio = (dev_config->flags) & SPI_DEVICE_3WIRE ? 1 : 0;
|
||||||
|
hal_dev->half_duplex = dev_config->flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0;
|
||||||
|
hal_dev->tx_lsbfirst = dev_config->flags & SPI_DEVICE_TXBIT_LSBFIRST ? 1 : 0;
|
||||||
|
hal_dev->rx_lsbfirst = dev_config->flags & SPI_DEVICE_RXBIT_LSBFIRST ? 1 : 0;
|
||||||
|
hal_dev->no_compensate = dev_config->flags & SPI_DEVICE_NO_DUMMY ? 1 : 0;
|
||||||
|
#ifdef SOC_SPI_SUPPORT_AS_CS
|
||||||
|
hal_dev->as_cs = dev_config->flags& SPI_DEVICE_CLK_AS_CS ? 1 : 0;
|
||||||
|
#endif
|
||||||
|
hal_dev->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0;
|
||||||
|
|
||||||
|
*handle = dev;
|
||||||
ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %dkHz", host_id+1, freecs, freq/1000);
|
ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %dkHz", host_id+1, freecs, freq/1000);
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@@ -447,24 +475,9 @@ static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev)
|
|||||||
//if the configuration is already applied, skip the following.
|
//if the configuration is already applied, skip the following.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
spi_hal_context_t *hal = &dev->host->hal;
|
||||||
spi_host_t* host = dev->host;
|
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
|
||||||
spi_hal_context_t *hal = &host->hal;
|
spi_hal_setup_device(hal, hal_dev);
|
||||||
hal->mode = dev->cfg.mode;
|
|
||||||
hal->tx_lsbfirst = dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST ? 1 : 0;
|
|
||||||
hal->rx_lsbfirst = dev->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST ? 1 : 0;
|
|
||||||
hal->no_compensate = dev->cfg.flags & SPI_DEVICE_NO_DUMMY ? 1 : 0;
|
|
||||||
hal->sio = dev->cfg.flags & SPI_DEVICE_3WIRE ? 1 : 0;
|
|
||||||
hal->dummy_bits = dev->cfg.dummy_bits;
|
|
||||||
hal->cs_setup = dev->cfg.cs_ena_pretrans;
|
|
||||||
hal->cs_hold =dev->cfg.cs_ena_posttrans;
|
|
||||||
//set hold_time to 0 will not actually append delay to CS
|
|
||||||
//set it to 1 since we do need at least one clock of hold time in most cases
|
|
||||||
if (hal->cs_hold == 0) hal->cs_hold = 1;
|
|
||||||
hal->cs_pin_id = dev->id;
|
|
||||||
hal->timing_conf = &dev->timing_conf;
|
|
||||||
|
|
||||||
spi_hal_setup_device(hal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SPI_MASTER_ISR_ATTR spi_device_t *get_acquiring_dev(spi_host_t *host)
|
static SPI_MASTER_ISR_ATTR spi_device_t *get_acquiring_dev(spi_host_t *host)
|
||||||
@@ -501,54 +514,53 @@ static void spi_bus_intr_disable(void *host)
|
|||||||
|
|
||||||
// The function is called to send a new transaction, in ISR or in the task.
|
// The function is called to send a new transaction, in ISR or in the task.
|
||||||
// Setup the transaction-specified registers and linked-list used by the DMA (or FIFO if DMA is not used)
|
// Setup the transaction-specified registers and linked-list used by the DMA (or FIFO if DMA is not used)
|
||||||
static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_t *trans_buf, spi_hal_context_t *hal)
|
static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_t *trans_buf)
|
||||||
{
|
{
|
||||||
spi_transaction_t *trans = NULL;
|
spi_transaction_t *trans = NULL;
|
||||||
spi_host_t *host = dev->host;
|
spi_host_t *host = dev->host;
|
||||||
int dev_id = dev->id;
|
spi_hal_context_t *hal = &(host->hal);
|
||||||
|
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
|
||||||
|
|
||||||
trans = trans_buf->trans;
|
trans = trans_buf->trans;
|
||||||
host->cur_cs = dev_id;
|
host->cur_cs = dev->id;
|
||||||
|
|
||||||
//Reconfigure according to device settings, the function only has effect when the dev_id is changed.
|
//Reconfigure according to device settings, the function only has effect when the dev_id is changed.
|
||||||
spi_setup_device(host->device[dev_id]);
|
spi_setup_device(dev);
|
||||||
|
|
||||||
hal->tx_bitlen = trans->length;
|
//set the transaction specific configuration each time before a transaction setup
|
||||||
hal->rx_bitlen = trans->rxlength;
|
spi_hal_trans_config_t hal_trans = {};
|
||||||
hal->rcv_buffer = (uint8_t*)host->cur_trans_buf.buffer_to_rcv;
|
hal_trans.tx_bitlen = trans->length;
|
||||||
hal->send_buffer = (uint8_t*)host->cur_trans_buf.buffer_to_send;
|
hal_trans.rx_bitlen = trans->rxlength;
|
||||||
hal->half_duplex = dev->cfg.flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0;
|
hal_trans.rcv_buffer = (uint8_t*)host->cur_trans_buf.buffer_to_rcv;
|
||||||
hal->cmd = trans->cmd;
|
hal_trans.send_buffer = (uint8_t*)host->cur_trans_buf.buffer_to_send;
|
||||||
hal->addr = trans->addr;
|
hal_trans.cmd = trans->cmd;
|
||||||
|
hal_trans.addr = trans->addr;
|
||||||
//Set up QIO/DIO if needed
|
//Set up QIO/DIO if needed
|
||||||
hal->io_mode = (trans->flags & SPI_TRANS_MODE_DIO ?
|
hal_trans.io_mode = (trans->flags & SPI_TRANS_MODE_DIO ?
|
||||||
(trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_DIO : SPI_LL_IO_MODE_DUAL) :
|
(trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_DIO : SPI_LL_IO_MODE_DUAL) :
|
||||||
(trans->flags & SPI_TRANS_MODE_QIO ?
|
(trans->flags & SPI_TRANS_MODE_QIO ?
|
||||||
(trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_QIO : SPI_LL_IO_MODE_QUAD) :
|
(trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_QIO : SPI_LL_IO_MODE_QUAD) :
|
||||||
SPI_LL_IO_MODE_NORMAL
|
SPI_LL_IO_MODE_NORMAL
|
||||||
));
|
));
|
||||||
|
|
||||||
hal->tx_bitlen = trans->length;
|
|
||||||
hal->rx_bitlen = trans->rxlength;
|
|
||||||
|
|
||||||
if (trans->flags & SPI_TRANS_VARIABLE_CMD) {
|
if (trans->flags & SPI_TRANS_VARIABLE_CMD) {
|
||||||
hal->cmd_bits = ((spi_transaction_ext_t *)trans)->command_bits;
|
hal_trans.cmd_bits = ((spi_transaction_ext_t *)trans)->command_bits;
|
||||||
} else {
|
} else {
|
||||||
hal->cmd_bits = dev->cfg.command_bits;
|
hal_trans.cmd_bits = dev->cfg.command_bits;
|
||||||
}
|
}
|
||||||
if (trans->flags & SPI_TRANS_VARIABLE_ADDR) {
|
if (trans->flags & SPI_TRANS_VARIABLE_ADDR) {
|
||||||
hal->addr_bits = ((spi_transaction_ext_t *)trans)->address_bits;
|
hal_trans.addr_bits = ((spi_transaction_ext_t *)trans)->address_bits;
|
||||||
} else {
|
} else {
|
||||||
hal->addr_bits = dev->cfg.address_bits;
|
hal_trans.addr_bits = dev->cfg.address_bits;
|
||||||
}
|
}
|
||||||
if (trans->flags & SPI_TRANS_VARIABLE_DUMMY) {
|
if (trans->flags & SPI_TRANS_VARIABLE_DUMMY) {
|
||||||
hal->dummy_bits = ((spi_transaction_ext_t *)trans)->dummy_bits;
|
hal_trans.dummy_bits = ((spi_transaction_ext_t *)trans)->dummy_bits;
|
||||||
} else {
|
} else {
|
||||||
hal->dummy_bits = dev->cfg.dummy_bits;
|
hal_trans.dummy_bits = dev->cfg.dummy_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_hal_setup_trans(hal);
|
spi_hal_setup_trans(hal, hal_dev, &hal_trans);
|
||||||
spi_hal_prepare_data(hal);
|
spi_hal_prepare_data(hal, hal_dev, &hal_trans);
|
||||||
|
|
||||||
//Call pre-transmission callback, if any
|
//Call pre-transmission callback, if any
|
||||||
if (dev->cfg.pre_cb) dev->cfg.pre_cb(trans);
|
if (dev->cfg.pre_cb) dev->cfg.pre_cb(trans);
|
||||||
@@ -561,6 +573,7 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_
|
|||||||
static void SPI_MASTER_ISR_ATTR spi_post_trans(spi_host_t *host)
|
static void SPI_MASTER_ISR_ATTR spi_post_trans(spi_host_t *host)
|
||||||
{
|
{
|
||||||
spi_transaction_t *cur_trans = host->cur_trans_buf.trans;
|
spi_transaction_t *cur_trans = host->cur_trans_buf.trans;
|
||||||
|
|
||||||
spi_hal_fetch_result(&host->hal);
|
spi_hal_fetch_result(&host->hal);
|
||||||
//Call post-transaction callback, if any
|
//Call post-transaction callback, if any
|
||||||
spi_device_t* dev = host->device[host->cur_cs];
|
spi_device_t* dev = host->device[host->cur_cs];
|
||||||
@@ -569,7 +582,6 @@ static void SPI_MASTER_ISR_ATTR spi_post_trans(spi_host_t *host)
|
|||||||
host->cur_cs = DEV_NUM_MAX;
|
host->cur_cs = DEV_NUM_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This is run in interrupt context.
|
// This is run in interrupt context.
|
||||||
static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
||||||
{
|
{
|
||||||
@@ -649,7 +661,7 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
|||||||
//mark channel as active, so that the DMA will not be reset by the slave
|
//mark channel as active, so that the DMA will not be reset by the slave
|
||||||
spicommon_dmaworkaround_transfer_active(bus_attr->dma_chan);
|
spicommon_dmaworkaround_transfer_active(bus_attr->dma_chan);
|
||||||
}
|
}
|
||||||
spi_new_trans(device_to_send, cur_trans_buf, (&host->hal));
|
spi_new_trans(device_to_send, cur_trans_buf);
|
||||||
}
|
}
|
||||||
// Exit of the ISR, handle interrupt re-enable (if sending transaction), retry (if there's coming BG),
|
// Exit of the ISR, handle interrupt re-enable (if sending transaction), retry (if there's coming BG),
|
||||||
// or resume acquiring device task (if quit due to bus acquiring).
|
// or resume acquiring device task (if quit due to bus acquiring).
|
||||||
@@ -667,7 +679,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
|||||||
bool rx_enabled = (trans_desc->flags & SPI_TRANS_USE_RXDATA) || (trans_desc->rx_buffer);
|
bool rx_enabled = (trans_desc->flags & SPI_TRANS_USE_RXDATA) || (trans_desc->rx_buffer);
|
||||||
spi_transaction_ext_t *t_ext = (spi_transaction_ext_t *)trans_desc;
|
spi_transaction_ext_t *t_ext = (spi_transaction_ext_t *)trans_desc;
|
||||||
bool dummy_enabled = (((trans_desc->flags & SPI_TRANS_VARIABLE_DUMMY)? t_ext->dummy_bits: handle->cfg.dummy_bits) != 0);
|
bool dummy_enabled = (((trans_desc->flags & SPI_TRANS_VARIABLE_DUMMY)? t_ext->dummy_bits: handle->cfg.dummy_bits) != 0);
|
||||||
bool extra_dummy_enabled = handle->timing_conf.timing_dummy;
|
bool extra_dummy_enabled = handle->hal_dev.timing_conf.timing_dummy;
|
||||||
bool is_half_duplex = ((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) != 0);
|
bool is_half_duplex = ((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) != 0);
|
||||||
|
|
||||||
//check transmission length
|
//check transmission length
|
||||||
@@ -763,7 +775,6 @@ clean_up:
|
|||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
|
esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
|
||||||
{
|
{
|
||||||
esp_err_t ret = check_trans_valid(handle, trans_desc);
|
esp_err_t ret = check_trans_valid(handle, trans_desc);
|
||||||
@@ -841,7 +852,6 @@ esp_err_t SPI_MASTER_ATTR spi_device_transmit(spi_device_handle_t handle, spi_tr
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t SPI_MASTER_ISR_ATTR spi_device_acquire_bus(spi_device_t *device, TickType_t wait)
|
esp_err_t SPI_MASTER_ISR_ATTR spi_device_acquire_bus(spi_device_t *device, TickType_t wait)
|
||||||
{
|
{
|
||||||
spi_host_t *const host = device->host;
|
spi_host_t *const host = device->host;
|
||||||
@@ -897,7 +907,6 @@ void SPI_MASTER_ISR_ATTR spi_device_release_bus(spi_device_t *dev)
|
|||||||
assert(ret == ESP_OK);
|
assert(ret == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
|
esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
|
||||||
{
|
{
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
@@ -923,12 +932,11 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl
|
|||||||
host->polling = true;
|
host->polling = true;
|
||||||
|
|
||||||
ESP_LOGV(SPI_TAG, "polling trans");
|
ESP_LOGV(SPI_TAG, "polling trans");
|
||||||
spi_new_trans(handle, &host->cur_trans_buf, (&host->hal));
|
spi_new_trans(handle, &host->cur_trans_buf);
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_end(spi_device_handle_t handle, TickType_t ticks_to_wait)
|
esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_end(spi_device_handle_t handle, TickType_t ticks_to_wait)
|
||||||
{
|
{
|
||||||
SPI_CHECK(handle != NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(handle != NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
|
||||||
@@ -960,7 +968,6 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_end(spi_device_handle_t handle,
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_transmit(spi_device_handle_t handle, spi_transaction_t* trans_desc)
|
esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_transmit(spi_device_handle_t handle, spi_transaction_t* trans_desc)
|
||||||
{
|
{
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "esp_rom_gpio.h"
|
#include "esp_rom_gpio.h"
|
||||||
#include "esp_rom_sys.h"
|
#include "esp_rom_sys.h"
|
||||||
|
#include "hal/spi_slave_hal.h"
|
||||||
|
|
||||||
static const char *SPI_TAG = "spi_slave";
|
static const char *SPI_TAG = "spi_slave";
|
||||||
#define SPI_CHECK(a, str, ret_val) \
|
#define SPI_CHECK(a, str, ret_val) \
|
||||||
@@ -192,7 +193,13 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
|||||||
}
|
}
|
||||||
|
|
||||||
spi_slave_hal_context_t *hal = &spihost[host]->hal;
|
spi_slave_hal_context_t *hal = &spihost[host]->hal;
|
||||||
spi_slave_hal_init(hal, host);
|
//assign the SPI, RX DMA and TX DMA peripheral registers beginning address
|
||||||
|
spi_slave_hal_config_t hal_config = {
|
||||||
|
.host_id = host,
|
||||||
|
.dma_in = SPI_LL_GET_HW(host),
|
||||||
|
.dma_out = SPI_LL_GET_HW(host)
|
||||||
|
};
|
||||||
|
spi_slave_hal_init(hal, &hal_config);
|
||||||
|
|
||||||
if (dma_desc_ct) {
|
if (dma_desc_ct) {
|
||||||
hal->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
|
hal->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
|
||||||
|
@@ -102,13 +102,14 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
|||||||
|
|
||||||
spi_slave_hd_hal_config_t hal_config = {
|
spi_slave_hd_hal_config_t hal_config = {
|
||||||
.host_id = host_id,
|
.host_id = host_id,
|
||||||
|
.dma_in = SPI_LL_GET_HW(host_id),
|
||||||
|
.dma_out = SPI_LL_GET_HW(host_id),
|
||||||
.tx_lsbfirst = (config->flags & SPI_SLAVE_HD_RXBIT_LSBFIRST),
|
.tx_lsbfirst = (config->flags & SPI_SLAVE_HD_RXBIT_LSBFIRST),
|
||||||
.rx_lsbfirst = (config->flags & SPI_SLAVE_HD_TXBIT_LSBFIRST),
|
.rx_lsbfirst = (config->flags & SPI_SLAVE_HD_TXBIT_LSBFIRST),
|
||||||
.dma_chan = config->dma_chan,
|
.dma_chan = config->dma_chan,
|
||||||
.mode = config->mode,
|
.mode = config->mode
|
||||||
};
|
};
|
||||||
|
spi_slave_hd_hal_init(&host->hal, &hal_config);
|
||||||
slave_hd_hal_init(&host->hal, &hal_config);
|
|
||||||
|
|
||||||
if (config->dma_chan != 0) {
|
if (config->dma_chan != 0) {
|
||||||
//See how many dma descriptors we need and allocate them
|
//See how many dma descriptors we need and allocate them
|
||||||
|
@@ -34,7 +34,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Registers to reset during initialization. Don't use in app.
|
/// Registers to reset during initialization. Don't use in app.
|
||||||
#define SPI_LL_RST_MASK (SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST)
|
#define SPI_LL_DMA_FIFO_RST_MASK (SPI_AHBM_RST | SPI_AHBM_FIFO_RST)
|
||||||
/// Interrupt not used. Don't use in app.
|
/// Interrupt not used. Don't use in app.
|
||||||
#define SPI_LL_UNUSED_INT_MASK (SPI_INT_EN | SPI_SLV_WR_STA_DONE | SPI_SLV_RD_STA_DONE | SPI_SLV_WR_BUF_DONE | SPI_SLV_RD_BUF_DONE)
|
#define SPI_LL_UNUSED_INT_MASK (SPI_INT_EN | SPI_SLV_WR_STA_DONE | SPI_SLV_RD_STA_DONE | SPI_SLV_WR_BUF_DONE | SPI_SLV_RD_BUF_DONE)
|
||||||
/// Swap the bit order to its correct place to send
|
/// Swap the bit order to its correct place to send
|
||||||
@@ -49,6 +49,9 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
typedef uint32_t spi_ll_clock_val_t;
|
typedef uint32_t spi_ll_clock_val_t;
|
||||||
|
|
||||||
|
//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. So set the registers of SPI peripheral to control DMA.
|
||||||
|
typedef spi_dev_t spi_dma_dev_t;
|
||||||
|
|
||||||
/** IO modes supported by the master. */
|
/** IO modes supported by the master. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases
|
SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases
|
||||||
@@ -58,11 +61,6 @@ 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_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases
|
||||||
} spi_ll_io_mode_t;
|
} spi_ll_io_mode_t;
|
||||||
|
|
||||||
/// Interrupt type for different working pattern
|
|
||||||
typedef enum {
|
|
||||||
SPI_LL_INT_TYPE_NORMAL = 0, ///< Typical pattern, only wait for trans done
|
|
||||||
} spi_ll_slave_intr_type;
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
* Control
|
* Control
|
||||||
@@ -74,11 +72,6 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
static inline void spi_ll_master_init(spi_dev_t *hw)
|
static inline void spi_ll_master_init(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
//Reset DMA
|
|
||||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
|
||||||
hw->dma_out_link.start = 0;
|
|
||||||
hw->dma_in_link.start = 0;
|
|
||||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
|
||||||
//Reset timing
|
//Reset timing
|
||||||
hw->ctrl2.val = 0;
|
hw->ctrl2.val = 0;
|
||||||
|
|
||||||
@@ -105,10 +98,6 @@ static inline void spi_ll_slave_init(spi_dev_t *hw)
|
|||||||
hw->user.doutdin = 1; //we only support full duplex
|
hw->user.doutdin = 1; //we only support full duplex
|
||||||
hw->user.sio = 0;
|
hw->user.sio = 0;
|
||||||
hw->slave.slave_mode = 1;
|
hw->slave.slave_mode = 1;
|
||||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
|
||||||
hw->dma_out_link.start = 0;
|
|
||||||
hw->dma_in_link.start = 0;
|
|
||||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
|
||||||
hw->slave.sync_reset = 1;
|
hw->slave.sync_reset = 1;
|
||||||
hw->slave.sync_reset = 0;
|
hw->slave.sync_reset = 0;
|
||||||
//use all 64 bytes of the buffer
|
//use all 64 bytes of the buffer
|
||||||
@@ -119,84 +108,6 @@ static inline void spi_ll_slave_init(spi_dev_t *hw)
|
|||||||
hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK;
|
hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset TX and RX DMAs.
|
|
||||||
*
|
|
||||||
* @param hw Beginning address of the peripheral registers.
|
|
||||||
*/
|
|
||||||
static inline void spi_ll_reset_dma(spi_dev_t *hw)
|
|
||||||
{
|
|
||||||
//Reset DMA peripheral
|
|
||||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
|
||||||
hw->dma_out_link.start = 0;
|
|
||||||
hw->dma_in_link.start = 0;
|
|
||||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
|
||||||
hw->dma_conf.out_data_burst_en = 1;
|
|
||||||
hw->dma_conf.indscr_burst_en = 1;
|
|
||||||
hw->dma_conf.outdscr_burst_en = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
hw->dma_in_link.addr = (int) addr & 0xFFFFF;
|
|
||||||
hw->dma_in_link.start = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
hw->dma_out_link.addr = (int) addr & 0xFFFFF;
|
|
||||||
hw->dma_out_link.start = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether user-defined transaction is done.
|
* Check whether user-defined transaction is done.
|
||||||
*
|
*
|
||||||
@@ -232,48 +143,110 @@ static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable the trans_done interrupt.
|
* Reset SPI CPU FIFO
|
||||||
*
|
*
|
||||||
* @param hw Beginning address of the peripheral registers.
|
* @param hw Beginning address of the peripheral registers.
|
||||||
*/
|
*/
|
||||||
static inline void spi_ll_disable_int(spi_dev_t *hw)
|
static inline void spi_ll_cpu_fifo_reset(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
hw->slave.trans_inten = 0;
|
//This is not used in esp32
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the trans_done interrupt.
|
* Reset SPI DMA FIFO
|
||||||
*
|
*
|
||||||
* @param hw Beginning address of the peripheral registers.
|
* @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_dma_fifo_reset(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
hw->slave.trans_done = 0;
|
hw->dma_conf.val |= SPI_LL_DMA_FIFO_RST_MASK;
|
||||||
|
hw->dma_conf.val &= ~SPI_LL_DMA_FIFO_RST_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the trans_done interrupt.
|
* Clear in fifo full error
|
||||||
*
|
*
|
||||||
* @param hw Beginning address of the peripheral registers.
|
* @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_infifo_full_clr(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
hw->slave.trans_done = 1;
|
//This is not used in esp32
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable the trans_done interrupt.
|
* Clear out fifo empty error
|
||||||
*
|
*
|
||||||
* @param hw Beginning address of the peripheral registers.
|
* @param hw Beginning address of the peripheral registers.
|
||||||
*/
|
*/
|
||||||
static inline void spi_ll_enable_int(spi_dev_t *hw)
|
static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
hw->slave.trans_inten = 1;
|
//This is not used in esp32
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_type int_type)
|
/*------------------------------------------------------------------------------
|
||||||
|
* SPI configuration for 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->slave.trans_inten = 1;
|
//This is not used in esp32
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
//This is not used in esp32
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Buffer
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
@@ -485,7 +458,7 @@ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id)
|
|||||||
* @param hw Beginning address of the peripheral registers.
|
* @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, spi_ll_clock_val_t *val)
|
static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_clock_val_t *val)
|
||||||
{
|
{
|
||||||
hw->clock.val = *(uint32_t *)val;
|
hw->clock.val = *(uint32_t *)val;
|
||||||
}
|
}
|
||||||
@@ -875,6 +848,167 @@ static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw)
|
|||||||
return hw->slv_rd_bit.slv_rdata_bit;
|
return hw->slv_rd_bit.slv_rdata_bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Interrupts
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* 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->slave.trans_inten = 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->slave.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->slave.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->slave.trans_inten = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* DMA:
|
||||||
|
* RX DMA (Peripherals->DMA->RAM)
|
||||||
|
* TX DMA (RAM->DMA->Peripherals)
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Reset RX DMA which stores the data received from a peripheral into RAM.
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in)
|
||||||
|
{
|
||||||
|
//Reset RX DMA peripheral
|
||||||
|
dma_in->dma_conf.in_rst = 1;
|
||||||
|
dma_in->dma_conf.in_rst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start RX DMA.
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
* @param addr Address of the beginning DMA descriptor.
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, lldesc_t *addr)
|
||||||
|
{
|
||||||
|
dma_in->dma_in_link.addr = (int) addr & 0xFFFFF;
|
||||||
|
dma_in->dma_in_link.start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable DMA RX channel burst for data
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_out, bool enable)
|
||||||
|
{
|
||||||
|
//This is not supported in esp32
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable DMA RX channel burst for descriptor
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, bool enable)
|
||||||
|
{
|
||||||
|
dma_in->dma_conf.indscr_burst_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration of RX DMA EOF interrupt generation way
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
* @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_dma_ll_set_rx_eof_generation(spi_dma_dev_t *dma_in, bool enable)
|
||||||
|
{
|
||||||
|
//does not available in ESP32
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset TX DMA which transmits the data from RAM to a peripheral.
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out)
|
||||||
|
{
|
||||||
|
//Reset TX DMA peripheral
|
||||||
|
dma_out->dma_conf.out_rst = 1;
|
||||||
|
dma_out->dma_conf.out_rst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start TX DMA.
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param addr Address of the beginning DMA descriptor.
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, lldesc_t *addr)
|
||||||
|
{
|
||||||
|
dma_out->dma_out_link.addr = (int) addr & 0xFFFFF;
|
||||||
|
dma_out->dma_out_link.start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable DMA TX channel burst for data
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_tx_enable_burst_data(spi_dma_dev_t *dma_out, bool enable)
|
||||||
|
{
|
||||||
|
dma_out->dma_conf.out_data_burst_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable DMA TX channel burst for descriptor
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_tx_enable_burst_desc(spi_dma_dev_t *dma_out, bool enable)
|
||||||
|
{
|
||||||
|
dma_out->dma_conf.outdscr_burst_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable automatic outlink-writeback
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_enable_out_auto_wrback(spi_dma_dev_t *dma_out, bool enable)
|
||||||
|
{
|
||||||
|
//does not configure it in ESP32
|
||||||
|
}
|
||||||
|
|
||||||
#undef SPI_LL_RST_MASK
|
#undef SPI_LL_RST_MASK
|
||||||
#undef SPI_LL_UNUSED_INT_MASK
|
#undef SPI_LL_UNUSED_INT_MASK
|
||||||
|
@@ -35,7 +35,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Registers to reset during initialization. Don't use in app.
|
/// Registers to reset during initialization. Don't use in app.
|
||||||
#define SPI_LL_RST_MASK (SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST)
|
#define SPI_LL_DMA_FIFO_RST_MASK (SPI_AHBM_RST | SPI_AHBM_FIFO_RST)
|
||||||
/// Interrupt not used. Don't use in app.
|
/// Interrupt not used. Don't use in app.
|
||||||
#define SPI_LL_UNUSED_INT_MASK (SPI_INT_TRANS_DONE_EN | SPI_INT_WR_DMA_DONE_EN | SPI_INT_RD_DMA_DONE_EN | SPI_INT_WR_BUF_DONE_EN | SPI_INT_RD_BUF_DONE_EN)
|
#define SPI_LL_UNUSED_INT_MASK (SPI_INT_TRANS_DONE_EN | SPI_INT_WR_DMA_DONE_EN | SPI_INT_RD_DMA_DONE_EN | SPI_INT_WR_BUF_DONE_EN | SPI_INT_RD_BUF_DONE_EN)
|
||||||
/// Swap the bit order to its correct place to send
|
/// Swap the bit order to its correct place to send
|
||||||
@@ -50,6 +50,9 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
typedef uint32_t spi_ll_clock_val_t;
|
typedef uint32_t spi_ll_clock_val_t;
|
||||||
|
|
||||||
|
//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. So set the registers of SPI peripheral to control DMA.
|
||||||
|
typedef spi_dev_t spi_dma_dev_t;
|
||||||
|
|
||||||
/** IO modes supported by the master. */
|
/** IO modes supported by the master. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases
|
SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases
|
||||||
@@ -59,12 +62,6 @@ 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_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases
|
||||||
} spi_ll_io_mode_t;
|
} spi_ll_io_mode_t;
|
||||||
|
|
||||||
/// Interrupt type for different working pattern
|
|
||||||
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;
|
|
||||||
|
|
||||||
/// Type definition of all supported interrupts
|
/// Type definition of all supported interrupts
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done
|
SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done
|
||||||
@@ -104,11 +101,6 @@ FLAG_ATTR(spi_ll_trans_len_cond_t)
|
|||||||
*/
|
*/
|
||||||
static inline void spi_ll_master_init(spi_dev_t *hw)
|
static inline void spi_ll_master_init(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
//Reset DMA
|
|
||||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
|
||||||
hw->dma_out_link.start = 0;
|
|
||||||
hw->dma_in_link.start = 0;
|
|
||||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
|
||||||
//Reset timing
|
//Reset timing
|
||||||
hw->ctrl2.val = 0;
|
hw->ctrl2.val = 0;
|
||||||
|
|
||||||
@@ -137,52 +129,26 @@ static inline void spi_ll_slave_init(spi_dev_t *hw)
|
|||||||
hw->user.doutdin = 1; //we only support full duplex
|
hw->user.doutdin = 1; //we only support full duplex
|
||||||
hw->user.sio = 0;
|
hw->user.sio = 0;
|
||||||
hw->slave.slave_mode = 1;
|
hw->slave.slave_mode = 1;
|
||||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
|
||||||
hw->dma_out_link.start = 0;
|
|
||||||
hw->dma_in_link.start = 0;
|
|
||||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
|
||||||
hw->slave.soft_reset = 1;
|
hw->slave.soft_reset = 1;
|
||||||
hw->slave.soft_reset = 0;
|
hw->slave.soft_reset = 0;
|
||||||
//use all 64 bytes of the buffer
|
//use all 64 bytes of the buffer
|
||||||
hw->user.usr_miso_highpart = 0;
|
hw->user.usr_miso_highpart = 0;
|
||||||
hw->user.usr_mosi_highpart = 0;
|
hw->user.usr_mosi_highpart = 0;
|
||||||
//by default seg mode is disabled
|
|
||||||
hw->dma_conf.dma_continue = 0;
|
|
||||||
|
|
||||||
//Disable unneeded ints
|
//Disable unneeded ints
|
||||||
hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK;
|
hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK;
|
||||||
hw->dma_int_ena.val = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_ll_slave_hd_init(spi_dev_t* hw)
|
static inline void spi_ll_slave_hd_init(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
hw->clock.val = 0;
|
hw->clock.val = 0;
|
||||||
hw->user.val = 0;
|
hw->user.val = 0;
|
||||||
hw->ctrl.val = 0;
|
hw->ctrl.val = 0;
|
||||||
hw->user.sio = 0;
|
hw->user.sio = 0;
|
||||||
//hw->user.tx_start_bit = 7;
|
|
||||||
|
|
||||||
hw->slave.soft_reset = 1;
|
hw->slave.soft_reset = 1;
|
||||||
hw->slave.soft_reset = 0;
|
hw->slave.soft_reset = 0;
|
||||||
|
|
||||||
//Reset DMA
|
|
||||||
hw->dma_conf.val |= SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST;
|
|
||||||
hw->dma_out_link.start = 0;
|
|
||||||
hw->dma_in_link.start = 0;
|
|
||||||
hw->dma_conf.val &= ~(SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
|
|
||||||
|
|
||||||
if (hw == &GPSPI2) {
|
|
||||||
hw->dma_conf.out_data_burst_en = 1;
|
|
||||||
} else {
|
|
||||||
hw->dma_conf.out_data_burst_en = 0;
|
|
||||||
}
|
|
||||||
hw->dma_conf.outdscr_burst_en = 1;
|
|
||||||
hw->dma_conf.indscr_burst_en = 1;
|
|
||||||
|
|
||||||
hw->dma_conf.rx_eof_en = 0;
|
|
||||||
hw->dma_conf.out_eof_mode = 1;
|
|
||||||
hw->dma_conf.out_auto_wrback = 1;
|
|
||||||
|
|
||||||
hw->user.doutdin = 0; //we only support full duplex
|
hw->user.doutdin = 0; //we only support full duplex
|
||||||
hw->slave.slave_mode = 1;
|
hw->slave.slave_mode = 1;
|
||||||
}
|
}
|
||||||
@@ -221,103 +187,83 @@ static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
|
|||||||
return hw->cmd.val;
|
return hw->cmd.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
|
||||||
* DMA
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
/**
|
/**
|
||||||
* Reset TX and RX DMAs.
|
* Reset SPI CPU FIFO
|
||||||
*
|
*
|
||||||
* @param hw Beginning address of the peripheral registers.
|
* @param hw Beginning address of the peripheral registers.
|
||||||
*/
|
*/
|
||||||
static inline void spi_ll_reset_dma(spi_dev_t *hw)
|
static inline void spi_ll_cpu_fifo_reset(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
//Reset DMA peripheral
|
//This is not used in esp32s2
|
||||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
|
||||||
hw->dma_out_link.start = 0;
|
|
||||||
hw->dma_in_link.start = 0;
|
|
||||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
|
||||||
hw->dma_conf.out_data_burst_en = 0;
|
|
||||||
hw->dma_conf.indscr_burst_en = 1;
|
|
||||||
hw->dma_conf.outdscr_burst_en = 1;
|
|
||||||
hw->dma_in_link.dma_rx_ena = 0;
|
|
||||||
assert(hw->dma_in_link.dma_rx_ena == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start RX DMA.
|
* Reset SPI DMA FIFO
|
||||||
*
|
*
|
||||||
* @param hw Beginning address of the peripheral registers.
|
* @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_dma_fifo_reset(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
hw->dma_in_link.addr = (int) addr & 0xFFFFF;
|
hw->dma_conf.val |= SPI_LL_DMA_FIFO_RST_MASK;
|
||||||
hw->dma_in_link.start = 1;
|
hw->dma_conf.val &= ~SPI_LL_DMA_FIFO_RST_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start TX DMA.
|
* Clear in fifo full error
|
||||||
*
|
*
|
||||||
* @param hw Beginning address of the peripheral registers.
|
* @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)
|
static inline void spi_ll_infifo_full_clr(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
hw->dma_out_link.addr = (int) addr & 0xFFFFF;
|
|
||||||
hw->dma_out_link.start = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void spi_ll_rxdma_reset(spi_dev_t* hw)
|
|
||||||
{
|
|
||||||
hw->dma_conf.in_rst = 1;
|
|
||||||
hw->dma_conf.in_rst = 0;
|
|
||||||
hw->dma_conf.infifo_full_clr = 1;
|
hw->dma_conf.infifo_full_clr = 1;
|
||||||
hw->dma_conf.infifo_full_clr = 0;
|
hw->dma_conf.infifo_full_clr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_ll_txdma_reset(spi_dev_t* hw)
|
/**
|
||||||
|
* 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_conf.out_rst = 1;
|
|
||||||
hw->dma_conf.out_rst = 0;
|
|
||||||
hw->dma_conf.outfifo_empty_clr = 1;
|
hw->dma_conf.outfifo_empty_clr = 1;
|
||||||
hw->dma_conf.outfifo_empty_clr = 0;
|
hw->dma_conf.outfifo_empty_clr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_ll_rxdma_restart(spi_dev_t* hw)
|
/*------------------------------------------------------------------------------
|
||||||
|
* SPI configuration for 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_in_link.restart = 1;
|
//This is not used in esp32s2
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_ll_txdma_restart(spi_dev_t* hw)
|
/**
|
||||||
|
* 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_out_link.restart = 1;
|
//This is not used in esp32s2
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_ll_rxdma_disable(spi_dev_t* hw)
|
/**
|
||||||
|
* Configuration of OUT EOF flag generation way
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param enable 1: when dma pop all data from fifo 0:when ahb push all data to fifo.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_dma_set_out_eof_generation(spi_dma_dev_t *dma_out, bool enable)
|
||||||
{
|
{
|
||||||
hw->dma_in_link.dma_rx_ena = 0;
|
dma_out->dma_conf.out_eof_mode = enable;
|
||||||
}
|
|
||||||
|
|
||||||
static inline void spi_ll_txdma_disable(spi_dev_t* hw)
|
|
||||||
{
|
|
||||||
hw->dma_out_link.dma_tx_ena = 0;
|
|
||||||
hw->dma_out_link.stop = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void spi_ll_rxdma_clr_err(spi_dev_t* hw)
|
|
||||||
{
|
|
||||||
hw->dma_conf.infifo_full_clr = 1;
|
|
||||||
hw->dma_conf.infifo_full_clr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void spi_ll_txdma_clr_err(spi_dev_t* hw)
|
|
||||||
{
|
|
||||||
hw->dma_int_clr.outfifo_empty_err= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool spi_ll_txdma_get_empty_err(spi_dev_t* hw)
|
|
||||||
{
|
|
||||||
return hw->dma_int_raw.outfifo_empty_err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
@@ -559,7 +505,7 @@ static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_ll_slave_set_seg_mode(spi_dev_t* hw, bool seg_trans)
|
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.dma_seg_trans_en = seg_trans;
|
||||||
hw->dma_conf.rx_eof_en = seg_trans;
|
hw->dma_conf.rx_eof_en = seg_trans;
|
||||||
@@ -590,7 +536,7 @@ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id)
|
|||||||
* @param hw Beginning address of the peripheral registers.
|
* @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, spi_ll_clock_val_t *val)
|
static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_clock_val_t *val)
|
||||||
{
|
{
|
||||||
hw->clock.val = *(uint32_t *)val;
|
hw->clock.val = *(uint32_t *)val;
|
||||||
}
|
}
|
||||||
@@ -784,7 +730,7 @@ 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.
|
* Enable/disable the segment transfer feature for the slave.
|
||||||
*
|
*
|
||||||
* @param hw Beginning address of the peripheral registers.
|
* @param hw Beginning address of the peripheral registers.
|
||||||
* @param en true to enable, false to disable.
|
* @param en true to enable, false to disable.
|
||||||
*/
|
*/
|
||||||
static inline void spi_ll_slave_set_seg_en(spi_dev_t *hw, bool en)
|
static inline void spi_ll_slave_set_seg_en(spi_dev_t *hw, bool en)
|
||||||
{
|
{
|
||||||
@@ -982,7 +928,7 @@ static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw)
|
|||||||
item(SPI_LL_INTR_OUT_EOF, dma_int_ena.out_eof, dma_int_raw.out_eof, dma_int_clr.out_eof=1) \
|
item(SPI_LL_INTR_OUT_EOF, dma_int_ena.out_eof, dma_int_raw.out_eof, dma_int_clr.out_eof=1) \
|
||||||
item(SPI_LL_INTR_OUT_TOTAL_EOF, dma_int_ena.out_total_eof, dma_int_raw.out_total_eof, dma_int_clr.out_total_eof=1) \
|
item(SPI_LL_INTR_OUT_TOTAL_EOF, dma_int_ena.out_total_eof, dma_int_raw.out_total_eof, dma_int_clr.out_total_eof=1) \
|
||||||
item(SPI_LL_INTR_SEG_DONE, slave.int_dma_seg_trans_en, hold.dma_seg_trans_done, hold.dma_seg_trans_done=0) \
|
item(SPI_LL_INTR_SEG_DONE, slave.int_dma_seg_trans_en, hold.dma_seg_trans_done, hold.dma_seg_trans_done=0) \
|
||||||
item(SPI_LL_INTR_IN_FULL, dma_int_ena.infifo_full_err, dma_int_raw.infifo_full_err, dma_int_clr.infifo_full_err=1) \
|
item(SPI_LL_INTR_IN_FULL, dma_int_ena.infifo_full_err, dma_int_raw.infifo_full_err, dma_int_clr.infifo_full_err=1) \
|
||||||
item(SPI_LL_INTR_OUT_EMPTY, dma_int_ena.outfifo_empty_err, dma_int_raw.outfifo_empty_err, dma_int_clr.outfifo_empty_err=1) \
|
item(SPI_LL_INTR_OUT_EMPTY, dma_int_ena.outfifo_empty_err, dma_int_raw.outfifo_empty_err, dma_int_clr.outfifo_empty_err=1) \
|
||||||
item(SPI_LL_INTR_WR_DONE, dma_int_ena.cmd7, dma_int_raw.cmd7, dma_int_clr.cmd7=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_CMD8, dma_int_ena.cmd8, dma_int_raw.cmd8, dma_int_clr.cmd8=1) \
|
||||||
@@ -1047,7 +993,6 @@ static inline void spi_ll_disable_int(spi_dev_t *hw)
|
|||||||
static inline void spi_ll_clear_int_stat(spi_dev_t *hw)
|
static inline void spi_ll_clear_int_stat(spi_dev_t *hw)
|
||||||
{
|
{
|
||||||
hw->slave.trans_done = 0;
|
hw->slave.trans_done = 0;
|
||||||
hw->dma_int_clr.val = UINT32_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1070,27 +1015,6 @@ static inline void spi_ll_enable_int(spi_dev_t *hw)
|
|||||||
hw->slave.int_trans_done_en = 1;
|
hw->slave.int_trans_done_en = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
switch (int_type) {
|
|
||||||
case SPI_LL_INT_TYPE_SEG:
|
|
||||||
hw->dma_int_ena.in_suc_eof = 1;
|
|
||||||
hw->dma_int_ena.out_total_eof = 1;
|
|
||||||
hw->slave.int_trans_done_en = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
hw->dma_int_ena.in_suc_eof = 0;
|
|
||||||
hw->dma_int_ena.out_total_eof = 0;
|
|
||||||
hw->slave.int_trans_done_en = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
* Slave HD
|
* Slave HD
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
@@ -1111,6 +1035,157 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t* hw)
|
|||||||
{
|
{
|
||||||
return hw->slave1.last_addr;
|
return hw->slave1.last_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* DMA:
|
||||||
|
* RX DMA (Peripherals->DMA->RAM)
|
||||||
|
* TX DMA (RAM->DMA->Peripherals)
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Reset RX DMA which stores the data received from a peripheral into RAM.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in)
|
||||||
|
{
|
||||||
|
//Reset RX DMA peripheral
|
||||||
|
dma_in->dma_in_link.dma_rx_ena = 0;
|
||||||
|
assert(dma_in->dma_in_link.dma_rx_ena == 0);
|
||||||
|
|
||||||
|
dma_in->dma_conf.in_rst = 1;
|
||||||
|
dma_in->dma_conf.in_rst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start RX DMA.
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
* @param addr Address of the beginning DMA descriptor.
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, lldesc_t *addr)
|
||||||
|
{
|
||||||
|
dma_in->dma_in_link.addr = (int) addr & 0xFFFFF;
|
||||||
|
dma_in->dma_in_link.start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable DMA RX channel burst for data
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_rx_enable_burst_data(spi_dma_dev_t *dma_out, bool enable)
|
||||||
|
{
|
||||||
|
//This is not supported in esp32s2
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable DMA TX channel burst for descriptor
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, bool enable)
|
||||||
|
{
|
||||||
|
dma_in->dma_conf.indscr_burst_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration of RX DMA EOF interrupt generation way
|
||||||
|
*
|
||||||
|
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
* @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_dma_ll_set_rx_eof_generation(spi_dma_dev_t *dma_in, bool enable)
|
||||||
|
{
|
||||||
|
dma_in->dma_conf.rx_eof_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset TX DMA which transmits the data from RAM to a peripheral.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out)
|
||||||
|
{
|
||||||
|
//Reset TX DMA peripheral
|
||||||
|
dma_out->dma_conf.out_rst = 1;
|
||||||
|
dma_out->dma_conf.out_rst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start TX DMA.
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param addr Address of the beginning DMA descriptor.
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, lldesc_t *addr)
|
||||||
|
{
|
||||||
|
dma_out->dma_out_link.addr = (int) addr & 0xFFFFF;
|
||||||
|
dma_out->dma_out_link.start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable DMA TX channel burst for data
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_tx_enable_burst_data(spi_dma_dev_t *dma_out, bool enable)
|
||||||
|
{
|
||||||
|
dma_out->dma_conf.out_data_burst_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable DMA TX channel burst for descriptor
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_tx_enable_burst_desc(spi_dma_dev_t *dma_out, bool enable)
|
||||||
|
{
|
||||||
|
dma_out->dma_conf.outdscr_burst_en = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable automatic outlink-writeback
|
||||||
|
*
|
||||||
|
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
|
* @param enable True to enable, false to disable
|
||||||
|
*/
|
||||||
|
static inline void spi_dma_ll_enable_out_auto_wrback(spi_dma_dev_t *dma_out, bool enable)
|
||||||
|
{
|
||||||
|
dma_out->dma_conf.out_auto_wrback = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void spi_dma_ll_rx_restart(spi_dma_dev_t *dma_in)
|
||||||
|
{
|
||||||
|
dma_in->dma_in_link.restart = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void spi_dma_ll_tx_restart(spi_dma_dev_t *dma_out)
|
||||||
|
{
|
||||||
|
dma_out->dma_out_link.restart = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void spi_dma_ll_rx_disable(spi_dma_dev_t *dma_in)
|
||||||
|
{
|
||||||
|
dma_in->dma_in_link.dma_rx_ena = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void spi_dma_ll_tx_disable(spi_dma_dev_t *dma_out)
|
||||||
|
{
|
||||||
|
dma_out->dma_out_link.dma_tx_ena = 0;
|
||||||
|
dma_out->dma_out_link.stop = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool spi_ll_tx_get_empty_err(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->dma_int_raw.outfifo_empty_err;
|
||||||
|
}
|
||||||
|
|
||||||
#undef SPI_LL_RST_MASK
|
#undef SPI_LL_RST_MASK
|
||||||
#undef SPI_LL_UNUSED_INT_MASK
|
#undef SPI_LL_UNUSED_INT_MASK
|
||||||
|
|
||||||
|
@@ -38,83 +38,115 @@
|
|||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
#include "soc/lldesc.h"
|
#include "soc/lldesc.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input parameters to the ``spi_hal_cal_clock_conf`` to calculate the timing configuration
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t half_duplex; ///< Whether half duplex mode is used, device specific
|
||||||
|
uint32_t no_compensate; ///< No need to add dummy to compensate the timing, device specific
|
||||||
|
uint32_t clock_speed_hz; ///< Desired frequency.
|
||||||
|
uint32_t duty_cycle; ///< Desired duty cycle of SPI clock
|
||||||
|
uint32_t input_delay_ns; /**< Maximum delay between SPI launch clock and the data to be valid.
|
||||||
|
* This is used to compensate/calculate the maximum frequency allowed.
|
||||||
|
* Left 0 if not known.
|
||||||
|
*/
|
||||||
|
bool use_gpio; ///< True if the GPIO matrix is used, otherwise false
|
||||||
|
} spi_hal_timing_param_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timing configuration structure that should be calculated by
|
* Timing configuration structure that should be calculated by
|
||||||
* ``spi_hal_setup_clock`` at initialization and hold. Filled into the
|
* ``spi_hal_cal_clock_conf`` at initialization and hold. Filled into the
|
||||||
* ``timing_conf`` member of the context of HAL before setup a device.
|
* ``timing_conf`` member of the context of HAL before setup a device.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
spi_ll_clock_val_t clock_reg; ///< Register value used by the LL layer
|
spi_ll_clock_val_t clock_reg; ///< Register value used by the LL layer
|
||||||
int timing_dummy; ///< Extra dummy needed to compensate the timing
|
int timing_dummy; ///< Extra dummy needed to compensate the timing
|
||||||
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
|
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
|
||||||
} spi_hal_timing_conf_t;
|
} spi_hal_timing_conf_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DMA configuration structure
|
||||||
|
* Should be set by driver at initialization
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
|
||||||
|
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
|
||||||
|
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
|
||||||
|
* The amount should be larger than dmadesc_n. The driver should ensure that
|
||||||
|
* the data to be sent is shorter than the descriptors can hold.
|
||||||
|
*/
|
||||||
|
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
|
||||||
|
* The amount should be larger than dmadesc_n. The driver should ensure that
|
||||||
|
* the data to be sent is shorter than the descriptors can hold.
|
||||||
|
*/
|
||||||
|
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
|
||||||
|
} spi_hal_dma_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transaction configuration structure, this should be assigned by driver each time.
|
||||||
|
* All these parameters will be updated to the peripheral every transaction.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t cmd; ///< Command value to be sent
|
||||||
|
int cmd_bits; ///< Length (in bits) of the command phase
|
||||||
|
int addr_bits; ///< Length (in bits) of the address phase
|
||||||
|
int dummy_bits; ///< Base length (in bits) of the dummy phase. Note when the compensation is enabled, some extra dummy bits may be appended.
|
||||||
|
int tx_bitlen; ///< TX length, in bits
|
||||||
|
int rx_bitlen; ///< RX length, in bits
|
||||||
|
uint64_t addr; ///< Address value to be sent
|
||||||
|
uint8_t *send_buffer; ///< Data to be sent
|
||||||
|
uint8_t *rcv_buffer; ///< Buffer to hold the receive data.
|
||||||
|
spi_ll_io_mode_t io_mode; ///< IO mode of the master
|
||||||
|
} spi_hal_trans_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context that should be maintained by both the driver and the HAL.
|
* Context that should be maintained by both the driver and the HAL.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* configured by driver at initialization, don't touch */
|
/* Configured by driver at initialization, don't touch */
|
||||||
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
|
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
|
||||||
/* should be configured by driver at initialization */
|
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM (DMA -> RAM).
|
||||||
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
|
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral (RAM -> DMA).
|
||||||
* The amount should be larger than dmadesc_n. The driver should ensure that
|
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
|
||||||
* the data to be sent is shorter than the descriptors can hold.
|
spi_hal_dma_config_t dma_config; ///< DMA configuration
|
||||||
*/
|
|
||||||
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
|
/* Internal parameters, don't touch */
|
||||||
* The amount should be larger than dmadesc_n. The driver should ensure that
|
spi_hal_trans_config_t trans_config; ///< Transaction configuration
|
||||||
* the data to be sent is shorter than the descriptors can hold.
|
} spi_hal_context_t;
|
||||||
*/
|
|
||||||
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
|
/**
|
||||||
/*
|
* Device configuration structure, this should be initialised by driver based on different devices respectively.
|
||||||
* Device specific, all these parameters will be updated to the peripheral
|
* All these parameters will be updated to the peripheral only when ``spi_hal_setup_device``.
|
||||||
* only when ``spi_hal_setup_device``. They may not get updated when
|
* They may not get updated when ``spi_hal_setup_trans``.
|
||||||
* ``spi_hal_setup_trans``.
|
*/
|
||||||
*/
|
typedef struct {
|
||||||
int mode; ///< SPI mode, device specific
|
int mode; ///< SPI mode, device specific
|
||||||
int cs_setup; ///< Setup time of CS active edge before the first SPI clock, device specific
|
int cs_setup; ///< Setup time of CS active edge before the first SPI clock, device specific
|
||||||
int cs_hold; ///< Hold time of CS inactive edge after the last SPI clock, device specific
|
int cs_hold; ///< Hold time of CS inactive edge after the last SPI clock, device specific
|
||||||
int cs_pin_id; ///< CS pin to use, 0-2, otherwise all the CS pins are not used. Device specific
|
int cs_pin_id; ///< CS pin to use, 0-2, otherwise all the CS pins are not used. Device specific
|
||||||
spi_hal_timing_conf_t *timing_conf; /**< Pointer to an structure holding
|
spi_hal_timing_conf_t timing_conf; /**< This structure holds the pre-calculated timing configuration for the device
|
||||||
* the pre-calculated timing configuration for the device at initialization,
|
* at initialization, device specific
|
||||||
* device specific
|
|
||||||
*/
|
*/
|
||||||
struct {
|
struct {
|
||||||
uint32_t sio : 1; ///< Whether to use SIO mode, device specific
|
uint32_t sio : 1; ///< Whether to use SIO mode, device specific
|
||||||
uint32_t half_duplex : 1; ///< Whether half duplex mode is used, device specific
|
uint32_t half_duplex : 1; ///< Whether half duplex mode is used, device specific
|
||||||
uint32_t tx_lsbfirst : 1; ///< Whether LSB is sent first for TX data, device specific
|
uint32_t tx_lsbfirst : 1; ///< Whether LSB is sent first for TX data, device specific
|
||||||
uint32_t rx_lsbfirst : 1; ///< Whether LSB is received first for RX data, device specific
|
uint32_t rx_lsbfirst : 1; ///< Whether LSB is received first for RX data, device specific
|
||||||
uint32_t dma_enabled : 1; ///< Whether the DMA is enabled, do not update after initialization
|
uint32_t no_compensate : 1; ///< No need to add dummy to compensate the timing, device specific
|
||||||
uint32_t no_compensate : 1; ///< No need to add dummy to compensate the timing, device specific
|
|
||||||
#ifdef SOC_SPI_SUPPORT_AS_CS
|
#ifdef SOC_SPI_SUPPORT_AS_CS
|
||||||
uint32_t as_cs : 1; ///< Whether to toggle the CS while the clock toggles, device specific
|
uint32_t as_cs : 1; ///< Whether to toggle the CS while the clock toggles, device specific
|
||||||
#endif
|
#endif
|
||||||
uint32_t positive_cs : 1; ///< Whether the postive CS feature is abled, device specific
|
uint32_t positive_cs : 1; ///< Whether the postive CS feature is abled, device specific
|
||||||
};//boolean configurations
|
};//boolean configurations
|
||||||
|
} spi_hal_dev_config_t;
|
||||||
/*
|
|
||||||
* Transaction specific (data), all these parameters will be updated to the
|
|
||||||
* peripheral every transaction.
|
|
||||||
*/
|
|
||||||
uint16_t cmd; ///< Command value to be sent
|
|
||||||
int cmd_bits; ///< Length (in bits) of the command phase
|
|
||||||
int addr_bits; ///< Length (in bits) of the address phase
|
|
||||||
int dummy_bits; ///< Base length (in bits) of the dummy phase. Note when the compensation is enabled, some extra dummy bits may be appended.
|
|
||||||
int tx_bitlen; ///< TX length, in bits
|
|
||||||
int rx_bitlen; ///< RX length, in bits
|
|
||||||
uint64_t addr; ///< Address value to be sent
|
|
||||||
uint8_t *send_buffer; ///< Data to be sent
|
|
||||||
uint8_t *rcv_buffer; ///< Buffer to hold the receive data.
|
|
||||||
spi_ll_io_mode_t io_mode; ///< IO mode of the master
|
|
||||||
|
|
||||||
} spi_hal_context_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init the peripheral and the context.
|
* Init the peripheral and the context.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer.
|
* @param hal Context of the HAL layer.
|
||||||
* @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for HSPI (SPI2) and 2 for VSPI (SPI3).
|
* @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for HSPI (SPI2) and 2 for VSPI (SPI3).
|
||||||
*/
|
*/
|
||||||
void spi_hal_init(spi_hal_context_t *hal, int host_id);
|
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_dma_config_t *hal_dma_config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deinit the peripheral (and the context if needed).
|
* Deinit the peripheral (and the context if needed).
|
||||||
@@ -126,23 +158,28 @@ void spi_hal_deinit(spi_hal_context_t *hal);
|
|||||||
/**
|
/**
|
||||||
* Setup device-related configurations according to the settings in the context.
|
* Setup device-related configurations according to the settings in the context.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer.
|
* @param hal Context of the HAL layer.
|
||||||
|
* @param hal_dev Device configuration
|
||||||
*/
|
*/
|
||||||
void spi_hal_setup_device(const spi_hal_context_t *hal);
|
void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup transaction related configurations according to the settings in the context.
|
* Setup transaction related configurations according to the settings in the context.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer.
|
* @param hal Context of the HAL layer.
|
||||||
|
* @param hal_dev Device configuration
|
||||||
|
* @param hal_trans Transaction configuration
|
||||||
*/
|
*/
|
||||||
void spi_hal_setup_trans(const spi_hal_context_t *hal);
|
void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the data for the current transaction.
|
* Prepare the data for the current transaction.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer.
|
* @param hal Context of the HAL layer.
|
||||||
|
* @param hal_dev Device configuration
|
||||||
|
* @param hal_trans Transaction configuration
|
||||||
*/
|
*/
|
||||||
void spi_hal_prepare_data(const spi_hal_context_t *hal);
|
void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger start a user-defined transaction.
|
* Trigger start a user-defined transaction.
|
||||||
@@ -161,7 +198,7 @@ bool spi_hal_usr_is_done(const spi_hal_context_t *hal);
|
|||||||
/**
|
/**
|
||||||
* Post transaction operations, mainly fetch data from the buffer.
|
* Post transaction operations, mainly fetch data from the buffer.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer.
|
* @param hal Context of the HAL layer.
|
||||||
*/
|
*/
|
||||||
void spi_hal_fetch_result(const spi_hal_context_t *hal);
|
void spi_hal_fetch_result(const spi_hal_context_t *hal);
|
||||||
|
|
||||||
@@ -173,50 +210,44 @@ void spi_hal_fetch_result(const spi_hal_context_t *hal);
|
|||||||
*
|
*
|
||||||
* It is highly suggested to do this at initialization, since it takes long time.
|
* It is highly suggested to do this at initialization, since it takes long time.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer.
|
* @param timing_param Input parameters to calculate timing configuration
|
||||||
* @param speed_hz Desired frequency.
|
* @param out_freq Output of the actual frequency, left NULL if not required.
|
||||||
* @param duty_cycle Desired duty cycle of SPI clock
|
* @param timing_conf Output of the timing configuration.
|
||||||
* @param use_gpio true if the GPIO matrix is used, otherwise false
|
|
||||||
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
|
|
||||||
* be valid. This is used to compensate/calculate the maximum frequency
|
|
||||||
* allowed. Left 0 if not known.
|
|
||||||
* @param out_freq Output of the actual frequency, left NULL if not required.
|
|
||||||
* @param timing_conf Output of the timing configuration.
|
|
||||||
*
|
*
|
||||||
* @return ESP_OK if desired is available, otherwise fail.
|
* @return ESP_OK if desired is available, otherwise fail.
|
||||||
*/
|
*/
|
||||||
esp_err_t spi_hal_cal_clock_conf(const spi_hal_context_t *hal, int speed_hz, int duty_cycle, bool use_gpio, int input_delay_ns, int *out_freq, spi_hal_timing_conf_t *timing_conf);
|
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, int *out_freq, spi_hal_timing_conf_t *timing_conf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the frequency actual used.
|
* Get the frequency actual used.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer.
|
* @param hal Context of the HAL layer.
|
||||||
* @param fapb APB clock frequency.
|
* @param fapb APB clock frequency.
|
||||||
* @param hz Desired frequencyc.
|
* @param hz Desired frequencyc.
|
||||||
* @param duty_cycle Desired duty cycle.
|
* @param duty_cycle Desired duty cycle.
|
||||||
*/
|
*/
|
||||||
int spi_hal_master_cal_clock(int fapb, int hz, int duty_cycle);
|
int spi_hal_master_cal_clock(int fapb, int hz, int duty_cycle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the timing configuration for given parameters.
|
* Get the timing configuration for given parameters.
|
||||||
*
|
*
|
||||||
* @param eff_clk Actual SPI clock frequency
|
* @param eff_clk Actual SPI clock frequency
|
||||||
* @param gpio_is_used true if the GPIO matrix is used, otherwise false.
|
* @param gpio_is_used true if the GPIO matrix is used, otherwise false.
|
||||||
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
|
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
|
||||||
* be valid. This is used to compensate/calculate the maximum frequency
|
* be valid. This is used to compensate/calculate the maximum frequency
|
||||||
* allowed. Left 0 if not known.
|
* allowed. Left 0 if not known.
|
||||||
* @param dummy_n Dummy cycles required to correctly read the data.
|
* @param dummy_n Dummy cycles required to correctly read the data.
|
||||||
* @param miso_delay_n suggested delay on the MISO line, in APB clocks.
|
* @param miso_delay_n suggested delay on the MISO line, in APB clocks.
|
||||||
*/
|
*/
|
||||||
void spi_hal_cal_timing(int eff_clk, bool gpio_is_used, int input_delay_ns, int *dummy_n, int *miso_delay_n);
|
void spi_hal_cal_timing(int eff_clk, bool gpio_is_used, int input_delay_ns, int *dummy_n, int *miso_delay_n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum frequency allowed to read if no compensation is used.
|
* Get the maximum frequency allowed to read if no compensation is used.
|
||||||
*
|
*
|
||||||
* @param gpio_is_used true if the GPIO matrix is used, otherwise false.
|
* @param gpio_is_used true if the GPIO matrix is used, otherwise false.
|
||||||
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
|
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
|
||||||
* be valid. This is used to compensate/calculate the maximum frequency
|
* be valid. This is used to compensate/calculate the maximum frequency
|
||||||
* allowed. Left 0 if not known.
|
* allowed. Left 0 if not known.
|
||||||
*/
|
*/
|
||||||
int spi_hal_get_freq_limit(bool gpio_is_used, int input_delay_ns);
|
int spi_hal_get_freq_limit(bool gpio_is_used, int input_delay_ns);
|
||||||
|
|
||||||
|
@@ -36,32 +36,35 @@
|
|||||||
#include "soc/spi_struct.h"
|
#include "soc/spi_struct.h"
|
||||||
#include <esp_types.h>
|
#include <esp_types.h>
|
||||||
#include "soc/spi_caps.h"
|
#include "soc/spi_caps.h"
|
||||||
|
#include "hal/spi_ll.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context that should be maintained by both the driver and the HAL.
|
* Context that should be maintained by both the driver and the HAL.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* configured by driver at initialization, don't touch */
|
/* configured by driver at initialization, don't touch */
|
||||||
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
|
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
|
||||||
|
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
|
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
/* should be configured by driver at initialization */
|
/* should be configured by driver at initialization */
|
||||||
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA.
|
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA.
|
||||||
* The amount should be larger than dmadesc_n. The driver should ensure that
|
* The amount should be larger than dmadesc_n. The driver should ensure that
|
||||||
* the data to be sent is shorter than the descriptors can hold.
|
* the data to be sent is shorter than the descriptors can hold.
|
||||||
*/
|
*/
|
||||||
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the RX DMA.
|
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the RX DMA.
|
||||||
* The amount should be larger than dmadesc_n. The driver should ensure that
|
* The amount should be larger than dmadesc_n. The driver should ensure that
|
||||||
* the data to be sent is shorter than the descriptors can hold.
|
* the data to be sent is shorter than the descriptors can hold.
|
||||||
*/
|
*/
|
||||||
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
|
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* configurations to be filled after ``spi_slave_hal_init``. Updated to
|
* configurations to be filled after ``spi_slave_hal_init``. Updated to
|
||||||
* peripheral registers when ``spi_slave_hal_setup_device`` is called.
|
* peripheral registers when ``spi_slave_hal_setup_device`` is called.
|
||||||
*/
|
*/
|
||||||
struct {
|
struct {
|
||||||
uint32_t rx_lsbfirst : 1;
|
uint32_t rx_lsbfirst : 1;
|
||||||
uint32_t tx_lsbfirst : 1;
|
uint32_t tx_lsbfirst : 1;
|
||||||
uint32_t use_dma : 1;
|
uint32_t use_dma : 1;
|
||||||
};
|
};
|
||||||
int mode;
|
int mode;
|
||||||
|
|
||||||
@@ -69,21 +72,27 @@ typedef struct {
|
|||||||
* Transaction specific (data), all these parameters will be updated to the
|
* Transaction specific (data), all these parameters will be updated to the
|
||||||
* peripheral every transaction.
|
* peripheral every transaction.
|
||||||
*/
|
*/
|
||||||
uint32_t bitlen; ///< Expected maximum length of the transaction, in bits.
|
uint32_t bitlen; ///< Expected maximum length of the transaction, in bits.
|
||||||
const void *tx_buffer; ///< Data to be sent
|
const void *tx_buffer; ///< Data to be sent
|
||||||
void *rx_buffer; ///< Buffer to hold the received data.
|
void *rx_buffer; ///< Buffer to hold the received data.
|
||||||
|
|
||||||
/* Other transaction result after one transaction */
|
/* Other transaction result after one transaction */
|
||||||
uint32_t rcv_bitlen; ///< Length of the last transaction, in bits.
|
uint32_t rcv_bitlen; ///< Length of the last transaction, in bits.
|
||||||
} spi_slave_hal_context_t;
|
} spi_slave_hal_context_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t host_id; ///< SPI controller ID
|
||||||
|
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
|
||||||
|
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
|
||||||
|
} spi_slave_hal_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init the peripheral and the context.
|
* Init the peripheral and the context.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer.
|
* @param hal Context of the HAL layer.
|
||||||
* @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for HSPI (SPI2) and 2 for VSPI (SPI3).
|
* @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for HSPI (SPI2) and 2 for VSPI (SPI3).
|
||||||
*/
|
*/
|
||||||
void spi_slave_hal_init(spi_slave_hal_context_t *hal, int host_id);
|
void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deinit the peripheral (and the context if needed).
|
* Deinit the peripheral (and the context if needed).
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
* The HAL layer for SPI Slave HD mode, currently only segment mode is supported
|
* The HAL layer for SPI Slave HD mode, currently only segment mode is supported
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* - Firstly, initialize the slave with `slave_hd_hal_init`
|
* - Firstly, initialize the slave with `spi_slave_hd_hal_init`
|
||||||
*
|
*
|
||||||
* - Event handling:
|
* - Event handling:
|
||||||
* - (Optional) Call ``spi_slave_hd_hal_enable_event_intr`` to enable the used interrupts
|
* - (Optional) Call ``spi_slave_hd_hal_enable_event_intr`` to enable the used interrupts
|
||||||
@@ -59,51 +59,54 @@
|
|||||||
|
|
||||||
/// Configuration of the HAL
|
/// Configuration of the HAL
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int host_id; ///< Host ID of the spi peripheral
|
uint32_t host_id; ///< Host ID of the spi peripheral
|
||||||
int spics_io_num; ///< CS GPIO pin for this device
|
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
|
||||||
uint8_t mode; ///< SPI mode (0-3)
|
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
|
||||||
int command_bits; ///< command field bits, multiples of 8 and at least 8.
|
uint32_t spics_io_num; ///< CS GPIO pin for this device
|
||||||
int address_bits; ///< address field bits, multiples of 8 and at least 8.
|
uint8_t mode; ///< SPI mode (0-3)
|
||||||
int dummy_bits; ///< dummy field bits, multiples of 8 and at least 8.
|
uint32_t command_bits; ///< command field bits, multiples of 8 and at least 8.
|
||||||
|
uint32_t address_bits; ///< address field bits, multiples of 8 and at least 8.
|
||||||
|
uint32_t dummy_bits; ///< dummy field bits, multiples of 8 and at least 8.
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t tx_lsbfirst : 1;///< Whether TX data should be sent with LSB first.
|
uint32_t tx_lsbfirst : 1; ///< Whether TX data should be sent with LSB first.
|
||||||
uint32_t rx_lsbfirst : 1;///< Whether RX data should be read with LSB first.
|
uint32_t rx_lsbfirst : 1; ///< Whether RX data should be read with LSB first.
|
||||||
};
|
};
|
||||||
int dma_chan; ///< The dma channel used.
|
uint32_t dma_chan; ///< The dma channel used.
|
||||||
} spi_slave_hd_hal_config_t;
|
} spi_slave_hd_hal_config_t;
|
||||||
|
|
||||||
/// Context of the HAL, initialized by :cpp:func:`slave_hd_hal_init`.
|
/// Context of the HAL, initialized by :cpp:func:`spi_slave_hd_hal_init`.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
spi_dev_t* dev; ///< Beginning address of the peripheral registers.
|
spi_dev_t *dev; ///< Beginning address of the peripheral registers.
|
||||||
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
|
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
|
||||||
* The amount should be larger than dmadesc_n. The driver should ensure that
|
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
|
||||||
* the data to be sent is shorter than the descriptors can hold.
|
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
|
||||||
*/
|
* The amount should be larger than dmadesc_n. The driver should ensure that
|
||||||
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
|
* the data to be sent is shorter than the descriptors can hold.
|
||||||
* The amount should be larger than dmadesc_n. The driver should ensure that
|
*/
|
||||||
* the data to be sent is shorter than the descriptors can hold.
|
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
|
||||||
*/
|
* The amount should be larger than dmadesc_n. The driver should ensure that
|
||||||
|
* the data to be sent is shorter than the descriptors can hold.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Internal status used by the HAL implementation, initialized as 0. */
|
/* Internal status used by the HAL implementation, initialized as 0. */
|
||||||
uint32_t intr_not_triggered;
|
uint32_t intr_not_triggered;
|
||||||
} spi_slave_hd_hal_context_t;
|
} spi_slave_hd_hal_context_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the hardware and part of the context
|
* @brief Initialize the hardware and part of the context
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer
|
* @param hal Context of the HAL layer
|
||||||
* @param config Configuration of the HAL
|
* @param hal_config Configuration of the HAL
|
||||||
*/
|
*/
|
||||||
void slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *config);
|
void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check and clear signal of one event
|
* @brief Check and clear signal of one event
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer
|
* @param hal Context of the HAL layer
|
||||||
* @param ev Event to check
|
* @param ev Event to check
|
||||||
* @return true if event triggered, otherwise false
|
* @return True if event triggered, otherwise false
|
||||||
*/
|
*/
|
||||||
bool spi_slave_hd_hal_check_clear_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
|
bool spi_slave_hd_hal_check_clear_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
|
||||||
|
|
||||||
@@ -116,7 +119,7 @@ bool spi_slave_hd_hal_check_clear_event(spi_slave_hd_hal_context_t* hal, spi_eve
|
|||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer
|
* @param hal Context of the HAL layer
|
||||||
* @param ev Event to check and disable
|
* @param ev Event to check and disable
|
||||||
* @return true if event triggered, otherwise false
|
* @return True if event triggered, otherwise false
|
||||||
*/
|
*/
|
||||||
bool spi_slave_hd_hal_check_disable_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
|
bool spi_slave_hd_hal_check_disable_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
|
||||||
|
|
||||||
@@ -156,7 +159,7 @@ void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, s
|
|||||||
* @brief Get the length of total received data
|
* @brief Get the length of total received data
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer
|
* @param hal Context of the HAL layer
|
||||||
* @return The received length
|
* @return The received length
|
||||||
*/
|
*/
|
||||||
int spi_slave_hd_hal_rxdma_get_len(spi_slave_hd_hal_context_t *hal);
|
int spi_slave_hd_hal_rxdma_get_len(spi_slave_hd_hal_context_t *hal);
|
||||||
|
|
||||||
@@ -167,8 +170,8 @@ int spi_slave_hd_hal_rxdma_get_len(spi_slave_hd_hal_context_t *hal);
|
|||||||
* @brief Start the TX DMA operation with the specified buffer
|
* @brief Start the TX DMA operation with the specified buffer
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer
|
* @param hal Context of the HAL layer
|
||||||
* @param data Buffer of data to send
|
* @param data Buffer of data to send
|
||||||
* @param len Size of the buffer, also the maximum length to send
|
* @param len Size of the buffer, also the maximum length to send
|
||||||
*/
|
*/
|
||||||
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len);
|
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len);
|
||||||
|
|
||||||
@@ -179,9 +182,9 @@ void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size
|
|||||||
* @brief Read from the shared register buffer
|
* @brief Read from the shared register buffer
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer
|
* @param hal Context of the HAL layer
|
||||||
* @param addr Address of the shared regsiter to read
|
* @param addr Address of the shared regsiter to read
|
||||||
* @param out_data Buffer to store the read data
|
* @param out_data Buffer to store the read data
|
||||||
* @param len Length to read from the shared buffer
|
* @param len Length to read from the shared buffer
|
||||||
*/
|
*/
|
||||||
void spi_slave_hd_hal_read_buffer(spi_slave_hd_hal_context_t *hal, int addr, uint8_t *out_data, size_t len);
|
void spi_slave_hd_hal_read_buffer(spi_slave_hd_hal_context_t *hal, int addr, uint8_t *out_data, size_t len);
|
||||||
|
|
||||||
@@ -199,7 +202,7 @@ void spi_slave_hd_hal_write_buffer(spi_slave_hd_hal_context_t *hal, int addr, ui
|
|||||||
* @brief Get the length of previous transaction.
|
* @brief Get the length of previous transaction.
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer
|
* @param hal Context of the HAL layer
|
||||||
* @return The length of previous transaction
|
* @return The length of previous transaction
|
||||||
*/
|
*/
|
||||||
int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal);
|
int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal);
|
||||||
|
|
||||||
@@ -207,6 +210,6 @@ int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal);
|
|||||||
* @brief Get the address of last transaction
|
* @brief Get the address of last transaction
|
||||||
*
|
*
|
||||||
* @param hal Context of the HAL layer
|
* @param hal Context of the HAL layer
|
||||||
* @return The address of last transaction
|
* @return The address of last transaction
|
||||||
*/
|
*/
|
||||||
int spi_slave_hd_hal_get_last_addr(spi_slave_hd_hal_context_t *hal);
|
int spi_slave_hd_hal_get_last_addr(spi_slave_hd_hal_context_t *hal);
|
||||||
|
@@ -24,12 +24,24 @@ static const char SPI_HAL_TAG[] = "spi_hal";
|
|||||||
return (ret_val); \
|
return (ret_val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_hal_init(spi_hal_context_t *hal, int host_id)
|
static void s_spi_hal_dma_init_config(const spi_hal_context_t *hal)
|
||||||
|
{
|
||||||
|
spi_dma_ll_rx_enable_burst_data(hal->dma_in, 1);
|
||||||
|
spi_dma_ll_tx_enable_burst_data(hal->dma_out, 1);
|
||||||
|
spi_dma_ll_rx_enable_burst_desc(hal->dma_in, 1);
|
||||||
|
spi_dma_ll_tx_enable_burst_desc(hal->dma_out, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_dma_config_t *dma_config)
|
||||||
{
|
{
|
||||||
memset(hal, 0, sizeof(spi_hal_context_t));
|
memset(hal, 0, sizeof(spi_hal_context_t));
|
||||||
spi_dev_t *hw = spi_periph_signal[host_id].hw;
|
spi_dev_t *hw = SPI_LL_GET_HW(host_id);
|
||||||
hal->hw = hw;
|
hal->hw = hw;
|
||||||
|
hal->dma_in = dma_config->dma_in;
|
||||||
|
hal->dma_out = dma_config->dma_out;
|
||||||
|
|
||||||
spi_ll_master_init(hw);
|
spi_ll_master_init(hw);
|
||||||
|
s_spi_hal_dma_init_config(hal);
|
||||||
|
|
||||||
//Force a transaction done interrupt. This interrupt won't fire yet because
|
//Force a transaction done interrupt. This interrupt won't fire yet because
|
||||||
//we initialized the SPI interrupt as disabled. This way, we can just
|
//we initialized the SPI interrupt as disabled. This way, we can just
|
||||||
@@ -38,6 +50,9 @@ void spi_hal_init(spi_hal_context_t *hal, int host_id)
|
|||||||
spi_ll_enable_int(hw);
|
spi_ll_enable_int(hw);
|
||||||
spi_ll_set_int_stat(hw);
|
spi_ll_set_int_stat(hw);
|
||||||
spi_ll_set_mosi_delay(hw, 0, 0);
|
spi_ll_set_mosi_delay(hw, 0, 0);
|
||||||
|
|
||||||
|
//Save the dma configuration in ``spi_hal_context_t``
|
||||||
|
memcpy(&hal->dma_config, dma_config, sizeof(spi_hal_dma_config_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_hal_deinit(spi_hal_context_t *hal)
|
void spi_hal_deinit(spi_hal_context_t *hal)
|
||||||
@@ -49,20 +64,20 @@ void spi_hal_deinit(spi_hal_context_t *hal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t spi_hal_cal_clock_conf(const spi_hal_context_t *hal, int speed_hz, int duty_cycle, bool use_gpio, int input_delay_ns, int *out_freq, spi_hal_timing_conf_t *timing_conf)
|
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, int *out_freq, spi_hal_timing_conf_t *timing_conf)
|
||||||
{
|
{
|
||||||
spi_hal_timing_conf_t temp_conf;
|
spi_hal_timing_conf_t temp_conf;
|
||||||
|
|
||||||
int eff_clk_n = spi_ll_master_cal_clock(APB_CLK_FREQ, speed_hz, duty_cycle, &temp_conf.clock_reg);
|
int eff_clk_n = spi_ll_master_cal_clock(APB_CLK_FREQ, timing_param->clock_speed_hz, timing_param->duty_cycle, &temp_conf.clock_reg);
|
||||||
|
|
||||||
//When the speed is too fast, we may need to use dummy cycles to compensate the reading.
|
//When the speed is too fast, we may need to use dummy cycles to compensate the reading.
|
||||||
//But these don't work for full-duplex connections.
|
//But these don't work for full-duplex connections.
|
||||||
spi_hal_cal_timing(eff_clk_n, use_gpio, input_delay_ns, &temp_conf.timing_dummy, &temp_conf.timing_miso_delay);
|
spi_hal_cal_timing(eff_clk_n, timing_param->use_gpio, timing_param->input_delay_ns, &temp_conf.timing_dummy, &temp_conf.timing_miso_delay);
|
||||||
|
|
||||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
const int freq_limit = spi_hal_get_freq_limit(use_gpio, input_delay_ns);
|
const int freq_limit = spi_hal_get_freq_limit(timing_param->use_gpio, timing_param->input_delay_ns);
|
||||||
|
|
||||||
SPI_HAL_CHECK(hal->half_duplex || temp_conf.timing_dummy == 0 || hal->no_compensate,
|
SPI_HAL_CHECK(timing_param->half_duplex || temp_conf.timing_dummy == 0 || timing_param->no_compensate,
|
||||||
"When work in full-duplex mode at frequency > %.1fMHz, device cannot read correct data.\n\
|
"When work in full-duplex mode at frequency > %.1fMHz, device cannot read correct data.\n\
|
||||||
Try to use IOMUX pins to increase the frequency limit, or use the half duplex mode.\n\
|
Try to use IOMUX pins to increase the frequency limit, or use the half duplex mode.\n\
|
||||||
Please note the SPI master can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\
|
Please note the SPI master can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\
|
||||||
|
@@ -17,29 +17,29 @@
|
|||||||
|
|
||||||
#include "hal/spi_hal.h"
|
#include "hal/spi_hal.h"
|
||||||
|
|
||||||
void spi_hal_setup_device(const spi_hal_context_t *hal)
|
void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev)
|
||||||
{
|
{
|
||||||
//Configure clock settings
|
//Configure clock settings
|
||||||
spi_dev_t *hw = hal->hw;
|
spi_dev_t *hw = hal->hw;
|
||||||
#ifdef SOC_SPI_SUPPORT_AS_CS
|
#ifdef SOC_SPI_SUPPORT_AS_CS
|
||||||
spi_ll_master_set_cksel(hw, hal->cs_pin_id, hal->as_cs);
|
spi_ll_master_set_cksel(hw, dev->cs_pin_id, dev->as_cs);
|
||||||
#endif
|
#endif
|
||||||
spi_ll_master_set_pos_cs(hw, hal->cs_pin_id, hal->positive_cs);
|
spi_ll_master_set_pos_cs(hw, dev->cs_pin_id, dev->positive_cs);
|
||||||
spi_ll_master_set_clock_by_reg(hw, &hal->timing_conf->clock_reg);
|
spi_ll_master_set_clock_by_reg(hw, &dev->timing_conf.clock_reg);
|
||||||
//Configure bit order
|
//Configure bit order
|
||||||
spi_ll_set_rx_lsbfirst(hw, hal->rx_lsbfirst);
|
spi_ll_set_rx_lsbfirst(hw, dev->rx_lsbfirst);
|
||||||
spi_ll_set_tx_lsbfirst(hw, hal->tx_lsbfirst);
|
spi_ll_set_tx_lsbfirst(hw, dev->tx_lsbfirst);
|
||||||
spi_ll_master_set_mode(hw, hal->mode);
|
spi_ll_master_set_mode(hw, dev->mode);
|
||||||
//Configure misc stuff
|
//Configure misc stuff
|
||||||
spi_ll_set_half_duplex(hw, hal->half_duplex);
|
spi_ll_set_half_duplex(hw, dev->half_duplex);
|
||||||
spi_ll_set_sio_mode(hw, hal->sio);
|
spi_ll_set_sio_mode(hw, dev->sio);
|
||||||
//Configure CS pin and timing
|
//Configure CS pin and timing
|
||||||
spi_ll_master_set_cs_setup(hw, hal->cs_setup);
|
spi_ll_master_set_cs_setup(hw, dev->cs_setup);
|
||||||
spi_ll_master_set_cs_hold(hw, hal->cs_hold);
|
spi_ll_master_set_cs_hold(hw, dev->cs_hold);
|
||||||
spi_ll_master_select_cs(hw, hal->cs_pin_id);
|
spi_ll_master_select_cs(hw, dev->cs_pin_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_hal_setup_trans(const spi_hal_context_t *hal)
|
void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans)
|
||||||
{
|
{
|
||||||
spi_dev_t *hw = hal->hw;
|
spi_dev_t *hw = hal->hw;
|
||||||
|
|
||||||
@@ -48,23 +48,23 @@ void spi_hal_setup_trans(const spi_hal_context_t *hal)
|
|||||||
//We should be done with the transmission.
|
//We should be done with the transmission.
|
||||||
assert(spi_ll_get_running_cmd(hw) == 0);
|
assert(spi_ll_get_running_cmd(hw) == 0);
|
||||||
|
|
||||||
spi_ll_master_set_io_mode(hw, hal->io_mode);
|
spi_ll_master_set_io_mode(hw, trans->io_mode);
|
||||||
|
|
||||||
int extra_dummy = 0;
|
int extra_dummy = 0;
|
||||||
//when no_dummy is not set and in half-duplex mode, sets the dummy bit if RX phase exist
|
//when no_dummy is not set and in half-duplex mode, sets the dummy bit if RX phase exist
|
||||||
if (hal->rcv_buffer && !hal->no_compensate && hal->half_duplex) {
|
if (trans->rcv_buffer && !dev->no_compensate && dev->half_duplex) {
|
||||||
extra_dummy = hal->timing_conf->timing_dummy;
|
extra_dummy = dev->timing_conf.timing_dummy;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SPI iface needs to be configured for a delay in some cases.
|
//SPI iface needs to be configured for a delay in some cases.
|
||||||
//configure dummy bits
|
//configure dummy bits
|
||||||
spi_ll_set_dummy(hw, extra_dummy + hal->dummy_bits);
|
spi_ll_set_dummy(hw, extra_dummy + trans->dummy_bits);
|
||||||
|
|
||||||
uint32_t miso_delay_num = 0;
|
uint32_t miso_delay_num = 0;
|
||||||
uint32_t miso_delay_mode = 0;
|
uint32_t miso_delay_mode = 0;
|
||||||
if (hal->timing_conf->timing_miso_delay < 0) {
|
if (dev->timing_conf.timing_miso_delay < 0) {
|
||||||
//if the data comes too late, delay half a SPI clock to improve reading
|
//if the data comes too late, delay half a SPI clock to improve reading
|
||||||
switch (hal->mode) {
|
switch (dev->mode) {
|
||||||
case 0:
|
case 0:
|
||||||
miso_delay_mode = 2;
|
miso_delay_mode = 2;
|
||||||
break;
|
break;
|
||||||
@@ -81,24 +81,24 @@ void spi_hal_setup_trans(const spi_hal_context_t *hal)
|
|||||||
miso_delay_num = 0;
|
miso_delay_num = 0;
|
||||||
} else {
|
} else {
|
||||||
//if the data is so fast that dummy_bit is used, delay some apb clocks to meet the timing
|
//if the data is so fast that dummy_bit is used, delay some apb clocks to meet the timing
|
||||||
miso_delay_num = extra_dummy ? hal->timing_conf->timing_miso_delay : 0;
|
miso_delay_num = extra_dummy ? dev->timing_conf.timing_miso_delay : 0;
|
||||||
miso_delay_mode = 0;
|
miso_delay_mode = 0;
|
||||||
}
|
}
|
||||||
spi_ll_set_miso_delay(hw, miso_delay_mode, miso_delay_num);
|
spi_ll_set_miso_delay(hw, miso_delay_mode, miso_delay_num);
|
||||||
|
|
||||||
spi_ll_set_mosi_bitlen(hw, hal->tx_bitlen);
|
spi_ll_set_mosi_bitlen(hw, trans->tx_bitlen);
|
||||||
|
|
||||||
if (hal->half_duplex) {
|
if (dev->half_duplex) {
|
||||||
spi_ll_set_miso_bitlen(hw, hal->rx_bitlen);
|
spi_ll_set_miso_bitlen(hw, trans->rx_bitlen);
|
||||||
} else {
|
} else {
|
||||||
//rxlength is not used in full-duplex mode
|
//rxlength is not used in full-duplex mode
|
||||||
spi_ll_set_miso_bitlen(hw, hal->tx_bitlen);
|
spi_ll_set_miso_bitlen(hw, trans->tx_bitlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Configure bit sizes, load addr and command
|
//Configure bit sizes, load addr and command
|
||||||
int cmdlen = hal->cmd_bits;
|
int cmdlen = trans->cmd_bits;
|
||||||
int addrlen = hal->addr_bits;
|
int addrlen = trans->addr_bits;
|
||||||
if (!hal->half_duplex && hal->cs_setup != 0) {
|
if (!dev->half_duplex && dev->cs_setup != 0) {
|
||||||
/* The command and address phase is not compatible with cs_ena_pretrans
|
/* The command and address phase is not compatible with cs_ena_pretrans
|
||||||
* in full duplex mode.
|
* in full duplex mode.
|
||||||
*/
|
*/
|
||||||
@@ -109,45 +109,61 @@ void spi_hal_setup_trans(const spi_hal_context_t *hal)
|
|||||||
spi_ll_set_addr_bitlen(hw, addrlen);
|
spi_ll_set_addr_bitlen(hw, addrlen);
|
||||||
spi_ll_set_command_bitlen(hw, cmdlen);
|
spi_ll_set_command_bitlen(hw, cmdlen);
|
||||||
|
|
||||||
spi_ll_set_command(hw, hal->cmd, cmdlen, hal->tx_lsbfirst);
|
spi_ll_set_command(hw, trans->cmd, cmdlen, dev->tx_lsbfirst);
|
||||||
spi_ll_set_address(hw, hal->addr, addrlen, hal->tx_lsbfirst);
|
spi_ll_set_address(hw, trans->addr, addrlen, dev->tx_lsbfirst);
|
||||||
|
|
||||||
|
//Save the transaction attributes for internal usage.
|
||||||
|
memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_hal_prepare_data(const spi_hal_context_t *hal)
|
void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans)
|
||||||
{
|
{
|
||||||
spi_dev_t *hw = hal->hw;
|
spi_dev_t *hw = hal->hw;
|
||||||
spi_ll_reset_dma(hw);
|
|
||||||
|
spi_ll_dma_fifo_reset(hal->hw);
|
||||||
|
|
||||||
//Fill DMA descriptors
|
//Fill DMA descriptors
|
||||||
if (hal->rcv_buffer) {
|
if (trans->rcv_buffer) {
|
||||||
if (!hal->dma_enabled) {
|
if (!hal->dma_enabled) {
|
||||||
//No need to setup anything; we'll copy the result out of the work registers directly later.
|
//No need to setup anything; we'll copy the result out of the work registers directly later.
|
||||||
} else {
|
} else {
|
||||||
lldesc_setup_link(hal->dmadesc_rx, hal->rcv_buffer, ((hal->rx_bitlen + 7) / 8), true);
|
lldesc_setup_link(hal->dma_config.dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true);
|
||||||
spi_ll_rxdma_start(hw, hal->dmadesc_rx);
|
|
||||||
|
spi_dma_ll_rx_reset(hal->dma_in);
|
||||||
|
|
||||||
|
spi_ll_dma_rx_enable(hal->hw, 1);
|
||||||
|
spi_dma_ll_rx_start(hal->dma_in, hal->dma_config.dmadesc_rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
|
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
|
||||||
if (hal->dma_enabled) {
|
if (hal->dma_enabled) {
|
||||||
spi_ll_rxdma_start(hw, 0);
|
spi_ll_dma_rx_enable(hal->hw, 1);
|
||||||
|
spi_dma_ll_rx_start(hal->dma_in, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hal->send_buffer) {
|
if (trans->send_buffer) {
|
||||||
if (!hal->dma_enabled) {
|
if (!hal->dma_enabled) {
|
||||||
//Need to copy data to registers manually
|
//Need to copy data to registers manually
|
||||||
spi_ll_write_buffer(hw, hal->send_buffer, hal->tx_bitlen);
|
spi_ll_write_buffer(hw, trans->send_buffer, trans->tx_bitlen);
|
||||||
} else {
|
} else {
|
||||||
lldesc_setup_link(hal->dmadesc_tx, hal->send_buffer, (hal->tx_bitlen + 7) / 8, false);
|
lldesc_setup_link(hal->dma_config.dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false);
|
||||||
spi_ll_txdma_start(hw, hal->dmadesc_tx);
|
|
||||||
|
spi_dma_ll_tx_reset(hal->dma_out);
|
||||||
|
|
||||||
|
spi_ll_dma_tx_enable(hal->hw, 1);
|
||||||
|
spi_dma_ll_tx_start(hal->dma_out, hal->dma_config.dmadesc_tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//in ESP32 these registers should be configured after the DMA is set
|
//in ESP32 these registers should be configured after the DMA is set
|
||||||
if ((!hal->half_duplex && hal->rcv_buffer) || hal->send_buffer) {
|
if ((!dev->half_duplex && trans->rcv_buffer) || trans->send_buffer) {
|
||||||
spi_ll_enable_mosi(hw, 1);
|
spi_ll_enable_mosi(hw, 1);
|
||||||
} else {
|
} else {
|
||||||
spi_ll_enable_mosi(hw, 0);
|
spi_ll_enable_mosi(hw, 0);
|
||||||
}
|
}
|
||||||
spi_ll_enable_miso(hw, (hal->rcv_buffer) ? 1 : 0);
|
spi_ll_enable_miso(hw, (trans->rcv_buffer) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_hal_user_start(const spi_hal_context_t *hal)
|
void spi_hal_user_start(const spi_hal_context_t *hal)
|
||||||
@@ -162,8 +178,10 @@ bool spi_hal_usr_is_done(const spi_hal_context_t *hal)
|
|||||||
|
|
||||||
void spi_hal_fetch_result(const spi_hal_context_t *hal)
|
void spi_hal_fetch_result(const spi_hal_context_t *hal)
|
||||||
{
|
{
|
||||||
if (hal->rcv_buffer && !hal->dma_enabled) {
|
const spi_hal_trans_config_t *trans = &hal->trans_config;
|
||||||
|
|
||||||
|
if (trans->rcv_buffer && !hal->dma_enabled) {
|
||||||
//Need to copy from SPI regs to result buffer.
|
//Need to copy from SPI regs to result buffer.
|
||||||
spi_ll_read_buffer(hal->hw, hal->rcv_buffer, hal->rx_bitlen);
|
spi_ll_read_buffer(hal->hw, trans->rcv_buffer, trans->rx_bitlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,30 @@
|
|||||||
#include "hal/spi_slave_hal.h"
|
#include "hal/spi_slave_hal.h"
|
||||||
#include "hal/spi_ll.h"
|
#include "hal/spi_ll.h"
|
||||||
|
|
||||||
void spi_slave_hal_init(spi_slave_hal_context_t *hal, int host_id)
|
static void s_spi_slave_hal_dma_init_config(const spi_slave_hal_context_t *hal)
|
||||||
|
{
|
||||||
|
spi_dma_ll_rx_enable_burst_data(hal->dma_in, 1);
|
||||||
|
spi_dma_ll_tx_enable_burst_data(hal->dma_out, 1);
|
||||||
|
spi_dma_ll_rx_enable_burst_desc(hal->dma_in, 1);
|
||||||
|
spi_dma_ll_tx_enable_burst_desc(hal->dma_out, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config)
|
||||||
{
|
{
|
||||||
memset(hal, 0, sizeof(spi_slave_hal_context_t));
|
memset(hal, 0, sizeof(spi_slave_hal_context_t));
|
||||||
spi_dev_t *hw = spi_periph_signal[host_id].hw;
|
spi_dev_t *hw = SPI_LL_GET_HW(hal_config->host_id);
|
||||||
hal->hw = hw;
|
hal->hw = hw;
|
||||||
|
hal->dma_in = hal_config->dma_in;
|
||||||
|
hal->dma_out = hal_config->dma_out;
|
||||||
|
|
||||||
|
s_spi_slave_hal_dma_init_config(hal);
|
||||||
spi_ll_slave_init(hal->hw);
|
spi_ll_slave_init(hal->hw);
|
||||||
|
|
||||||
//Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
|
//Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
|
||||||
//disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
|
//disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
|
||||||
//any transactions that are queued.
|
//any transactions that are queued.
|
||||||
spi_ll_set_int_stat(hal->hw);
|
spi_ll_set_int_stat(hal->hw);
|
||||||
spi_ll_slave_set_int_type(hal->hw, SPI_LL_INT_TYPE_NORMAL);
|
spi_ll_enable_int(hal->hw);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal)
|
void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal)
|
||||||
|
@@ -14,28 +14,43 @@ void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal)
|
|||||||
|
|
||||||
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
|
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
|
||||||
{
|
{
|
||||||
spi_ll_slave_reset(hal->hw);
|
|
||||||
if (hal->use_dma) {
|
if (hal->use_dma) {
|
||||||
spi_ll_reset_dma(hal->hw);
|
spi_ll_dma_fifo_reset(hal->hw);
|
||||||
|
|
||||||
//Fill DMA descriptors
|
//Fill DMA descriptors
|
||||||
if (hal->rx_buffer) {
|
if (hal->rx_buffer) {
|
||||||
lldesc_setup_link(hal->dmadesc_rx, hal->rx_buffer, ((hal->bitlen + 7) / 8), true);
|
lldesc_setup_link(hal->dmadesc_rx, hal->rx_buffer, ((hal->bitlen + 7) / 8), true);
|
||||||
spi_ll_rxdma_start(hal->hw, &hal->dmadesc_rx[0]);
|
|
||||||
|
//reset dma inlink, this should be reset before spi related reset
|
||||||
|
spi_dma_ll_rx_reset(hal->dma_in);
|
||||||
|
spi_ll_slave_reset(hal->hw);
|
||||||
|
spi_ll_infifo_full_clr(hal->hw);
|
||||||
|
|
||||||
|
spi_ll_dma_rx_enable(hal->hw, 1);
|
||||||
|
spi_dma_ll_rx_start(hal->dma_in, &hal->dmadesc_rx[0]);
|
||||||
}
|
}
|
||||||
if (hal->tx_buffer) {
|
if (hal->tx_buffer) {
|
||||||
lldesc_setup_link(hal->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false);
|
lldesc_setup_link(hal->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false);
|
||||||
spi_ll_txdma_start(hal->hw, (&hal->dmadesc_tx[0]));
|
|
||||||
|
//reset dma outlink, this should be reset before spi related reset
|
||||||
|
spi_dma_ll_tx_reset(hal->dma_out);
|
||||||
|
spi_ll_slave_reset(hal->hw);
|
||||||
|
spi_ll_outfifo_empty_clr(hal->hw);
|
||||||
|
|
||||||
|
spi_ll_dma_tx_enable(hal->hw, 1);
|
||||||
|
spi_dma_ll_tx_start(hal->dma_out, (&hal->dmadesc_tx[0]));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//No DMA. Turn off SPI and copy data to transmit buffers.
|
//No DMA. Turn off SPI and copy data to transmit buffers.
|
||||||
if (hal->tx_buffer) {
|
if (hal->tx_buffer) {
|
||||||
|
spi_ll_slave_reset(hal->hw);
|
||||||
spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen);
|
spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen);
|
spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen);
|
||||||
spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen);
|
spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen);
|
||||||
|
|
||||||
spi_ll_enable_mosi(hal->hw, (hal->tx_buffer == NULL) ? 0 : 1);
|
spi_ll_enable_mosi(hal->hw, (hal->tx_buffer == NULL) ? 0 : 1);
|
||||||
spi_ll_enable_miso(hal->hw, (hal->rx_buffer == NULL) ? 0 : 1);
|
spi_ll_enable_miso(hal->hw, (hal->rx_buffer == NULL) ? 0 : 1);
|
||||||
}
|
}
|
||||||
@@ -53,7 +68,6 @@ void spi_slave_hal_store_result(spi_slave_hal_context_t *hal)
|
|||||||
//Copy result out
|
//Copy result out
|
||||||
spi_ll_read_buffer(hal->hw, hal->rx_buffer, hal->bitlen);
|
spi_ll_read_buffer(hal->hw, hal->rx_buffer, hal->bitlen);
|
||||||
}
|
}
|
||||||
spi_ll_slave_set_int_type(hal->hw, SPI_LL_INT_TYPE_NORMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal)
|
uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal)
|
||||||
|
@@ -19,27 +19,36 @@
|
|||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#include "soc/spi_periph.h"
|
#include "soc/spi_periph.h"
|
||||||
#include "soc/lldesc.h"
|
#include "soc/lldesc.h"
|
||||||
|
|
||||||
#include "hal/spi_slave_hd_hal.h"
|
#include "hal/spi_slave_hd_hal.h"
|
||||||
|
|
||||||
|
static void s_spi_slave_hd_hal_dma_init_config(const spi_slave_hd_hal_context_t *hal)
|
||||||
|
{
|
||||||
|
spi_dma_ll_rx_enable_burst_data(hal->dma_in, 1);
|
||||||
|
spi_dma_ll_tx_enable_burst_data(hal->dma_out, 1);
|
||||||
|
spi_dma_ll_rx_enable_burst_desc(hal->dma_in, 1);
|
||||||
|
spi_dma_ll_tx_enable_burst_desc(hal->dma_out, 1);
|
||||||
|
}
|
||||||
|
|
||||||
void slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *config)
|
void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config)
|
||||||
{
|
{
|
||||||
memset(hal, 0, sizeof(spi_slave_hd_hal_context_t));
|
memset(hal, 0, sizeof(spi_slave_hd_hal_context_t));
|
||||||
spi_dev_t* hw = SPI_LL_GET_HW(config->host_id);
|
spi_dev_t* hw = SPI_LL_GET_HW(hal_config->host_id);
|
||||||
hal->dev = hw;
|
hal->dev = hw;
|
||||||
|
hal->dma_in = hal_config->dma_in;
|
||||||
|
hal->dma_out = hal_config->dma_out;
|
||||||
|
|
||||||
//Configure slave
|
//Configure slave
|
||||||
|
s_spi_slave_hd_hal_dma_init_config(hal);
|
||||||
|
|
||||||
spi_ll_slave_hd_init(hw);
|
spi_ll_slave_hd_init(hw);
|
||||||
spi_ll_set_addr_bitlen(hw, config->address_bits);
|
spi_ll_set_addr_bitlen(hw, hal_config->address_bits);
|
||||||
spi_ll_set_command_bitlen(hw, config->command_bits);
|
spi_ll_set_command_bitlen(hw, hal_config->command_bits);
|
||||||
spi_ll_set_dummy(hw, config->dummy_bits);
|
spi_ll_set_dummy(hw, hal_config->dummy_bits);
|
||||||
spi_ll_set_rx_lsbfirst(hw, config->rx_lsbfirst);
|
spi_ll_set_rx_lsbfirst(hw, hal_config->rx_lsbfirst);
|
||||||
spi_ll_set_tx_lsbfirst(hw, config->tx_lsbfirst);
|
spi_ll_set_tx_lsbfirst(hw, hal_config->tx_lsbfirst);
|
||||||
spi_ll_slave_set_mode(hw, config->mode, (config->dma_chan != 0));
|
spi_ll_slave_set_mode(hw, hal_config->mode, (hal_config->dma_chan != 0));
|
||||||
|
|
||||||
spi_ll_disable_intr(hw, UINT32_MAX);
|
spi_ll_disable_intr(hw, UINT32_MAX);
|
||||||
spi_ll_clear_intr(hw, UINT32_MAX);
|
spi_ll_clear_intr(hw, UINT32_MAX);
|
||||||
@@ -66,25 +75,31 @@ void slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_c
|
|||||||
SPI_LL_TRANS_LEN_COND_RDBUF |
|
SPI_LL_TRANS_LEN_COND_RDBUF |
|
||||||
SPI_LL_TRANS_LEN_COND_RDDMA);
|
SPI_LL_TRANS_LEN_COND_RDDMA);
|
||||||
|
|
||||||
spi_ll_slave_set_seg_mode(hw, true);
|
spi_ll_slave_set_seg_mode(hal->dev, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, size_t len)
|
void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, size_t len)
|
||||||
{
|
{
|
||||||
lldesc_setup_link(hal->dmadesc_rx, out_buf, len, true);
|
lldesc_setup_link(hal->dmadesc_rx, out_buf, len, true);
|
||||||
|
|
||||||
spi_ll_rxdma_reset(hal->dev);
|
spi_dma_ll_rx_reset(hal->dma_in);
|
||||||
|
spi_ll_infifo_full_clr(hal->dev);
|
||||||
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_WR_DONE);
|
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_WR_DONE);
|
||||||
spi_ll_rxdma_start(hal->dev, &hal->dmadesc_rx[0]);
|
|
||||||
|
spi_ll_dma_rx_enable(hal->dev, 1);
|
||||||
|
spi_dma_ll_rx_start(hal->dma_in, &hal->dmadesc_rx[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len)
|
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
lldesc_setup_link(hal->dmadesc_tx, data, len, false);
|
lldesc_setup_link(hal->dmadesc_tx, data, len, false);
|
||||||
|
|
||||||
spi_ll_txdma_reset(hal->dev);
|
spi_dma_ll_tx_reset(hal->dma_out);
|
||||||
|
spi_ll_outfifo_empty_clr(hal->dev);
|
||||||
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD8);
|
spi_ll_clear_intr(hal->dev, SPI_LL_INTR_CMD8);
|
||||||
spi_ll_txdma_start(hal->dev, &hal->dmadesc_tx[0]);
|
|
||||||
|
spi_ll_dma_tx_enable(hal->dev, 1);
|
||||||
|
spi_dma_ll_tx_start(hal->dma_out, &hal->dmadesc_tx[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static spi_ll_intr_t get_event_intr(spi_event_t ev)
|
static spi_ll_intr_t get_event_intr(spi_event_t ev)
|
||||||
@@ -179,4 +194,4 @@ int spi_slave_hd_hal_rxdma_get_len(spi_slave_hd_hal_context_t *hal)
|
|||||||
{
|
{
|
||||||
lldesc_t* desc = &hal->dmadesc_rx[0];
|
lldesc_t* desc = &hal->dmadesc_rx[0];
|
||||||
return lldesc_get_received_len(desc, NULL);
|
return lldesc_get_received_len(desc, NULL);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user