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