1 // Copyright 2010-2019 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 #pragma once
16 
17 #include <stdint.h>
18 #include <stdbool.h>
19 #include "esp_err.h"
20 #include "soc/lldesc.h"
21 #include "soc/spi_periph.h"
22 #include "hal/spi_types.h"
23 #include "sdkconfig.h"
24 
25 #ifdef __cplusplus
26 extern "C"
27 {
28 #endif
29 
30 //Maximum amount of bytes that can be put in one DMA descriptor
31 #define SPI_MAX_DMA_LEN (4096-4)
32 
33 /**
34  * Transform unsigned integer of length <= 32 bits to the format which can be
35  * sent by the SPI driver directly.
36  *
37  * E.g. to send 9 bits of data, you can:
38  *
39  *      uint16_t data = SPI_SWAP_DATA_TX(0x145, 9);
40  *
41  * Then points tx_buffer to ``&data``.
42  *
43  * @param DATA Data to be sent, can be uint8_t, uint16_t or uint32_t.
44  * @param LEN Length of data to be sent, since the SPI peripheral sends from
45  *      the MSB, this helps to shift the data to the MSB.
46  */
47 #define SPI_SWAP_DATA_TX(DATA, LEN) __builtin_bswap32((uint32_t)(DATA)<<(32-(LEN)))
48 
49 /**
50  * Transform received data of length <= 32 bits to the format of an unsigned integer.
51  *
52  * E.g. to transform the data of 15 bits placed in a 4-byte array to integer:
53  *
54  *      uint16_t data = SPI_SWAP_DATA_RX(*(uint32_t*)t->rx_data, 15);
55  *
56  * @param DATA Data to be rearranged, can be uint8_t, uint16_t or uint32_t.
57  * @param LEN Length of data received, since the SPI peripheral writes from
58  *      the MSB, this helps to shift the data to the LSB.
59  */
60 #define SPI_SWAP_DATA_RX(DATA, LEN) (__builtin_bswap32(DATA)>>(32-(LEN)))
61 
62 #define SPICOMMON_BUSFLAG_SLAVE         0          ///< Initialize I/O in slave mode
63 #define SPICOMMON_BUSFLAG_MASTER        (1<<0)     ///< Initialize I/O in master mode
64 #define SPICOMMON_BUSFLAG_IOMUX_PINS    (1<<1)     ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
65 #define SPICOMMON_BUSFLAG_GPIO_PINS     (1<<2)     ///< Force the signals to be routed through GPIO matrix. Or indicates the pins are routed through the GPIO matrix.
66 #define SPICOMMON_BUSFLAG_SCLK          (1<<3)     ///< Check existing of SCLK pin. Or indicates CLK line initialized.
67 #define SPICOMMON_BUSFLAG_MISO          (1<<4)     ///< Check existing of MISO pin. Or indicates MISO line initialized.
68 #define SPICOMMON_BUSFLAG_MOSI          (1<<5)     ///< Check existing of MOSI pin. Or indicates MOSI line initialized.
69 #define SPICOMMON_BUSFLAG_DUAL          (1<<6)     ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
70 #define SPICOMMON_BUSFLAG_WPHD          (1<<7)     ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
71 #define SPICOMMON_BUSFLAG_QUAD          (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD)     ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
72 
73 #define SPICOMMON_BUSFLAG_NATIVE_PINS   SPICOMMON_BUSFLAG_IOMUX_PINS
74 
75 /**
76  * @brief SPI DMA channels
77  */
78 typedef enum {
79   SPI_DMA_DISABLED = 0,     ///< Do not enable DMA for SPI
80 #if CONFIG_IDF_TARGET_ESP32
81   SPI_DMA_CH1      = 1,     ///< Enable DMA, select DMA Channel 1
82   SPI_DMA_CH2      = 2,     ///< Enable DMA, select DMA Channel 2
83 #endif
84   SPI_DMA_CH_AUTO  = 3,     ///< Enable DMA, channel is automatically selected by driver
85 } spi_common_dma_t;
86 
87 #if __cplusplus
88 /* Needed for C++ backwards compatibility with earlier ESP-IDF where this argument is a bare 'int'. Can be removed in ESP-IDF 5 */
89 typedef int spi_dma_chan_t;
90 #else
91 typedef spi_common_dma_t spi_dma_chan_t;
92 #endif
93 
94 /**
95  * @brief This is a configuration structure for a SPI bus.
96  *
97  * You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the
98  * GPIO matrix to route the signals. An exception is made when all signals either can be routed through
99  * the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.
100  *
101  * @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.
102  */
103 typedef struct {
104     int mosi_io_num;                ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
105     int miso_io_num;                ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.
106     int sclk_io_num;                ///< GPIO pin for Spi CLocK signal, or -1 if not used.
107     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.
108     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.
109     int max_transfer_sz;            ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
110     uint32_t flags;                 ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
111     int intr_flags;    /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
112                          *  ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
113                          *  by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
114                          *  the driver, and their callee functions, should be put in the IRAM.
115                          */
116 } spi_bus_config_t;
117 
118 
119 /**
120  * @brief Initialize a SPI bus
121  *
122  * @warning SPI0/1 is not supported
123  *
124  * @param host_id       SPI peripheral that controls this bus
125  * @param bus_config    Pointer to a spi_bus_config_t struct specifying how the host should be initialized
126  * @param dma_chan      - Selecting a DMA channel for an SPI bus allows transactions on the bus with size only limited by the amount of internal memory.
127  *                      - Selecting SPI_DMA_DISABLED limits the size of transactions.
128  *                      - Set to SPI_DMA_DISABLED if only the SPI flash uses this bus.
129  *                      - Set to SPI_DMA_CH_AUTO to let the driver to allocate the DMA channel.
130  *
131  * @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
132  *          DMA-capable memory.
133  *
134  * @warning The ISR of SPI is always executed on the core which calls this
135  *          function. Never starve the ISR on this core or the SPI transactions will not
136  *          be handled.
137  *
138  * @return
139  *         - ESP_ERR_INVALID_ARG   if configuration is invalid
140  *         - ESP_ERR_INVALID_STATE if host already is in use
141  *         - ESP_ERR_NOT_FOUND     if there is no available DMA channel
142  *         - ESP_ERR_NO_MEM        if out of memory
143  *         - ESP_OK                on success
144  */
145 esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan);
146 
147 /**
148  * @brief Free a SPI bus
149  *
150  * @warning In order for this to succeed, all devices have to be removed first.
151  *
152  * @param host_id SPI peripheral to free
153  * @return
154  *         - ESP_ERR_INVALID_ARG   if parameter is invalid
155  *         - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
156  *         - ESP_OK                on success
157  */
158 esp_err_t spi_bus_free(spi_host_device_t host_id);
159 
160 #ifdef __cplusplus
161 }
162 #endif
163