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 "stm32l1xx.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 ( STM32L1xxx )
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_1, 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     Gpio_t ioPin;
177 
178     AdcDeInit( &Adc );
179 
180     SpiDeInit( &SX1272.Spi );
181     SX1272IoDeInit( );
182 
183     GpioInit( &ioPin, OSC_HSE_IN, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
184     GpioInit( &ioPin, OSC_HSE_OUT, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
185 
186     GpioInit( &ioPin, OSC_LSE_IN, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_DOWN, 1 );
187     GpioInit( &ioPin, OSC_LSE_OUT, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_DOWN, 1 );
188 }
189 
BoardGetRandomSeed(void)190 uint32_t BoardGetRandomSeed( void )
191 {
192     return ( ( *( uint32_t* )ID1 ) ^ ( *( uint32_t* )ID2 ) ^ ( *( uint32_t* )ID3 ) );
193 }
194 
BoardGetUniqueId(uint8_t * id)195 void BoardGetUniqueId( uint8_t *id )
196 {
197     id[7] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 24;
198     id[6] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 16;
199     id[5] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) ) >> 8;
200     id[4] = ( ( *( uint32_t* )ID1 )+ ( *( uint32_t* )ID3 ) );
201     id[3] = ( ( *( uint32_t* )ID2 ) ) >> 24;
202     id[2] = ( ( *( uint32_t* )ID2 ) ) >> 16;
203     id[1] = ( ( *( uint32_t* )ID2 ) ) >> 8;
204     id[0] = ( ( *( uint32_t* )ID2 ) );
205 }
206 
207 /*!
208  * Potentiometer max and min levels definition
209  */
210 #define POTI_MAX_LEVEL 900
211 #define POTI_MIN_LEVEL 10
212 
BoardGetPotiLevel(void)213 uint8_t BoardGetPotiLevel( void )
214 {
215     uint8_t potiLevel = 0;
216     uint16_t vpoti = 0;
217 
218     // Read the current potentiometer setting
219     vpoti = AdcReadChannel( &Adc , ADC_CHANNEL_3 );
220 
221     // check the limits
222     if( vpoti >= POTI_MAX_LEVEL )
223     {
224         potiLevel = 100;
225     }
226     else if( vpoti <= POTI_MIN_LEVEL )
227     {
228         potiLevel = 0;
229     }
230     else
231     {
232         // if the value is in the area, calculate the percentage value
233         potiLevel = ( ( vpoti - POTI_MIN_LEVEL ) * 100 ) / POTI_MAX_LEVEL;
234     }
235     return potiLevel;
236 }
237 
238 /*!
239  * Factory power supply
240  */
241 #define FACTORY_POWER_SUPPLY                        3300 // mV
242 
243 /*!
244  * VREF calibration value
245  */
246 #define VREFINT_CAL                                 ( *( uint16_t* )0x1FF800F8U )
247 
248 /*!
249  * ADC maximum value
250  */
251 #define ADC_MAX_VALUE                               4095
252 
253 /*!
254  * VREF bandgap value
255  */
256 #define ADC_VREF_BANDGAP                            1224 // mV
257 
258 /*!
259  * Battery thresholds
260  */
261 #define BATTERY_MAX_LEVEL                           3000 // mV
262 #define BATTERY_MIN_LEVEL                           2400 // mV
263 #define BATTERY_SHUTDOWN_LEVEL                      2300 // mV
264 
265 static uint16_t BatteryVoltage = BATTERY_MAX_LEVEL;
266 
BoardBatteryMeasureVoltage(void)267 uint16_t BoardBatteryMeasureVoltage( void )
268 {
269     uint16_t vref = 0;
270     uint32_t batteryVoltage = 0;
271 
272     // Read the current Voltage
273     vref = AdcReadChannel( &Adc , ADC_CHANNEL_17 );
274 
275     // We don't use the VREF from calibValues here.
276     // calculate the Voltage in millivolt
277     batteryVoltage = ( uint32_t )ADC_VREF_BANDGAP * ( uint32_t )ADC_MAX_VALUE;
278     batteryVoltage = batteryVoltage / ( uint32_t )vref;
279 
280     return batteryVoltage;
281 }
282 
BoardGetBatteryVoltage(void)283 uint32_t BoardGetBatteryVoltage( void )
284 {
285     return BatteryVoltage;
286 }
287 
BoardGetBatteryLevel(void)288 uint8_t BoardGetBatteryLevel( void )
289 {
290     uint8_t batteryLevel = 0;
291 
292     BatteryVoltage = BoardBatteryMeasureVoltage( );
293 
294     if( GetBoardPowerSource( ) == USB_POWER )
295     {
296         batteryLevel = 0;
297     }
298     else
299     {
300         if( BatteryVoltage >= BATTERY_MAX_LEVEL )
301         {
302             batteryLevel = 254;
303         }
304         else if( ( BatteryVoltage > BATTERY_MIN_LEVEL ) && ( BatteryVoltage < BATTERY_MAX_LEVEL ) )
305         {
306             batteryLevel = ( ( 253 * ( BatteryVoltage - BATTERY_MIN_LEVEL ) ) / ( BATTERY_MAX_LEVEL - BATTERY_MIN_LEVEL ) ) + 1;
307         }
308         else if( ( BatteryVoltage > BATTERY_SHUTDOWN_LEVEL ) && ( BatteryVoltage <= BATTERY_MIN_LEVEL ) )
309         {
310             batteryLevel = 1;
311         }
312         else //if( BatteryVoltage <= BATTERY_SHUTDOWN_LEVEL )
313         {
314             batteryLevel = 255;
315         }
316     }
317     return batteryLevel;
318 }
319 
BoardUnusedIoInit(void)320 static void BoardUnusedIoInit( void )
321 {
322     Gpio_t ioPin;
323 
324     if( GetBoardPowerSource( ) == BATTERY_POWER )
325     {
326         GpioInit( &ioPin, USB_DM, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
327         GpioInit( &ioPin, USB_DP, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
328     }
329 
330 #if defined( USE_DEBUGGER )
331     HAL_DBGMCU_EnableDBGSleepMode( );
332     HAL_DBGMCU_EnableDBGStopMode( );
333     HAL_DBGMCU_EnableDBGStandbyMode( );
334 #else
335     HAL_DBGMCU_DisableDBGSleepMode( );
336     HAL_DBGMCU_DisableDBGStopMode( );
337     HAL_DBGMCU_DisableDBGStandbyMode( );
338 
339     GpioInit( &ioPin, JTAG_TMS, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
340     GpioInit( &ioPin, JTAG_TCK, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
341     GpioInit( &ioPin, JTAG_TDI, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
342     GpioInit( &ioPin, JTAG_TDO, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
343     GpioInit( &ioPin, JTAG_NRST, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
344 #endif
345 }
346 
SystemClockConfig(void)347 void SystemClockConfig( void )
348 {
349     RCC_OscInitTypeDef RCC_OscInitStruct;
350     RCC_ClkInitTypeDef RCC_ClkInitStruct;
351     RCC_PeriphCLKInitTypeDef PeriphClkInit;
352 
353     __HAL_RCC_PWR_CLK_ENABLE( );
354 
355     __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 );
356 
357     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_LSE;
358     RCC_OscInitStruct.HSEState       = RCC_HSE_ON;
359     RCC_OscInitStruct.LSEState       = RCC_LSE_ON;
360     RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_ON;
361     RCC_OscInitStruct.PLL.PLLSource  = RCC_PLLSOURCE_HSE;
362     RCC_OscInitStruct.PLL.PLLMUL     = RCC_PLL_MUL6;
363     RCC_OscInitStruct.PLL.PLLDIV     = RCC_PLL_DIV3;
364     if( HAL_RCC_OscConfig( &RCC_OscInitStruct ) != HAL_OK )
365     {
366         assert_param( LMN_STATUS_ERROR );
367     }
368 
369     RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
370                                   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 HSE
401     __HAL_RCC_HSE_CONFIG( RCC_HSE_ON );
402 
403     // Wait till HSE is ready
404     while( __HAL_RCC_GET_FLAG( RCC_FLAG_HSERDY ) == 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     return USB_POWER;
434 }
435 
436 /**
437   * \brief Enters Low Power Stop Mode
438   *
439   * \note ARM exists the function when waking up
440   */
LpmEnterStopMode(void)441 void LpmEnterStopMode( void)
442 {
443     CRITICAL_SECTION_BEGIN( );
444 
445     BoardDeInitMcu( );
446 
447     // Disable the Power Voltage Detector
448     HAL_PWR_DisablePVD( );
449 
450     // Clear wake up flag
451     SET_BIT( PWR->CR, PWR_CR_CWUF );
452 
453     // Enable Ultra low power mode
454     HAL_PWREx_EnableUltraLowPower( );
455 
456     // Enable the fast wake up from Ultra low power mode
457     HAL_PWREx_EnableFastWakeUp( );
458 
459     CRITICAL_SECTION_END( );
460 
461     // Enter Stop Mode
462     HAL_PWR_EnterSTOPMode( PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI );
463 }
464 
465 /*!
466  * \brief Exists Low Power Stop Mode
467  */
LpmExitStopMode(void)468 void LpmExitStopMode( void )
469 {
470     // Disable IRQ while the MCU is not running on HSI
471     CRITICAL_SECTION_BEGIN( );
472 
473     // Initilizes the peripherals
474     BoardInitMcu( );
475 
476     CRITICAL_SECTION_END( );
477 }
478 
479 /*!
480  * \brief Enters Low Power Sleep Mode
481  *
482  * \note ARM exits the function when waking up
483  */
LpmEnterSleepMode(void)484 void LpmEnterSleepMode( void)
485 {
486     HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
487 }
488 
BoardLowPowerHandler(void)489 void BoardLowPowerHandler( void )
490 {
491     __disable_irq( );
492     /*!
493      * If an interrupt has occurred after __disable_irq( ), it is kept pending
494      * and cortex will not enter low power anyway
495      */
496 
497     LpmEnterLowPower( );
498 
499     __enable_irq( );
500 }
501 
502 #if !defined ( __CC_ARM )
503 
504 /*
505  * Function to be used by stdout for printf etc
506  */
_write(int fd,const void * buf,size_t count)507 int _write( int fd, const void *buf, size_t count )
508 {
509     while( UartPutBuffer( &Uart1, ( uint8_t* )buf, ( uint16_t )count ) != 0 ){ };
510     return count;
511 }
512 
513 /*
514  * Function to be used by stdin for scanf etc
515  */
_read(int fd,const void * buf,size_t count)516 int _read( int fd, const void *buf, size_t count )
517 {
518     size_t bytesRead = 0;
519     while( UartGetBuffer( &Uart1, ( uint8_t* )buf, count, ( uint16_t* )&bytesRead ) != 0 ){ };
520     // Echo back the character
521     while( UartPutBuffer( &Uart1, ( uint8_t* )buf, ( uint16_t )bytesRead ) != 0 ){ };
522     return bytesRead;
523 }
524 
525 #else
526 
527 #include <stdio.h>
528 
529 // Keil compiler
fputc(int c,FILE * stream)530 int fputc( int c, FILE *stream )
531 {
532     while( UartPutChar( &Uart1, ( uint8_t )c ) != 0 );
533     return c;
534 }
535 
fgetc(FILE * stream)536 int fgetc( FILE *stream )
537 {
538     uint8_t c = 0;
539     while( UartGetChar( &Uart1, &c ) != 0 );
540     // Echo back the character
541     while( UartPutChar( &Uart1, c ) != 0 );
542     return ( int )c;
543 }
544 
545 #endif
546 
547 #ifdef USE_FULL_ASSERT
548 
549 #include <stdio.h>
550 
551 /*
552  * Function Name  : assert_failed
553  * Description    : Reports the name of the source file and the source line number
554  *                  where the assert_param error has occurred.
555  * Input          : - file: pointer to the source file name
556  *                  - line: assert_param error line source number
557  * Output         : None
558  * Return         : None
559  */
assert_failed(uint8_t * file,uint32_t line)560 void assert_failed( uint8_t* file, uint32_t line )
561 {
562     /* User can add his own implementation to report the file name and line number,
563      ex: printf("Wrong parameters value: file %s on line %lu\n", file, line) */
564 
565     printf( "Wrong parameters value: file %s on line %lu\n", ( const char* )file, line );
566     /* Infinite loop */
567     while( 1 )
568     {
569     }
570 }
571 #endif
572