1 // Copyright 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 // DO NOT USE THESE APIS IN ANY APPLICATIONS
16 // GDMA driver is not public for end users, but for ESP-IDF developpers.
17 
18 #pragma once
19 
20 #include <stdbool.h>
21 #include "soc/gdma_channel.h"
22 #include "esp_err.h"
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 /**
29  * @brief Type of GDMA channel handle
30  *
31  */
32 typedef struct gdma_channel_t *gdma_channel_handle_t;
33 
34 /**
35  * @brief Enumeration of peripherals which have the DMA capability
36  * @note Some peripheral might not be available on certain chip, please refer to `soc_caps.h` for detail.
37  *
38  */
39 typedef enum {
40     GDMA_TRIG_PERIPH_M2M,  /*!< GDMA trigger peripheral: M2M */
41     GDMA_TRIG_PERIPH_UART, /*!< GDMA trigger peripheral: UART */
42     GDMA_TRIG_PERIPH_SPI,  /*!< GDMA trigger peripheral: SPI */
43     GDMA_TRIG_PERIPH_I2S,  /*!< GDMA trigger peripheral: I2S */
44     GDMA_TRIG_PERIPH_AES,  /*!< GDMA trigger peripheral: AES */
45     GDMA_TRIG_PERIPH_SHA,  /*!< GDMA trigger peripheral: SHA */
46     GDMA_TRIG_PERIPH_ADC,  /*!< GDMA trigger peripheral: ADC */
47     GDMA_TRIG_PERIPH_DAC,  /*!< GDMA trigger peripheral: DAC */
48     GDMA_TRIG_PERIPH_LCD,  /*!< GDMA trigger peripheral: LCD */
49     GDMA_TRIG_PERIPH_CAM   /*!< GDMA trigger peripheral: CAM */
50 } gdma_trigger_peripheral_t;
51 
52 /**
53  * @brief Enumeration of GDMA channel direction
54  *
55  */
56 typedef enum {
57     GDMA_CHANNEL_DIRECTION_TX, /*!< GDMA channel direction: TX */
58     GDMA_CHANNEL_DIRECTION_RX, /*!< GDMA channel direction: RX */
59 } gdma_channel_direction_t;
60 
61 /**
62  * @brief Collection of configuration items that used for allocating GDMA channel
63  *
64  */
65 typedef struct {
66     gdma_channel_handle_t sibling_chan; /*!< DMA sibling channel handle (NULL means having sibling is not necessary) */
67     gdma_channel_direction_t direction; /*!< DMA channel direction */
68     struct {
69         int reserve_sibling: 1;   /*!< If set, DMA channel allocator would prefer to allocate new channel in a new pair, and reserve sibling channel for future use */
70     } flags;
71 } gdma_channel_alloc_config_t;
72 
73 /**
74  * @brief Type of GDMA event data
75  *
76  */
77 typedef struct {
78     union {
79         intptr_t rx_eof_desc_addr; /*!< EOF descriptor address of RX channel */
80         intptr_t tx_eof_desc_addr; /*!< EOF descriptor address of TX channel */
81     };
82 } gdma_event_data_t;
83 
84 /**
85  * @brief Type of GDMA event callback
86  * @param dma_chan GDMA channel handle, created from `gdma_new_channel`
87  * @param event_data GDMA event data
88  * @param user_data User registered data from `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`
89  *
90  */
91 typedef bool (*gdma_event_callback_t)(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
92 
93 /**
94  * @brief Group of supported GDMA TX callbacks
95  * @note The callbacks are all running under ISR environment
96  *
97  */
98 typedef struct {
99     gdma_event_callback_t on_trans_eof; /*!< Invoked when TX engine meets EOF descriptor */
100 } gdma_tx_event_callbacks_t;
101 
102 /**
103  * @brief Group of supported GDMA RX callbacks
104  * @note The callbacks are all running under ISR environment
105  *
106  */
107 typedef struct {
108     gdma_event_callback_t on_recv_eof; /*!< Invoked when RX engine meets EOF descriptor */
109 } gdma_rx_event_callbacks_t;
110 
111 /**
112  * @brief Type of GDMA engine trigger
113  * @note It's recommended to initialize this structure with `GDMA_MAKE_TRIGGER`.
114  *
115  */
116 typedef struct {
117     gdma_trigger_peripheral_t periph; /*!< Target peripheral which will trigger DMA operations */
118     int instance_id;                  /*!< Peripheral instance ID. Supported IDs are listed in `soc/gdma_channel.h`, e.g. SOC_GDMA_TRIG_PERIPH_UART0 */
119 } gdma_trigger_t;
120 
121 /**
122  * @brief Helper macro to initialize GDMA trigger
123  * @note value of `peri` must be selected from `gdma_trigger_peripheral_t` enum.
124  *       e.g. GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UART,0)
125  *
126  */
127 #define GDMA_MAKE_TRIGGER(peri, id) \
128     (gdma_trigger_t) { .periph = peri, .instance_id = SOC_##peri##id }
129 
130 /**
131  * @brief A collection of strategy item that each GDMA channel could apply
132  *
133  */
134 typedef struct {
135     bool owner_check;      /*!< If set / clear, DMA channel enables / disables checking owner validity */
136     bool auto_update_desc; /*!< If set / clear, DMA channel enables / disables hardware to update descriptor automatically (TX channel only) */
137 } gdma_strategy_config_t;
138 
139 /**
140  * @brief Create GDMA channel
141  * @note This API won't install interrupt service for the allocated channel.
142  *       If interrupt service is needed, user has to register GDMA event callback by `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`.
143  *
144  * @param[in] config Pointer to a collection of configurations for allocating GDMA channel
145  * @param[out] ret_chan Returnned channel handle
146  * @return
147  *      - ESP_OK: Create DMA channel successfully
148  *      - ESP_ERR_INVALID_ARG: Create DMA channel failed because of invalid argument
149  *      - ESP_ERR_NO_MEM: Create DMA channel failed because out of memory
150  *      - ESP_FAIL: Create DMA channel failed because of other error
151  */
152 esp_err_t gdma_new_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan);
153 
154 /**
155  * @brief Connect GDMA channel to trigger peripheral
156  *
157  * @note Suggest to use helper macro `GDMA_MAKE_TRIGGER` to construct parameter `trig_periph`. e.g. GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA,0)
158  *
159  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
160  * @param[in] trig_periph GDMA trigger peripheral
161  * @return
162  *      - ESP_OK: Connect GDMA channel successfully
163  *      - ESP_ERR_INVALID_ARG: Connect GDMA channel failed because of invalid argument
164  *      - ESP_ERR_INVALID_STATE: Connect GDMA channel failed because DMA channel is working with another peripheral
165  *      - ESP_FAIL: Connect GDMA channel failed because of other error
166  */
167 esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_periph);
168 
169 /**
170  * @brief Disconnect GMA channel from peripheral
171  *
172  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
173  * @return
174  *      - ESP_OK: Disconnect GDMA channel successfully
175  *      - ESP_ERR_INVALID_ARG: Disconnect GDMA channel failed because of invalid argument
176  *      - ESP_ERR_INVALID_STATE: Disconnect GDMA channel failed because DMA channel is not connected to any peripheral
177  *      - ESP_FAIL: Disconnect DMA channel failed because of other error
178  */
179 esp_err_t gdma_disconnect(gdma_channel_handle_t dma_chan);
180 
181 /**
182  * @brief Apply channel strategy for GDMA channel
183  *
184  * @param dma_chan GDMA channel handle, allocated by `gdma_new_channel`
185  * @param config Configuration of GDMA channel strategy
186  *      - ESP_OK: Apply channel strategy successfully
187  *      - ESP_ERR_INVALID_ARG: Apply channel strategy failed because of invalid argument
188  *      - ESP_FAIL: Apply channel strategy failed because of other error
189  */
190 esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strategy_config_t *config);
191 
192 /**
193  * @brief Delete GDMA channel
194  * @note If you call `gdma_new_channel` several times for a same peripheral, make sure you call this API the same times.
195  *
196  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
197  * @return
198  *      - ESP_OK: Delete GDMA channel successfully
199  *      - ESP_ERR_INVALID_ARG: Delete GDMA channel failed because of invalid argument
200  *      - ESP_FAIL: Delete GDMA channel failed because of other error
201  */
202 esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan);
203 
204 /**
205  * @brief Get the channel ID
206  *
207  * @note This API breaks the encapsulation of GDMA Channel Object.
208  *       With the returned channel ID, you can even bypass all other GDMA driver API and access Low Level API directly.
209  *
210  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
211  * @param[out] channel_id Returned channel ID
212  * @return
213  *      - ESP_OK: Get GDMA channel ID successfully
214  *      - ESP_ERR_INVALID_ARG: Get GDMA channel ID failed because of invalid argument
215  *      - ESP_FAIL: Get GDMA channel ID failed because of other error
216  */
217 esp_err_t gdma_get_channel_id(gdma_channel_handle_t dma_chan, int *channel_id);
218 
219 /**
220  * @brief Set GDMA event callbacks for TX channel
221  * @note This API will install GDMA interrupt service for the channel internally
222  *
223  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
224  * @param[in] cbs Group of callback functions
225  * @param[in] user_data User data, which will be passed to callback functions directly
226  * @return
227  *      - ESP_OK: Set event callbacks successfully
228  *      - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument
229  *      - ESP_FAIL: Set event callbacks failed because of other error
230  */
231 esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_tx_event_callbacks_t *cbs, void *user_data);
232 
233 /**
234  * @brief Set GDMA event callbacks for RX channel
235  * @note This API will install GDMA interrupt service for the channel internally
236  *
237  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
238  * @param[in] cbs Group of callback functions
239  * @param[in] user_data User data, which will be passed to callback functions directly
240  * @return
241  *      - ESP_OK: Set event callbacks successfully
242  *      - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument
243  *      - ESP_FAIL: Set event callbacks failed because of other error
244  */
245 esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_rx_event_callbacks_t *cbs, void *user_data);
246 
247 /**
248  * @brief Set DMA descriptor address and start engine
249  *
250  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
251  * @param[in] desc_base_addr Base address of descriptors (usually the descriptors are chained into a link or ring)
252  * @return
253  *      - ESP_OK: Start DMA engine successfully
254  *      - ESP_ERR_INVALID_ARG: Start DMA engine failed because of invalid argument
255  *      - ESP_FAIL: Start DMA engine failed because of other error
256  */
257 esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr);
258 
259 /**
260  * @brief Stop DMA engine
261  *
262  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
263  * @return
264  *      - ESP_OK: Stop DMA engine successfully
265  *      - ESP_ERR_INVALID_ARG: Stop DMA engine failed because of invalid argument
266  *      - ESP_FAIL: Stop DMA engine failed because of other error
267  */
268 esp_err_t gdma_stop(gdma_channel_handle_t dma_chan);
269 
270 /**
271  * @brief Make the appended descriptors be aware to the DMA engine
272  * @note This API could also resume a paused DMA engine, make sure new descriptors have been appended to the descriptor chain before calling it.
273  *
274  * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
275  * @return
276  *      - ESP_OK: Send append command to DMA engine successfully
277  *      - ESP_ERR_INVALID_ARG: Send append command to DMA engine failed because of invalid argument
278  *      - ESP_FAIL: Send append command to DMA engine failed because of other error
279  */
280 esp_err_t gdma_append(gdma_channel_handle_t dma_chan);
281 
282 #ifdef __cplusplus
283 }
284 #endif
285