1 /*
2 * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <nrfx.h>
33
34 #if NRFX_CHECK(NRFX_PPI_ENABLED)
35
36 #include <nrfx_ppi.h>
37
38 #define NRFX_LOG_MODULE PPI
39 #include <nrfx_log.h>
40
41
42 static uint32_t m_channels_allocated; /**< Bitmap representing channels availability. 1 when a channel is allocated, 0 otherwise. */
43 static uint8_t m_groups_allocated; /**< Bitmap representing groups availability. 1 when a group is allocated, 0 otherwise.*/
44
45
46 /**
47 * @brief Compute a group mask (needed for driver internals, not used for NRF_PPI registers).
48 *
49 * @param[in] group Group number to transform to a mask.
50 *
51 * @retval Group mask.
52 */
group_to_mask(nrf_ppi_channel_group_t group)53 __STATIC_INLINE uint32_t group_to_mask(nrf_ppi_channel_group_t group)
54 {
55 return (1uL << (uint32_t) group);
56 }
57
58
59 /**
60 * @brief Check whether a channel is a programmable channel and can be used by an application.
61 *
62 * @param[in] channel Channel to check.
63 *
64 * @retval true The channel is a programmable application channel.
65 * @retval false The channel is used by a stack (for example SoftDevice) or is preprogrammed.
66 */
is_programmable_app_channel(nrf_ppi_channel_t channel)67 __STATIC_INLINE bool is_programmable_app_channel(nrf_ppi_channel_t channel)
68 {
69 return ((NRFX_PPI_PROG_APP_CHANNELS_MASK & nrfx_ppi_channel_to_mask(channel)) != 0);
70 }
71
72
73 /**
74 * @brief Check whether channels can be used by an application.
75 *
76 * @param[in] channel_mask Channel mask to check.
77 *
78 * @retval true All specified channels can be used by an application.
79 * @retval false At least one specified channel is used by a stack (for example SoftDevice).
80 */
are_app_channels(uint32_t channel_mask)81 __STATIC_INLINE bool are_app_channels(uint32_t channel_mask)
82 {
83 //lint -e(587)
84 return ((~(NRFX_PPI_ALL_APP_CHANNELS_MASK) & channel_mask) == 0);
85 }
86
87
88 /**
89 * @brief Check whether a channel can be used by an application.
90 *
91 * @param[in] channel Channel to check.
92 *
93 * @retval true The channel can be used by an application.
94 * @retval false The channel is used by a stack (for example SoftDevice).
95 */
is_app_channel(nrf_ppi_channel_t channel)96 __STATIC_INLINE bool is_app_channel(nrf_ppi_channel_t channel)
97 {
98 return are_app_channels(nrfx_ppi_channel_to_mask(channel));
99 }
100
101
102 /**
103 * @brief Check whether a channel group can be used by an application.
104 *
105 * @param[in] group Group to check.
106 *
107 * @retval true The group is an application group.
108 * @retval false The group is not an application group (this group either does not exist or
109 * it is used by a stack (for example SoftDevice)).
110 */
is_app_group(nrf_ppi_channel_group_t group)111 __STATIC_INLINE bool is_app_group(nrf_ppi_channel_group_t group)
112 {
113 return ((NRFX_PPI_ALL_APP_GROUPS_MASK & group_to_mask(group)) != 0);
114 }
115
116
117 /**
118 * @brief Check whether a channel is allocated.
119 *
120 * @param[in] channel_num Channel number to check.
121 *
122 * @retval true The channel is allocated.
123 * @retval false The channel is not allocated.
124 */
is_allocated_channel(nrf_ppi_channel_t channel)125 __STATIC_INLINE bool is_allocated_channel(nrf_ppi_channel_t channel)
126 {
127 return ((m_channels_allocated & nrfx_ppi_channel_to_mask(channel)) != 0);
128 }
129
130
131 /**
132 * @brief Set channel allocated indication.
133 *
134 * @param[in] channel_num Specifies the channel to set the "allocated" indication.
135 */
channel_allocated_set(nrf_ppi_channel_t channel)136 __STATIC_INLINE void channel_allocated_set(nrf_ppi_channel_t channel)
137 {
138 m_channels_allocated |= nrfx_ppi_channel_to_mask(channel);
139 }
140
141
142 /**
143 * @brief Clear channel allocated indication.
144 *
145 * @param[in] channel_num Specifies the channel to clear the "allocated" indication.
146 */
channel_allocated_clr(nrf_ppi_channel_t channel)147 __STATIC_INLINE void channel_allocated_clr(nrf_ppi_channel_t channel)
148 {
149 m_channels_allocated &= ~nrfx_ppi_channel_to_mask(channel);
150 }
151
152
153 /**
154 * @brief Clear all allocated channels.
155 */
channel_allocated_clr_all(void)156 __STATIC_INLINE void channel_allocated_clr_all(void)
157 {
158 m_channels_allocated &= ~NRFX_PPI_ALL_APP_CHANNELS_MASK;
159 }
160
161
162 /**
163 * @brief Check whether a group is allocated.
164 *
165 * @param[in] group_num Group number to check.
166 *
167 * @retval true The group is allocated.
168 * false The group is not allocated.
169 */
is_allocated_group(nrf_ppi_channel_group_t group)170 __STATIC_INLINE bool is_allocated_group(nrf_ppi_channel_group_t group)
171 {
172 return ((m_groups_allocated & group_to_mask(group)) != 0);
173 }
174
175
176 /**
177 * @brief Set group allocated indication.
178 *
179 * @param[in] group_num Specifies the group to set the "allocated" indication.
180 */
group_allocated_set(nrf_ppi_channel_group_t group)181 __STATIC_INLINE void group_allocated_set(nrf_ppi_channel_group_t group)
182 {
183 m_groups_allocated |= group_to_mask(group);
184 }
185
186
187 /**
188 * @brief Clear group allocated indication.
189 *
190 * @param[in] group_num Specifies the group to clear the "allocated" indication.
191 */
group_allocated_clr(nrf_ppi_channel_group_t group)192 __STATIC_INLINE void group_allocated_clr(nrf_ppi_channel_group_t group)
193 {
194 m_groups_allocated &= ~group_to_mask(group);
195 }
196
197
198 /**
199 * @brief Clear all allocated groups.
200 */
group_allocated_clr_all()201 __STATIC_INLINE void group_allocated_clr_all()
202 {
203 m_groups_allocated &= ~NRFX_PPI_ALL_APP_GROUPS_MASK;
204 }
205
206
nrfx_ppi_free_all(void)207 void nrfx_ppi_free_all(void)
208 {
209 uint32_t mask = NRFX_PPI_ALL_APP_GROUPS_MASK;
210 nrf_ppi_channel_group_t group;
211
212 // Disable all channels and groups
213 nrf_ppi_channels_disable(NRFX_PPI_ALL_APP_CHANNELS_MASK);
214
215 for (group = NRF_PPI_CHANNEL_GROUP0; mask != 0; mask &= ~group_to_mask(group), group++)
216 {
217 if (mask & group_to_mask(group))
218 {
219 nrf_ppi_channel_group_clear(group);
220 }
221 }
222 channel_allocated_clr_all();
223 group_allocated_clr_all();
224 }
225
226
nrfx_ppi_channel_alloc(nrf_ppi_channel_t * p_channel)227 nrfx_err_t nrfx_ppi_channel_alloc(nrf_ppi_channel_t * p_channel)
228 {
229 nrfx_err_t err_code = NRFX_SUCCESS;
230 nrf_ppi_channel_t channel;
231 uint32_t mask = 0;
232 err_code = NRFX_ERROR_NO_MEM;
233
234 mask = NRFX_PPI_PROG_APP_CHANNELS_MASK;
235 for (channel = NRF_PPI_CHANNEL0;
236 mask != 0;
237 mask &= ~nrfx_ppi_channel_to_mask(channel), channel++)
238 {
239 NRFX_CRITICAL_SECTION_ENTER();
240 if ((mask & nrfx_ppi_channel_to_mask(channel)) && (!is_allocated_channel(channel)))
241 {
242 channel_allocated_set(channel);
243 *p_channel = channel;
244 err_code = NRFX_SUCCESS;
245 }
246 NRFX_CRITICAL_SECTION_EXIT();
247 if (err_code == NRFX_SUCCESS)
248 {
249 NRFX_LOG_INFO("Allocated channel: %d.", channel);
250 break;
251 }
252 }
253
254 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
255 return err_code;
256 }
257
258
nrfx_ppi_channel_free(nrf_ppi_channel_t channel)259 nrfx_err_t nrfx_ppi_channel_free(nrf_ppi_channel_t channel)
260 {
261 nrfx_err_t err_code = NRFX_SUCCESS;
262
263 if (!is_programmable_app_channel(channel))
264 {
265 err_code = NRFX_ERROR_INVALID_PARAM;
266 }
267 else
268 {
269 // First disable this channel
270 nrf_ppi_channel_disable(channel);
271 NRFX_CRITICAL_SECTION_ENTER();
272 channel_allocated_clr(channel);
273 NRFX_CRITICAL_SECTION_EXIT();
274 }
275 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
276 return err_code;
277 }
278
279
nrfx_ppi_channel_assign(nrf_ppi_channel_t channel,uint32_t eep,uint32_t tep)280 nrfx_err_t nrfx_ppi_channel_assign(nrf_ppi_channel_t channel, uint32_t eep, uint32_t tep)
281 {
282 if ((uint32_t *)eep == NULL || (uint32_t *)tep == NULL)
283 {
284 return NRFX_ERROR_NULL;
285 }
286
287 nrfx_err_t err_code = NRFX_SUCCESS;
288
289 if (!is_programmable_app_channel(channel))
290 {
291 err_code = NRFX_ERROR_INVALID_PARAM;
292 }
293 else if (!is_allocated_channel(channel))
294 {
295 err_code = NRFX_ERROR_INVALID_STATE;
296 }
297 else
298 {
299 nrf_ppi_channel_endpoint_setup(channel, eep, tep);
300 NRFX_LOG_INFO("Assigned channel: %d, event end point: %x, task end point: %x.",
301 channel,
302 eep,
303 tep);
304 }
305 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
306 return err_code;
307 }
308
nrfx_ppi_channel_fork_assign(nrf_ppi_channel_t channel,uint32_t fork_tep)309 nrfx_err_t nrfx_ppi_channel_fork_assign(nrf_ppi_channel_t channel, uint32_t fork_tep)
310 {
311 nrfx_err_t err_code = NRFX_SUCCESS;
312 #ifdef PPI_FEATURE_FORKS_PRESENT
313 if (!is_allocated_channel(channel))
314 {
315 err_code = NRFX_ERROR_INVALID_STATE;
316 }
317 else
318 {
319 nrf_ppi_fork_endpoint_setup(channel, fork_tep);
320 NRFX_LOG_INFO("Fork assigned channel: %d, task end point: %d.", channel, fork_tep);
321 }
322 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
323 return err_code;
324 #else
325 err_code = NRFX_ERROR_NOT_SUPPORTED;
326 NRFX_LOG_WARNING("Function: %s, error code: %s.",
327 __func__,
328 NRFX_LOG_ERROR_STRING_GET(err_code));
329 return err_code;
330 #endif
331 }
332
nrfx_ppi_channel_enable(nrf_ppi_channel_t channel)333 nrfx_err_t nrfx_ppi_channel_enable(nrf_ppi_channel_t channel)
334 {
335 nrfx_err_t err_code = NRFX_SUCCESS;
336
337 if (!is_app_channel(channel))
338 {
339 err_code = NRFX_ERROR_INVALID_PARAM;
340 }
341 else if (is_programmable_app_channel(channel) && !is_allocated_channel(channel))
342 {
343 err_code = NRFX_ERROR_INVALID_STATE;
344 }
345 else
346 {
347 nrf_ppi_channel_enable(channel);
348 }
349 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
350 return err_code;
351 }
352
353
nrfx_ppi_channel_disable(nrf_ppi_channel_t channel)354 nrfx_err_t nrfx_ppi_channel_disable(nrf_ppi_channel_t channel)
355 {
356 nrfx_err_t err_code = NRFX_SUCCESS;
357
358 if (!is_app_channel(channel))
359 {
360 err_code = NRFX_ERROR_INVALID_PARAM;
361 }
362 else if (is_programmable_app_channel(channel) && !is_allocated_channel(channel))
363 {
364 err_code = NRFX_ERROR_INVALID_STATE;
365 }
366 else
367 {
368 nrf_ppi_channel_disable(channel);
369 err_code = NRFX_SUCCESS;
370 }
371 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
372 return err_code;
373 }
374
375
nrfx_ppi_group_alloc(nrf_ppi_channel_group_t * p_group)376 nrfx_err_t nrfx_ppi_group_alloc(nrf_ppi_channel_group_t * p_group)
377 {
378 nrfx_err_t err_code;
379 uint32_t mask = 0;
380 nrf_ppi_channel_group_t group;
381
382 err_code = NRFX_ERROR_NO_MEM;
383
384 mask = NRFX_PPI_ALL_APP_GROUPS_MASK;
385 for (group = NRF_PPI_CHANNEL_GROUP0; mask != 0; mask &= ~group_to_mask(group), group++)
386 {
387 NRFX_CRITICAL_SECTION_ENTER();
388 if ((mask & group_to_mask(group)) && (!is_allocated_group(group)))
389 {
390 group_allocated_set(group);
391 *p_group = group;
392 err_code = NRFX_SUCCESS;
393 }
394 NRFX_CRITICAL_SECTION_EXIT();
395 if (err_code == NRFX_SUCCESS)
396 {
397 NRFX_LOG_INFO("Allocated group: %d.", group);
398 break;
399 }
400 }
401
402 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
403 return err_code;
404 }
405
406
nrfx_ppi_group_free(nrf_ppi_channel_group_t group)407 nrfx_err_t nrfx_ppi_group_free(nrf_ppi_channel_group_t group)
408 {
409 nrfx_err_t err_code = NRFX_SUCCESS;
410
411 if (!is_app_group(group))
412 {
413 err_code = NRFX_ERROR_INVALID_PARAM;
414 }
415 if (!is_allocated_group(group))
416 {
417 err_code = NRFX_ERROR_INVALID_STATE;
418 }
419 else
420 {
421 nrf_ppi_group_disable(group);
422 NRFX_CRITICAL_SECTION_ENTER();
423 group_allocated_clr(group);
424 NRFX_CRITICAL_SECTION_EXIT();
425 }
426 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
427 return err_code;
428 }
429
430
nrfx_ppi_group_enable(nrf_ppi_channel_group_t group)431 nrfx_err_t nrfx_ppi_group_enable(nrf_ppi_channel_group_t group)
432 {
433 nrfx_err_t err_code = NRFX_SUCCESS;
434
435 if (!is_app_group(group))
436 {
437 err_code = NRFX_ERROR_INVALID_PARAM;
438 }
439 else if (!is_allocated_group(group))
440 {
441 err_code = NRFX_ERROR_INVALID_STATE;
442 }
443 else
444 {
445 nrf_ppi_group_enable(group);
446 }
447 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
448 return err_code;
449 }
450
451
nrfx_ppi_group_disable(nrf_ppi_channel_group_t group)452 nrfx_err_t nrfx_ppi_group_disable(nrf_ppi_channel_group_t group)
453 {
454 nrfx_err_t err_code = NRFX_SUCCESS;
455
456 if (!is_app_group(group))
457 {
458 err_code = NRFX_ERROR_INVALID_PARAM;
459 }
460 else
461 {
462 nrf_ppi_group_disable(group);
463 }
464 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
465 return err_code;
466 }
467
nrfx_ppi_channels_remove_from_group(uint32_t channel_mask,nrf_ppi_channel_group_t group)468 nrfx_err_t nrfx_ppi_channels_remove_from_group(uint32_t channel_mask,
469 nrf_ppi_channel_group_t group)
470 {
471 nrfx_err_t err_code = NRFX_SUCCESS;
472
473 if (!is_app_group(group))
474 {
475 err_code = NRFX_ERROR_INVALID_PARAM;
476 }
477 else if (!is_allocated_group(group))
478 {
479 err_code = NRFX_ERROR_INVALID_STATE;
480 }
481 else if (!are_app_channels(channel_mask))
482 {
483 err_code = NRFX_ERROR_INVALID_PARAM;
484 }
485 else
486 {
487 NRFX_CRITICAL_SECTION_ENTER();
488 nrf_ppi_channels_remove_from_group(channel_mask, group);
489 NRFX_CRITICAL_SECTION_EXIT();
490 }
491 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
492 return err_code;
493 }
494
nrfx_ppi_channels_include_in_group(uint32_t channel_mask,nrf_ppi_channel_group_t group)495 nrfx_err_t nrfx_ppi_channels_include_in_group(uint32_t channel_mask,
496 nrf_ppi_channel_group_t group)
497 {
498 nrfx_err_t err_code = NRFX_SUCCESS;
499
500 if (!is_app_group(group))
501 {
502 err_code = NRFX_ERROR_INVALID_PARAM;
503 }
504 else if (!is_allocated_group(group))
505 {
506 err_code = NRFX_ERROR_INVALID_STATE;
507 }
508 else if (!are_app_channels(channel_mask))
509 {
510 err_code = NRFX_ERROR_INVALID_PARAM;
511 }
512 else
513 {
514 NRFX_CRITICAL_SECTION_ENTER();
515 nrf_ppi_channels_include_in_group(channel_mask, group);
516 NRFX_CRITICAL_SECTION_EXIT();
517 }
518 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
519 return err_code;
520 }
521 #endif // NRFX_CHECK(NRFX_PPI_ENABLED)
522