xref: /nrf52832-nimble/nordic/nrfx/drivers/src/nrfx_ppi.c (revision 150812a83cab50279bd772ef6db1bfaf255f2c5b)
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