EFM32 Happy Gecko Software Documentation  efm32hg-doc-4.2.1
em_burtc.c
Go to the documentation of this file.
1 /***************************************************************************/
34 #include "em_burtc.h"
35 #if defined(BURTC_PRESENT)
36 
37 /***************************************************************************/
42 /***************************************************************************/
48 /*******************************************************************************
49  ******************************* DEFINES ***********************************
50  ******************************************************************************/
51 
52 /*******************************************************************************
53  ************************** LOCAL FUNCTIONS ********************************
54  ******************************************************************************/
55 
57 /***************************************************************************/
63 __STATIC_INLINE uint32_t divToLog2(uint32_t div)
64 {
65  uint32_t log2;
66 
67  /* Prescaler accepts an argument of 128 or less, valid values being 2^n */
68  EFM_ASSERT((div > 0) && (div <= 32768));
69 
70  /* Count leading zeroes and "reverse" result, Cortex-M3 intrinsic */
71  log2 = (31 - __CLZ(div));
72 
73  return log2;
74 }
75 
76 
77 /***************************************************************************/
85 __STATIC_INLINE void regSync(uint32_t mask)
86 {
87  /* Avoid deadlock if modifying the same register twice when freeze mode is
88  activated, or when no clock is selected for the BURTC. If no clock is
89  selected, then the sync is done once the clock source is set. */
90  if ((BURTC->FREEZE & BURTC_FREEZE_REGFREEZE)
91  || ((BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK) != _BURTC_CTRL_CLKSEL_NONE))
92  {
93  return;
94  }
95  /* Wait for any pending previous write operation to have been completed */
96  /* in low frequency domain. This is only required for the Gecko Family */
97  while (BURTC->SYNCBUSY & mask)
98  ;
99 }
103 /*******************************************************************************
104  ************************** GLOBAL FUNCTIONS *******************************
105  ******************************************************************************/
106 
107 /***************************************************************************/
125 void BURTC_Init(const BURTC_Init_TypeDef *burtcInit)
126 {
127  uint32_t ctrl;
128  uint32_t presc;
129 
130  /* Check initializer structure integrity */
131  EFM_ASSERT(burtcInit != (BURTC_Init_TypeDef *) 0);
132  /* Clock divider must be between 1 and 128, really on the form 2^n */
133  EFM_ASSERT((burtcInit->clkDiv >= 1) && (burtcInit->clkDiv <= 128));
134  /* Ignored compare bits during low power operation must be less than 7 */
135  /* Note! Giant Gecko revision C errata, do NOT use LPCOMP=7 */
136  EFM_ASSERT(burtcInit->lowPowerComp <= 6);
137  /* You cannot enable the BURTC if mode is set to disabled */
138  EFM_ASSERT((burtcInit->enable == false) ||
139  ((burtcInit->enable == true)
140  && (burtcInit->mode != burtcModeDisable)));
141  /* Low power mode is only available with LFRCO or LFXO as clock source */
142  EFM_ASSERT((burtcInit->clkSel != burtcClkSelULFRCO)
143  || ((burtcInit->clkSel == burtcClkSelULFRCO)
144  && (burtcInit->lowPowerMode == burtcLPDisable)));
145 
146  /* Calculate prescaler value from clock divider input */
147  /* Note! If clock select (clkSel) is ULFRCO, a clock divisor (clkDiv) of
148  value 1 will select a 2kHz ULFRCO clock, while any other value will
149  select a 1kHz ULFRCO clock source. */
150  presc = divToLog2(burtcInit->clkDiv);
151 
152  /* Make sure all registers are updated simultaneously */
153  if (burtcInit->enable)
154  {
155  BURTC_FreezeEnable(true);
156  }
157 
158  /* Modification of LPMODE register requires sync with potential ongoing
159  * register updates in LF domain. */
160  regSync(BURTC_SYNCBUSY_LPMODE);
161 
162  /* Configure low power mode */
163  BURTC->LPMODE = (uint32_t) (burtcInit->lowPowerMode);
164 
165  /* New configuration */
166  ctrl = (BURTC_CTRL_RSTEN
167  | (burtcInit->mode)
168  | (burtcInit->debugRun << _BURTC_CTRL_DEBUGRUN_SHIFT)
169  | (burtcInit->compare0Top << _BURTC_CTRL_COMP0TOP_SHIFT)
170  | (burtcInit->lowPowerComp << _BURTC_CTRL_LPCOMP_SHIFT)
171  | (presc << _BURTC_CTRL_PRESC_SHIFT)
172  | (burtcInit->clkSel)
173  | (burtcInit->timeStamp << _BURTC_CTRL_BUMODETSEN_SHIFT));
174 
175  /* Clear interrupts */
176  BURTC_IntClear(0xFFFFFFFF);
177 
178  /* Set new configuration */
179  BURTC->CTRL = ctrl;
180 
181  /* Enable BURTC and counter */
182  if (burtcInit->enable)
183  {
184  /* To enable BURTC counter, we need to disable reset */
185  BURTC_Enable(true);
186 
187  /* Clear freeze */
188  BURTC_FreezeEnable(false);
189  }
190 }
191 
192 
193 /***************************************************************************/
200 void BURTC_CompareSet(unsigned int comp, uint32_t value)
201 {
202  (void) comp; /* Unused parameter when EFM_ASSERT is undefined. */
203 
204  EFM_ASSERT(comp == 0);
205 
206  /* Modification of COMP0 register requires sync with potential ongoing
207  * register updates in LF domain. */
208  regSync(BURTC_SYNCBUSY_COMP0);
209 
210  /* Configure compare channel 0 */
211  BURTC->COMP0 = value;
212 }
213 
214 
215 /***************************************************************************/
222 uint32_t BURTC_CompareGet(unsigned int comp)
223 {
224  (void) comp; /* Unused parameter when EFM_ASSERT is undefined. */
225 
226  EFM_ASSERT(comp == 0);
227 
228  return BURTC->COMP0;
229 }
230 
231 
232 /***************************************************************************/
235 void BURTC_CounterReset(void)
236 {
237  /* Set and clear reset bit */
238  BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 1);
239  BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 0);
240 }
241 
242 
243 /***************************************************************************/
251 void BURTC_Reset(void)
252 {
253  bool buResetState;
254 
255  /* Read reset state, set reset and restore state */
256  buResetState = BUS_RegBitRead(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT);
257  BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, 1);
258  BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, buResetState);
259 }
260 
261 
262 /***************************************************************************/
269 uint32_t BURTC_ClockFreqGet(void)
270 {
271  uint32_t clkSel;
272  uint32_t clkDiv;
273  uint32_t frequency;
274 
275  clkSel = BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK;
276  clkDiv = (BURTC->CTRL & _BURTC_CTRL_PRESC_MASK) >> _BURTC_CTRL_PRESC_SHIFT;
277 
278  switch (clkSel)
279  {
281  case BURTC_CTRL_CLKSEL_ULFRCO:
282  if (_BURTC_CTRL_PRESC_DIV1 == clkDiv)
283  {
284  frequency = 2000; /* 2KHz when clock divisor is 1. */
285  }
286  else
287  {
288  frequency = SystemULFRCOClockGet(); /* 1KHz when divisor is different
289  from 1. */
290  }
291  break;
292 
294  case BURTC_CTRL_CLKSEL_LFRCO:
295  frequency = SystemLFRCOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */
296  break;
297 
299  case BURTC_CTRL_CLKSEL_LFXO:
300  frequency = SystemLFXOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */
301  break;
302 
303  default:
304  /* No clock selected for BURTC. */
305  frequency = 0;
306  }
307  return frequency;
308 }
309 
310 
314 #endif /* BURTC_PRESENT */
__STATIC_INLINE unsigned int BUS_RegBitRead(volatile const uint32_t *addr, unsigned int bit)
Perform a single-bit read operation on a peripheral register.
Definition: em_bus.h:185
uint32_t SystemLFXOClockGet(void)
Get low frequency crystal oscillator clock frequency for target system.
uint32_t SystemULFRCOClockGet(void)
Get ultra low frequency RC oscillator clock frequency for target system.
Backup Real Time Counter (BURTC) peripheral API.
uint32_t SystemLFRCOClockGet(void)
Get low frequency RC oscillator clock frequency for target system.
__STATIC_INLINE void BUS_RegBitWrite(volatile uint32_t *addr, unsigned int bit, unsigned int val)
Perform a single-bit write operation on a peripheral register.
Definition: em_bus.h:146
#define RMU