]> granicus.if.org Git - esp-idf/blob - components/driver/include/driver/spi_common.h
Merge branch 'feature/build_warn_undefined_vars' into 'master'
[esp-idf] / components / driver / include / driver / spi_common.h
1 // Copyright 2010-2017 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 #ifndef _DRIVER_SPI_COMMON_H_
17 #define _DRIVER_SPI_COMMON_H_
18
19 #include <stdint.h>
20 #include <stdbool.h>
21 #include "esp_err.h"
22 #include "soc/spi_struct.h"
23 #include "rom/lldesc.h"
24
25
26 #ifdef __cplusplus
27 extern "C"
28 {
29 #endif
30
31
32 //Maximum amount of bytes that can be put in one DMA descriptor
33 #define SPI_MAX_DMA_LEN (4096-4)
34
35
36 /**
37  * @brief Enum with the three SPI peripherals that are software-accessible in it
38  */
39 typedef enum {
40     SPI_HOST=0,                     ///< SPI1, SPI
41     HSPI_HOST=1,                    ///< SPI2, HSPI
42     VSPI_HOST=2                     ///< SPI3, VSPI
43 } spi_host_device_t;
44
45 /**
46  * @brief This is a configuration structure for a SPI bus.
47  *
48  * You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the
49  * GPIO matrix to route the signals. An exception is made when all signals either can be routed through 
50  * the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.
51  *
52  * @note Be advised that the slave driver does not use the quadwp/quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized.
53  */
54 typedef struct {
55     int mosi_io_num;                ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
56     int miso_io_num;                ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.
57     int sclk_io_num;                ///< GPIO pin for Spi CLocK signal, or -1 if not used.
58     int quadwp_io_num;              ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.
59     int quadhd_io_num;              ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
60     int max_transfer_sz;            ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
61 } spi_bus_config_t;
62
63
64 /**
65  * @brief Try to claim a SPI peripheral
66  *
67  * Call this if your driver wants to manage a SPI peripheral.
68  *
69  * @param host Peripheral to claim
70  * @return True if peripheral is claimed successfully; false if peripheral already is claimed.
71  */
72 bool spicommon_periph_claim(spi_host_device_t host);
73
74 /**
75  * @brief Return the SPI peripheral so another driver can claim it.
76  *
77  * @param host Peripheral to return
78  * @return True if peripheral is returned successfully; false if peripheral was free to claim already.
79  */
80 bool spicommon_periph_free(spi_host_device_t host);
81
82 /**
83  * @brief Try to claim a SPI DMA channel
84  * 
85  *  Call this if your driver wants to use SPI with a DMA channnel.
86  * 
87  * @param dma_chan channel to claim
88  * 
89  * @return True if success; false otherwise.
90  */
91 bool spicommon_dma_chan_claim(int dma_chan);
92
93 /**
94  * @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA.
95  * 
96  * @param dma_chan channel to return
97  * 
98  * @return True if success; false otherwise.
99  */
100 bool spicommon_dma_chan_free(int dma_chan);
101
102 #define SPICOMMON_BUSFLAG_SLAVE  0          ///< Initialize I/O in slave mode
103 #define SPICOMMON_BUSFLAG_MASTER (1<<0)     ///< Initialize I/O in master mode
104 #define SPICOMMON_BUSFLAG_QUAD   (1<<1)     ///< Also initialize WP/HD pins, if specified
105
106 /**
107  * @brief Connect a SPI peripheral to GPIO pins
108  *
109  * This routine is used to connect a SPI peripheral to the IO-pads and DMA channel given in
110  * the arguments. Depending on the IO-pads requested, the routing is done either using the 
111  * IO_mux or using the GPIO matrix.
112  *
113  * @param host SPI peripheral to be routed
114  * @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins
115  * @param dma_chan DMA-channel (1 or 2) to use, or 0 for no DMA.
116  * @param flags Combination of SPICOMMON_BUSFLAG_* flags
117  * @param[out] is_native A value of 'true' will be written to this address if the GPIOs can be
118  *                  routed using the IO_mux, 'false' if the GPIO matrix is used.
119  * @return 
120  *         - ESP_ERR_INVALID_ARG   if parameter is invalid
121  *         - ESP_OK                on success
122  */
123 esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, int flags, bool *is_native);
124
125 /**
126  * @brief Free the IO used by a SPI peripheral
127  *
128  * @param host SPI peripheral to be freed
129  * @return 
130  *         - ESP_ERR_INVALID_ARG   if parameter is invalid
131  *         - ESP_OK                on success
132  */
133
134 esp_err_t spicommon_bus_free_io(spi_host_device_t host);
135
136 /**
137  * @brief Initialize a Chip Select pin for a specific SPI peripheral
138  *
139  *
140  * @param host SPI peripheral
141  * @param cs_io_num GPIO pin to route
142  * @param cs_num CS id to route
143  * @param force_gpio_matrix If true, CS will always be routed through the GPIO matrix. If false,
144  *                          if the GPIO number allows it, the routing will happen through the IO_mux.
145  */
146
147 void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix);
148
149 /**
150  * @brief Free a chip select line
151  *
152  * @param host SPI peripheral
153  * @param cs_num CS id to free
154  */
155 void spicommon_cs_free(spi_host_device_t host, int cs_num);
156
157
158 /**
159  * @brief Setup a DMA link chain
160  *
161  * This routine will set up a chain of linked DMA descriptors in the array pointed to by
162  * ``dmadesc``. Enough DMA descriptors will be used to fit the buffer of ``len`` bytes in, and the
163  * descriptors will point to the corresponding positions in ``buffer`` and linked together. The
164  * end result is that feeding ``dmadesc[0]`` into DMA hardware results in the entirety ``len`` bytes
165  * of ``data`` being read or written.
166  *
167  * @param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ``len`` bytes
168  * @param len Length of buffer
169  * @param data Data buffer to use for DMA transfer
170  * @param isrx True if data is to be written into ``data``, false if it's to be read from ``data``.
171  */
172 void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx);
173
174 /**
175  * @brief Get the position of the hardware registers for a specific SPI host
176  *
177  * @param host The SPI host
178  *
179  * @return A register descriptor stuct pointer, pointed at the hardware registers
180  */
181 spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
182
183 /**
184  * @brief Get the IRQ source for a specific SPI host
185  *
186  * @param host The SPI host
187  *
188  * @return The hosts IRQ source
189  */
190 int spicommon_irqsource_for_host(spi_host_device_t host);
191
192 /**
193  * Callback, to be called when a DMA engine reset is completed
194 */
195 typedef void(*dmaworkaround_cb_t)(void *arg);
196
197
198 /**
199  * @brief Request a reset for a certain DMA channel
200  *
201  * @note In some (well-defined) cases in the ESP32 (at least rev v.0 and v.1), a SPI DMA channel will get confused. This can be remedied
202  * by resetting the SPI DMA hardware in case this happens. Unfortunately, the reset knob used for thsi will reset _both_ DMA channels, and
203  * as such can only done safely when both DMA channels are idle. These functions coordinate this.
204  * 
205  * Essentially, when a reset is needed, a driver can request this using spicommon_dmaworkaround_req_reset. This is supposed to be called
206  * with an user-supplied function as an argument. If both DMA channels are idle, this call will reset the DMA subsystem and return true. 
207  * If the other DMA channel is still busy, it will return false; as soon as the other DMA channel is done, however, it will reset the 
208  * DMA subsystem and call the callback. The callback is then supposed to be used to continue the SPI drivers activity.
209  *
210  * @param dmachan DMA channel associated with the SPI host that needs a reset
211  * @param cb Callback to call in case DMA channel cannot be reset immediately
212  * @param arg Argument to the callback
213  *
214  * @return True when a DMA reset could be executed immediately. False when it could not; in this
215  *         case the callback will be called with the specified argument when the logic can execute
216  *         a reset, after that reset.
217  */
218 bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg);
219
220
221 /**
222  * @brief Check if a DMA reset is requested but has not completed yet
223  *
224  * @return True when a DMA reset is requested but hasn't completed yet. False otherwise.
225  */
226 bool spicommon_dmaworkaround_reset_in_progress();
227
228
229 /**
230  * @brief Mark a DMA channel as idle.
231  *
232  * A call to this function tells the workaround logic that this channel will
233  * not be affected by a global SPI DMA reset.
234  */
235 void spicommon_dmaworkaround_idle(int dmachan);
236
237 /**
238  * @brief Mark a DMA channel as active.
239  *
240  * A call to this function tells the workaround logic that this channel will
241  * be affected by a global SPI DMA reset, and a reset like that should not be attempted.
242  */
243 void spicommon_dmaworkaround_transfer_active(int dmachan);
244
245
246
247 #ifdef __cplusplus
248 }
249 #endif
250
251 #endif