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