]> granicus.if.org Git - esp-idf/blob - components/driver/spi_master.c
Add SPI Master driver, example, test and docs
[esp-idf] / components / driver / spi_master.c
1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
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
6
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 /*
16 Architecture:
17
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)
21
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.
28
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.
32 */
33
34
35
36 #include <string.h>
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"
45 #include "esp_attr.h"
46 #include "esp_intr.h"
47 #include "esp_intr_alloc.h"
48 #include "esp_log.h"
49 #include "esp_err.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"
55 #include "soc/soc.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"
63
64 typedef struct spi_device_t spi_device_t;
65
66 #define NO_CS 3     //Number of CS pins per SPI host
67
68 typedef struct {
69     spi_device_t *device[NO_CS];
70     intr_handle_t intr;
71     spi_dev_t *hw;
72     spi_transaction_t *cur_trans;
73     int cur_cs;
74     lldesc_t dmadesc_tx, dmadesc_rx;
75     bool no_gpio_matrix;
76 } spi_host_t;
77
78 struct spi_device_t {
79     QueueHandle_t trans_queue;
80     QueueHandle_t ret_queue;
81     spi_device_interface_config_t cfg;
82     spi_host_t *host;
83 };
84
85 static spi_host_t *spihost[3];
86
87
88 static const char *SPI_TAG = "spi_master";
89 #define SPI_CHECK(a, str, ret_val) \
90     if (!(a)) { \
91         ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
92         return (ret_val); \
93     }
94
95 /*
96  Stores a bunch of per-spi-peripheral data.
97 */
98 typedef struct {
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
119 } spi_signal_conn_t;
120
121 /*
122  Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc
123 */
124 static const spi_signal_conn_t io_signal[3]={
125     {
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},
136         .spiclk_native=6,
137         .spid_native=8,
138         .spiq_native=7,
139         .spiwp_native=10,
140         .spihd_native=9,
141         .spics0_native=11,
142         .irq=ETS_SPI1_INTR_SOURCE,
143         .irq_dma=ETS_SPI1_DMA_INTR_SOURCE,
144         .module=PERIPH_SPI_MODULE,
145         .hw=&SPI1
146     }, {
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},
157         .spiclk_native=14,
158         .spid_native=13,
159         .spiq_native=12,
160         .spiwp_native=2,
161         .spihd_native=4,
162         .spics0_native=15,
163         .irq=ETS_SPI2_INTR_SOURCE,
164         .irq_dma=ETS_SPI2_DMA_INTR_SOURCE,
165         .module=PERIPH_HSPI_MODULE,
166         .hw=&SPI2
167     }, {
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},
178         .spiclk_native=18,
179         .spid_native=23,
180         .spiq_native=19,
181         .spiwp_native=22,
182         .spihd_native=21,
183         .spics0_native=5,
184         .irq=ETS_SPI3_INTR_SOURCE,
185         .irq_dma=ETS_SPI3_DMA_INTR_SOURCE,
186         .module=PERIPH_VSPI_MODULE,
187         .hw=&SPI3
188     }
189 };
190
191 static void spi_intr(void *arg);
192
193
194 esp_err_t spi_bus_initialize(spi_host_device_t host, spi_bus_config_t *bus_config, int dma_chan)
195 {
196     bool native=true;
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);
199
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);
202     
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);
208
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));
213     
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;
220     
221     spihost[host]->no_gpio_matrix=native;
222     if (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);
230     } else {
231         //Use GPIO 
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);
237         }
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);
243         }
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);
249         }
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);
255         }
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);
260         }
261     }
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;
265
266     //Reset DMA
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);
271     
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;
281
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;
287
288     //Select DMA channel.
289     SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
290
291     return ESP_OK;
292 }
293
294 esp_err_t spi_bus_free(spi_host_device_t host)
295 {
296     int x;
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);
301     }
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);
306     free(spihost[host]);
307     spihost[host]=NULL;
308     return ESP_OK;
309 }
310
311 /*
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.
314 */
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)
316 {
317     int freecs;
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;
324     }
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);
329
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;
335
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];
341
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));
344
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);
350         } else {
351             //Use GPIO matrix
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);
355         }
356     }
357     if (dev_config->flags&SPI_DEVICE_CLK_AS_CS) {
358         spihost[host]->hw->pin.master_ck_sel |= (1<<freecs);
359     } else {
360         spihost[host]->hw->pin.master_ck_sel &= (1<<freecs);
361     }
362     if (dev_config->flags&SPI_DEVICE_POSITIVE_CS) {
363         spihost[host]->hw->pin.master_cs_pol |= (1<<freecs);
364     } else {
365         spihost[host]->hw->pin.master_cs_pol &= (1<<freecs);
366     }
367     *handle=dev;
368     return ESP_OK;
369 }
370
371 esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
372 {
373     int x;
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);
380
381     //Kill queues
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;
387     }
388     free(handle);
389     return ESP_OK;
390 }
391
392 static void spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) {
393     int pre, n, h, l;
394     //In hw, n, h and l are 1-32, pre is 0-8K. Value written to register is one lower than used value.
395     if (hz>(fapb/2)) {
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;
402     } else {
403         //For best duty cycle resolution, we want n to be as close to 32 as possible.
404         //ToDo: 
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
410         //Also ToDo:
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
413         n=(fapb/(hz*32));
414         if (n>32) {
415             //Need to use prescaler
416             n=32;
417         }
418         if (n<32) {
419             //No need for prescaler.
420             n=(fapb/hz);
421         }
422         pre=(fapb/n)/hz;
423         h=n;
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;
430     }
431 }
432
433
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)
437
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)
442 {
443     int i;
444     int prevCs=-1;
445     BaseType_t r;
446     BaseType_t do_yield=pdFALSE;
447     spi_transaction_t *trans=NULL;
448     spi_host_t *host=(spi_host_t*)arg;
449
450     //Ignore all but the trans_done int.
451     if (!host->hw->slave.trans_done) return;
452
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.
457             uint32_t *data;
458             if (host->cur_trans->flags & SPI_USE_RXDATA) {
459                 data=(uint32_t*)&host->cur_trans->rx_data[0];
460             } else {
461                 data=(uint32_t*)host->cur_trans->rx_buffer;
462             }
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);
467             }
468         }
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;
474         prevCs=host->cur_cs;
475     }
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.
481             if (r) break;
482         }
483     }
484     if (i==NO_CS) {
485         //No packet waiting. Disable interrupt.
486         esp_intr_disable(host->intr);
487     } else {
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);
494         
495         //Default rxlength to be the same as length, if not filled in.
496         if (trans->rxlength==0) {
497             trans->rxlength=trans->length;
498         }
499         
500         //Reconfigure accoding to device settings, but only if we change CSses.
501         if (i!=prevCs) {
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;
509             
510             //Configure polarity
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;
529             }
530
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;
541
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;
546
547             //Configure CS pin
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;
551         }
552         //Reset DMA
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);
557         //QIO/DIO
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;
564             } else {
565                 host->hw->ctrl.fread_dual=1;
566                 host->hw->user.fwrite_dual=1;
567             }
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;
573             } else {
574                 host->hw->ctrl.fread_quad=1;
575                 host->hw->user.fwrite_quad=1;
576             }
577             host->hw->ctrl.fastrd_mode=1;
578         }
579
580
581         //Fill DMA descriptors
582         if (trans->rx_buffer || (trans->flags & SPI_USE_RXDATA)) {
583             uint32_t *data;
584             if (trans->flags & SPI_USE_RXDATA) {
585                 data=(uint32_t *)&trans->rx_data[0];
586             } else {
587                 data=trans->rx_buffer;
588             }
589             if (trans->rxlength<THRESH_DMA_TRANS) {
590                 //No need for DMA; we'll copy the result out of the work registers directly later.
591             } else {
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;
601             }
602             host->hw->user.usr_miso=1;
603         } else {
604             host->hw->user.usr_miso=0;
605         }
606
607         if (trans->tx_buffer || (trans->flags & SPI_USE_TXDATA)) {
608             uint32_t *data;
609             if (trans->flags & SPI_USE_TXDATA) {
610                 data=(uint32_t *)&trans->tx_data[0];
611             } else {
612                 data=(uint32_t *)trans->tx_buffer;
613             }
614             if (trans->rxlength < 8*32) {
615                 //No need for DMA.
616                 for (int x=0; x < trans->rxlength; x+=32) {
617                     //Use memcpy to get around alignment issues for txdata
618                     uint32_t word;
619                     memcpy(&word, &data[x/32], 4);
620                     host->hw->data_buf[(x/32)+8]=word;
621                 }
622                 host->hw->user.usr_mosi_highpart=1;
623             } else {
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;
633             }
634         }
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;
641         } else {
642             host->hw->addr=trans->address & 0xffffffff;
643         }
644         host->hw->user.usr_mosi=(trans->tx_buffer==NULL)?0:1;
645         host->hw->user.usr_miso=(trans->tx_buffer==NULL)?0:1;
646
647         //Call pre-transmission callback, if any
648         if (dev->cfg.pre_cb) dev->cfg.pre_cb(trans);
649         //Kick off transfer
650         host->hw->cmd.usr=1;
651     }
652     if (do_yield) portYIELD_FROM_ISR();
653 }
654
655
656 esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc,  TickType_t ticks_to_wait)
657 {
658     BaseType_t r;
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);
667     return ESP_OK;
668 }
669
670 esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transaction_t **trans_desc, TickType_t ticks_to_wait)
671 {
672     BaseType_t r;
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;
676     return ESP_OK;
677 }
678
679 //Porcelain to do one blocking transmission.
680 esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)
681 {
682     esp_err_t ret;
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);
690     return ESP_OK;
691 }
692