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