• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015-2020 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  * NOTICE
17  * The hal is not public api, don't use in application code.
18  * See readme.md in hal/include/hal/readme.md
19  ******************************************************************************/
20 
21 /*
22  * The HAL layer for SPI Slave HD mode.
23  *
24  * Usage (segment mode):
25  * - Firstly, initialize the slave with `spi_slave_hd_hal_init`
26  *
27  * - Event handling:
28  *     - (Optional) Call ``spi_slave_hd_hal_enable_event_intr`` to enable the used interrupts
29  *     - (Basic) Call ``spi_slave_hd_hal_check_clear_event`` to check whether an event happen, and also
30  *       clear its interrupt. For events: SPI_EV_BUF_TX, SPI_EV_BUF_RX, SPI_EV_BUF_RX, SPI_EV_CMD9,
31  *       SPI_EV_CMDA.
32  *     - (Advanced) Call ``spi_slave_hd_hal_check_disable_event`` to disable the interrupt of an event,
33  *       so that the task can call ``spi_slave_hd_hal_invoke_event_intr`` later to manually invoke the
34  *       ISR. For SPI_EV_SEND, SPI_EV_RECV.
35  *
36  * - TXDMA:
37  *     - To send data through DMA, call `spi_slave_hd_hal_txdma`
38  *     - When the operation is done, SPI_EV_SEND will be triggered.
39  *
40  * - RXDMA:
41  *     - To receive data through DMA, call `spi_slave_hd_hal_rxdma`
42  *     - When the operation is done, SPI_EV_RECV will be triggered.
43  *     - Call ``spi_slave_hd_hal_rxdma_seg_get_len`` to get the received length
44  *
45  *  - Shared buffer:
46  *      - Call ``spi_slave_hd_hal_write_buffer`` to write the shared register buffer. When the buffer is
47  *        read by the master (regardless of the read address), SPI_EV_BUF_TX will be triggered
48  *      - Call ``spi_slave_hd_hal_read_buffer`` to read the shared register buffer. When the buffer is
49  *        written by the master (regardless of the written address), SPI_EV_BUF_RX will be triggered.
50  */
51 
52 #pragma once
53 
54 #include <esp_types.h>
55 #include "esp_err.h"
56 #include "hal/spi_ll.h"
57 #include "hal/spi_types.h"
58 
59 /**
60  * @brief Type of dma descriptor with appended members
61  *        this structure inherits DMA descriptor, with a pointer to the transaction descriptor passed from users.
62  */
63 typedef struct {
64     lldesc_t      desc;                             ///< DMA descriptor
65     void          *arg;                             ///< This points to the transaction descriptor user passed in
66 } spi_slave_hd_hal_desc_append_t;
67 
68 /// Configuration of the HAL
69 typedef struct {
70     uint32_t      host_id;                          ///< Host ID of the spi peripheral
71     spi_dma_dev_t *dma_in;                          ///< Input  DMA(DMA -> RAM) peripheral register address
72     spi_dma_dev_t *dma_out;                         ///< Output DMA(RAM -> DMA) peripheral register address
73     bool          dma_enabled;                      ///< DMA enabled or not
74     uint32_t      tx_dma_chan;                      ///< TX DMA channel used.
75     uint32_t      rx_dma_chan;                      ///< RX DMA channel used.
76     bool          append_mode;                      ///< True for DMA append mode, false for segment mode
77     uint32_t      spics_io_num;                     ///< CS GPIO pin for this device
78     uint8_t       mode;                             ///< SPI mode (0-3)
79     uint32_t      command_bits;                     ///< command field bits, multiples of 8 and at least 8.
80     uint32_t      address_bits;                     ///< address field bits, multiples of 8 and at least 8.
81     uint32_t      dummy_bits;                       ///< dummy field bits, multiples of 8 and at least 8.
82 
83     struct {
84         uint32_t  tx_lsbfirst : 1;                  ///< Whether TX data should be sent with LSB first.
85         uint32_t  rx_lsbfirst : 1;                  ///< Whether RX data should be read with LSB first.
86     };
87 } spi_slave_hd_hal_config_t;
88 
89 /// Context of the HAL, initialized by :cpp:func:`spi_slave_hd_hal_init`.
90 typedef struct {
91     /* These two need to be malloced by the driver first */
92     spi_slave_hd_hal_desc_append_t  *dmadesc_tx;            ///< Head of the TX DMA descriptors.
93     spi_slave_hd_hal_desc_append_t  *dmadesc_rx;            ///< Head of the RX DMA descriptors.
94 
95     /* address of the hardware */
96     spi_dev_t                       *dev;                   ///< Beginning address of the peripheral registers.
97     spi_dma_dev_t                   *dma_in;                ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
98     spi_dma_dev_t                   *dma_out;               ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
99     bool                            dma_enabled;            ///< DMA enabled or not
100     uint32_t                        tx_dma_chan;            ///< TX DMA channel used.
101     uint32_t                        rx_dma_chan;            ///< RX DMA channel used.
102     bool                            append_mode;            ///< True for DMA append mode, false for segment mode
103     uint32_t                        dma_desc_num;           ///< Number of the available DMA descriptors. Calculated from ``bus_max_transfer_size``.
104     spi_slave_hd_hal_desc_append_t  *tx_cur_desc;           ///< Current TX DMA descriptor that could be linked (set up).
105     spi_slave_hd_hal_desc_append_t  *tx_dma_head;           ///< Head of the linked TX DMA descriptors which are not used by hardware
106     spi_slave_hd_hal_desc_append_t  *tx_dma_tail;           ///< Tail of the linked TX DMA descriptors which are not used by hardware
107     spi_slave_hd_hal_desc_append_t  tx_dummy_head;          ///< Dummy descriptor for ``tx_dma_head`` to start
108     uint32_t                        tx_used_desc_cnt;       ///< Number of the TX descriptors that have been setup
109     uint32_t                        tx_recycled_desc_cnt;   ///< Number of the TX descriptors that could be recycled
110     spi_slave_hd_hal_desc_append_t  *rx_cur_desc;           ///< Current RX DMA descriptor that could be linked (set up).
111     spi_slave_hd_hal_desc_append_t  *rx_dma_head;           ///< Head of the linked RX DMA descriptors which are not used by hardware
112     spi_slave_hd_hal_desc_append_t  *rx_dma_tail;           ///< Tail of the linked RX DMA descriptors which are not used by hardware
113     spi_slave_hd_hal_desc_append_t  rx_dummy_head;          ///< Dummy descriptor for ``rx_dma_head`` to start
114     uint32_t                        rx_used_desc_cnt;       ///< Number of the RX descriptors that have been setup
115     uint32_t                        rx_recycled_desc_cnt;   ///< Number of the RX descriptors that could be recycled
116 
117     /* Internal status used by the HAL implementation, initialized as 0. */
118     uint32_t                        intr_not_triggered;
119     bool                            tx_dma_started;
120     bool                            rx_dma_started;
121 } spi_slave_hd_hal_context_t;
122 
123 /**
124  * @brief Initialize the hardware and part of the context
125  *
126  * @param hal        Context of the HAL layer
127  * @param hal_config Configuration of the HAL
128  */
129 void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config);
130 
131 /**
132  * @brief Get the size of one DMA descriptor
133  *
134  * @param hal       Context of the HAL layer
135  * @param bus_size  SPI bus maximum transfer size, in bytes.
136  * @return          Total size needed for all the DMA descriptors
137  */
138 uint32_t spi_slave_hd_hal_get_total_desc_size(spi_slave_hd_hal_context_t *hal, uint32_t bus_size);
139 
140 /**
141  * @brief Get the actual bus size
142  *
143  * @param hal       Context of the HAL layer
144  * @return          Actual bus transaction size
145  */
146 uint32_t spi_salve_hd_hal_get_max_bus_size(spi_slave_hd_hal_context_t *hal);
147 
148 /**
149  * @brief Check and clear signal of one event
150  *
151  * @param hal       Context of the HAL layer
152  * @param ev        Event to check
153  * @return          True if event triggered, otherwise false
154  */
155 bool spi_slave_hd_hal_check_clear_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
156 
157 /**
158  * @brief Check and clear the interrupt of one event.
159  *
160  * @note The event source will be kept, so that the interrupt can be invoked by
161  *       :cpp:func:`spi_slave_hd_hal_invoke_event_intr`. If event not triggered, its interrupt source
162  *       will not be disabled either.
163  *
164  * @param hal       Context of the HAL layer
165  * @param ev        Event to check and disable
166  * @return          True if event triggered, otherwise false
167  */
168 bool spi_slave_hd_hal_check_disable_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
169 
170 /**
171  * @brief Enable to invole the ISR of corresponding event.
172  *
173  * @note The function, compared with :cpp:func:`spi_slave_hd_hal_enable_event_intr`, contains a
174  *       workaround to force trigger the interrupt, even if the interrupt source cannot be initialized
175  *       correctly.
176  *
177  * @param hal       Context of the HAL layer
178  * @param ev        Event (reason) to invoke the ISR
179  */
180 void spi_slave_hd_hal_invoke_event_intr(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
181 
182 /**
183  * @brief Enable the interrupt source of corresponding event.
184  *
185  * @param hal       Context of the HAL layer
186  * @param ev        Event whose corresponding interrupt source should be enabled.
187  */
188 void spi_slave_hd_hal_enable_event_intr(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 // RX DMA
192 ////////////////////////////////////////////////////////////////////////////////
193 /**
194  * @brief Start the RX DMA operation to the specified buffer.
195  *
196  * @param hal       Context of the HAL layer
197  * @param[out] out_buf  Buffer to receive the data
198  * @param len       Maximul length to receive
199  */
200 void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, size_t len);
201 
202 /**
203  * @brief Get the length of total received data
204  *
205  * @param hal       Context of the HAL layer
206  * @return          The received length
207  */
208 int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal);
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 // TX DMA
212 ////////////////////////////////////////////////////////////////////////////////
213 /**
214  * @brief Start the TX DMA operation with the specified buffer
215  *
216  * @param hal       Context of the HAL layer
217  * @param data      Buffer of data to send
218  * @param len       Size of the buffer, also the maximum length to send
219  */
220 void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len);
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 // Shared buffer
224 ////////////////////////////////////////////////////////////////////////////////
225 /**
226  * @brief Read from the shared register buffer
227  *
228  * @param hal       Context of the HAL layer
229  * @param addr      Address of the shared regsiter to read
230  * @param out_data  Buffer to store the read data
231  * @param len       Length to read from the shared buffer
232  */
233 void spi_slave_hd_hal_read_buffer(spi_slave_hd_hal_context_t *hal, int addr, uint8_t *out_data, size_t len);
234 
235 /**
236  * @brief Write the shared register buffer
237  *
238  * @param hal       Context of the HAL layer
239  * @param addr      Address of the shared register to write
240  * @param data      Buffer of the data to write
241  * @param len       Length to write into the shared buffer
242  */
243 void spi_slave_hd_hal_write_buffer(spi_slave_hd_hal_context_t *hal, int addr, uint8_t *data, size_t len);
244 
245 /**
246  * @brief Get the length of previous transaction.
247  *
248  * @param hal       Context of the HAL layer
249  * @return          The length of previous transaction
250  */
251 int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal);
252 
253 /**
254  * @brief Get the address of last transaction
255  *
256  * @param hal       Context of the HAL layer
257  * @return          The address of last transaction
258  */
259 int spi_slave_hd_hal_get_last_addr(spi_slave_hd_hal_context_t *hal);
260 
261 #if CONFIG_IDF_TARGET_ESP32S2
262 //Append mode is only supported on ESP32S2 now
263 ////////////////////////////////////////////////////////////////////////////////
264 // Append Mode
265 ////////////////////////////////////////////////////////////////////////////////
266 /**
267  * @brief Return the finished TX transaction
268  *
269  * @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer.
270  * This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour,
271  * this API will go wrong.
272  *
273  * @param hal            Context of the HAL layer
274  * @param out_trans      Pointer to the caller-defined transaction
275  * @return               1: Transaction is finished; 0: Transaction is not finished
276  */
277 bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans);
278 
279 /**
280  * @brief Return the finished RX transaction
281  *
282  * @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer.
283  * This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour,
284  * this API will go wrong.
285  *
286  * @param hal            Context of the HAL layer
287  * @param out_trans      Pointer to the caller-defined transaction
288  * @param out_len        Actual number of bytes of received data
289  * @return               1: Transaction is finished; 0: Transaction is not finished
290  */
291 bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, size_t *out_len);
292 
293 /**
294  * @brief Load the TX DMA descriptors without stopping the DMA
295  *
296  * @param hal            Context of the HAL layer
297  * @param data           Buffer of the transaction data
298  * @param len            Length of the data
299  * @param arg            Pointer used by the caller to indicate the tranaction. Will be returned by ``spi_slave_hd_hal_get_tx_finished_trans`` when transaction is finished
300  * @return
301  *        - ESP_OK: on success
302  *        - ESP_ERR_INVALID_STATE: Function called in invalid state.
303  */
304 esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg);
305 
306 /**
307  * @brief Load the RX DMA descriptors without stopping the DMA
308  *
309  * @param hal            Context of the HAL layer
310  * @param data           Buffer of the transaction data
311  * @param len            Length of the data
312  * @param arg            Pointer used by the caller to indicate the tranaction. Will be returned by ``spi_slave_hd_hal_get_rx_finished_trans`` when transaction is finished
313  * @return
314  *        - ESP_OK: on success
315  *        - ESP_ERR_INVALID_STATE: Function called in invalid state.
316  */
317 esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg);
318 #endif  //#if CONFIG_IDF_TARGET_ESP32S2
319