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