1 /***************************************************************************//**
2  * @file
3  * @brief Peripheral Reflex System (PRS) Peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_prs.h"
32 #if defined(PRS_COUNT) && (PRS_COUNT > 0)
33 
34 #include "sl_assert.h"
35 
36 /***************************************************************************//**
37  * @addtogroup prs PRS - Peripheral Reflex System
38  * @brief Peripheral Reflex System (PRS) Peripheral API
39  * @details
40  *  This module contains functions to control the PRS peripheral of Silicon
41  *  Labs 32-bit MCUs and SoCs. The PRS allows configurable, fast, and autonomous
42  *  communication between peripherals on the MCU or SoC.
43  * @{
44  ******************************************************************************/
45 
46 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
47 
48 /*******************************************************************************
49  *******************************   DEFINES   ***********************************
50  ******************************************************************************/
51 
52 /* Generic defines for async and sync signals applying to all TIMER instances.
53  * Those defines map to TIMER2 but it could be any TIMER instance number. */
54 #define   _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERUF   _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2UF
55 #define   _PRS_ASYNC_CH_CTRL_SIGSEL_TIMEROF   _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2OF
56 #define   _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC0  _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2CC0
57 #define   _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC1  _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2CC1
58 #define   _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC2  _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2CC2
59 
60 #define   _PRS_SYNC_CH_CTRL_SIGSEL_TIMERUF   _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2UF
61 #define   _PRS_SYNC_CH_CTRL_SIGSEL_TIMEROF   _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2OF
62 #define   _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC0  _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2CC0
63 #define   _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC1  _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2CC1
64 #define   _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC2  _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2CC2
65 
66 /*******************************************************************************
67  **************************   LOCAL FUNCTIONS   ********************************
68  ******************************************************************************/
69 
70 /***************************************************************************//**
71  * @brief
72  *   Get PRS source signal for a channel.
73  *
74  * @param[in] type
75  *   PRS channel type. This can be either @ref prsTypeAsync or
76  *   @ref prsTypeSync.
77  *
78  * @param[in] ch
79  *   channel number.
80  *
81  * @return
82  *   PRS signal assigned to the channel.
83  ******************************************************************************/
getSignal(unsigned int ch,PRS_ChType_t type)84 static PRS_Signal_t getSignal(unsigned int ch, PRS_ChType_t type)
85 {
86   PRS_Signal_t signal;
87 
88 #if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_MASK)
89   if (type == prsTypeAsync) {
90     signal = (PRS_Signal_t) (PRS->ASYNC_CH[ch].CTRL
91                              & (_PRS_ASYNC_CH_CTRL_SOURCESEL_MASK | _PRS_ASYNC_CH_CTRL_SIGSEL_MASK));
92   } else {
93     signal = (PRS_Signal_t) (PRS->SYNC_CH[ch].CTRL
94                              & (_PRS_SYNC_CH_CTRL_SOURCESEL_MASK | _PRS_SYNC_CH_CTRL_SIGSEL_MASK));
95   }
96 #else
97   (void) type;
98   signal = (PRS_Signal_t) (PRS->CH[ch].CTRL
99                            & (_PRS_CH_CTRL_SOURCESEL_MASK | _PRS_CH_CTRL_SIGSEL_MASK));
100 #endif
101   return signal;
102 }
103 
104 /** @endcond */
105 
106 /*******************************************************************************
107  **************************   GLOBAL FUNCTIONS   *******************************
108  ******************************************************************************/
109 
110 #if defined(_SILICON_LABS_32B_SERIES_2)
111 /***************************************************************************//**
112  * @brief
113  *   Convert an async PRS source to a sync source.
114  *
115  * @details
116  *   This conversion must be done because the id's of the same peripheral
117  *   source is different depending on if it's used as an asynchronous PRS source
118  *   or a synchronous PRS source.
119  *
120  * @param[in] asyncSource
121  *   The id of the asynchronous PRS source.
122  *
123  * @return
124  *   The id of the corresponding synchronous PRS source.
125  ******************************************************************************/
PRS_ConvertToSyncSource(uint32_t asyncSource)126 uint32_t PRS_ConvertToSyncSource(uint32_t asyncSource)
127 {
128   uint32_t syncSource = 0;
129 
130   switch (asyncSource) {
131     case _PRS_ASYNC_CH_CTRL_SOURCESEL_NONE:
132       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_NONE;
133       break;
134 #if defined(IADC_PRESENT)
135     case _PRS_ASYNC_CH_CTRL_SOURCESEL_IADC0:
136       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_IADC0;
137       break;
138 #endif
139     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER0:
140       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER0;
141       break;
142     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER1:
143       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER1;
144       break;
145     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER2:
146       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER2;
147       break;
148     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER3:
149       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER3;
150       break;
151 #if defined(TIMER4)
152     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER4:
153       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER4;
154       break;
155 #endif
156 #if defined(TIMER5)
157     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER5:
158       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER5;
159       break;
160 #endif
161 #if defined(TIMER6)
162     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER6:
163       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER6;
164       break;
165 #endif
166 #if defined(TIMER7)
167     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER7:
168       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER7;
169       break;
170 #endif
171 #if defined(VDAC0)
172     case _PRS_ASYNC_CH_CTRL_SOURCESEL_VDAC0L:
173       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_VDAC0;
174       break;
175 #endif
176 #if defined(VDAC1)
177     case _PRS_ASYNC_CH_CTRL_SOURCESEL_VDAC1L:
178       syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_VDAC1;
179       break;
180 #endif
181     default:
182       EFM_ASSERT(false);
183       break;
184   }
185   return syncSource;
186 }
187 
188 /***************************************************************************//**
189  * @brief
190  *   Convert an async PRS signal to a sync signal.
191  *
192  * @details
193  *   PRS values for some peripherals signals differ between asynchronous and
194  *   synchronous PRS channels. This function must be used to handle the
195  *   conversion.
196  *
197  * @param[in] asyncSource
198  *   The id of the asynchronous PRS source.
199  *
200  * @param[in] asyncSignal
201  *   The id of the asynchronous PRS signal.
202  *
203  * @return
204  *   The id of the corresponding synchronous PRS signal.
205  ******************************************************************************/
PRS_ConvertToSyncSignal(uint32_t asyncSource,uint32_t asyncSignal)206 uint32_t PRS_ConvertToSyncSignal(uint32_t asyncSource, uint32_t asyncSignal)
207 {
208   uint32_t syncSignal = asyncSignal;
209 
210   switch (asyncSource) {
211     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER0:
212     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER1:
213     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER2:
214     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER3:
215 #if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER4)
216     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER4:
217 #endif
218 #if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER5)
219     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER5:
220 #endif
221 #if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER6)
222     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER6:
223 #endif
224 #if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER7)
225     case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER7:
226 #endif
227       /* Async and sync signal values are consistent across all timers instances.
228        * Generic defines are used. */
229       switch (asyncSignal) {
230         case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERUF:
231           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMERUF;
232           break;
233         case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMEROF:
234           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMEROF;
235           break;
236         case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC0:
237           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC0;
238           break;
239         case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC1:
240           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC1;
241           break;
242         case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC2:
243           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC2;
244           break;
245         default:
246           EFM_ASSERT(false);
247           break;
248       }
249       break;
250 #if defined(IADC0)
251     case _PRS_ASYNC_CH_CTRL_SOURCESEL_IADC0:
252       switch (asyncSignal) {
253         case _PRS_ASYNC_CH_CTRL_SIGSEL_IADC0SCANENTRYDONE:
254           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_IADC0SCANENTRYDONE;
255           break;
256         case _PRS_ASYNC_CH_CTRL_SIGSEL_IADC0SCANTABLEDONE:
257           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_IADC0SCANTABLEDONE;
258           break;
259         case _PRS_ASYNC_CH_CTRL_SIGSEL_IADC0SINGLEDONE:
260           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_IADC0SINGLEDONE;
261           break;
262         default:
263           EFM_ASSERT(false);
264           break;
265       }
266       break;
267 #endif
268 #if defined(VDAC0)
269     case _PRS_ASYNC_CH_CTRL_SOURCESEL_VDAC0L:
270       switch (asyncSignal) {
271         case _PRS_ASYNC_CH_CTRL_SIGSEL_VDAC0LCH0DONEASYNC:
272           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_VDAC0CH0DONESYNC;
273           break;
274         case _PRS_ASYNC_CH_CTRL_SIGSEL_VDAC0LCH1DONEASYNC:
275           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_VDAC0CH1DONESYNC;
276           break;
277         default:
278           EFM_ASSERT(false);
279           break;
280       }
281       break;
282 #endif
283 #if defined(VDAC1)
284     case _PRS_ASYNC_CH_CTRL_SOURCESEL_VDAC1L:
285       switch (asyncSignal) {
286         case _PRS_ASYNC_CH_CTRL_SIGSEL_VDAC1LCH0DONEASYNC:
287           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_VDAC1CH0DONESYNC;
288           break;
289         case _PRS_ASYNC_CH_CTRL_SIGSEL_VDAC1LCH1DONEASYNC:
290           syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_VDAC1CH1DONESYNC;
291           break;
292         default:
293           EFM_ASSERT(false);
294           break;
295       }
296       break;
297 #endif
298     default:
299       // No translation
300       break;
301   }
302   return syncSignal;
303 }
304 #endif
305 
306 /***************************************************************************//**
307  * @brief
308  *   Set a source and signal for a channel.
309  *
310  * @param[in] ch
311  *   A channel to define the signal and source for.
312  *
313  * @param[in] source
314  *   A source to select for the channel. Use one of PRS_CH_CTRL_SOURCESEL_x defines.
315  *
316  * @param[in] signal
317  *   A signal (for selected @p source) to use. Use one of PRS_CH_CTRL_SIGSEL_x
318  *   defines.
319  *
320  * @param[in] edge
321  *   An edge (for selected source/signal) to generate the pulse for.
322  ******************************************************************************/
PRS_SourceSignalSet(unsigned int ch,uint32_t source,uint32_t signal,PRS_Edge_TypeDef edge)323 void PRS_SourceSignalSet(unsigned int ch,
324                          uint32_t source,
325                          uint32_t signal,
326                          PRS_Edge_TypeDef edge)
327 {
328 #if defined(_PRS_SYNC_CH_CTRL_MASK)
329   (void) edge;
330   EFM_ASSERT(ch < PRS_SYNC_CHAN_COUNT);
331   PRS->SYNC_CH[ch].CTRL = (source & _PRS_SYNC_CH_CTRL_SOURCESEL_MASK)
332                           | (signal & _PRS_SYNC_CH_CTRL_SIGSEL_MASK);
333 #else
334   EFM_ASSERT(ch < PRS_CHAN_COUNT);
335   PRS->CH[ch].CTRL = (source & _PRS_CH_CTRL_SOURCESEL_MASK)
336                      | (signal & _PRS_CH_CTRL_SIGSEL_MASK)
337                      | (uint32_t)edge << _PRS_CH_CTRL_EDSEL_SHIFT;
338 #endif
339 }
340 
341 #if defined(PRS_ASYNC_SUPPORTED)
342 /***************************************************************************//**
343  * @brief
344  *   Set the source and asynchronous signal for a channel.
345  *
346  * @details
347  *   Asynchronous reflexes are not clocked on HFPERCLK and can be used even in
348  *   EM2/EM3.
349  *   There is a limitation to reflexes operating in asynchronous mode in
350  *   that they can only be used by a subset of the reflex consumers. See
351  *   the PRS chapter in the reference manual for the complete list of
352  *   supported asynchronous signals and consumers.
353  *
354  * @note
355  *   This function is not supported on EFM32GxxxFyyy parts.
356  *   In asynchronous mode, the edge detector only works in EM0 and should
357  *   not be used. The EDSEL parameter in PRS_CHx_CTRL register is set to 0 (OFF)
358  *   by default.
359  *
360  * @param[in] ch
361  *   A channel to define the source and asynchronous signal for.
362  *
363  * @param[in] source
364  *   A source to select for the channel. Use one of PRS_CH_CTRL_SOURCESEL_x defines.
365  *
366  * @param[in] signal
367  *   An asynchronous signal (for selected @p source) to use. Use one of the
368  *   PRS_CH_CTRL_SIGSEL_x defines that support asynchronous operation.
369  ******************************************************************************/
PRS_SourceAsyncSignalSet(unsigned int ch,uint32_t source,uint32_t signal)370 void PRS_SourceAsyncSignalSet(unsigned int ch,
371                               uint32_t source,
372                               uint32_t signal)
373 {
374   PRS_ConnectSignal(ch, prsTypeAsync, (PRS_Signal_t) (source | signal));
375 }
376 #endif
377 
378 #if defined(_PRS_ROUTELOC0_MASK) || (defined(_PRS_ROUTE_MASK) && (_PRS_ROUTE_MASK))
379 /***************************************************************************//**
380  * @brief
381  *   Send the output of a PRS channel to a GPIO pin.
382  *
383  * @details
384  *   This function is used to send the output of a PRS channel to a GPIO pin.
385  *   Note that there are certain restrictions to where a PRS channel can be
386  *   routed. Consult the datasheet of the device to see if a channel can be
387  *   routed to the requested GPIO pin.
388  *
389  * @param[in] ch
390  *   PRS channel number.
391  *
392  * @param[in] location
393  *   PRS routing location.
394  ******************************************************************************/
PRS_GpioOutputLocation(unsigned int ch,unsigned int location)395 void PRS_GpioOutputLocation(unsigned int ch,
396                             unsigned int location)
397 {
398   EFM_ASSERT(ch < PRS_CHAN_COUNT);
399 
400 #if defined(_PRS_ROUTE_MASK)
401   PRS->ROUTE |= (location << _PRS_ROUTE_LOCATION_SHIFT)
402                 | (1 << ch);
403 #else
404   uint32_t shift = (ch % 4) * 8;
405   uint32_t mask = location << shift;
406   uint32_t locationGroup = ch / 4;
407   /* Since all ROUTELOCx registers are in consecutive memory locations, treat them
408    * as an array starting at ROUTELOC0 and use locationGroup to index into this array */
409   volatile uint32_t * routeloc = &PRS->ROUTELOC0;
410   routeloc[locationGroup] |= mask;
411   PRS->ROUTEPEN |= 1 << ch;
412 #endif
413 }
414 #endif
415 
416 /***************************************************************************//**
417  * @brief
418  *   Search for the first free PRS channel.
419  *
420  * @param[in] type
421  *   PRS channel type. This can be either @ref prsTypeAsync or
422  *   @ref prsTypeSync.
423  *
424  * @return
425  *   Channel number >= 0 if an unused PRS channel was found. If no free PRS
426  *   channel was found then -1 is returned.
427  ******************************************************************************/
PRS_GetFreeChannel(PRS_ChType_t type)428 int PRS_GetFreeChannel(PRS_ChType_t type)
429 {
430   int ch = -1;
431   PRS_Signal_t signal;
432   int max;
433 
434   if (type == prsTypeAsync) {
435     max = PRS_ASYNC_CHAN_COUNT;
436   } else {
437     max = PRS_SYNC_CHAN_COUNT;
438   }
439 
440   for (int i = 0; i < max; i++) {
441     signal = getSignal(i, type);
442     if (signal == prsSignalNone) {
443       ch = i;
444       break;
445     }
446   }
447   return ch;
448 }
449 
450 /***************************************************************************//**
451  * @brief
452  *   Reset all PRS channels
453  *
454  * @details
455  *   This function will reset all the PRS channel configuration.
456  ******************************************************************************/
PRS_Reset(void)457 void PRS_Reset(void)
458 {
459   unsigned int i;
460 
461 #if defined(_SILICON_LABS_32B_SERIES_2)
462   PRS->ASYNC_SWLEVEL = 0;
463   for (i = 0; i < PRS_ASYNC_CHAN_COUNT; i++) {
464     PRS->ASYNC_CH[i].CTRL = _PRS_ASYNC_CH_CTRL_RESETVALUE;
465   }
466   for (i = 0; i < PRS_SYNC_CHAN_COUNT; i++) {
467     PRS->SYNC_CH[i].CTRL = _PRS_SYNC_CH_CTRL_RESETVALUE;
468   }
469 #else
470   PRS->SWLEVEL = 0x0;
471   for (i = 0; i < PRS_CHAN_COUNT; i++) {
472     PRS->CH[i].CTRL = _PRS_CH_CTRL_RESETVALUE;
473   }
474 #endif
475 }
476 
477 /***************************************************************************//**
478  * @brief
479  *   Connect a PRS signal to a channel.
480  *
481  * @details
482  *   This function will make the PRS signal available on the specific channel.
483  *   Only a single PRS signal can be connected to any given channel.
484  *
485  * @param[in] ch
486  *   PRS channel number.
487  *
488  * @param[in] type
489  *   PRS channel type. This can be either @ref prsTypeAsync or
490  *   @ref prsTypeSync.
491  *
492  * @param[in] signal
493  *   This is the PRS signal that should be placed on the channel.
494  ******************************************************************************/
PRS_ConnectSignal(unsigned int ch,PRS_ChType_t type,PRS_Signal_t signal)495 void PRS_ConnectSignal(unsigned int ch, PRS_ChType_t type, PRS_Signal_t signal)
496 {
497 #if defined(_PRS_ASYNC_CH_CTRL_MASK)
498   // Series 2 devices
499   uint32_t sourceField = ((uint32_t)signal & _PRS_ASYNC_CH_CTRL_SOURCESEL_MASK)
500                          >> _PRS_ASYNC_CH_CTRL_SOURCESEL_SHIFT;
501   uint32_t signalField = ((uint32_t)signal & _PRS_ASYNC_CH_CTRL_SIGSEL_MASK)
502                          >> _PRS_ASYNC_CH_CTRL_SIGSEL_SHIFT;
503   if (type == prsTypeAsync) {
504     EFM_ASSERT(ch < PRS_ASYNC_CHAN_COUNT);
505     PRS->ASYNC_CH[ch].CTRL = PRS_ASYNC_CH_CTRL_FNSEL_A
506                              | (sourceField << _PRS_ASYNC_CH_CTRL_SOURCESEL_SHIFT)
507                              | (signalField << _PRS_ASYNC_CH_CTRL_SIGSEL_SHIFT);
508   } else {
509     EFM_ASSERT(ch < PRS_SYNC_CHAN_COUNT);
510     signalField = PRS_ConvertToSyncSignal(sourceField, signalField);
511     sourceField = PRS_ConvertToSyncSource(sourceField);
512     PRS->SYNC_CH[ch].CTRL = (sourceField << _PRS_SYNC_CH_CTRL_SOURCESEL_SHIFT)
513                             | (signalField << _PRS_SYNC_CH_CTRL_SIGSEL_SHIFT);
514   }
515 #else
516   // Series 0 and Series 1 devices
517   uint32_t signalField = (uint32_t) signal & (_PRS_CH_CTRL_SOURCESEL_MASK
518                                               | _PRS_CH_CTRL_SIGSEL_MASK);
519   if (type == prsTypeAsync) {
520 #if defined(PRS_ASYNC_SUPPORTED)
521     EFM_ASSERT(ch < PRS_ASYNC_CHAN_COUNT);
522     PRS->CH[ch].CTRL = PRS_CH_CTRL_EDSEL_OFF
523                        | PRS_CH_CTRL_ASYNC
524                        | signalField;
525 #endif
526   } else {
527     EFM_ASSERT(ch < PRS_SYNC_CHAN_COUNT);
528     PRS->CH[ch].CTRL = PRS_CH_CTRL_EDSEL_OFF
529                        | signalField;
530   }
531 #endif
532 }
533 
534 #if defined(_SILICON_LABS_32B_SERIES_2)
535 /***************************************************************************//**
536  * @brief
537  *   Connect a peripheral consumer to a PRS channel.
538  *
539  * @details
540  *   Different peripherals can use PRS channels as their input. This function
541  *   can be used to connect a peripheral consumer to a PRS channel. Multiple
542  *   consumers can be connected to a single PRS channel.
543  *
544  * @param[in] ch
545  *   PRS channel number.
546  *
547  * @param[in] type
548  *   PRS channel type. This can be either @ref prsTypeAsync or
549  *   @ref prsTypeSync.
550  *
551  * @param[in] consumer
552  *   This is the PRS consumer.
553  ******************************************************************************/
PRS_ConnectConsumer(unsigned int ch,PRS_ChType_t type,PRS_Consumer_t consumer)554 void PRS_ConnectConsumer(unsigned int ch, PRS_ChType_t type, PRS_Consumer_t consumer)
555 {
556   EFM_ASSERT((uint32_t)consumer <= 0xFFF);
557   volatile uint32_t * addr = (volatile uint32_t *) PRS;
558   uint32_t offset = (uint32_t) consumer;
559   addr = addr + offset / 4;
560 
561   if (consumer != prsConsumerNone) {
562     if (type == prsTypeAsync) {
563       *addr = ch << _PRS_CONSUMER_TIMER0_CC0_PRSSEL_SHIFT;
564     } else {
565       *addr = ch << _PRS_CONSUMER_TIMER0_CC0_SPRSSEL_SHIFT;
566     }
567   }
568 }
569 
570 /***************************************************************************//**
571  * @brief
572  *   Send the output of a PRS channel to a GPIO pin.
573  *
574  * @details
575  *   This function is used to send the output of a PRS channel to a GPIO pin.
576  *   Note that there are certain restrictions to where a PRS channel can be
577  *   routed. Consult the datasheet of the device to see if a channel can be
578  *   routed to the requested GPIO pin. Some devices for instance can only route
579  *   the async channels 0-5 on GPIO pins PAx and PBx while async channels 6-11
580  *   can only be routed to GPIO pins PCx and PDx
581  *
582  * @param[in] ch
583  *   PRS channel number.
584  *
585  * @param[in] type
586  *   PRS channel type. This can be either @ref prsTypeAsync or
587  *   @ref prsTypeSync.
588  *
589  * @param[in] port
590  *   GPIO port
591  *
592  * @param[in] pin
593  *   GPIO pin
594  ******************************************************************************/
PRS_PinOutput(unsigned int ch,PRS_ChType_t type,GPIO_Port_TypeDef port,uint8_t pin)595 void PRS_PinOutput(unsigned int ch, PRS_ChType_t type, GPIO_Port_TypeDef port, uint8_t pin)
596 {
597   volatile uint32_t * addr;
598   if (type == prsTypeAsync) {
599     addr = &GPIO->PRSROUTE[0].ASYNCH0ROUTE;
600   } else {
601     addr = &GPIO->PRSROUTE[0].SYNCH0ROUTE;
602   }
603   addr += ch;
604   *addr = ((uint32_t)port << _GPIO_PRS_ASYNCH0ROUTE_PORT_SHIFT)
605           | ((uint32_t)pin << _GPIO_PRS_ASYNCH0ROUTE_PIN_SHIFT);
606 
607   if (type == prsTypeAsync) {
608     GPIO->PRSROUTE[0].ROUTEEN |= 0x1 << (ch + _GPIO_PRS_ROUTEEN_ASYNCH0PEN_SHIFT);
609   } else {
610     GPIO->PRSROUTE[0].ROUTEEN |= 0x1 << (ch + _GPIO_PRS_ROUTEEN_SYNCH0PEN_SHIFT);
611   }
612 }
613 
614 /***************************************************************************//**
615  * @brief
616  *   Combine two PRS channels using a logic function.
617  *
618  * @details
619  *   This function allows you to combine the output of one PRS channel with the
620  *   the signal of another PRS channel using various logic functions. Note that
621  *   for series 2, config 1 devices, the hardware only allows a PRS channel to
622  *   be combined with the previous channel. So for instance channel 5 can be
623  *   combined only with channel 4.
624  *
625  *   The logic function operates on two PRS channels called A and B. The output
626  *   of PRS channel B is combined with the PRS source configured for channel A
627  *   to produce an output. This output is used as the output of channel A.
628  *
629  * @param[in] chA
630  *   PRS Channel for the A input.
631  *
632  * @param[in] chB
633  *   PRS Channel for the B input.
634  *
635  * @param[in] logic
636  *   The logic function to use when combining the Channel A and Channel B. The
637  *   output of the logic function is the output of Channel A. Function like
638  *   AND, OR, XOR, NOT and more are available.
639  ******************************************************************************/
PRS_Combine(unsigned int chA,unsigned int chB,PRS_Logic_t logic)640 void PRS_Combine(unsigned int chA, unsigned int chB, PRS_Logic_t logic)
641 {
642   EFM_ASSERT(chA < PRS_ASYNC_CHAN_COUNT);
643   EFM_ASSERT(chB < PRS_ASYNC_CHAN_COUNT);
644 
645 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
646   EFM_ASSERT(chA == ((chB + 1) % PRS_ASYNC_CHAN_COUNT));
647   PRS->ASYNC_CH[chA].CTRL = (PRS->ASYNC_CH[chA].CTRL & ~_PRS_ASYNC_CH_CTRL_FNSEL_MASK)
648                             | ((uint32_t)logic << _PRS_ASYNC_CH_CTRL_FNSEL_SHIFT);
649 
650 #else
651   PRS->ASYNC_CH[chA].CTRL = (PRS->ASYNC_CH[chA].CTRL
652                              & ~(_PRS_ASYNC_CH_CTRL_FNSEL_MASK
653                                  | _PRS_ASYNC_CH_CTRL_AUXSEL_MASK))
654                             | ((uint32_t)logic << _PRS_ASYNC_CH_CTRL_FNSEL_SHIFT)
655                             | ((uint32_t)chB << _PRS_ASYNC_CH_CTRL_AUXSEL_SHIFT);
656 #endif
657 }
658 #endif
659 
660 /** @} (end addtogroup prs) */
661 #endif /* defined(PRS_COUNT) && (PRS_COUNT > 0) */
662