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 "stm32l1xx.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
36 #if defined( SX1261MBXBAS ) || defined( SX1262MBXCAS ) || defined( SX1262MBXDAS )
37 #include "sx126x-board.h"
38 #elif defined( LR1110MB1XXS )
39 #include "lr1110-board.h"
40 #elif defined( SX1272MB2DAS)
41 #include "sx1272-board.h"
42 #elif defined( SX1276MB1LAS ) || defined( SX1276MB1MAS )
43 #include "sx1276-board.h"
44 #endif
45 #include "board.h"
46
47 /*!
48 * Unique Devices IDs register set ( STM32L152x )
49 */
50 #define ID1 ( 0x1FF800D0 )
51 #define ID2 ( 0x1FF800D4 )
52 #define ID3 ( 0x1FF800E4 )
53
54 /*!
55 * LED GPIO pins objects
56 */
57 Gpio_t Led1;
58 Gpio_t Led2;
59
60 /*
61 * MCU objects
62 */
63 Adc_t Adc;
64 Uart_t Uart2;
65
66 #if defined( LR1110MB1XXS )
67 extern lr1110_t LR1110;
68 #endif
69
70 /*!
71 * Initializes the unused GPIO to a know status
72 */
73 static void BoardUnusedIoInit( void );
74
75 /*!
76 * System Clock Configuration
77 */
78 static void SystemClockConfig( void );
79
80 /*!
81 * System Clock Re-Configuration when waking up from STOP mode
82 */
83 static void SystemClockReConfig( void );
84
85 /*!
86 * Flag to indicate if the MCU is Initialized
87 */
88 static bool McuInitialized = false;
89
90 /*!
91 * Flag used to indicate if board is powered from the USB
92 */
93 static bool UsbIsConnected = false;
94
95 /*!
96 * UART2 FIFO buffers size
97 */
98 #define UART2_FIFO_TX_SIZE 1024
99 #define UART2_FIFO_RX_SIZE 1024
100
101 uint8_t Uart2TxBuffer[UART2_FIFO_TX_SIZE];
102 uint8_t Uart2RxBuffer[UART2_FIFO_RX_SIZE];
103
BoardCriticalSectionBegin(uint32_t * mask)104 void BoardCriticalSectionBegin( uint32_t *mask )
105 {
106 *mask = __get_PRIMASK( );
107 __disable_irq( );
108 }
109
BoardCriticalSectionEnd(uint32_t * mask)110 void BoardCriticalSectionEnd( uint32_t *mask )
111 {
112 __set_PRIMASK( *mask );
113 }
114
BoardInitPeriph(void)115 void BoardInitPeriph( void )
116 {
117
118 }
119
BoardInitMcu(void)120 void BoardInitMcu( void )
121 {
122 if( McuInitialized == false )
123 {
124 HAL_Init( );
125
126 // LEDs
127 GpioInit( &Led1, LED_1, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
128 GpioInit( &Led2, LED_2, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
129
130 SystemClockConfig( );
131
132 UsbIsConnected = true;
133
134 FifoInit( &Uart2.FifoTx, Uart2TxBuffer, UART2_FIFO_TX_SIZE );
135 FifoInit( &Uart2.FifoRx, Uart2RxBuffer, UART2_FIFO_RX_SIZE );
136 // Configure your terminal for 8 Bits data (7 data bit + 1 parity bit), no parity and no flow ctrl
137 UartInit( &Uart2, UART_2, UART_TX, UART_RX );
138 UartConfig( &Uart2, RX_TX, 921600, UART_8_BIT, UART_1_STOP_BIT, NO_PARITY, NO_FLOW_CTRL );
139
140 RtcInit( );
141
142 BoardUnusedIoInit( );
143 if( GetBoardPowerSource( ) == BATTERY_POWER )
144 {
145 // Disables OFF mode - Enables lowest power mode (STOP)
146 LpmSetOffMode( LPM_APPLI_ID, LPM_DISABLE );
147 }
148 }
149 else
150 {
151 SystemClockReConfig( );
152 }
153
154 AdcInit( &Adc, NC ); // Just initialize ADC
155
156 #if defined( SX1261MBXBAS ) || defined( SX1262MBXCAS ) || defined( SX1262MBXDAS )
157 SpiInit( &SX126x.Spi, SPI_1, RADIO_MOSI, RADIO_MISO, RADIO_SCLK, NC );
158 SX126xIoInit( );
159 #elif defined( LR1110MB1XXS )
160 SpiInit( &LR1110.spi, SPI_1, RADIO_MOSI, RADIO_MISO, RADIO_SCLK, NC );
161 lr1110_board_init_io( &LR1110 );
162 #elif defined( SX1272MB2DAS )
163 SpiInit( &SX1272.Spi, SPI_1, RADIO_MOSI, RADIO_MISO, RADIO_SCLK, NC );
164 SX1272IoInit( );
165 #elif defined( SX1276MB1LAS ) || defined( SX1276MB1MAS )
166 SpiInit( &SX1276.Spi, SPI_1, RADIO_MOSI, RADIO_MISO, RADIO_SCLK, NC );
167 SX1276IoInit( );
168 #endif
169
170 if( McuInitialized == false )
171 {
172 McuInitialized = true;
173 #if defined( SX1261MBXBAS ) || defined( SX1262MBXCAS ) || defined( SX1262MBXDAS )
174 SX126xIoDbgInit( );
175 // WARNING: If necessary the TCXO control is initialized by SX126xInit function.
176 #elif defined( LR1110MB1XXS )
177 lr1110_board_init_dbg_io( &LR1110 );
178 // WARNING: If necessary the TCXO control is initialized by SX126xInit function.
179 #elif defined( SX1272MB2DAS )
180 SX1272IoDbgInit( );
181 SX1272IoTcxoInit( );
182 #elif defined( SX1276MB1LAS ) || defined( SX1276MB1MAS )
183 SX1276IoDbgInit( );
184 SX1276IoTcxoInit( );
185 #endif
186 }
187 }
188
BoardResetMcu(void)189 void BoardResetMcu( void )
190 {
191 CRITICAL_SECTION_BEGIN( );
192
193 //Restart system
194 NVIC_SystemReset( );
195 }
196
BoardDeInitMcu(void)197 void BoardDeInitMcu( void )
198 {
199 AdcDeInit( &Adc );
200
201 #if defined( SX1261MBXBAS ) || defined( SX1262MBXCAS ) || defined( SX1262MBXDAS )
202 SpiDeInit( &SX126x.Spi );
203 SX126xIoDeInit( );
204 #elif defined( LR1110MB1XXS )
205 SpiDeInit( &LR1110.spi );
206 lr1110_board_deinit_io( &LR1110 );
207 #elif defined( SX1272MB2DAS )
208 SpiDeInit( &SX1272.Spi );
209 SX1272IoDeInit( );
210 #elif defined( SX1276MB1LAS ) || defined( SX1276MB1MAS )
211 SpiDeInit( &SX1276.Spi );
212 SX1276IoDeInit( );
213 #endif
214 }
215
BoardGetRandomSeed(void)216 uint32_t BoardGetRandomSeed( void )
217 {
218 return ( ( *( uint32_t* )ID1 ) ^ ( *( uint32_t* )ID2 ) ^ ( *( uint32_t* )ID3 ) );
219 }
220
BoardGetUniqueId(uint8_t * id)221 void BoardGetUniqueId( uint8_t *id )
222 {
223 id[7] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 24;
224 id[6] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 16;
225 id[5] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 8;
226 id[4] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) );
227 id[3] = ( ( *( uint32_t* )ID2 ) ) >> 24;
228 id[2] = ( ( *( uint32_t* )ID2 ) ) >> 16;
229 id[1] = ( ( *( uint32_t* )ID2 ) ) >> 8;
230 id[0] = ( ( *( uint32_t* )ID2 ) );
231 }
232
233 /*!
234 * Factory power supply
235 */
236 #define VDDA_VREFINT_CAL ( ( uint32_t ) 3000 ) // mV
237
238 /*!
239 * VREF calibration value
240 */
241 #define VREFINT_CAL ( *( uint16_t* ) ( ( uint32_t ) 0x1FF800F8 ) )
242
243 /*
244 * Internal temperature sensor, parameter TS_CAL1: TS ADC raw data acquired at
245 * a temperature of 110 DegC (+-5 DegC), VDDA = 3.3 V (+-10 mV).
246 */
247 #define TEMP30_CAL_ADDR ( *( uint16_t* ) ( ( uint32_t ) 0x1FF8007A ) )
248
249 /* Internal temperature sensor, parameter TS_CAL2: TS ADC raw data acquired at
250 *a temperature of 30 DegC (+-5 DegC), VDDA = 3.3 V (+-10 mV). */
251 #define TEMP110_CAL_ADDR ( *( uint16_t* ) ( ( uint32_t ) 0x1FF8007E ) )
252
253 /* Vdda value with which temperature sensor has been calibrated in production
254 (+-10 mV). */
255 #define VDDA_TEMP_CAL ( ( uint32_t ) 3000 )
256
257 /*!
258 * Battery thresholds
259 */
260 #define BATTERY_MAX_LEVEL 3000 // mV
261 #define BATTERY_MIN_LEVEL 2400 // mV
262 #define BATTERY_SHUTDOWN_LEVEL 2300 // mV
263
264 #define BATTERY_LORAWAN_UNKNOWN_LEVEL 255
265 #define BATTERY_LORAWAN_MAX_LEVEL 254
266 #define BATTERY_LORAWAN_MIN_LEVEL 1
267 #define BATTERY_LORAWAN_EXT_PWR 0
268
269 #define COMPUTE_TEMPERATURE( TS_ADC_DATA, VDDA_APPLI ) \
270 ( ( ( ( ( ( ( int32_t )( ( TS_ADC_DATA * VDDA_APPLI ) / VDDA_TEMP_CAL ) - ( int32_t ) TEMP30_CAL_ADDR ) ) * \
271 ( int32_t )( 110 - 30 ) ) \
272 << 8 ) / \
273 ( int32_t )( TEMP110_CAL_ADDR - TEMP30_CAL_ADDR ) ) + \
274 ( 30 << 8 ) )
275
276 static uint16_t BatteryVoltage = BATTERY_MAX_LEVEL;
277
BoardBatteryMeasureVoltage(void)278 uint16_t BoardBatteryMeasureVoltage( void )
279 {
280 uint16_t vref = 0;
281
282 // Read the current Voltage
283 vref = AdcReadChannel( &Adc, ADC_CHANNEL_VREFINT );
284
285 // Compute and return the Voltage in millivolt
286 return ( ( ( uint32_t ) VDDA_VREFINT_CAL * VREFINT_CAL ) / vref );
287 }
288
BoardGetBatteryVoltage(void)289 uint32_t BoardGetBatteryVoltage( void )
290 {
291 return BatteryVoltage;
292 }
293
BoardGetBatteryLevel(void)294 uint8_t BoardGetBatteryLevel( void )
295 {
296 uint8_t batteryLevel = 0;
297
298 BatteryVoltage = BoardBatteryMeasureVoltage( );
299
300 if( GetBoardPowerSource( ) == USB_POWER )
301 {
302 batteryLevel = BATTERY_LORAWAN_EXT_PWR;
303 }
304 else
305 {
306 if( BatteryVoltage >= BATTERY_MAX_LEVEL )
307 {
308 batteryLevel = BATTERY_LORAWAN_MAX_LEVEL;
309 }
310 else if( ( BatteryVoltage > BATTERY_MIN_LEVEL ) && ( BatteryVoltage < BATTERY_MAX_LEVEL ) )
311 {
312 batteryLevel =
313 ( ( 253 * ( BatteryVoltage - BATTERY_MIN_LEVEL ) ) / ( BATTERY_MAX_LEVEL - BATTERY_MIN_LEVEL ) ) + 1;
314 }
315 else if( ( BatteryVoltage > BATTERY_SHUTDOWN_LEVEL ) && ( BatteryVoltage <= BATTERY_MIN_LEVEL ) )
316 {
317 batteryLevel = 1;
318 }
319 else // if( BatteryVoltage <= BATTERY_SHUTDOWN_LEVEL )
320 {
321 batteryLevel = BATTERY_LORAWAN_UNKNOWN_LEVEL;
322 }
323 }
324 return batteryLevel;
325 }
326
BoardGetTemperature(void)327 int16_t BoardGetTemperature( void )
328 {
329 uint16_t tempRaw = 0;
330
331 BatteryVoltage = BoardBatteryMeasureVoltage( );
332
333 tempRaw = AdcReadChannel( &Adc, ADC_CHANNEL_TEMPSENSOR );
334
335 // Compute and return the temperature in degree celcius * 256
336 return ( int16_t ) COMPUTE_TEMPERATURE( tempRaw, BatteryVoltage );
337 }
338
BoardUnusedIoInit(void)339 static void BoardUnusedIoInit( void )
340 {
341 HAL_DBGMCU_EnableDBGSleepMode( );
342 HAL_DBGMCU_EnableDBGStopMode( );
343 HAL_DBGMCU_EnableDBGStandbyMode( );
344 }
345
SystemClockConfig(void)346 void SystemClockConfig( void )
347 {
348 RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
349 RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
350 RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };
351
352 __HAL_RCC_PWR_CLK_ENABLE( );
353
354 __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 );
355
356 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE;
357 RCC_OscInitStruct.HSEState = RCC_HSE_OFF;
358 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
359 RCC_OscInitStruct.LSEState = RCC_LSE_ON;
360 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
361 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
362 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
363 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
364 RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV3;
365 if( HAL_RCC_OscConfig( &RCC_OscInitStruct ) != HAL_OK )
366 {
367 assert_param( LMN_STATUS_ERROR );
368 }
369
370 RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
371 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
372 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
373 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
374 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
375 if( HAL_RCC_ClockConfig( &RCC_ClkInitStruct, FLASH_LATENCY_1 ) != HAL_OK )
376 {
377 assert_param( LMN_STATUS_ERROR );
378 }
379
380 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
381 PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
382 if( HAL_RCCEx_PeriphCLKConfig( &PeriphClkInit ) != HAL_OK )
383 {
384 assert_param( LMN_STATUS_ERROR );
385 }
386
387 HAL_SYSTICK_Config( HAL_RCC_GetHCLKFreq( ) / 1000 );
388
389 HAL_SYSTICK_CLKSourceConfig( SYSTICK_CLKSOURCE_HCLK );
390
391 // SysTick_IRQn interrupt configuration
392 HAL_NVIC_SetPriority( SysTick_IRQn, 0, 0 );
393 }
394
SystemClockReConfig(void)395 void SystemClockReConfig( void )
396 {
397 __HAL_RCC_PWR_CLK_ENABLE( );
398 __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 );
399
400 // Enable HSI
401 __HAL_RCC_HSI_ENABLE( );
402
403 // Wait till HSI is ready
404 while( __HAL_RCC_GET_FLAG( RCC_FLAG_HSIRDY ) == RESET )
405 {
406 }
407
408 // Enable PLL
409 __HAL_RCC_PLL_ENABLE( );
410
411 // Wait till PLL is ready
412 while( __HAL_RCC_GET_FLAG( RCC_FLAG_PLLRDY ) == RESET )
413 {
414 }
415
416 // Select PLL as system clock source
417 __HAL_RCC_SYSCLK_CONFIG ( RCC_SYSCLKSOURCE_PLLCLK );
418
419 // Wait till PLL is used as system clock source
420 while( __HAL_RCC_GET_SYSCLK_SOURCE( ) != RCC_SYSCLKSOURCE_STATUS_PLLCLK )
421 {
422 }
423 }
424
SysTick_Handler(void)425 void SysTick_Handler( void )
426 {
427 HAL_IncTick( );
428 HAL_SYSTICK_IRQHandler( );
429 }
430
GetBoardPowerSource(void)431 uint8_t GetBoardPowerSource( void )
432 {
433 if( UsbIsConnected == false )
434 {
435 return BATTERY_POWER;
436 }
437 else
438 {
439 return USB_POWER;
440 }
441 }
442
443 /**
444 * \brief Enters Low Power Stop Mode
445 *
446 * \note ARM exists the function when waking up
447 */
LpmEnterStopMode(void)448 void LpmEnterStopMode( void)
449 {
450 CRITICAL_SECTION_BEGIN( );
451
452 BoardDeInitMcu( );
453
454 // Disable the Power Voltage Detector
455 HAL_PWR_DisablePVD( );
456
457 // Clear wake up flag
458 SET_BIT( PWR->CR, PWR_CR_CWUF );
459
460 // Enable Ultra low power mode
461 HAL_PWREx_EnableUltraLowPower( );
462
463 // Enable the fast wake up from Ultra low power mode
464 HAL_PWREx_EnableFastWakeUp( );
465
466 CRITICAL_SECTION_END( );
467
468 // Enter Stop Mode
469 HAL_PWR_EnterSTOPMode( PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI );
470 }
471
472 /*!
473 * \brief Exists Low Power Stop Mode
474 */
LpmExitStopMode(void)475 void LpmExitStopMode( void )
476 {
477 // Disable IRQ while the MCU is not running on HSI
478 CRITICAL_SECTION_BEGIN( );
479
480 // Initilizes the peripherals
481 BoardInitMcu( );
482
483 CRITICAL_SECTION_END( );
484 }
485
486 /*!
487 * \brief Enters Low Power Sleep Mode
488 *
489 * \note ARM exits the function when waking up
490 */
LpmEnterSleepMode(void)491 void LpmEnterSleepMode( void)
492 {
493 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
494 }
495
BoardLowPowerHandler(void)496 void BoardLowPowerHandler( void )
497 {
498 __disable_irq( );
499 /*!
500 * If an interrupt has occurred after __disable_irq( ), it is kept pending
501 * and cortex will not enter low power anyway
502 */
503
504 LpmEnterLowPower( );
505
506 __enable_irq( );
507 }
508
509 #if !defined ( __CC_ARM )
510
511 /*
512 * Function to be used by stdout for printf etc
513 */
_write(int fd,const void * buf,size_t count)514 int _write( int fd, const void *buf, size_t count )
515 {
516 while( UartPutBuffer( &Uart2, ( uint8_t* )buf, ( uint16_t )count ) != 0 ){ };
517 return count;
518 }
519
520 /*
521 * Function to be used by stdin for scanf etc
522 */
_read(int fd,const void * buf,size_t count)523 int _read( int fd, const void *buf, size_t count )
524 {
525 size_t bytesRead = 0;
526 while( UartGetBuffer( &Uart2, ( uint8_t* )buf, count, ( uint16_t* )&bytesRead ) != 0 ){ };
527 // Echo back the character
528 while( UartPutBuffer( &Uart2, ( uint8_t* )buf, ( uint16_t )bytesRead ) != 0 ){ };
529 return bytesRead;
530 }
531
532 #else
533
534 #include <stdio.h>
535
536 // Keil compiler
fputc(int c,FILE * stream)537 int fputc( int c, FILE *stream )
538 {
539 while( UartPutChar( &Uart2, ( uint8_t )c ) != 0 );
540 return c;
541 }
542
fgetc(FILE * stream)543 int fgetc( FILE *stream )
544 {
545 uint8_t c = 0;
546 while( UartGetChar( &Uart2, &c ) != 0 );
547 // Echo back the character
548 while( UartPutChar( &Uart2, c ) != 0 );
549 return ( int )c;
550 }
551
552 #endif
553
554 #ifdef USE_FULL_ASSERT
555
556 #include <stdio.h>
557
558 /*
559 * Function Name : assert_failed
560 * Description : Reports the name of the source file and the source line number
561 * where the assert_param error has occurred.
562 * Input : - file: pointer to the source file name
563 * - line: assert_param error line source number
564 * Output : None
565 * Return : None
566 */
assert_failed(uint8_t * file,uint32_t line)567 void assert_failed( uint8_t* file, uint32_t line )
568 {
569 /* User can add his own implementation to report the file name and line number,
570 ex: printf("Wrong parameters value: file %s on line %lu\n", file, line) */
571
572 printf( "Wrong parameters value: file %s on line %lu\n", ( const char* )file, line );
573 /* Infinite loop */
574 while( 1 )
575 {
576 }
577 }
578 #endif
579