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