1 /**
2 ****************************************************************************************
3 * @file app_dma.c
4 * @author BLE Driver Team
5 * @brief HAL APP module driver.
6 ****************************************************************************************
7 * @attention
8 #####Copyright (c) 2019 GOODIX
9 All rights reserved.
10
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are met:
13 * Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 * Neither the name of GOODIX nor the names of its contributors may be used
19 to endorse or promote products derived from this software without
20 specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
26 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33 ****************************************************************************************
34 */
35
36 /*
37 * INCLUDE FILES
38 *****************************************************************************************
39 */
40 #include <string.h>
41 #include <stdbool.h>
42 #include "app_pwr_mgmt.h"
43 #include "platform_sdk.h"
44 #include "app_dma.h"
45
46 /*
47 * DEFINES
48 *****************************************************************************************
49 */
50 #define DMA_HANDLE_MAX 8
51
52 /*
53 * STRUCT DEFINE
54 *****************************************************************************************
55 */
56
57 /**@brief App dma state types. */
58 typedef enum {
59 APP_DMA_INVALID = 0,
60 APP_DMA_ACTIVITY,
61 #ifdef APP_DRIVER_WAKEUP_CALL_FUN
62 APP_DMA_SLEEP,
63 #endif
64 } app_dma_state_t;
65
66 struct dma_env_t {
67 app_dma_state_t dma_state;
68 dma_handle_t handle;
69 app_dma_evt_handler_t evt_handler;
70 };
71
72 /*
73 * LOCAL FUNCTION DECLARATION
74 *****************************************************************************************
75 */
76 static bool dma_prepare_for_sleep(void);
77 static void dma_sleep_canceled(void);
78 static void dma_wake_up_ind(void);
79
80 /*
81 * LOCAL VARIABLE DEFINITIONS
82 *****************************************************************************************
83 */
84 static bool s_sleep_cb_registered_flag = false;
85 static struct dma_env_t s_dma_env[DMA_HANDLE_MAX];
86 static int16_t s_dma_pwr_id;
87
88 static const app_sleep_callbacks_t dma_sleep_cb = {
89 .app_prepare_for_sleep = dma_prepare_for_sleep,
90 .app_sleep_canceled = dma_sleep_canceled,
91 .app_wake_up_ind = dma_wake_up_ind,
92 };
93
94 /*
95 * LOCAL FUNCTION DEFINITIONS
96 *****************************************************************************************
97 */
dma_prepare_for_sleep(void)98 static bool dma_prepare_for_sleep(void)
99 {
100 hal_dma_state_t state;
101
102 for (uint8_t i = 0; i < DMA_HANDLE_MAX; i++) {
103 if (s_dma_env[i].dma_state == APP_DMA_ACTIVITY) {
104 state = hal_dma_get_state(&s_dma_env[i].handle);
105 if ((state != HAL_DMA_STATE_RESET) && (state != HAL_DMA_STATE_READY)) {
106 return false;
107 }
108 hal_dma_suspend_reg(&s_dma_env[i].handle);
109 #ifdef APP_DRIVER_WAKEUP_CALL_FUN
110 s_dma_env[i].dma_state = APP_DMA_SLEEP;
111 #endif
112 }
113 }
114
115 return true;
116 }
117
dma_sleep_canceled(void)118 static void dma_sleep_canceled(void)
119 {
120 }
121
dma_wake_up_ind(void)122 SECTION_RAM_CODE static void dma_wake_up_ind(void)
123 {
124 #ifndef APP_DRIVER_WAKEUP_CALL_FUN
125 bool find = false;
126
127 for (uint8_t i = 0; i < DMA_HANDLE_MAX; i++) {
128 if (s_dma_env[i].dma_state == APP_DMA_ACTIVITY) {
129 hal_dma_resume_reg(&s_dma_env[i].handle);
130 find = true;
131 }
132 }
133
134 if (find) {
135 hal_nvic_clear_pending_irq(DMA_IRQn);
136 hal_nvic_enable_irq(DMA_IRQn);
137 }
138 #endif
139 }
140
141 #ifdef APP_DRIVER_WAKEUP_CALL_FUN
dma_wake_up(int16_t id)142 void dma_wake_up(int16_t id)
143 {
144 if (id<0 || id >= DMA_HANDLE_MAX) {
145 return;
146 }
147
148 if (s_dma_env[id].dma_state == APP_DMA_SLEEP) {
149 hal_dma_resume_reg(&s_dma_env[id].handle);
150 s_dma_env[id].dma_state = APP_DMA_ACTIVITY;
151
152 if (!NVIC_GetEnableIRQ(DMA_IRQn)) {
153 hal_nvic_clear_pending_irq(DMA_IRQn);
154 hal_nvic_enable_irq(DMA_IRQn);
155 }
156 }
157 }
158 #endif
159
160 /*
161 * GLOBAL FUNCTION DEFINITIONS
162 ****************************************************************************************
163 */
dma_tfr_callback(struct _dma_handle * hdma)164 void dma_tfr_callback(struct _dma_handle *hdma)
165 {
166 uint8_t i;
167
168 for (i = 0; i < DMA_HANDLE_MAX; i++) {
169 if ((s_dma_env[i].dma_state == APP_DMA_ACTIVITY) &&
170 (s_dma_env[i].handle.channel == hdma->channel)) {
171 if (s_dma_env[i].evt_handler != NULL) {
172 s_dma_env[i].evt_handler(APP_DMA_EVT_TFR);
173 }
174 break;
175 }
176 }
177 }
178
dma_err_callback(struct _dma_handle * hdma)179 void dma_err_callback(struct _dma_handle * hdma)
180 {
181 uint8_t i;
182
183 for (i = 0; i < DMA_HANDLE_MAX; i++) {
184 if ((s_dma_env[i].dma_state == APP_DMA_ACTIVITY) &&
185 (s_dma_env[i].handle.channel == hdma->channel)) {
186 if (s_dma_env[i].evt_handler != NULL) {
187 s_dma_env[i].evt_handler(APP_DMA_EVT_ERROR);
188 }
189 break;
190 }
191 }
192 }
193
194
dma_handle_config(uint8_t * p_i,int16_t * p_id,app_dma_params_t * p_params)195 static void dma_handle_config(uint8_t *p_i, int16_t *p_id, app_dma_params_t *p_params)
196 {
197 GLOBAL_EXCEPTION_DISABLE();
198 for (*p_i = 0; (*p_i) < DMA_HANDLE_MAX; (*p_i)++) {
199 if (s_dma_env[*p_i].dma_state == APP_DMA_INVALID || \
200 s_dma_env[*p_i].handle.channel == p_params->channel_number) {
201 if (HAL_DMA_STATE_BUSY == s_dma_env[*p_i].handle.state) {
202 *p_i = DMA_HANDLE_MAX;
203 break;
204 } else {
205 *p_id = *p_i;
206 s_dma_env[*p_i].dma_state = APP_DMA_ACTIVITY;
207 break;
208 }
209 }
210 }
211 GLOBAL_EXCEPTION_ENABLE();
212 }
213
app_dma_init(app_dma_params_t * p_params,app_dma_evt_handler_t evt_handler)214 int16_t app_dma_init(app_dma_params_t *p_params, app_dma_evt_handler_t evt_handler)
215 {
216 uint8_t i = 0;
217 int16_t id = -1;
218 hal_status_t status = HAL_ERROR;
219
220 if (p_params != NULL) {
221 if (!IS_DMA_ALL_INSTANCE(p_params->channel_number)) {
222 return -1;
223 }
224
225 dma_handle_config(&i, &id, p_params);
226
227 if (i < DMA_HANDLE_MAX) {
228 if (s_sleep_cb_registered_flag == false) { // register sleep callback
229 s_sleep_cb_registered_flag = true;
230 s_dma_pwr_id = pwr_register_sleep_cb(&dma_sleep_cb, APP_DRIVER_DMA_WAPEUP_PRIORITY);
231 }
232 s_dma_env[i].handle.channel = p_params->channel_number;
233 memcpy_s(&s_dma_env[i].handle.init, sizeof(s_dma_env[i].handle.init), &p_params->init, sizeof(dma_init_t));
234 s_dma_env[i].handle.xfer_tfr_callback = dma_tfr_callback;
235 s_dma_env[i].handle.xfer_error_callback = dma_err_callback;
236 s_dma_env[i].handle.xfer_abort_callback = NULL;
237 s_dma_env[i].evt_handler = evt_handler;
238
239 hal_nvic_clear_pending_irq(DMA_IRQn);
240 hal_nvic_enable_irq(DMA_IRQn);
241 status = hal_dma_init(&s_dma_env[i].handle);
242 }
243 }
244
245 if (HAL_OK != status) {
246 id = -1;
247 }
248
249 return id;
250 }
251
252
app_dma_deinit(int16_t id)253 uint16_t app_dma_deinit(int16_t id)
254 {
255 uint8_t i;
256
257 if ((id < 0) || (id >= DMA_HANDLE_MAX) || (s_dma_env[id].dma_state == APP_DMA_INVALID)) {
258 return APP_DRV_ERR_INVALID_ID;
259 }
260
261 GLOBAL_EXCEPTION_DISABLE();
262 hal_dma_deinit(&s_dma_env[id].handle);
263 s_dma_env[id].dma_state = APP_DMA_INVALID;
264 s_dma_env[id].handle.channel = (dma_channel_t)(-1);
265
266 for (i = 0; i < DMA_HANDLE_MAX; i++) {
267 if (s_dma_env[i].dma_state == APP_DMA_ACTIVITY) {
268 break;
269 }
270 }
271
272 if (i == DMA_HANDLE_MAX) {
273 pwr_unregister_sleep_cb(s_dma_pwr_id);
274 s_sleep_cb_registered_flag = false;
275 hal_nvic_disable_irq(DMA_IRQn);
276 }
277 GLOBAL_EXCEPTION_ENABLE();
278
279 return APP_DRV_SUCCESS;
280 }
281
app_dma_get_handle(int16_t id)282 dma_handle_t *app_dma_get_handle(int16_t id)
283 {
284 if (id < 0 || id >= DMA_HANDLE_MAX || s_dma_env[id].dma_state == APP_DMA_INVALID) {
285 return NULL;
286 }
287
288 #ifdef APP_DRIVER_WAKEUP_CALL_FUN
289 dma_wake_up(id);
290 #endif
291
292 return &s_dma_env[id].handle;
293 }
294
app_dma_start(int16_t id,uint32_t src_address,uint32_t dst_address,uint32_t data_length)295 uint16_t app_dma_start(int16_t id, uint32_t src_address, uint32_t dst_address, uint32_t data_length)
296 {
297 hal_status_t status = HAL_ERROR;
298
299 if (id < 0 || id >= DMA_HANDLE_MAX || s_dma_env[id].dma_state == APP_DMA_INVALID) {
300 return APP_DRV_ERR_INVALID_PARAM;
301 }
302
303 #ifdef APP_DRIVER_WAKEUP_CALL_FUN
304 dma_wake_up(id);
305 #endif
306
307 status = hal_dma_start_it(&s_dma_env[id].handle, src_address, dst_address, data_length);
308 if (HAL_OK != status) {
309 return (uint16_t)status;
310 }
311
312 return APP_DRV_SUCCESS;
313 }
314
DMA_IRQHandler(void)315 SECTION_RAM_CODE void DMA_IRQHandler(void)
316 {
317 #if FLASH_PROTECT_PRIORITY
318 platform_interrupt_protection_push();
319 #endif
320 uint8_t i;
321 for (i = 0; i < DMA_HANDLE_MAX; i++) {
322 if (s_dma_env[i].dma_state == APP_DMA_ACTIVITY) {
323 hal_dma_irq_handler(&s_dma_env[i].handle);
324 }
325 }
326 #if FLASH_PROTECT_PRIORITY
327 platform_interrupt_protection_pop();
328 #endif
329 }
330
331