Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_system.c
1 #include <bc_system.h>
2 #include <bc_scheduler.h>
3 #include <bc_irq.h>
4 #include <bc_i2c.h>
5 #include <bc_timer.h>
6 #include <stm32l0xx.h>
7 
8 #define _BC_SYSTEM_DEBUG_ENABLE 0
9 
10 static const uint32_t bc_system_clock_table[3] =
11 {
12  RCC_CFGR_SW_MSI,
13  RCC_CFGR_SW_HSI,
14  RCC_CFGR_SW_PLL
15 };
16 
17 static int _bc_system_hsi16_enable_semaphore;
18 
19 static int _bc_system_pll_enable_semaphore;
20 
21 static int _bc_system_deep_sleep_disable_semaphore;
22 
23 static void _bc_system_init_flash(void);
24 
25 static void _bc_system_init_debug(void);
26 
27 static void _bc_system_init_clock(void);
28 
29 static void _bc_system_init_power(void);
30 
31 static void _bc_system_init_gpio(void);
32 
33 static void _bc_system_init_rtc(void);
34 
35 static void _bc_system_init_shutdown_tmp112(void);
36 
37 static void _bc_system_switch_clock(bc_system_clock_t clock);
38 
39 void bc_system_init(void)
40 {
41  _bc_system_init_flash();
42 
43  _bc_system_init_debug();
44 
45  _bc_system_init_clock();
46 
47  _bc_system_init_power();
48 
49  _bc_system_init_gpio();
50 
51  _bc_system_init_rtc();
52 
53  _bc_system_init_shutdown_tmp112();
54 }
55 
56 static void _bc_system_init_flash(void)
57 {
58  // Enable prefetch
59  FLASH->ACR |= FLASH_ACR_PRFTEN;
60 
61  // One wait state is used to read word from NVM
62  FLASH->ACR |= FLASH_ACR_LATENCY;
63 }
64 
65 static void _bc_system_init_debug(void)
66 {
67 #if _BC_SYSTEM_DEBUG_ENABLE == 1
68 
69  // Enable clock for DBG
70  RCC->APB2ENR |= RCC_APB2ENR_DBGMCUEN;
71 
72  // Errata workaround
73  RCC->APB2ENR;
74 
75  // Enable debug in Standby mode
76  DBGMCU->CR |= DBGMCU_CR_DBG_STANDBY;
77 
78  // Enable debug in Stop mode
79  DBGMCU->CR |= DBGMCU_CR_DBG_STOP;
80 
81  // Enable debug in Sleep mode
82  DBGMCU->CR |= DBGMCU_CR_DBG_SLEEP;
83 
84  // LPTIM1 counter stopped when core is halted
85  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_LPTIMER_STOP;
86 
87  // I2C3 SMBUS timeout mode stopped when core is halted
88  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_I2C3_STOP;
89 
90  // I2C1 SMBUS timeout mode stopped when core is halted
91  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_I2C1_STOP;
92 
93  // Debug independent watchdog stopped when core is halted
94  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_IWDG_STOP;
95 
96  // Debug window watchdog stopped when core is halted
97  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_WWDG_STOP;
98 
99  // Debug RTC stopped when core is halted
100  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_RTC_STOP;
101 
102  // TIM7 counter stopped when core is halted
103  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM7_STOP;
104 
105  // TIM6 counter stopped when core is halted
106  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM6_STOP;
107 
108  // TIM3 counter stopped when core is halted
109  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM3_STOP;
110 
111  // TIM2 counter stopped when core is halted
112  DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM2_STOP;
113 
114  // TIM22 counter stopped when core is halted
115  DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM22_STOP;
116 
117  // TIM21 counter stopped when core is halted
118  DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM21_STOP;
119 
120 #endif
121 }
122 
123 static void _bc_system_init_clock(void)
124 {
125 
126  // Update SystemCoreClock variable
127  SystemCoreClock = 2097000;
128 
129  RCC->APB1ENR |= RCC_APB1ENR_PWREN;
130 
131  // Set regulator range to 1.2V
132  PWR->CR |= PWR_CR_VOS;
133 
134  // Set PLL divider and multiplier
135  RCC->CFGR = RCC_CFGR_PLLDIV2 | RCC_CFGR_PLLMUL4;
136 
137  // Set SysTick reload value
138  SysTick->LOAD = 2097 - 1;
139 
140  // Reset SysTick counter
141  SysTick->VAL = 0;
142 
143  // Use processor clock as SysTick clock source
144  SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
145 
146  // Enable SysTick interrupt
147  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
148 
149  // Enable SysTick counter
150  SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
151 }
152 
153 static void _bc_system_init_power(void)
154 {
155  // Enable clock for PWR
156  RCC->APB1ENR |= RCC_APB1ENR_PWREN;
157 
158  // Errata workaround
159  RCC->APB1ENR;
160 
161  // Disable backup write protection
162  PWR->CR |= PWR_CR_DBP;
163 
164  // Enable fast wake-up
165  PWR->CR |= PWR_CR_FWU;
166 
167  // Enable ultra-low-power mode
168  PWR->CR |= PWR_CR_ULP;
169 
170  // Enable regulator low-power mode
171  PWR->CR |= PWR_CR_LPSDSR;
172 
173  // Enable deep-sleep
174  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
175 }
176 
177 static void _bc_system_init_gpio(void)
178 {
179  // Enable clock for GPIOA
180  RCC->IOPENR = RCC_IOPENR_GPIOAEN;
181 
182  // Errata workaround
183  RCC->IOPENR;
184 
185  // Set analog mode on PA4
186  GPIOA->MODER |= GPIO_MODER_MODE4_1 | GPIO_MODER_MODE4_0;
187 }
188 
189 static void _bc_system_init_rtc(void)
190 {
191 
192  // Set LSE oscillator drive capability to medium low drive
193  RCC->CSR |= RCC_CSR_LSEDRV_1;
194 
195  // Enable LSE oscillator
196  RCC->CSR |= RCC_CSR_LSEON;
197 
198  // Wait for LSE oscillator to be ready...
199  while ((RCC->CSR & RCC_CSR_LSERDY) == 0)
200  {
201  continue;
202  }
203 
204  // LSE oscillator clock used as RTC clock
205  RCC->CSR |= RCC_CSR_RTCSEL_LSE;
206 
207  // Enable RTC clock
208  RCC->CSR |= RCC_CSR_RTCEN;
209 
210  // Errata workaround
211  RCC->CSR;
212 
213  // Disable write protection
214  RTC->WPR = 0xca;
215  RTC->WPR = 0x53;
216 
217  // Initialize RTC only once
218  if ((RTC->ISR & RTC_ISR_INITS) == 0)
219  {
220 
221  // Enable initialization mode
222  RTC->ISR |= RTC_ISR_INIT;
223 
224  // Wait for RTC to be in initialization mode...
225  while ((RTC->ISR & RTC_ISR_INITF) == 0)
226  {
227  continue;
228  }
229 
230  // Set RTC prescaler
231  RTC->PRER = (127 << 16) | 255;
232 
233  // Exit from initialization mode
234  RTC->ISR &= ~RTC_ISR_INIT;
235 
236  }
237 
238  // Disable timer
239  RTC->CR &= ~RTC_CR_WUTE;
240 
241  // Wait until timer configuration update is allowed...
242  while ((RTC->ISR & RTC_ISR_WUTWF) == 0)
243  {
244  continue;
245  }
246 
247  // Set wake-up auto-reload value
248  RTC->WUTR = 20;
249 
250  // Clear timer flag
251  RTC->ISR &= ~RTC_ISR_WUTF;
252 
253  // Enable timer interrupts
254  RTC->CR |= RTC_CR_WUTIE;
255 
256  // Enable timer
257  RTC->CR |= RTC_CR_WUTE;
258 
259  // Enable write protection
260  RTC->WPR = 0xff;
261 
262 
263  // RTC IRQ needs to be configured through EXTI
264  EXTI->IMR |= EXTI_IMR_IM20;
265 
266  // Enable rising edge trigger
267  EXTI->RTSR |= EXTI_IMR_IM20;
268 
269  // Enable RTC interrupt requests
270  NVIC_EnableIRQ(RTC_IRQn);
271 }
272 
273 static void _bc_system_init_shutdown_tmp112(void)
274 {
276 
277  bc_i2c_memory_write_16b(BC_I2C_I2C0, 0x49, 0x01, 0x0180);
278 
280 }
281 
282 void bc_system_sleep(void)
283 {
284  __WFI();
285 }
286 
287 void bc_system_deep_sleep_enable(void)
288 {
289  _bc_system_deep_sleep_disable_semaphore--;
290 
291  if (_bc_system_deep_sleep_disable_semaphore == 0)
292  {
293  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
294  }
295 }
296 
297 void bc_system_deep_sleep_disable(void)
298 {
299  if (_bc_system_deep_sleep_disable_semaphore == 0)
300  {
301  SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
302  }
303 
304  _bc_system_deep_sleep_disable_semaphore++;
305 }
306 
307 void bc_system_enter_standby_mode(void)
308 {
310 
311  // tmp112
312  bc_i2c_memory_write_16b(BC_I2C_I2C0, 0x49, 0x01, 0x0180);
313 
314  // lis2dh12
315  bc_i2c_memory_write_16b(BC_I2C_I2C0, 0x19, 0x20, 0x07);
316 
318 
319  __disable_irq();
320 
321  GPIOA->MODER = 0xFFFFFFFF;
322  GPIOB->MODER = 0xFFFFFFFF;
323  GPIOC->MODER = 0xFFFFFFFF;
324  GPIOH->MODER = 0xFFFFFFFF;
325 
326  // Disable RTC clock
327  RCC->CSR &= ~(RCC_CSR_RTCEN | RCC_CSR_LSEON | RCC_CSR_RTCSEL_LSE);
328 
329  // Errata workaround
330  RCC->CSR;
331 
332  RCC->CSR &= ~RCC_CSR_LSEDRV_Msk;
333 
334  PWR->CR &= ~PWR_CR_LPSDSR;
335 
336  PWR->CR |= PWR_CR_PDDS;
337 
338  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
339 
340  PWR->CR |= PWR_CR_CWUF;
341 
342  __WFI();
343 }
344 
345 bc_system_clock_t bc_system_clock_get(void)
346 {
347  if (_bc_system_pll_enable_semaphore != 0)
348  {
349  return BC_SYSTEM_CLOCK_PLL;
350  }
351  else if (_bc_system_hsi16_enable_semaphore != 0)
352  {
353  return BC_SYSTEM_CLOCK_HSI;
354  }
355  else
356  {
357  return BC_SYSTEM_CLOCK_MSI;
358  }
359 }
360 
361 void bc_system_hsi16_enable(void)
362 {
363  if (++_bc_system_hsi16_enable_semaphore == 1)
364  {
365  // Set regulator range to 1.8V
366  PWR->CR |= PWR_CR_VOS_0;
367  PWR->CR &= ~PWR_CR_VOS_1;
368 
369  // Enable flash latency and preread
370  FLASH->ACR |= FLASH_ACR_LATENCY | FLASH_ACR_PRE_READ;
371 
372  // Turn HSI16 on
373  RCC->CR |= RCC_CR_HSION;
374 
375  while ((RCC->CR & RCC_CR_HSIRDY) == 0)
376  {
377  continue;
378  }
379 
380  _bc_system_switch_clock(BC_SYSTEM_CLOCK_HSI);
381 
382  // Set SysTick reload value
383  SysTick->LOAD = 16000 - 1;
384 
385  // Update SystemCoreClock variable
386  SystemCoreClock = 16000000;
387  }
388 
390 }
391 
392 void bc_system_hsi16_disable(void)
393 {
394  if (--_bc_system_hsi16_enable_semaphore == 0)
395  {
396  _bc_system_switch_clock(BC_SYSTEM_CLOCK_MSI);
397 
398  // Turn HSI16 off
399  RCC->CR &= ~RCC_CR_HSION;
400 
401  while ((RCC->CR & RCC_CR_HSIRDY) != 0)
402  {
403  continue;
404  }
405 
406  // Set SysTick reload value
407  SysTick->LOAD = 2097 - 1;
408 
409  // Update SystemCoreClock variable
410  SystemCoreClock = 2097000;
411 
412  // Disable latency
413  FLASH->ACR &= ~(FLASH_ACR_LATENCY | FLASH_ACR_PRE_READ);
414 
415  // Set regulator range to 1.2V
416  PWR->CR |= PWR_CR_VOS;
417  }
418 
420 }
421 
422 void bc_system_pll_enable(void)
423 {
424  if (++_bc_system_pll_enable_semaphore == 1)
425  {
426  bc_system_hsi16_enable();
427 
428  // Turn PLL on
429  RCC->CR |= RCC_CR_PLLON;
430 
431  while ((RCC->CR & RCC_CR_PLLRDY) == 0)
432  {
433  continue;
434  }
435 
436  _bc_system_switch_clock(BC_SYSTEM_CLOCK_PLL);
437 
438  // Set SysTick reload value
439  SysTick->LOAD = 32000 - 1;
440 
441  // Update SystemCoreClock variable
442  SystemCoreClock = 32000000;
443  }
444 }
445 
446 void bc_system_pll_disable(void)
447 {
448  if (--_bc_system_pll_enable_semaphore == 0)
449  {
450  _bc_system_switch_clock(BC_SYSTEM_CLOCK_HSI);
451 
452  // Turn PLL off
453  RCC->CR &= ~RCC_CR_PLLON;
454 
455  while ((RCC->CR & RCC_CR_PLLRDY) != 0)
456  {
457  continue;
458  }
459 
460  bc_system_hsi16_disable();
461  }
462 }
463 
464 uint32_t bc_system_get_clock(void)
465 {
466  return SystemCoreClock;
467 }
468 
469 void bc_system_reset(void)
470 {
471  NVIC_SystemReset();
472 }
473 
474 bool bc_system_get_vbus_sense(void)
475 {
476  static bool init = false;
477 
478  if (!init)
479  {
480  init = true;
481 
482  // Enable clock for GPIOA
483  RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
484 
485  // Errata workaround
486  RCC->IOPENR;
487 
488  // Enable pull-down
489  GPIOA->PUPDR |= GPIO_PUPDR_PUPD12_1;
490 
491  // Input mode
492  GPIOA->MODER &= ~GPIO_MODER_MODE12_Msk;
493 
494  bc_timer_init();
495  bc_timer_start();
496  bc_timer_delay(10);
497  bc_timer_stop();
498  }
499 
500  return (GPIOA->IDR & GPIO_IDR_ID12) != 0;
501 }
502 
503 __attribute__((weak)) void bc_system_error(void)
504 {
505 #ifdef RELEASE
506  bc_system_reset();
507 #else
508  for (;;);
509 #endif
510 }
511 
512 void HardFault_Handler(void)
513 {
514  bc_system_error();
515 }
516 
517 void RTC_IRQHandler(void)
518 {
519  // If wake-up timer flag is set...
520  if (RTC->ISR & RTC_ISR_WUTF)
521  {
522  // Clear wake-up timer flag
523  RTC->ISR &= ~RTC_ISR_WUTF;
524 
525  bc_tick_inrement_irq(10);
526  }
527 
528  // Clear EXTI interrupt flag
529  EXTI->PR = EXTI_IMR_IM20;
530 }
531 
532 
533 static void _bc_system_switch_clock(bc_system_clock_t clock)
534 {
535  uint32_t clock_mask = bc_system_clock_table[clock];
536 
537  bc_irq_disable();
538 
539  uint32_t rcc_cfgr = RCC->CFGR;
540  rcc_cfgr &= ~RCC_CFGR_SW_Msk;
541  rcc_cfgr |= clock_mask;
542  RCC->CFGR = rcc_cfgr;
543 
544  bc_irq_enable();
545 }
bool bc_i2c_memory_write_16b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint16_t data)
Memory write 2 bytes to I2C channel.
Definition: bc_i2c.c:414
void bc_irq_enable(void)
Enable interrupt requests globally (call can be nested)
Definition: bc_irq.c:21
I2C channel I2C0.
Definition: bc_i2c.h:18
void bc_timer_start(void)
Start timer.
Definition: bc_timer.c:24
void bc_timer_delay(uint16_t microseconds)
Relative delay.
Definition: bc_timer.c:40
void bc_scheduler_disable_sleep(void)
Disable sleep mode, implemented as semaphore.
Definition: bc_scheduler.c:109
void bc_i2c_init(bc_i2c_channel_t channel, bc_i2c_speed_t speed)
Initialize I2C channel.
Definition: bc_i2c.c:54
void bc_i2c_deinit(bc_i2c_channel_t channel)
Deitialize I2C channel.
Definition: bc_i2c.c:139
I2C communication speed is 100 kHz.
Definition: bc_i2c.h:33
void bc_scheduler_enable_sleep(void)
Enable sleep mode, implemented as semaphore.
Definition: bc_scheduler.c:114
void bc_timer_stop(void)
Stop timer.
Definition: bc_timer.c:55
void bc_irq_disable(void)
Disable interrupt requests globally (call can be nested)
Definition: bc_irq.c:7
void bc_timer_init(void)
Initialize timer.
Definition: bc_timer.c:18