mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 13:09:38 +00: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:
		| @@ -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 freq; |     int no_compensate = dev_config->flags & SPI_DEVICE_NO_DUMMY ? 1 : 0; | ||||||
|     spi_hal_context_t *hal = &(host->hal); |     int duty_cycle = (dev_config->duty_cycle_pos==0) ? 128 : dev_config->duty_cycle_pos; | ||||||
|     hal->half_duplex = dev_config->flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0; |     int use_gpio = !(bus_attr->flags & SPICOMMON_BUSFLAG_IOMUX_PINS); | ||||||
| #ifdef SOC_SPI_SUPPORT_AS_CS |     spi_hal_timing_param_t timing_param = { | ||||||
|     hal->as_cs = dev_config->flags & SPI_DEVICE_CLK_AS_CS ? 1 : 0; |         .half_duplex = half_duplex, | ||||||
| #endif |         .no_compensate = no_compensate, | ||||||
|     hal->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0; |         .clock_speed_hz = dev_config->clock_speed_hz, | ||||||
|     hal->no_compensate = dev_config->flags & SPI_DEVICE_NO_DUMMY ? 1 : 0; |         .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;           |     spi_hal_timing_conf_t temp_timing_conf;           | ||||||
|  |     int freq; | ||||||
|     esp_err_t ret = spi_hal_cal_clock_conf(hal, dev_config->clock_speed_hz, duty_cycle, |     esp_err_t ret = spi_hal_cal_clock_conf(&timing_param, &freq, &temp_timing_conf); | ||||||
|                                         !(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,9 +385,36 @@ 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); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     //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; |     *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); | ||||||
|  |  | ||||||
| @@ -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,21 +129,14 @@ 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) | ||||||
| @@ -160,29 +145,10 @@ static inline void spi_ll_slave_hd_init(spi_dev_t* hw) | |||||||
|     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; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /*------------------------------------------------------------------------------ | /*------------------------------------------------------------------------------ | ||||||
| @@ -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; | ||||||
| } | } | ||||||
| @@ -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,9 +38,24 @@ | |||||||
| #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 { | ||||||
| @@ -50,12 +65,12 @@ typedef struct { | |||||||
| } spi_hal_timing_conf_t; | } spi_hal_timing_conf_t; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Context that should be maintained by both the driver and the HAL. |  * DMA configuration structure | ||||||
|  |  * Should be set by driver at initialization | ||||||
|  */  |  */  | ||||||
| typedef struct { | typedef struct { | ||||||
|     /* configured by driver at initialization, don't touch */ |     spi_dma_dev_t *dma_in;              ///< Input  DMA(DMA -> RAM) peripheral register address | ||||||
|     spi_dev_t *hw;        ///< Beginning address of the peripheral registers. |     spi_dma_dev_t *dma_out;             ///< Output DMA(RAM -> DMA) peripheral register address | ||||||
|     /* should be configured by driver at initialization */ |  | ||||||
|     lldesc_t  *dmadesc_tx;              /**< Array of DMA descriptor used by the TX DMA. |     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 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. | ||||||
| @@ -65,36 +80,13 @@ typedef struct { | |||||||
|                                          *   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. | ||||||
|     /* | } spi_hal_dma_config_t; | ||||||
|      * Device specific, all these parameters will be updated to the peripheral |  | ||||||
|      * only when ``spi_hal_setup_device``. They may not get updated when |  | ||||||
|      * ``spi_hal_setup_trans``. |  | ||||||
|      */ |  | ||||||
|     int mode;                           ///< SPI mode, 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_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 |  | ||||||
|                                          *   the pre-calculated timing configuration for the device at initialization, |  | ||||||
|                                          *   device specific |  | ||||||
|                                          */ |  | ||||||
|     struct { |  | ||||||
|         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 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 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 |  | ||||||
| #ifdef SOC_SPI_SUPPORT_AS_CS |  | ||||||
|         uint32_t as_cs  : 1;        ///< Whether to toggle the CS while the clock toggles, device specific |  | ||||||
| #endif |  | ||||||
|         uint32_t positive_cs : 1;   ///< Whether the postive CS feature is abled, device specific |  | ||||||
|     };//boolean configurations |  | ||||||
|  |  | ||||||
|     /* | /** | ||||||
|      * Transaction specific (data), all these parameters will be updated to the |  * Transaction configuration structure, this should be assigned by driver each time. | ||||||
|      * peripheral every transaction. |  * All these parameters will be updated to the peripheral every transaction. | ||||||
|  */ |  */ | ||||||
|  | typedef struct { | ||||||
|     uint16_t cmd;                       ///< Command value to be sent |     uint16_t cmd;                       ///< Command value to be sent | ||||||
|     int cmd_bits;                       ///< Length (in bits) of the command phase |     int cmd_bits;                       ///< Length (in bits) of the command phase | ||||||
|     int addr_bits;                      ///< Length (in bits) of the address phase |     int addr_bits;                      ///< Length (in bits) of the address phase | ||||||
| @@ -105,16 +97,56 @@ typedef struct { | |||||||
|     uint8_t *send_buffer;               ///< Data to be sent |     uint8_t *send_buffer;               ///< Data to be sent | ||||||
|     uint8_t *rcv_buffer;                ///< Buffer to hold the receive data. |     uint8_t *rcv_buffer;                ///< Buffer to hold the receive data. | ||||||
|     spi_ll_io_mode_t io_mode;           ///< IO mode of the master |     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. | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  |     /* Configured by driver at initialization, don't touch */ | ||||||
|  |     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 (DMA -> RAM). | ||||||
|  |     spi_dma_dev_t *dma_out;             ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral (RAM -> DMA). | ||||||
|  |     bool  dma_enabled;                  ///< Whether the DMA is enabled, do not update after initialization | ||||||
|  |     spi_hal_dma_config_t dma_config;    ///< DMA configuration | ||||||
|  |  | ||||||
|  |     /* Internal parameters, don't touch */ | ||||||
|  |     spi_hal_trans_config_t trans_config; ///< Transaction configuration | ||||||
| } spi_hal_context_t; | } spi_hal_context_t; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Device configuration structure, this should be initialised by driver based on different devices respectively. | ||||||
|  |  * All these parameters will be updated to the peripheral only when ``spi_hal_setup_device``.  | ||||||
|  |  * They may not get updated when ``spi_hal_setup_trans``. | ||||||
|  |  */ | ||||||
|  | typedef struct { | ||||||
|  |     int mode;                           ///< SPI mode, 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_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;  /**< This structure holds the pre-calculated timing configuration for the device | ||||||
|  |                                          *   at initialization, device specific | ||||||
|  |                                          */ | ||||||
|  |     struct { | ||||||
|  |         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 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 no_compensate : 1;     ///< No need to add dummy to compensate the timing, device specific | ||||||
|  | #ifdef SOC_SPI_SUPPORT_AS_CS | ||||||
|  |         uint32_t as_cs  : 1;            ///< Whether to toggle the CS while the clock toggles, device specific | ||||||
|  | #endif | ||||||
|  |         uint32_t positive_cs : 1;       ///< Whether the postive CS feature is abled, device specific | ||||||
|  |     };//boolean configurations | ||||||
|  | } spi_hal_dev_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_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). | ||||||
| @@ -127,22 +159,27 @@ 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. | ||||||
| @@ -173,19 +210,13 @@ 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 duty_cycle Desired duty cycle of SPI clock |  | ||||||
|  * @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 out_freq       Output of the actual frequency, left NULL if not required. | ||||||
|  * @param timing_conf    Output of the timing configuration. |  * @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. | ||||||
|   | |||||||
| @@ -36,6 +36,7 @@ | |||||||
| #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. | ||||||
| @@ -43,6 +44,8 @@ | |||||||
| 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 | ||||||
| @@ -77,13 +80,19 @@ typedef struct { | |||||||
|     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,23 +59,27 @@ | |||||||
|  |  | ||||||
| /// 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 | ||||||
|  |     spi_dma_dev_t *dma_out;             ///< Output DMA(RAM -> DMA) peripheral register address | ||||||
|  |     uint32_t      spics_io_num;         ///< CS GPIO pin for this device | ||||||
|     uint8_t       mode;                 ///< SPI mode (0-3) |     uint8_t       mode;                 ///< SPI mode (0-3) | ||||||
|     int     command_bits;           ///< command field bits, multiples of 8 and at least 8. |     uint32_t      command_bits;         ///< command field bits, multiples of 8 and at least 8. | ||||||
|     int     address_bits;           ///< address field bits, multiples of 8 and at least 8. |     uint32_t      address_bits;         ///< address field bits, multiples of 8 and at least 8. | ||||||
|     int     dummy_bits;             ///< dummy 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. | ||||||
|  |     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. | ||||||
|     lldesc_t      *dmadesc_tx;          /**< Array of DMA descriptor used by the TX DMA. |     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 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. | ||||||
| @@ -89,21 +93,20 @@ typedef struct { | |||||||
|     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); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Michael (XIAO Xufeng)
					Michael (XIAO Xufeng)