1 /*!
2 * \file board.c
3 *
4 * \brief Target board general functions implementation
5 *
6 * \copyright Revised BSD License, see section \ref LICENSE.
7 *
8 * \code
9 * ______ _
10 * / _____) _ | |
11 * ( (____ _____ ____ _| |_ _____ ____| |__
12 * \____ \| ___ | (_ _) ___ |/ ___) _ \
13 * _____) ) ____| | | || |_| ____( (___| | | |
14 * (______/|_____)_|_|_| \__)_____)\____)_| |_|
15 * (C)2013-2017 Semtech
16 *
17 * \endcode
18 *
19 * \author Miguel Luis ( Semtech )
20 *
21 * \author Gregory Cristian ( Semtech )
22 */
23 #include "stm32l0xx.h"
24 #include "utilities.h"
25 #include "gpio.h"
26 #include "adc.h"
27 #include "spi.h"
28 #include "i2c.h"
29 #include "uart.h"
30 #include "timer.h"
31 #include "sysIrqHandlers.h"
32 #include "board-config.h"
33 #include "lpm-board.h"
34 #include "rtc-board.h"
35 #include "sx1276-board.h"
36 #include "board.h"
37
38 /*!
39 * Unique Devices IDs register set ( STM32L0xxx )
40 */
41 #define ID1 ( 0x1FF80050 )
42 #define ID2 ( 0x1FF80054 )
43 #define ID3 ( 0x1FF80064 )
44
45 /*!
46 * LED GPIO pins objects
47 */
48 Gpio_t Led1;
49 Gpio_t Led2;
50 Gpio_t Led3;
51 Gpio_t Led4;
52
53 /*
54 * MCU objects
55 */
56 Uart_t Uart2;
57
58 /*!
59 * Initializes the unused GPIO to a know status
60 */
61 static void BoardUnusedIoInit( void );
62
63 /*!
64 * System Clock Configuration
65 */
66 static void SystemClockConfig( void );
67
68 /*!
69 * System Clock Re-Configuration when waking up from STOP mode
70 */
71 static void SystemClockReConfig( void );
72
73 /*!
74 * Flag to indicate if the MCU is Initialized
75 */
76 static bool McuInitialized = false;
77
78 /*!
79 * Flag used to indicate if board is powered from the USB
80 */
81 static bool UsbIsConnected = false;
82
83 /*!
84 * UART2 FIFO buffers size
85 */
86 #define UART2_FIFO_TX_SIZE 1024
87 #define UART2_FIFO_RX_SIZE 1024
88
89 uint8_t Uart2TxBuffer[UART2_FIFO_TX_SIZE];
90 uint8_t Uart2RxBuffer[UART2_FIFO_RX_SIZE];
91
BoardCriticalSectionBegin(uint32_t * mask)92 void BoardCriticalSectionBegin( uint32_t *mask )
93 {
94 *mask = __get_PRIMASK( );
95 __disable_irq( );
96 }
97
BoardCriticalSectionEnd(uint32_t * mask)98 void BoardCriticalSectionEnd( uint32_t *mask )
99 {
100 __set_PRIMASK( *mask );
101 }
102
BoardInitPeriph(void)103 void BoardInitPeriph( void )
104 {
105
106 }
107
BoardInitMcu(void)108 void BoardInitMcu( void )
109 {
110 if( McuInitialized == false )
111 {
112 HAL_Init( );
113
114 // LEDs
115 GpioInit( &Led1, LED_1, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
116 GpioInit( &Led2, LED_2, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
117 GpioInit( &Led3, LED_3, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
118 GpioInit( &Led4, LED_4, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
119
120 SystemClockConfig( );
121
122 UsbIsConnected = true;
123
124 FifoInit( &Uart2.FifoTx, Uart2TxBuffer, UART2_FIFO_TX_SIZE );
125 FifoInit( &Uart2.FifoRx, Uart2RxBuffer, UART2_FIFO_RX_SIZE );
126 // Configure your terminal for 8 Bits data (7 data bit + 1 parity bit), no parity and no flow ctrl
127 UartInit( &Uart2, UART_2, UART_TX, UART_RX );
128 UartConfig( &Uart2, RX_TX, 921600, UART_8_BIT, UART_1_STOP_BIT, NO_PARITY, NO_FLOW_CTRL );
129
130 RtcInit( );
131
132 GpioWrite( &Led1, 0 );
133 GpioWrite( &Led2, 0 );
134 GpioWrite( &Led3, 0 );
135 GpioWrite( &Led4, 0 );
136
137 BoardUnusedIoInit( );
138 if( GetBoardPowerSource( ) == BATTERY_POWER )
139 {
140 // Disables OFF mode - Enables lowest power mode (STOP)
141 LpmSetOffMode( LPM_APPLI_ID, LPM_DISABLE );
142 }
143 }
144 else
145 {
146 SystemClockReConfig( );
147 }
148
149 SpiInit( &SX1276.Spi, SPI_1, RADIO_MOSI, RADIO_MISO, RADIO_SCLK, NC );
150 SX1276IoInit( );
151
152 if( McuInitialized == false )
153 {
154 McuInitialized = true;
155 SX1276IoDbgInit( );
156 SX1276IoTcxoInit( );
157 }
158 }
159
BoardResetMcu(void)160 void BoardResetMcu( void )
161 {
162 CRITICAL_SECTION_BEGIN( );
163
164 //Restart system
165 NVIC_SystemReset( );
166 }
167
BoardDeInitMcu(void)168 void BoardDeInitMcu( void )
169 {
170 SpiDeInit( &SX1276.Spi );
171 SX1276IoDeInit( );
172 }
173
BoardGetRandomSeed(void)174 uint32_t BoardGetRandomSeed( void )
175 {
176 return ( ( *( uint32_t* )ID1 ) ^ ( *( uint32_t* )ID2 ) ^ ( *( uint32_t* )ID3 ) );
177 }
178
BoardGetUniqueId(uint8_t * id)179 void BoardGetUniqueId( uint8_t *id )
180 {
181 id[7] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 24;
182 id[6] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 16;
183 id[5] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 8;
184 id[4] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) );
185 id[3] = ( ( *( uint32_t* )ID2 ) ) >> 24;
186 id[2] = ( ( *( uint32_t* )ID2 ) ) >> 16;
187 id[1] = ( ( *( uint32_t* )ID2 ) ) >> 8;
188 id[0] = ( ( *( uint32_t* )ID2 ) );
189 }
190
BoardBatteryMeasureVoltage(void)191 uint16_t BoardBatteryMeasureVoltage( void )
192 {
193 return 0;
194 }
195
BoardGetBatteryVoltage(void)196 uint32_t BoardGetBatteryVoltage( void )
197 {
198 return 0;
199 }
200
BoardGetBatteryLevel(void)201 uint8_t BoardGetBatteryLevel( void )
202 {
203 return 0;
204 }
205
BoardUnusedIoInit(void)206 static void BoardUnusedIoInit( void )
207 {
208 HAL_DBGMCU_EnableDBGSleepMode( );
209 HAL_DBGMCU_EnableDBGStopMode( );
210 HAL_DBGMCU_EnableDBGStandbyMode( );
211 }
212
SystemClockConfig(void)213 void SystemClockConfig( void )
214 {
215 RCC_OscInitTypeDef RCC_OscInitStruct;
216 RCC_ClkInitTypeDef RCC_ClkInitStruct;
217 RCC_PeriphCLKInitTypeDef PeriphClkInit;
218
219 __HAL_RCC_PWR_CLK_ENABLE( );
220
221 __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 );
222
223 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE;
224 RCC_OscInitStruct.HSEState = RCC_HSE_OFF;
225 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
226 RCC_OscInitStruct.LSEState = RCC_LSE_ON;
227 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
228 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
229 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
230 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_6;
231 RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_3;
232 if( HAL_RCC_OscConfig( &RCC_OscInitStruct ) != HAL_OK )
233 {
234 assert_param( LMN_STATUS_ERROR );
235 }
236
237 RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
238 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
239 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
240 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
241 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
242 if( HAL_RCC_ClockConfig( &RCC_ClkInitStruct, FLASH_LATENCY_1 ) != HAL_OK )
243 {
244 assert_param( LMN_STATUS_ERROR );
245 }
246
247 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
248 PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
249 if( HAL_RCCEx_PeriphCLKConfig( &PeriphClkInit ) != HAL_OK )
250 {
251 assert_param( LMN_STATUS_ERROR );
252 }
253
254 HAL_SYSTICK_Config( HAL_RCC_GetHCLKFreq( ) / 1000 );
255
256 HAL_SYSTICK_CLKSourceConfig( SYSTICK_CLKSOURCE_HCLK );
257
258 // SysTick_IRQn interrupt configuration
259 HAL_NVIC_SetPriority( SysTick_IRQn, 0, 0 );
260 }
261
SystemClockReConfig(void)262 void SystemClockReConfig( void )
263 {
264 __HAL_RCC_PWR_CLK_ENABLE( );
265 __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 );
266
267 // Enable HSI
268 __HAL_RCC_HSI_CONFIG( RCC_HSI_ON );
269
270 // Wait till HSI is ready
271 while( __HAL_RCC_GET_FLAG( RCC_FLAG_HSIRDY ) == RESET )
272 {
273 }
274
275 // Enable PLL
276 __HAL_RCC_PLL_ENABLE( );
277
278 // Wait till PLL is ready
279 while( __HAL_RCC_GET_FLAG( RCC_FLAG_PLLRDY ) == RESET )
280 {
281 }
282
283 // Select PLL as system clock source
284 __HAL_RCC_SYSCLK_CONFIG ( RCC_SYSCLKSOURCE_PLLCLK );
285
286 // Wait till PLL is used as system clock source
287 while( __HAL_RCC_GET_SYSCLK_SOURCE( ) != RCC_SYSCLKSOURCE_STATUS_PLLCLK )
288 {
289 }
290 }
291
SysTick_Handler(void)292 void SysTick_Handler( void )
293 {
294 HAL_IncTick( );
295 HAL_SYSTICK_IRQHandler( );
296 }
297
GetBoardPowerSource(void)298 uint8_t GetBoardPowerSource( void )
299 {
300 if( UsbIsConnected == false )
301 {
302 return BATTERY_POWER;
303 }
304 else
305 {
306 return USB_POWER;
307 }
308 }
309
310 /**
311 * \brief Enters Low Power Stop Mode
312 *
313 * \note ARM exists the function when waking up
314 */
LpmEnterStopMode(void)315 void LpmEnterStopMode( void)
316 {
317 CRITICAL_SECTION_BEGIN( );
318
319 BoardDeInitMcu( );
320
321 // Disable the Power Voltage Detector
322 HAL_PWR_DisablePVD( );
323
324 // Clear wake up flag
325 SET_BIT( PWR->CR, PWR_CR_CWUF );
326
327 // Enable Ultra low power mode
328 HAL_PWREx_EnableUltraLowPower( );
329
330 // Enable the fast wake up from Ultra low power mode
331 HAL_PWREx_EnableFastWakeUp( );
332
333 CRITICAL_SECTION_END( );
334
335 // Enter Stop Mode
336 HAL_PWR_EnterSTOPMode( PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI );
337 }
338
339 /*!
340 * \brief Exists Low Power Stop Mode
341 */
LpmExitStopMode(void)342 void LpmExitStopMode( void )
343 {
344 // Disable IRQ while the MCU is not running on HSI
345 CRITICAL_SECTION_BEGIN( );
346
347 // Initilizes the peripherals
348 BoardInitMcu( );
349
350 CRITICAL_SECTION_END( );
351 }
352
353 /*!
354 * \brief Enters Low Power Sleep Mode
355 *
356 * \note ARM exits the function when waking up
357 */
LpmEnterSleepMode(void)358 void LpmEnterSleepMode( void)
359 {
360 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
361 }
362
BoardLowPowerHandler(void)363 void BoardLowPowerHandler( void )
364 {
365 __disable_irq( );
366 /*!
367 * If an interrupt has occurred after __disable_irq( ), it is kept pending
368 * and cortex will not enter low power anyway
369 */
370
371 LpmEnterLowPower( );
372
373 __enable_irq( );
374 }
375
376 #if !defined ( __CC_ARM )
377
378 /*
379 * Function to be used by stdout for printf etc
380 */
_write(int fd,const void * buf,size_t count)381 int _write( int fd, const void *buf, size_t count )
382 {
383 while( UartPutBuffer( &Uart2, ( uint8_t* )buf, ( uint16_t )count ) != 0 ){ };
384 return count;
385 }
386
387 /*
388 * Function to be used by stdin for scanf etc
389 */
_read(int fd,const void * buf,size_t count)390 int _read( int fd, const void *buf, size_t count )
391 {
392 size_t bytesRead = 0;
393 while( UartGetBuffer( &Uart2, ( uint8_t* )buf, count, ( uint16_t* )&bytesRead ) != 0 ){ };
394 // Echo back the character
395 while( UartPutBuffer( &Uart2, ( uint8_t* )buf, ( uint16_t )bytesRead ) != 0 ){ };
396 return bytesRead;
397 }
398
399 #else
400
401 #include <stdio.h>
402
403 // Keil compiler
fputc(int c,FILE * stream)404 int fputc( int c, FILE *stream )
405 {
406 while( UartPutChar( &Uart2, ( uint8_t )c ) != 0 );
407 return c;
408 }
409
fgetc(FILE * stream)410 int fgetc( FILE *stream )
411 {
412 uint8_t c = 0;
413 while( UartGetChar( &Uart2, &c ) != 0 );
414 // Echo back the character
415 while( UartPutChar( &Uart2, c ) != 0 );
416 return ( int )c;
417 }
418
419 #endif
420
421 #ifdef USE_FULL_ASSERT
422
423 #include <stdio.h>
424
425 /*
426 * Function Name : assert_failed
427 * Description : Reports the name of the source file and the source line number
428 * where the assert_param error has occurred.
429 * Input : - file: pointer to the source file name
430 * - line: assert_param error line source number
431 * Output : None
432 * Return : None
433 */
assert_failed(uint8_t * file,uint32_t line)434 void assert_failed( uint8_t* file, uint32_t line )
435 {
436 /* User can add his own implementation to report the file name and line number,
437 ex: printf("Wrong parameters value: file %s on line %lu\n", file, line) */
438
439 printf( "Wrong parameters value: file %s on line %lu\n", ( const char* )file, line );
440 /* Infinite loop */
441 while( 1 )
442 {
443 }
444 }
445 #endif
446