px-lib  0.9.3
Cross-platform embedded library and documentation for 8/16/32-bit microcontrollers
px_board.c
1 /* =============================================================================
2  ____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
3  | _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
4  | |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
5  | __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
6  |_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
7 
8  Copyright (c) 2017 Pieter Conradie <https://piconomix.com>
9 
10  License: MIT
11  https://github.com/piconomix/piconomix-fwlib/blob/master/LICENSE.md
12 
13  Title: board.h : Piconomix STM32 Hero Board
14  Author(s): Pieter Conradie
15  Creation Date: 2017-11-13
16 
17 ============================================================================= */
18 
19 /* _____STANDARD INCLUDES____________________________________________________ */
20 
21 /* _____PROJECT INCLUDES_____________________________________________________ */
22 #include "px_board.h"
23 #include "px_gpio_init_port_a.h"
24 #include "px_gpio_init_port_b.h"
25 #include "px_gpio_init_port_c.h"
26 #include "px_gpio_init_port_d.h"
27 #include "px_gpio_init_port_h.h"
28 #include "px_lib_stm32cube.h"
29 
30 /* _____LOCAL DEFINITIONS____________________________________________________ */
31 // Check that correct 'board.h' has been included
32 #ifndef PX_BOARD_PICONOMIX_HERO_BOARD
33 #warning "Wrong 'board.h' has been included. Check that include path is correct."
34 #endif
35 
36 // Report board support package
37 #warning "This BSP is for Piconomix STM32 Hero Board"
38 
39 // Test for correct microcontroller
40 #ifndef STM32L072xx
41 #warning "This Board contains a different microcontroller"
42 #endif
43 
44 /* _____MACROS_______________________________________________________________ */
45 
46 /* _____GLOBAL VARIABLES_____________________________________________________ */
47 
48 /* _____LOCAL VARIABLES______________________________________________________ */
49 
50 /* _____LOCAL FUNCTION DECLARATIONS__________________________________________ */
51 
52 /* _____LOCAL FUNCTIONS______________________________________________________ */
53 static void px_board_fatal_error(void)
54 {
55  while(true)
56  {
57  ;
58  }
59 }
60 
61 static void px_board_clocks_init(void)
62 {
63  // Enable SYSCFG peripheral clock
64  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
65  // Enable PWR peripheral clock
66  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
67 
68  // Select 1 wait state to read from Flash (NVM), because core frequency will
69  // be set to 32 MHz (0 wait state if core freq <= 16 MHz)
70  LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
71  if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
72  {
73  px_board_fatal_error();
74  }
75  // Set internal core voltage regulator to 1.8V so that core can operate at
76  // maximum frequency (32 MHz)
77  LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
78 
79  // Enable High Speed Internal 16 MHz RC Oscillator (HSI)
80  LL_RCC_HSI_Enable();
81  while(!LL_RCC_HSI_IsReady())
82  {
83  ;
84  }
85  // Trim HSI RC Oscillator to 16 MHz +- 1%
86  LL_RCC_HSI_SetCalibTrimming(16);
87 
88  // Enable High Speed Internal 48 MHz RC Oscillator (HSI48) for USB
89  LL_RCC_HSI48_Enable();
90  // Enable buffer used to generate VREFINT reference for HSI48 oscillator
91  LL_SYSCFG_VREFINT_EnableHSI48();
92  while(!LL_RCC_HSI48_IsReady())
93  {
94  ;
95  }
96 
97  // Enable CRS (Clock Recovery System) peripheral clock
98  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_CRS);
99  // Enable synchronisation to trim HSI48 oscillator with 1 kHz USB SOF (Start Of Frame)
100  LL_CRS_ConfigSynchronization(LL_CRS_HSI48CALIBRATION_DEFAULT,
101  LL_CRS_ERRORLIMIT_DEFAULT,
102  LL_CRS_RELOADVALUE_DEFAULT,
103  LL_CRS_SYNC_DIV_1 | LL_CRS_SYNC_SOURCE_USB | LL_CRS_SYNC_POLARITY_RISING);
104  // Enable automatic trimming
105  LL_CRS_EnableAutoTrimming();
106  // Enable frequency error counter
107  LL_CRS_EnableFreqErrorCounter();
108 
109  // Enable write access to RTC, RTC Backup registers and
110  // Reset and Clock Control Control Status Register (RCC_CSR)
111  LL_PWR_EnableBkUpAccess();
112 #if 0
113  // Reset the RTC peripheral, it's clock source selection and backup registers
114  LL_RCC_ForceBackupDomainReset();
115  LL_RCC_ReleaseBackupDomainReset();
116 #endif
117  // Set Low Speed External 32768 Hz Oscillator (LSE) drive to low
118  LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_LOW);
119  // Enable Low Speed External 32768 Hz crystal oscillator (LSE)
120  LL_RCC_LSE_Enable();
121  while(!LL_RCC_LSE_IsReady())
122  {
123  ;
124  }
125 
126  // Select LSE as clock source for RTC
127  LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
128  // Enable RTC
129  LL_RCC_EnableRTC();
130 
131  // Configure Phase Locked Loop (PLL) to use
132  // High Speed Internal 16 MHz RC Oscillator (HSI) as source and
133  // output 32 MHz
134  LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI,
135  LL_RCC_PLL_MUL_4,
136  LL_RCC_PLL_DIV_2);
137  // Enable PLL
138  LL_RCC_PLL_Enable();
139  while(!LL_RCC_PLL_IsReady())
140  {
141  ;
142  }
143 
144  // Set Arm High Performance Bus (AHB) clock prescaler to 1
145  LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
146  // Set Arm Peripheral Bus 1 (APB1) clock prescaler to 1
147  LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
148  // Set Arm Peripheral Bus 2 (APB2) clock prescaler to 1
149  LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
150 
151  // Select 32 MHz output of PLL as clock source for system
152  LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
153  while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
154  {
155  ;
156  }
157 
158  // Store system frequency in global SystemCoreClock CMSIS variable
159  LL_SetSystemCoreClock(PX_BOARD_SYS_CLK_HZ);
160 
161  // Select clock sources for USART1, USART2, I2C1 and USB peripherals
162  LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
163  LL_RCC_SetUSARTClockSource(LL_RCC_USART2_CLKSOURCE_PCLK1);
164  LL_RCC_SetI2CClockSource (LL_RCC_I2C1_CLKSOURCE_PCLK1);
165  LL_RCC_SetUSBClockSource (LL_RCC_USB_CLKSOURCE_HSI48);
166 }
167 
168 static void px_board_gpio_init(void)
169 {
170  // Enable GPIO peripheral clocks
171  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
172  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
173  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOC);
174  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOD);
175  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOH);
176 
177  // Initialise GPIO ports
178  px_gpio_port_init(&px_gpio_port_a_init);
179  px_gpio_port_init(&px_gpio_port_b_init);
180  px_gpio_port_init(&px_gpio_port_c_init);
181  px_gpio_port_init(&px_gpio_port_d_init);
182  px_gpio_port_init(&px_gpio_port_h_init);
183 }
184 
185 /* _____GLOBAL FUNCTIONS_____________________________________________________ */
186 void px_board_init(void)
187 {
188  // Initialise clock system
189  px_board_clocks_init();
190 
191  // Enable pre-read flash buffer
192  LL_FLASH_EnablePreRead();
193 
194  // Initialise GPIOs
195  px_board_gpio_init();
196 
197  // Initialise delay
199 }
200 
201 void px_board_spi_cs_lo(uint8_t cs_id)
202 {
203  switch(cs_id)
204  {
205  case PX_BOARD_SPI1_CS: PX_GPIO_PIN_SET_LO(PX_GPIO_SPI1_CS); break;
206  case PX_BOARD_SPI1_CS_SD: PX_GPIO_PIN_SET_LO(PX_GPIO_SPI1_CS_SD); break;
207  case PX_BOARD_SPI2_CS_LCD: PX_GPIO_PIN_SET_LO(PX_GPIO_SPI2_CS_LCD); break;
208  case PX_BOARD_SPI2_CS_SF: PX_GPIO_PIN_SET_LO(PX_GPIO_SPI2_CS_SF); break;
209  default: break;
210  }
211 }
212 
213 void px_board_spi_cs_hi(uint8_t cs_id)
214 {
215  switch(cs_id)
216  {
217  case PX_BOARD_SPI1_CS: PX_GPIO_PIN_SET_HI(PX_GPIO_SPI1_CS); break;
218  case PX_BOARD_SPI1_CS_SD: PX_GPIO_PIN_SET_HI(PX_GPIO_SPI1_CS_SD); break;
219  case PX_BOARD_SPI2_CS_LCD: PX_GPIO_PIN_SET_HI(PX_GPIO_SPI2_CS_LCD); break;
220  case PX_BOARD_SPI2_CS_SF: PX_GPIO_PIN_SET_HI(PX_GPIO_SPI2_CS_SF); break;
221  default: break;
222  }
223 }
224 
226 {
227  // Enable TIM6 peripheral clock
228  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
229  // Set prescaler so that eack clock tick is 1 us
230  TIM6->PSC = PX_UDIV_ROUND(PX_BOARD_PER_CLK_HZ, 1000000) - 1;
231  // Set auto-reload value to maximum
232  TIM6->ARR = 0xffff;
233  // Enable one-pulse mode
234  TIM6->CR1 |= TIM_CR1_OPM;
235 }
236 
238 {
239  // Disable TIM6 peripheral clock
240  LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM6);
241 }
242 
243 void px_board_delay_us(uint16_t delay_us)
244 {
245  // Set auto-reload register to delay (in us)
246  TIM6->ARR = delay_us;
247  // Re-initialize the timer counter (prescaler counter is cleared too)
248  TIM6->EGR = TIM_EGR_UG;
249  // Enable counter
250  TIM6->CR1 |= TIM_CR1_CEN;
251  // Wait until CEN is cleared (in one-pulse mode when an update event occurs)
252  while(TIM6->CR1 & TIM_CR1_CEN)
253  {
254  ;
255  }
256 }
257 
258 void px_board_delay_ms(uint16_t delay_ms)
259 {
260  while(delay_ms != 0)
261  {
262  px_board_delay_us(1000);
263  delay_ms--;
264  }
265 }
266 
267 void px_board_buzzer_on(uint16_t freq_hz)
268 {
269  uint32_t psc;
270  uint32_t arr;
271 
272  // Enable TIM3 peripheral clock
273  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
274 
275  // Set prescaler
276  psc = __LL_TIM_CALC_PSC(PX_BOARD_PER_CLK_HZ, 100000);
277  LL_TIM_SetPrescaler(TIM3, psc);
278 
279  // Set auto reload value according to desired frequency (in Hz)
280  LL_TIM_EnableARRPreload(TIM3);
281  arr = __LL_TIM_CALC_ARR(PX_BOARD_PER_CLK_HZ, psc, ((uint32_t)freq_hz) * 2);
282  LL_TIM_SetAutoReload(TIM3, arr);
283 
284  // Select output toggle mode (when counter reaches maximum value)
285  LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_TOGGLE);
286  LL_TIM_OC_SetPolarity(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_OCPOLARITY_HIGH);
287 
288  // Change PWM pin GPIO mode from Analog to Alternative Function
289  px_gpio_mode_set(&px_gpio_pwm_buzzer, PX_GPIO_MODE_AF);
290 
291  // Start PWM
292  LL_TIM_OC_EnablePreload(TIM3, LL_TIM_CHANNEL_CH1);
293  LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH1);
294  LL_TIM_EnableCounter(TIM3);
295  LL_TIM_GenerateEvent_UPDATE(TIM3);
296 }
297 
299 {
300  // Change PWM pin GPIO mode from Alternative Function to Analog
301  px_gpio_mode_set(&px_gpio_pwm_buzzer, PX_GPIO_MODE_ANA);
302 
303  // Disable timer
304  LL_TIM_DisableCounter(TIM3);
305  LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM3);
306 }
307 
309 {
310  // Enable SWD pins with pull resistors
311  px_gpio_mode_set(&px_gpio_swdck, PX_GPIO_MODE_AF);
312  px_gpio_pulldn_enable(&px_gpio_swdck);
313  px_gpio_mode_set(&px_gpio_swdio, PX_GPIO_MODE_AF);
314  px_gpio_pullup_enable(&px_gpio_swdio);
315 
316  // Enable Debug Module during SLEEP and STOP mode
317  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_DBGMCU);
318  LL_DBGMCU_EnableDBGSleepMode();
319  LL_DBGMCU_EnableDBGStopMode();
320 }
321 
323 {
324  // Set SWD pins to analog with no pull resistors
325  px_gpio_mode_set(&px_gpio_swdck, PX_GPIO_MODE_ANA);
326  px_gpio_pull_disable(&px_gpio_swdck);
327  px_gpio_mode_set(&px_gpio_swdio, PX_GPIO_MODE_ANA);
328  px_gpio_pull_disable(&px_gpio_swdio);
329 
330  // Disable Debug Module during STOP mode
331  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_DBGMCU);
332  LL_DBGMCU_DisableDBGStopMode();
333  LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_DBGMCU);
334 }
335 
337 {
338  uint32_t primask;
339  bool systick_int_enabled;
340 
341  // Save interrupt status
342  primask = __get_PRIMASK();
343  // Disable interrupts
344  __disable_irq();
345  // Is SysTick interrupt enabled?
346  if(LL_SYSTICK_IsEnabledIT())
347  {
348  // Set flag
349  systick_int_enabled = true;
350  // Disable SysTick interrupt.
351  // This is only required if Debug during STOP mode is enabled.
352  LL_SYSTICK_DisableIT();
353  }
354  else
355  {
356  // Clear flag
357  systick_int_enabled = false;
358  }
359 
360  // Enable ultra low power mode by switching off VREFINT during STOP mode
361  LL_PWR_EnableUltraLowPower();
362  // Enable fast wake up from ultra low power mode
363  LL_PWR_EnableFastWakeUp();
364  // Select HSI16 clock after wake up from STOP mode (default is MSI)
365  LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
366  // Clear PDDS bit to enter STOP mode when the CPU enters Deepsleep
367  LL_PWR_SetPowerMode(LL_PWR_MODE_STOP);
368  // Set LPSDSR bit to switch regulator to low-power mode when the CPU enters Deepsleep
369  LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_LOW_POWER);
370  // Clear the WUF flag (after 2 clock cycles)
371  LL_PWR_ClearFlag_WU();
372  // Set SLEEPDEEP bit of Cortex System Control Register
373  LL_LPM_EnableDeepSleep();
374 
375  // Put core into STOP mode until an interrupt occurs.
376  // Core will wake up even though interrupts are disabled.
377  __WFI();
378  // After wakeup clock is 16 MHz (HSI16)
379 
380  // Enable PLL
381  LL_RCC_PLL_Enable();
382  while(!LL_RCC_PLL_IsReady())
383  {
384  ;
385  }
386  // Select 32 MHz output of PLL as clock source for system
387  LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
388  while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
389  {
390  ;
391  }
392 
393  // Clear SLEEPDEEP bit of Cortex System Control Register
394  LL_LPM_EnableSleep();
395  // Clear LPSDSR bit to switch regulator back to main mode
396  LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_MAIN);
397  // Must SysTick interrupt be restored?
398  if(systick_int_enabled)
399  {
400  // Enable SysTick interrupt
401  LL_SYSTICK_EnableIT();
402  }
403  // Restore interrupt (after clock has been restored to 32 MHz)
404  __set_PRIMASK(primask);
405 }
Peripheral CS.
Definition: px_board.h:55
void px_board_stop_mode(void)
Enter low power STOP mode and wait for interrupt to wake up core.
Definition: px_board.c:336
void px_board_dbg_enable(void)
Enable DBG module during SLEEP and STOP mode.
Definition: px_board.c:308
void px_board_spi_cs_lo(uint8_t cs_id)
Set specified SPI Chip Select low.
Definition: px_board.c:201
void px_board_spi_cs_hi(uint8_t cs_id)
Set specified SPI Chip Select high.
Definition: px_board.c:213
void px_board_delay_ms(uint16_t delay_ms)
Blocking delay for specified number of milliseconds.
Definition: px_board.c:258
#define PX_GPIO_PIN_SET_LO(gpio)
Set GPIO pin output low.
Definition: px_gpio.h:225
void px_board_delay_deinit(void)
Disable Timer 6.
Definition: px_board.c:237
#define PX_UDIV_ROUND(dividend, divisor)
Calculate unsigned division with rounding to nearest integer value.
Definition: px_defines.h:275
#define PX_BOARD_SYS_CLK_HZ
System clock frequency in Hz.
Definition: px_board.h:45
Set pin mode to alternative function.
Definition: px_gpio.h:57
JHD JHD12864-G176BSW 128x64 monochrome LCD.
Definition: px_board.h:57
void px_board_buzzer_off(void)
Disable PWM output to piezo buzzer.
Definition: px_board.c:298
Adesto AT25S Serial FLASH.
Definition: px_board.h:58
void px_board_delay_us(uint16_t delay_us)
Blocking delay for specified number of microseconds.
Definition: px_board.c:243
void px_board_init(void)
Initialise the board hardware.
Definition: px_board.c:186
void px_board_delay_init(void)
Initialise Timer 6 with 1 us clock ticks for delay use.
Definition: px_board.c:225
Set pin mode to analog.
Definition: px_gpio.h:58
void px_board_buzzer_on(uint16_t freq_hz)
Enable PWM output to piezo buzzer at specified frequency.
Definition: px_board.c:267
void px_gpio_port_init(const px_gpio_port_init_t *init)
Initialise a GPIO port.
Definition: px_gpio.c:103
#define PX_BOARD_PER_CLK_HZ
Peripheral clock frequency in Hz.
Definition: px_board.h:48
#define PX_GPIO_PIN_SET_HI(gpio)
Set GPIO pin output high.
Definition: px_gpio.h:220
void px_board_dbg_disable(void)
Disable DBG module.
Definition: px_board.c:322
void px_gpio_pullup_enable(const px_gpio_handle_t *gpio)
Enable pull-up on GPIO pin.
Definition: px_gpio.h:473