1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
18 We can initialize a SPI driver, but we don't talk to the SPI driver itself, we address a device. A device essentially
19 is a combination of SPI port and CS pin, plus some information about the specifics of communication to the device
20 (timing, command/address length etc)
22 The essence of the interface to a device is a set of queues; one per device. The idea is that to send something to a SPI
23 device, you allocate a transaction descriptor. It contains some information about the transfer like the lenghth, address,
24 command etc, plus pointers to transmit and receive buffer. The address of this block gets pushed into the transmit queue.
25 The SPI driver does its magic, and sends and retrieves the data eventually. The data gets written to the receive buffers,
26 if needed the transaction descriptor is modified to indicate returned parameters and the entire thing goes into the return
27 queue, where whatever software initiated the transaction can retrieve it.
29 The entire thing is run from the SPI interrupt handler. If SPI is done transmitting/receiving but nothing is in the queue,
30 it will not clear the SPI interrupt but just disable it. This way, when a new thing is sent, pushing the packet into the send
31 queue and re-enabling the interrupt will trigger the interrupt again, which can then take care of the sending.
37 #include "driver/spi_master.h"
38 #include "soc/gpio_sig_map.h"
39 #include "soc/spi_reg.h"
40 #include "soc/dport_reg.h"
41 #include "soc/spi_struct.h"
42 #include "soc/rtc_cntl_reg.h"
43 #include "rom/ets_sys.h"
44 #include "esp_types.h"
47 #include "esp_intr_alloc.h"
50 #include "freertos/FreeRTOS.h"
51 #include "freertos/semphr.h"
52 #include "freertos/xtensa_api.h"
53 #include "freertos/task.h"
54 #include "freertos/ringbuf.h"
56 #include "soc/dport_reg.h"
57 #include "soc/uart_struct.h"
58 #include "rom/lldesc.h"
59 #include "driver/uart.h"
60 #include "driver/gpio.h"
61 #include "driver/periph_ctrl.h"
62 #include "esp_heap_alloc_caps.h"
64 typedef struct spi_device_t spi_device_t;
66 #define NO_CS 3 //Number of CS pins per SPI host
69 spi_device_t *device[NO_CS];
72 spi_transaction_t *cur_trans;
74 lldesc_t dmadesc_tx, dmadesc_rx;
79 QueueHandle_t trans_queue;
80 QueueHandle_t ret_queue;
81 spi_device_interface_config_t cfg;
85 static spi_host_t *spihost[3];
88 static const char *SPI_TAG = "spi_master";
89 #define SPI_CHECK(a, str, ret_val) \
91 ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
96 Stores a bunch of per-spi-peripheral data.
99 const uint8_t spiclk_out; //GPIO mux output signals
100 const uint8_t spid_out;
101 const uint8_t spiq_out;
102 const uint8_t spiwp_out;
103 const uint8_t spihd_out;
104 const uint8_t spid_in; //GPIO mux input signals
105 const uint8_t spiq_in;
106 const uint8_t spiwp_in;
107 const uint8_t spihd_in;
108 const uint8_t spics_out[3]; // /CS GPIO output mux signals
109 const uint8_t spiclk_native; //IO pins of IO_MUX muxed signals
110 const uint8_t spid_native;
111 const uint8_t spiq_native;
112 const uint8_t spiwp_native;
113 const uint8_t spihd_native;
114 const uint8_t spics0_native;
115 const uint8_t irq; //irq source for interrupt mux
116 const uint8_t irq_dma; //dma irq source for interrupt mux
117 const periph_module_t module; //peripheral module, for enabling clock etc
118 spi_dev_t *hw; //Pointer to the hardware registers
122 Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc
124 static const spi_signal_conn_t io_signal[3]={
126 .spiclk_out=SPICLK_OUT_IDX,
127 .spid_out=SPID_OUT_IDX,
128 .spiq_out=SPIQ_OUT_IDX,
129 .spiwp_out=SPIWP_OUT_IDX,
130 .spihd_out=SPIHD_OUT_IDX,
131 .spid_in=SPID_IN_IDX,
132 .spiq_in=SPIQ_IN_IDX,
133 .spiwp_in=SPIWP_IN_IDX,
134 .spihd_in=SPIHD_IN_IDX,
135 .spics_out={SPICS0_OUT_IDX, SPICS1_OUT_IDX, SPICS2_OUT_IDX},
142 .irq=ETS_SPI1_INTR_SOURCE,
143 .irq_dma=ETS_SPI1_DMA_INTR_SOURCE,
144 .module=PERIPH_SPI_MODULE,
147 .spiclk_out=HSPICLK_OUT_IDX,
148 .spid_out=HSPID_OUT_IDX,
149 .spiq_out=HSPIQ_OUT_IDX,
150 .spiwp_out=HSPIWP_OUT_IDX,
151 .spihd_out=HSPIHD_OUT_IDX,
152 .spid_in=HSPID_IN_IDX,
153 .spiq_in=HSPIQ_IN_IDX,
154 .spiwp_in=HSPIWP_IN_IDX,
155 .spihd_in=HSPIHD_IN_IDX,
156 .spics_out={HSPICS0_OUT_IDX, HSPICS1_OUT_IDX, HSPICS2_OUT_IDX},
163 .irq=ETS_SPI2_INTR_SOURCE,
164 .irq_dma=ETS_SPI2_DMA_INTR_SOURCE,
165 .module=PERIPH_HSPI_MODULE,
168 .spiclk_out=VSPICLK_OUT_IDX,
169 .spid_out=VSPID_OUT_IDX,
170 .spiq_out=VSPIQ_OUT_IDX,
171 .spiwp_out=VSPIWP_OUT_IDX,
172 .spihd_out=VSPIHD_OUT_IDX,
173 .spid_in=VSPID_IN_IDX,
174 .spiq_in=VSPIQ_IN_IDX,
175 .spiwp_in=VSPIWP_IN_IDX,
176 .spihd_in=VSPIHD_IN_IDX,
177 .spics_out={VSPICS0_OUT_IDX, VSPICS1_OUT_IDX, VSPICS2_OUT_IDX},
184 .irq=ETS_SPI3_INTR_SOURCE,
185 .irq_dma=ETS_SPI3_DMA_INTR_SOURCE,
186 .module=PERIPH_VSPI_MODULE,
191 static void spi_intr(void *arg);
194 esp_err_t spi_bus_initialize(spi_host_device_t host, spi_bus_config_t *bus_config, int dma_chan)
197 /* ToDo: remove this when we have flash operations cooperating with this */
198 SPI_CHECK(host!=SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED);
200 SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
201 SPI_CHECK(spihost[host]==NULL, "host already in use", ESP_ERR_INVALID_STATE);
203 SPI_CHECK(bus_config->spid_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->spid_io_num), "spid pin invalid", ESP_ERR_INVALID_ARG);
204 SPI_CHECK(bus_config->spiclk_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->spiclk_io_num), "spiclk pin invalid", ESP_ERR_INVALID_ARG);
205 SPI_CHECK(bus_config->spiq_io_num<0 || GPIO_IS_VALID_GPIO(bus_config->spiq_io_num), "spiq pin invalid", ESP_ERR_INVALID_ARG);
206 SPI_CHECK(bus_config->spiwp_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->spiwp_io_num), "spiwp pin invalid", ESP_ERR_INVALID_ARG);
207 SPI_CHECK(bus_config->spihd_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->spihd_io_num), "spihd pin invalid", ESP_ERR_INVALID_ARG);
209 //The host struct contains two dma descriptors, so we need DMA'able memory for this.
210 spihost[host]=pvPortMallocCaps(sizeof(spi_host_t), MALLOC_CAP_DMA);
211 if (spihost[host]==NULL) return ESP_ERR_NO_MEM;
212 memset(spihost[host], 0, sizeof(spi_host_t));
214 //Check if the selected pins correspond to the native pins of the peripheral
215 if (bus_config->spid_io_num >= 0 && bus_config->spid_io_num!=io_signal[host].spid_native) native=false;
216 if (bus_config->spiq_io_num >= 0 && bus_config->spiq_io_num!=io_signal[host].spiq_native) native=false;
217 if (bus_config->spiclk_io_num >= 0 && bus_config->spiclk_io_num!=io_signal[host].spiclk_native) native=false;
218 if (bus_config->spiwp_io_num >= 0 && bus_config->spiwp_io_num!=io_signal[host].spiwp_native) native=false;
219 if (bus_config->spihd_io_num >= 0 && bus_config->spihd_io_num!=io_signal[host].spihd_native) native=false;
221 spihost[host]->no_gpio_matrix=native;
223 //All SPI native pin selections resolve to 1, so we put that here instead of trying to figure
224 //out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
225 if (bus_config->spid_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spid_io_num], 1);
226 if (bus_config->spiq_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spiq_io_num], 1);
227 if (bus_config->spiwp_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spiwp_io_num], 1);
228 if (bus_config->spihd_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spihd_io_num], 1);
229 if (bus_config->spiclk_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spiclk_io_num], 1);
232 if (bus_config->spid_io_num>0) {
233 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spid_io_num], PIN_FUNC_GPIO);
234 gpio_set_direction(bus_config->spid_io_num, GPIO_MODE_OUTPUT);
235 gpio_matrix_out(bus_config->spid_io_num, io_signal[host].spid_out, false, false);
236 gpio_matrix_in(bus_config->spid_io_num, io_signal[host].spid_in, false);
238 if (bus_config->spiq_io_num>0) {
239 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spiq_io_num], PIN_FUNC_GPIO);
240 gpio_set_direction(bus_config->spiq_io_num, GPIO_MODE_INPUT);
241 gpio_matrix_out(bus_config->spiq_io_num, io_signal[host].spiq_out, false, false);
242 gpio_matrix_in(bus_config->spiq_io_num, io_signal[host].spiq_in, false);
244 if (bus_config->spiwp_io_num>0) {
245 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spiwp_io_num], PIN_FUNC_GPIO);
246 gpio_set_direction(bus_config->spiwp_io_num, GPIO_MODE_OUTPUT);
247 gpio_matrix_out(bus_config->spiwp_io_num, io_signal[host].spiwp_out, false, false);
248 gpio_matrix_in(bus_config->spiwp_io_num, io_signal[host].spiwp_in, false);
250 if (bus_config->spihd_io_num>0) {
251 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spihd_io_num], PIN_FUNC_GPIO);
252 gpio_set_direction(bus_config->spihd_io_num, GPIO_MODE_OUTPUT);
253 gpio_matrix_out(bus_config->spihd_io_num, io_signal[host].spihd_out, false, false);
254 gpio_matrix_in(bus_config->spihd_io_num, io_signal[host].spihd_in, false);
256 if (bus_config->spiclk_io_num>0) {
257 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spiclk_io_num], PIN_FUNC_GPIO);
258 gpio_set_direction(bus_config->spiclk_io_num, GPIO_MODE_OUTPUT);
259 gpio_matrix_out(bus_config->spiclk_io_num, io_signal[host].spiclk_out, false, false);
262 periph_module_enable(io_signal[host].module);
263 esp_intr_alloc(io_signal[host].irq, ESP_INTR_FLAG_INTRDISABLED, spi_intr, (void*)spihost[host], &spihost[host]->intr);
264 spihost[host]->hw=io_signal[host].hw;
267 spihost[host]->hw->dma_conf.val|=SPI_OUT_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
268 spihost[host]->hw->dma_out_link.start=0;
269 spihost[host]->hw->dma_in_link.start=0;
270 spihost[host]->hw->dma_conf.val&=~(SPI_OUT_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
272 //Disable unneeded ints
273 spihost[host]->hw->slave.rd_buf_done=0;
274 spihost[host]->hw->slave.wr_buf_done=0;
275 spihost[host]->hw->slave.rd_sta_done=0;
276 spihost[host]->hw->slave.wr_sta_done=0;
277 spihost[host]->hw->slave.rd_buf_inten=0;
278 spihost[host]->hw->slave.wr_buf_inten=0;
279 spihost[host]->hw->slave.rd_sta_inten=0;
280 spihost[host]->hw->slave.wr_sta_inten=0;
282 //Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
283 //disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
284 //any transactions that are queued.
285 spihost[host]->hw->slave.trans_inten=1;
286 spihost[host]->hw->slave.trans_done=1;
288 //Select DMA channel.
289 SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
294 esp_err_t spi_bus_free(spi_host_device_t host)
297 SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
298 SPI_CHECK(spihost[host]!=NULL, "host not in use", ESP_ERR_INVALID_STATE);
299 for (x=0; x<NO_CS; x++) {
300 SPI_CHECK(spihost[host]->device[x]==NULL, "not all CSses freed", ESP_ERR_INVALID_STATE);
302 spihost[host]->hw->slave.trans_inten=0;
303 spihost[host]->hw->slave.trans_done=0;
304 esp_intr_free(spihost[host]->intr);
305 periph_module_disable(io_signal[host].module);
312 Add a device. This allocates a CS line for the device, allocates memory for the device structure and hooks
313 up the CS pin to whatever is specified.
315 esp_err_t spi_bus_add_device(spi_host_device_t host, spi_device_interface_config_t *dev_config, spi_device_handle_t *handle)
318 SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
319 SPI_CHECK(spihost[host]!=NULL, "host not initialized", ESP_ERR_INVALID_STATE);
320 SPI_CHECK(dev_config->spics_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_io_num), "spics pin invalid", ESP_ERR_INVALID_ARG);
321 for (freecs=0; freecs<NO_CS; freecs++) {
322 //See if this slot is free; reserve if it is by putting a dummy pointer in the slot. We use an atomic compare&swap to make this thread-safe.
323 if (__sync_bool_compare_and_swap(&spihost[host]->device[freecs], NULL, (spi_device_t *)1)) break;
325 SPI_CHECK(freecs!=NO_CS, "no free cs pins for host", ESP_ERR_NOT_FOUND);
326 //The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full
327 //duplex mode does absolutely nothing on the ESP32.
328 SPI_CHECK(dev_config->cs_ena_pretrans==0 || (dev_config->flags & SPI_DEVICE_HALFDUPLEX), "cs pretrans delay incompatible with full-duplex", ESP_ERR_INVALID_ARG);
330 //Allocate memory for device
331 spi_device_t *dev=malloc(sizeof(spi_device_t));
332 if (dev==NULL) return ESP_ERR_NO_MEM;
333 memset(dev, 0, sizeof(spi_device_t));
334 spihost[host]->device[freecs]=dev;
336 //Allocate queues, set defaults
337 dev->trans_queue=xQueueCreate(dev_config->queue_size, sizeof(spi_transaction_t *));
338 dev->ret_queue=xQueueCreate(dev_config->queue_size, sizeof(spi_transaction_t *));
339 if (dev_config->duty_cycle_pos==0) dev_config->duty_cycle_pos=128;
340 dev->host=spihost[host];
342 //We want to save a copy of the dev config in the dev struct.
343 memcpy(&dev->cfg, dev_config, sizeof(spi_device_interface_config_t));
345 //Set CS pin, CS options
346 if (dev_config->spics_io_num > 0) {
347 if (spihost[host]->no_gpio_matrix &&dev_config->spics_io_num == io_signal[host].spics0_native && freecs==0) {
348 //Again, the cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
349 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], 1);
352 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], PIN_FUNC_GPIO);
353 gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT);
354 gpio_matrix_out(dev_config->spics_io_num, io_signal[host].spics_out[freecs], false, false);
357 if (dev_config->flags&SPI_DEVICE_CLK_AS_CS) {
358 spihost[host]->hw->pin.master_ck_sel |= (1<<freecs);
360 spihost[host]->hw->pin.master_ck_sel &= (1<<freecs);
362 if (dev_config->flags&SPI_DEVICE_POSITIVE_CS) {
363 spihost[host]->hw->pin.master_cs_pol |= (1<<freecs);
365 spihost[host]->hw->pin.master_cs_pol &= (1<<freecs);
371 esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
374 SPI_CHECK(handle!=NULL, "invalid handle", ESP_ERR_INVALID_ARG);
375 //These checks aren't exhaustive; another thread could sneak in a transaction inbetween. These are only here to
376 //catch design errors and aren't meant to be triggered during normal operation.
377 SPI_CHECK(uxQueueMessagesWaiting(handle->trans_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
378 SPI_CHECK(handle->host->cur_trans==0 || handle->host->device[handle->host->cur_cs]!=handle, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
379 SPI_CHECK(uxQueueMessagesWaiting(handle->ret_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
382 vQueueDelete(handle->trans_queue);
383 vQueueDelete(handle->ret_queue);
384 //Remove device from list of csses and free memory
385 for (x=0; x<NO_CS; x++) {
386 if (handle->host->device[x] == handle) handle->host->device[x]=NULL;
392 static void spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) {
394 //In hw, n, h and l are 1-32, pre is 0-8K. Value written to register is one lower than used value.
396 //Can only solve this using fapb directly.
397 hw->clock.clkcnt_l=0;
398 hw->clock.clkcnt_h=0;
399 hw->clock.clkcnt_n=0;
400 hw->clock.clkdiv_pre=0;
401 hw->clock.clk_equ_sysclk=1;
403 //For best duty cycle resolution, we want n to be as close to 32 as possible.
405 //This algo could use some tweaking; at the moment it either fixes n to 32 and
406 //uses the prescaler to get a suitable division factor, or sets the prescaler to 0
407 //and uses n to set a value. In practice, sometimes a better result can be
408 //obtained by setting both n and pre to well-chosen valued... ToDo: fix up some algo to
409 //do this automatically (worst-case: bruteforce n/pre combo's) - JD
411 //The ESP32 has a SPI_CK_OUT_HIGH_MODE and SPI_CK_OUT_LOW_MODE register; it looks like we can
412 //use those to specify the duty cycle in a more precise way. Figure out how to use these. - JD
415 //Need to use prescaler
419 //No need for prescaler.
424 l=(((256-duty_cycle)*n+127)/256);
425 hw->clock.clk_equ_sysclk=0;
426 hw->clock.clkcnt_n=n-1;
427 hw->clock.clkdiv_pre=pre-1;
428 hw->clock.clkcnt_h=h-1;
429 hw->clock.clkcnt_l=l-1;
434 //If a transaction is smaller than or equal to of bits, we do not use DMA; instead, we directly copy/paste
435 //bits from/to the work registers. Keep between 32 and (8*32) please.
436 #define THRESH_DMA_TRANS (8*32)
438 //This is run in interrupt context and apart from initialization and destruction, this is the only code
439 //touching the host (=spihost[x]) variable. The rest of the data arrives in queues. That is why there are
440 //no muxes in this code.
441 static void IRAM_ATTR spi_intr(void *arg)
446 BaseType_t do_yield=pdFALSE;
447 spi_transaction_t *trans=NULL;
448 spi_host_t *host=(spi_host_t*)arg;
450 //Ignore all but the trans_done int.
451 if (!host->hw->slave.trans_done) return;
453 if (host->cur_trans) {
454 //Okay, transaction is done.
455 if ((host->cur_trans->rx_buffer || (host->cur_trans->flags & SPI_USE_RXDATA)) && host->cur_trans->rxlength<=THRESH_DMA_TRANS) {
456 //Need to copy from SPI regs to result buffer.
458 if (host->cur_trans->flags & SPI_USE_RXDATA) {
459 data=(uint32_t*)&host->cur_trans->rx_data[0];
461 data=(uint32_t*)host->cur_trans->rx_buffer;
463 for (int x=0; x < host->cur_trans->rxlength; x+=32) {
464 //Do a memcpy to get around possible alignment issues in rx_buffer
465 uint32_t word=host->hw->data_buf[x/32];
466 memcpy(&data[x/32], &word, 4);
469 //Call post-transaction callback, if any
470 if (host->device[host->cur_cs]->cfg.post_cb) host->device[host->cur_cs]->cfg.post_cb(host->cur_trans);
471 //Return transaction descriptor.
472 xQueueSendFromISR(host->device[host->cur_cs]->ret_queue, &host->cur_trans, &do_yield);
473 host->cur_trans=NULL;
476 //ToDo: This is a stupidly simple low-cs-first priority scheme. Make this configurable somehow. - JD
477 for (i=0; i<NO_CS; i++) {
478 if (host->device[i]) {
479 r=xQueueReceiveFromISR(host->device[i]->trans_queue, &trans, &do_yield);
480 //Stop looking if we have a transaction to send.
485 //No packet waiting. Disable interrupt.
486 esp_intr_disable(host->intr);
488 host->hw->slave.trans_done=0; //clear int bit
489 //We have a transaction. Send it.
490 spi_device_t *dev=host->device[i];
491 host->cur_trans=trans;
492 //We should be done with the transmission.
493 assert(host->hw->cmd.usr == 0);
495 //Default rxlength to be the same as length, if not filled in.
496 if (trans->rxlength==0) {
497 trans->rxlength=trans->length;
500 //Reconfigure accoding to device settings, but only if we change CSses.
502 //Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have
503 //clock scaling working.
504 int apbclk=APB_CLK_FREQ;
505 spi_set_clock(host->hw, apbclk, dev->cfg.clock_speed_hz, dev->cfg.duty_cycle_pos);
506 //Configure bit order
507 host->hw->ctrl.rd_bit_order=(dev->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0;
508 host->hw->ctrl.wr_bit_order=(dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0;
511 //SPI iface needs to be configured for a delay unless it is not routed through GPIO and clock is >=apb/2
512 int nodelay=(host->no_gpio_matrix && dev->cfg.clock_speed_hz >= (apbclk/2));
513 if (dev->cfg.mode==0) {
514 host->hw->pin.ck_idle_edge=0;
515 host->hw->user.ck_out_edge=0;
516 host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
517 } else if (dev->cfg.mode==1) {
518 host->hw->pin.ck_idle_edge=0;
519 host->hw->user.ck_out_edge=1;
520 host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
521 } else if (dev->cfg.mode==2) {
522 host->hw->pin.ck_idle_edge=1;
523 host->hw->user.ck_out_edge=1;
524 host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
525 } else if (dev->cfg.mode==3) {
526 host->hw->pin.ck_idle_edge=1;
527 host->hw->user.ck_out_edge=0;
528 host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
531 //Configure bit sizes, load addr and command
532 host->hw->user.usr_dummy=(dev->cfg.dummy_bits)?1:0;
533 host->hw->user.usr_addr=(dev->cfg.address_bits)?1:0;
534 host->hw->user.usr_command=(dev->cfg.command_bits)?1:0;
535 host->hw->user1.usr_addr_bitlen=dev->cfg.address_bits-1;
536 host->hw->user1.usr_dummy_cyclelen=dev->cfg.dummy_bits-1;
537 host->hw->user2.usr_command_bitlen=dev->cfg.command_bits-1;
538 //Configure misc stuff
539 host->hw->user.doutdin=(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX)?0:1;
540 host->hw->user.sio=(dev->cfg.flags & SPI_DEVICE_3WIRE)?1:0;
542 host->hw->ctrl2.setup_time=dev->cfg.cs_ena_pretrans-1;
543 host->hw->user.cs_setup=dev->cfg.cs_ena_pretrans?1:0;
544 host->hw->ctrl2.hold_time=dev->cfg.cs_ena_posttrans-1;
545 host->hw->user.cs_hold=(dev->cfg.cs_ena_posttrans)?1:0;
548 host->hw->pin.cs0_dis=(i==0)?0:1;
549 host->hw->pin.cs1_dis=(i==1)?0:1;
550 host->hw->pin.cs2_dis=(i==2)?0:1;
553 host->hw->dma_conf.val |= SPI_OUT_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
554 host->hw->dma_out_link.start=0;
555 host->hw->dma_in_link.start=0;
556 host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
558 host->hw->ctrl.val &= ~(SPI_FREAD_DUAL|SPI_FREAD_QUAD|SPI_FREAD_DIO|SPI_FREAD_QIO);
559 host->hw->user.val &= ~(SPI_FWRITE_DUAL|SPI_FWRITE_QUAD|SPI_FWRITE_DIO|SPI_FWRITE_QIO);
560 if (trans->flags & SPI_MODE_DIO) {
561 if (trans->flags & SPI_MODE_DIOQIO_ADDR) {
562 host->hw->ctrl.fread_dio=1;
563 host->hw->user.fwrite_dio=1;
565 host->hw->ctrl.fread_dual=1;
566 host->hw->user.fwrite_dual=1;
568 host->hw->ctrl.fastrd_mode=1;
569 } else if (trans->flags & SPI_MODE_QIO) {
570 if (trans->flags & SPI_MODE_DIOQIO_ADDR) {
571 host->hw->ctrl.fread_qio=1;
572 host->hw->user.fwrite_qio=1;
574 host->hw->ctrl.fread_quad=1;
575 host->hw->user.fwrite_quad=1;
577 host->hw->ctrl.fastrd_mode=1;
581 //Fill DMA descriptors
582 if (trans->rx_buffer || (trans->flags & SPI_USE_RXDATA)) {
584 if (trans->flags & SPI_USE_RXDATA) {
585 data=(uint32_t *)&trans->rx_data[0];
587 data=trans->rx_buffer;
589 if (trans->rxlength<THRESH_DMA_TRANS) {
590 //No need for DMA; we'll copy the result out of the work registers directly later.
592 host->hw->user.usr_miso_highpart=0;
593 host->dmadesc_rx.size=(trans->rxlength+7)/8;
594 host->dmadesc_rx.length=(trans->rxlength+7)/8;
595 host->dmadesc_rx.buf=(uint8_t*)data;
596 host->dmadesc_rx.eof=1;
597 host->dmadesc_rx.sosf=0;
598 host->dmadesc_rx.owner=1;
599 host->hw->dma_in_link.addr=(int)(&host->dmadesc_rx)&0xFFFFF;
600 host->hw->dma_in_link.start=1;
602 host->hw->user.usr_miso=1;
604 host->hw->user.usr_miso=0;
607 if (trans->tx_buffer || (trans->flags & SPI_USE_TXDATA)) {
609 if (trans->flags & SPI_USE_TXDATA) {
610 data=(uint32_t *)&trans->tx_data[0];
612 data=(uint32_t *)trans->tx_buffer;
614 if (trans->rxlength < 8*32) {
616 for (int x=0; x < trans->rxlength; x+=32) {
617 //Use memcpy to get around alignment issues for txdata
619 memcpy(&word, &data[x/32], 4);
620 host->hw->data_buf[(x/32)+8]=word;
622 host->hw->user.usr_mosi_highpart=1;
624 host->hw->user.usr_mosi_highpart=0;
625 host->dmadesc_tx.size=(trans->length+7)/8;
626 host->dmadesc_tx.length=(trans->length+7)/8;
627 host->dmadesc_tx.buf=(uint8_t*)data;
628 host->dmadesc_tx.eof=1;
629 host->dmadesc_tx.sosf=0;
630 host->dmadesc_tx.owner=1;
631 host->hw->dma_out_link.addr=(int)(&host->dmadesc_tx) & 0xFFFFF;
632 host->hw->dma_out_link.start=1;
635 host->hw->mosi_dlen.usr_mosi_dbitlen=trans->length-1;
636 host->hw->miso_dlen.usr_miso_dbitlen=trans->rxlength-1;
637 host->hw->user2.usr_command_value=trans->command;
638 if (dev->cfg.address_bits>32) {
639 host->hw->addr=trans->address >> 32;
640 host->hw->slv_wr_status=trans->address & 0xffffffff;
642 host->hw->addr=trans->address & 0xffffffff;
644 host->hw->user.usr_mosi=(trans->tx_buffer==NULL)?0:1;
645 host->hw->user.usr_miso=(trans->tx_buffer==NULL)?0:1;
647 //Call pre-transmission callback, if any
648 if (dev->cfg.pre_cb) dev->cfg.pre_cb(trans);
652 if (do_yield) portYIELD_FROM_ISR();
656 esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
659 SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
660 SPI_CHECK((trans_desc->flags & SPI_USE_RXDATA)==0 ||trans_desc->length <= 32, "rxdata transfer > 32bytes", ESP_ERR_INVALID_ARG);
661 SPI_CHECK((trans_desc->flags & SPI_USE_TXDATA)==0 ||trans_desc->length <= 32, "txdata transfer > 32bytes", ESP_ERR_INVALID_ARG);
662 SPI_CHECK(!((trans_desc->flags & (SPI_MODE_DIO|SPI_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG);
663 SPI_CHECK(!((trans_desc->flags & (SPI_MODE_DIO|SPI_MODE_QIO)) && (!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX))), "incompatible iface params", ESP_ERR_INVALID_ARG);
664 r=xQueueSend(handle->trans_queue, (void*)&trans_desc, ticks_to_wait);
665 if (!r) return ESP_ERR_TIMEOUT;
666 esp_intr_enable(handle->host->intr);
670 esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transaction_t **trans_desc, TickType_t ticks_to_wait)
673 SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
674 r=xQueueReceive(handle->ret_queue, (void*)trans_desc, ticks_to_wait);
675 if (!r) return ESP_ERR_TIMEOUT;
679 //Porcelain to do one blocking transmission.
680 esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)
683 spi_transaction_t *ret_trans;
684 //ToDo: check if any spi transfers in flight
685 ret=spi_device_queue_trans(handle, trans_desc, portMAX_DELAY);
686 if (ret!=ESP_OK) return ret;
687 ret=spi_device_get_trans_result(handle, &ret_trans, portMAX_DELAY);
688 if (ret!=ESP_OK) return ret;
689 assert(ret_trans==trans_desc);