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 * \author Andreas Pella ( IMST GmbH )
24 */
25 #include "stm32l0xx.h"
26 #include "utilities.h"
27 #include "gpio.h"
28 #include "adc.h"
29 #include "spi.h"
30 #include "i2c.h"
31 #include "uart.h"
32 #include "timer.h"
33 #include "sysIrqHandlers.h"
34 #include "board-config.h"
35 #include "lpm-board.h"
36 #include "rtc-board.h"
37 #include "sx1272-board.h"
38 #include "board.h"
39
40 /*!
41 * Unique Devices IDs register set ( STM32L0xxx )
42 */
43 #define ID1 ( 0x1FF80050 )
44 #define ID2 ( 0x1FF80054 )
45 #define ID3 ( 0x1FF80064 )
46
47 /*!
48 * LED GPIO pins objects
49 */
50 #if ( USE_POTENTIOMETER == 0 )
51 Gpio_t Led1;
52 #endif
53 Gpio_t Led2;
54 Gpio_t Led3;
55 Gpio_t Led4;
56
57 /*
58 * MCU objects
59 */
60 Adc_t Adc;
61 I2c_t I2c;
62 Uart_t Uart1;
63
64 /*!
65 * Initializes the unused GPIO to a know status
66 */
67 static void BoardUnusedIoInit( void );
68
69 /*!
70 * System Clock Configuration
71 */
72 static void SystemClockConfig( void );
73
74 /*!
75 * System Clock Re-Configuration when waking up from STOP mode
76 */
77 static void SystemClockReConfig( void );
78
79 /*!
80 * Flag to indicate if the MCU is Initialized
81 */
82 static bool McuInitialized = false;
83
84 /*!
85 * UART2 FIFO buffers size
86 */
87 #define UART1_FIFO_TX_SIZE 1024
88 #define UART1_FIFO_RX_SIZE 1024
89
90 uint8_t Uart1TxBuffer[UART1_FIFO_TX_SIZE];
91 uint8_t Uart1RxBuffer[UART1_FIFO_RX_SIZE];
92
BoardCriticalSectionBegin(uint32_t * mask)93 void BoardCriticalSectionBegin( uint32_t *mask )
94 {
95 *mask = __get_PRIMASK( );
96 __disable_irq( );
97 }
98
BoardCriticalSectionEnd(uint32_t * mask)99 void BoardCriticalSectionEnd( uint32_t *mask )
100 {
101 __set_PRIMASK( *mask );
102 }
103
BoardInitPeriph(void)104 void BoardInitPeriph( void )
105 {
106
107 }
108
BoardInitMcu(void)109 void BoardInitMcu( void )
110 {
111 if( McuInitialized == false )
112 {
113 HAL_Init( );
114
115 // LEDs
116 #if ( USE_POTENTIOMETER == 0 )
117 GpioInit( &Led1, LED_1, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
118 #endif
119 GpioInit( &Led2, LED_2, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
120 GpioInit( &Led3, LED_3, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
121 GpioInit( &Led4, LED_4, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
122
123 SystemClockConfig( );
124
125 FifoInit( &Uart1.FifoTx, Uart1TxBuffer, UART1_FIFO_TX_SIZE );
126 FifoInit( &Uart1.FifoRx, Uart1RxBuffer, UART1_FIFO_RX_SIZE );
127 // Configure your terminal for 8 Bits data (7 data bit + 1 parity bit), no parity and no flow ctrl
128 UartInit( &Uart1, UART_1, UART_TX, UART_RX );
129 UartConfig( &Uart1, RX_TX, 921600, UART_8_BIT, UART_1_STOP_BIT, NO_PARITY, NO_FLOW_CTRL );
130
131 RtcInit( );
132
133 // Switch LED 1, 2, 3, 4 OFF
134 #if ( USE_POTENTIOMETER == 0 )
135 GpioWrite( &Led1, 0 );
136 #endif
137 GpioWrite( &Led2, 0 );
138 GpioWrite( &Led3, 0 );
139 GpioWrite( &Led4, 0 );
140
141 BoardUnusedIoInit( );
142 if( GetBoardPowerSource( ) == BATTERY_POWER )
143 {
144 // Disables OFF mode - Enables lowest power mode (STOP)
145 LpmSetOffMode( LPM_APPLI_ID, LPM_DISABLE );
146 }
147 }
148 else
149 {
150 SystemClockReConfig( );
151 }
152
153 AdcInit( &Adc, POTI );
154
155 SpiInit( &SX1272.Spi, SPI_2, RADIO_MOSI, RADIO_MISO, RADIO_SCLK, NC );
156 SX1272IoInit( );
157
158 if( McuInitialized == false )
159 {
160 McuInitialized = true;
161 SX1272IoDbgInit( );
162 SX1272IoTcxoInit( );
163 }
164 }
165
BoardResetMcu(void)166 void BoardResetMcu( void )
167 {
168 CRITICAL_SECTION_BEGIN( );
169
170 //Restart system
171 NVIC_SystemReset( );
172 }
173
BoardDeInitMcu(void)174 void BoardDeInitMcu( void )
175 {
176 AdcDeInit( &Adc );
177
178 SpiDeInit( &SX1272.Spi );
179 SX1272IoDeInit( );
180 }
181
BoardGetRandomSeed(void)182 uint32_t BoardGetRandomSeed( void )
183 {
184 return ( ( *( uint32_t* )ID1 ) ^ ( *( uint32_t* )ID2 ) ^ ( *( uint32_t* )ID3 ) );
185 }
186
BoardGetUniqueId(uint8_t * id)187 void BoardGetUniqueId( uint8_t *id )
188 {
189 id[7] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 24;
190 id[6] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 16;
191 id[5] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 8;
192 id[4] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) );
193 id[3] = ( ( *( uint32_t* )ID2 ) ) >> 24;
194 id[2] = ( ( *( uint32_t* )ID2 ) ) >> 16;
195 id[1] = ( ( *( uint32_t* )ID2 ) ) >> 8;
196 id[0] = ( ( *( uint32_t* )ID2 ) );
197 }
198
199 /*!
200 * Potentiometer max and min levels definition
201 */
202 #define POTI_MAX_LEVEL 900
203 #define POTI_MIN_LEVEL 10
204
BoardGetPotiLevel(void)205 uint8_t BoardGetPotiLevel( void )
206 {
207 uint8_t potiLevel = 0;
208 uint16_t vpoti = 0;
209
210 // Read the current potentiometer setting
211 vpoti = AdcReadChannel( &Adc , ADC_CHANNEL_3 );
212
213 // check the limits
214 if( vpoti >= POTI_MAX_LEVEL )
215 {
216 potiLevel = 100;
217 }
218 else if( vpoti <= POTI_MIN_LEVEL )
219 {
220 potiLevel = 0;
221 }
222 else
223 {
224 // if the value is in the area, calculate the percentage value
225 potiLevel = ( ( vpoti - POTI_MIN_LEVEL ) * 100 ) / POTI_MAX_LEVEL;
226 }
227 return potiLevel;
228 }
229
230 /*!
231 * Factory power supply
232 */
233 #define FACTORY_POWER_SUPPLY 3300 // mV
234
235 /*!
236 * VREF calibration value
237 */
238 #define VREFINT_CAL ( *( uint16_t* )0x1FF80078 )
239
240 /*!
241 * ADC maximum value
242 */
243 #define ADC_MAX_VALUE 4095
244
245 /*!
246 * VREF bandgap value
247 */
248 #define ADC_VREF_BANDGAP 1224 // mV
249
250 /*!
251 * Battery thresholds
252 */
253 #define BATTERY_MAX_LEVEL 3000 // mV
254 #define BATTERY_MIN_LEVEL 2400 // mV
255 #define BATTERY_SHUTDOWN_LEVEL 2300 // mV
256
257 static uint16_t BatteryVoltage = BATTERY_MAX_LEVEL;
258
BoardBatteryMeasureVoltage(void)259 uint16_t BoardBatteryMeasureVoltage( void )
260 {
261 uint16_t vref = 0;
262 uint32_t batteryVoltage = 0;
263
264 // Read the current Voltage
265 vref = AdcReadChannel( &Adc , ADC_CHANNEL_17 );
266
267 // We don't use the VREF from calibValues here.
268 // calculate the Voltage in millivolt
269 batteryVoltage = ( uint32_t )ADC_VREF_BANDGAP * ( uint32_t )ADC_MAX_VALUE;
270 batteryVoltage = batteryVoltage / ( uint32_t )vref;
271
272 return batteryVoltage;
273 }
274
BoardGetBatteryVoltage(void)275 uint32_t BoardGetBatteryVoltage( void )
276 {
277 return BatteryVoltage;
278 }
279
BoardGetBatteryLevel(void)280 uint8_t BoardGetBatteryLevel( void )
281 {
282 uint8_t batteryLevel = 0;
283
284 BatteryVoltage = BoardBatteryMeasureVoltage( );
285
286 if( GetBoardPowerSource( ) == USB_POWER )
287 {
288 batteryLevel = 0;
289 }
290 else
291 {
292 if( BatteryVoltage >= BATTERY_MAX_LEVEL )
293 {
294 batteryLevel = 254;
295 }
296 else if( ( BatteryVoltage > BATTERY_MIN_LEVEL ) && ( BatteryVoltage < BATTERY_MAX_LEVEL ) )
297 {
298 batteryLevel = ( ( 253 * ( BatteryVoltage - BATTERY_MIN_LEVEL ) ) / ( BATTERY_MAX_LEVEL - BATTERY_MIN_LEVEL ) ) + 1;
299 }
300 else if( ( BatteryVoltage > BATTERY_SHUTDOWN_LEVEL ) && ( BatteryVoltage <= BATTERY_MIN_LEVEL ) )
301 {
302 batteryLevel = 1;
303 }
304 else //if( BatteryVoltage <= BATTERY_SHUTDOWN_LEVEL )
305 {
306 batteryLevel = 255;
307 }
308 }
309 return batteryLevel;
310 }
311
BoardUnusedIoInit(void)312 static void BoardUnusedIoInit( void )
313 {
314 HAL_DBGMCU_EnableDBGSleepMode( );
315 HAL_DBGMCU_EnableDBGStopMode( );
316 HAL_DBGMCU_EnableDBGStandbyMode( );
317 }
318
SystemClockConfig(void)319 void SystemClockConfig( void )
320 {
321 RCC_OscInitTypeDef RCC_OscInitStruct;
322 RCC_ClkInitTypeDef RCC_ClkInitStruct;
323 RCC_PeriphCLKInitTypeDef PeriphClkInit;
324
325 __HAL_RCC_SYSCFG_CLK_ENABLE( );
326 __HAL_RCC_PWR_CLK_ENABLE( );
327
328 __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 );
329
330 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_LSE;
331 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
332 RCC_OscInitStruct.LSEState = RCC_LSE_ON;
333 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
334 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
335 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_4;
336 RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
337 if( HAL_RCC_OscConfig( &RCC_OscInitStruct ) != HAL_OK )
338 {
339 assert_param( LMN_STATUS_ERROR );
340 }
341
342 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
343 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
344 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
345 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
346 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
347 if( HAL_RCC_ClockConfig( &RCC_ClkInitStruct, FLASH_LATENCY_1 ) != HAL_OK )
348 {
349 assert_param( LMN_STATUS_ERROR );
350 }
351
352 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1 | RCC_PERIPHCLK_RTC;
353 PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
354 PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
355 if( HAL_RCCEx_PeriphCLKConfig( &PeriphClkInit ) != HAL_OK )
356 {
357 assert_param( LMN_STATUS_ERROR );
358 }
359
360 HAL_SYSTICK_Config( HAL_RCC_GetHCLKFreq( ) / 1000 );
361
362 HAL_SYSTICK_CLKSourceConfig( SYSTICK_CLKSOURCE_HCLK );
363
364 // SysTick_IRQn interrupt configuration
365 HAL_NVIC_SetPriority( SysTick_IRQn, 0, 0 );
366 }
367
SystemClockReConfig(void)368 void SystemClockReConfig( void )
369 {
370 __HAL_RCC_PWR_CLK_ENABLE( );
371 __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 );
372
373 // Enable HSE
374 __HAL_RCC_HSE_CONFIG( RCC_HSE_ON );
375
376 // Wait till HSE is ready
377 while( __HAL_RCC_GET_FLAG( RCC_FLAG_HSERDY ) == RESET )
378 {
379 }
380
381 // Enable PLL
382 __HAL_RCC_PLL_ENABLE( );
383
384 // Wait till PLL is ready
385 while( __HAL_RCC_GET_FLAG( RCC_FLAG_PLLRDY ) == RESET )
386 {
387 }
388
389 // Select PLL as system clock source
390 __HAL_RCC_SYSCLK_CONFIG ( RCC_SYSCLKSOURCE_PLLCLK );
391
392 // Wait till PLL is used as system clock source
393 while( __HAL_RCC_GET_SYSCLK_SOURCE( ) != RCC_SYSCLKSOURCE_STATUS_PLLCLK )
394 {
395 }
396 }
397
SysTick_Handler(void)398 void SysTick_Handler( void )
399 {
400 HAL_IncTick( );
401 HAL_SYSTICK_IRQHandler( );
402 }
403
GetBoardPowerSource(void)404 uint8_t GetBoardPowerSource( void )
405 {
406 return USB_POWER;
407 }
408
409 /**
410 * \brief Enters Low Power Stop Mode
411 *
412 * \note ARM exists the function when waking up
413 */
LpmEnterStopMode(void)414 void LpmEnterStopMode( void)
415 {
416 CRITICAL_SECTION_BEGIN( );
417
418 BoardDeInitMcu( );
419
420 // Disable the Power Voltage Detector
421 HAL_PWR_DisablePVD( );
422
423 // Clear wake up flag
424 SET_BIT( PWR->CR, PWR_CR_CWUF );
425
426 // Enable Ultra low power mode
427 HAL_PWREx_EnableUltraLowPower( );
428
429 // Enable the fast wake up from Ultra low power mode
430 HAL_PWREx_EnableFastWakeUp( );
431
432 CRITICAL_SECTION_END( );
433
434 // Enter Stop Mode
435 HAL_PWR_EnterSTOPMode( PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI );
436 }
437
438 /*!
439 * \brief Exists Low Power Stop Mode
440 */
LpmExitStopMode(void)441 void LpmExitStopMode( void )
442 {
443 // Disable IRQ while the MCU is not running on HSI
444 CRITICAL_SECTION_BEGIN( );
445
446 // Initilizes the peripherals
447 BoardInitMcu( );
448
449 CRITICAL_SECTION_END( );
450 }
451
452 /*!
453 * \brief Enters Low Power Sleep Mode
454 *
455 * \note ARM exits the function when waking up
456 */
LpmEnterSleepMode(void)457 void LpmEnterSleepMode( void)
458 {
459 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
460 }
461
BoardLowPowerHandler(void)462 void BoardLowPowerHandler( void )
463 {
464 __disable_irq( );
465 /*!
466 * If an interrupt has occurred after __disable_irq( ), it is kept pending
467 * and cortex will not enter low power anyway
468 */
469
470 LpmEnterLowPower( );
471
472 __enable_irq( );
473 }
474
475 #if !defined ( __CC_ARM )
476
477 /*
478 * Function to be used by stdout for printf etc
479 */
_write(int fd,const void * buf,size_t count)480 int _write( int fd, const void *buf, size_t count )
481 {
482 while( UartPutBuffer( &Uart1, ( uint8_t* )buf, ( uint16_t )count ) != 0 ){ };
483 return count;
484 }
485
486 /*
487 * Function to be used by stdin for scanf etc
488 */
_read(int fd,const void * buf,size_t count)489 int _read( int fd, const void *buf, size_t count )
490 {
491 size_t bytesRead = 0;
492 while( UartGetBuffer( &Uart1, ( uint8_t* )buf, count, ( uint16_t* )&bytesRead ) != 0 ){ };
493 // Echo back the character
494 while( UartPutBuffer( &Uart1, ( uint8_t* )buf, ( uint16_t )bytesRead ) != 0 ){ };
495 return bytesRead;
496 }
497
498 #else
499
500 #include <stdio.h>
501
502 // Keil compiler
fputc(int c,FILE * stream)503 int fputc( int c, FILE *stream )
504 {
505 while( UartPutChar( &Uart1, ( uint8_t )c ) != 0 );
506 return c;
507 }
508
fgetc(FILE * stream)509 int fgetc( FILE *stream )
510 {
511 uint8_t c = 0;
512 while( UartGetChar( &Uart1, &c ) != 0 );
513 // Echo back the character
514 while( UartPutChar( &Uart1, c ) != 0 );
515 return ( int )c;
516 }
517
518 #endif
519
520 #ifdef USE_FULL_ASSERT
521
522 #include <stdio.h>
523
524 /*
525 * Function Name : assert_failed
526 * Description : Reports the name of the source file and the source line number
527 * where the assert_param error has occurred.
528 * Input : - file: pointer to the source file name
529 * - line: assert_param error line source number
530 * Output : None
531 * Return : None
532 */
assert_failed(uint8_t * file,uint32_t line)533 void assert_failed( uint8_t* file, uint32_t line )
534 {
535 /* User can add his own implementation to report the file name and line number,
536 ex: printf("Wrong parameters value: file %s on line %lu\n", file, line) */
537
538 printf( "Wrong parameters value: file %s on line %lu\n", ( const char* )file, line );
539 /* Infinite loop */
540 while( 1 )
541 {
542 }
543 }
544 #endif
545