1 /*!
2  * \file      sx1276-board.c
3  *
4  * \brief     Target board SX1276 driver 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    Marten Lootsma(TWTG) on behalf of Microchip/Atmel (c)2017
24  */
25 #include <peripheral_clk_config.h>
26 #include <hal_ext_irq.h>
27 #include <hal_gpio.h>
28 #include "board-config.h"
29 #include "delay.h"
30 #include "radio.h"
31 #include "sx1276-board.h"
32 
33 /*!
34  * \brief Gets the board PA selection configuration
35  *
36  * \param [IN] channel Channel frequency in Hz
37  * \retval PaSelect RegPaConfig PaSelect value
38  */
39 static uint8_t SX1276GetPaSelect( uint32_t channel );
40 
41 /*!
42  * Flag used to set the RF switch control pins in low power mode when the radio is not active.
43  */
44 static bool RadioIsActive = false;
45 
46 /*!
47  * Radio driver structure initialization
48  */
49 const struct Radio_s Radio =
50 {
51     SX1276Init,
52     SX1276GetStatus,
53     SX1276SetModem,
54     SX1276SetChannel,
55     SX1276IsChannelFree,
56     SX1276Random,
57     SX1276SetRxConfig,
58     SX1276SetTxConfig,
59     SX1276CheckRfFrequency,
60     SX1276GetTimeOnAir,
61     SX1276Send,
62     SX1276SetSleep,
63     SX1276SetStby,
64     SX1276SetRx,
65     SX1276StartCad,
66     SX1276SetTxContinuousWave,
67     SX1276ReadRssi,
68     SX1276Write,
69     SX1276Read,
70     SX1276WriteBuffer,
71     SX1276ReadBuffer,
72     SX1276SetMaxPayloadLength,
73     SX1276SetPublicNetwork,
74     SX1276GetWakeupTime,
75     NULL, // void ( *IrqProcess )( void )
76     NULL, // void ( *RxBoosted )( uint32_t timeout ) - SX126x Only
77     NULL, // void ( *SetRxDutyCycle )( uint32_t rxTime, uint32_t sleepTime ) - SX126x Only
78 };
79 
80 /*!
81  * TCXO power control pin
82  */
83 Gpio_t tcxo_pin;
84 
85 /*!
86  * Antenna switch GPIO pins objects
87  */
88 Gpio_t rfswitch_pin;
89 
90 /*!
91  * Debug GPIO pins objects
92  */
93 #if defined( USE_RADIO_DEBUG )
94 Gpio_t DbgPinTx;
95 Gpio_t DbgPinRx;
96 #endif
97 
SX1276IoInit(void)98 void SX1276IoInit( void )
99 {
100     GpioInit( &SX1276.Spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
101     GpioInit( &rfswitch_pin, RF_SWITCH_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
102     ext_irq_init( );
103 
104     GpioInit( &SX1276.DIO0, RADIO_DIO_0, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
105     gpio_set_pin_function( RADIO_DIO_0, PINMUX_PB16A_EIC_EXTINT0 );
106     GpioInit( &SX1276.DIO1, RADIO_DIO_1, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
107     // Must be setup to be trigged on both edges. See CONF_EIC_SENSE11 under hpl_eic_config.h
108     gpio_set_pin_function( RADIO_DIO_1, PINMUX_PA11A_EIC_EXTINT11 );
109     GpioInit( &SX1276.DIO2, RADIO_DIO_2, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
110     gpio_set_pin_function( RADIO_DIO_2, PINMUX_PA12A_EIC_EXTINT12 );
111     GpioInit( &SX1276.DIO3, RADIO_DIO_3, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
112     gpio_set_pin_function( RADIO_DIO_3, PINMUX_PB17A_EIC_EXTINT1 );
113 }
114 
115 static void Dio0IrqHandler( void );
116 static void Dio1IrqHandler( void );
117 static void Dio2IrqHandler( void );
118 static void Dio3IrqHandler( void );
119 
120 static Gpio_t *DioIrqs[] = {
121     &SX1276.DIO0,
122     &SX1276.DIO1,
123     &SX1276.DIO2,
124     &SX1276.DIO3
125 };
126 
127 static ext_irq_cb_t ExtIrqHandlers[] = {
128     Dio0IrqHandler,
129     Dio1IrqHandler,
130     Dio2IrqHandler,
131     Dio3IrqHandler
132 };
133 
DioIrqHanlderProcess(uint8_t index)134 static void DioIrqHanlderProcess( uint8_t index )
135 {
136     if( ( DioIrqs[index] != NULL ) && ( DioIrqs[index]->IrqHandler != NULL ) )
137     {
138         DioIrqs[index]->IrqHandler( DioIrqs[index]->Context );
139     }
140 }
141 
Dio0IrqHandler(void)142 static void Dio0IrqHandler( void )
143 {
144     DioIrqHanlderProcess( 0 );
145 }
146 
Dio1IrqHandler(void)147 static void Dio1IrqHandler( void )
148 {
149     DioIrqHanlderProcess( 1 );
150 }
151 
Dio2IrqHandler(void)152 static void Dio2IrqHandler( void )
153 {
154     DioIrqHanlderProcess( 2 );
155 }
156 
Dio3IrqHandler(void)157 static void Dio3IrqHandler( void )
158 {
159     DioIrqHanlderProcess( 3 );
160 }
161 
IoIrqInit(uint8_t index,DioIrqHandler * irqHandler)162 static void IoIrqInit( uint8_t index, DioIrqHandler *irqHandler )
163 {
164     DioIrqs[index]->IrqHandler = irqHandler;
165     ext_irq_register( DioIrqs[index]->pin, ExtIrqHandlers[index] );
166 }
167 
SX1276IoIrqInit(DioIrqHandler ** irqHandlers)168 void SX1276IoIrqInit( DioIrqHandler **irqHandlers )
169 {
170     for( int8_t i = 0; i < 4; i++ )
171     {
172         IoIrqInit( i, irqHandlers[i] );
173     }
174 }
175 
SX1276IoDeInit(void)176 void SX1276IoDeInit( void )
177 {
178     GpioInit( &SX1276.Spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 1 );
179     GpioInit( &rfswitch_pin, RF_SWITCH_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
180     ext_irq_init( );
181 
182     GpioInit( &SX1276.DIO0, RADIO_DIO_0, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
183     gpio_set_pin_function( RADIO_DIO_0, PINMUX_PB16A_EIC_EXTINT0 );
184     GpioInit( &SX1276.DIO1, RADIO_DIO_1, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
185     gpio_set_pin_function( RADIO_DIO_1, PINMUX_PA11A_EIC_EXTINT11 );
186     GpioInit( &SX1276.DIO2, RADIO_DIO_2, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
187     gpio_set_pin_function( RADIO_DIO_2, PINMUX_PA12A_EIC_EXTINT12 );
188     GpioInit( &SX1276.DIO3, RADIO_DIO_3, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
189     gpio_set_pin_function( RADIO_DIO_3, PINMUX_PB17A_EIC_EXTINT1 );
190 }
191 
SX1276IoDbgInit(void)192 void SX1276IoDbgInit( void )
193 {
194 #if defined( USE_RADIO_DEBUG )
195     GpioInit( &DbgPinTx, RADIO_DBG_PIN_TX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
196     GpioInit( &DbgPinRx, RADIO_DBG_PIN_RX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
197 #endif
198 }
199 
SX1276IoTcxoInit(void)200 void SX1276IoTcxoInit( void )
201 {
202     GpioInit( &tcxo_pin, TCXO_PWR_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
203 }
204 
SX1276SetBoardTcxo(uint8_t state)205 void SX1276SetBoardTcxo( uint8_t state )
206 {
207     GpioWrite( &tcxo_pin, state );
208     DelayMs( BOARD_TCXO_WAKEUP_TIME );
209 }
210 
SX1276GetBoardTcxoWakeupTime(void)211 uint32_t SX1276GetBoardTcxoWakeupTime( void )
212 {
213     return BOARD_TCXO_WAKEUP_TIME;
214 }
215 
SX1276Reset(void)216 void SX1276Reset( void )
217 {
218     // Enables the TCXO if available on the board design
219     SX1276SetBoardTcxo( true );
220 
221     // Set RESET pin to 0
222     GpioInit( &SX1276.Reset, RADIO_RESET, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
223 
224     // Wait 1 ms
225     DelayMs( 1 );
226 
227     // Configure RESET as input
228     GpioInit( &SX1276.Reset, RADIO_RESET, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
229 
230     // Wait 6 ms
231     DelayMs( 6 );
232 }
233 
SX1276SetRfTxPower(int8_t power)234 void SX1276SetRfTxPower( int8_t power )
235 {
236     uint8_t paConfig = 0;
237     uint8_t paDac = 0;
238 
239     paConfig = SX1276Read( REG_PACONFIG );
240     paDac = SX1276Read( REG_PADAC );
241 
242     paConfig = ( paConfig & RF_PACONFIG_PASELECT_MASK ) | SX1276GetPaSelect( SX1276.Settings.Channel );
243 
244     if( ( paConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
245     {
246         if( power > 17 )
247         {
248             paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_ON;
249         }
250         else
251         {
252             paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_OFF;
253         }
254         if( ( paDac & RF_PADAC_20DBM_ON ) == RF_PADAC_20DBM_ON )
255         {
256             if( power < 5 )
257             {
258                 power = 5;
259             }
260             if( power > 20 )
261             {
262                 power = 20;
263             }
264             paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F );
265         }
266         else
267         {
268             if( power < 2 )
269             {
270                 power = 2;
271             }
272             if( power > 17 )
273             {
274                 power = 17;
275             }
276             paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F );
277         }
278     }
279     else
280     {
281         if( power > 0 )
282         {
283             if( power > 15 )
284             {
285                 power = 15;
286             }
287             paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 7 << 4 ) | ( power );
288         }
289         else
290         {
291             if( power < -4 )
292             {
293                 power = -4;
294             }
295             paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 0 << 4 ) | ( power + 4 );
296         }
297     }
298     SX1276Write( REG_PACONFIG, paConfig );
299     SX1276Write( REG_PADAC, paDac );
300 }
301 
SX1276GetPaSelect(uint32_t channel)302 static uint8_t SX1276GetPaSelect( uint32_t channel )
303 {
304     return RF_PACONFIG_PASELECT_PABOOST;
305 }
306 
SX1276SetAntSwLowPower(bool status)307 void SX1276SetAntSwLowPower( bool status )
308 {
309     // Control the TCXO and Antenna switch
310     if( RadioIsActive != status )
311     {
312         RadioIsActive = status;
313     }
314 }
315 
SX1276SetAntSw(uint8_t opMode)316 void SX1276SetAntSw( uint8_t opMode )
317 {
318 }
319 
SX1276CheckRfFrequency(uint32_t frequency)320 bool SX1276CheckRfFrequency( uint32_t frequency )
321 {
322     // Implement check. Currently all frequencies are supported
323     return true;
324 }
325 
SX1276GetDio1PinState(void)326 uint32_t SX1276GetDio1PinState( void )
327 {
328     return GpioRead( &SX1276.DIO1 );
329 }
330 
331 #if defined( USE_RADIO_DEBUG )
SX1276DbgPinTxWrite(uint8_t state)332 void SX1276DbgPinTxWrite( uint8_t state )
333 {
334     GpioWrite( &DbgPinTx, state );
335 }
336 
SX1276DbgPinRxWrite(uint8_t state)337 void SX1276DbgPinRxWrite( uint8_t state )
338 {
339     GpioWrite( &DbgPinRx, state );
340 }
341 #endif
342