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 #include <stdlib.h>
24 #include "utilities.h"
25 #include "board-config.h"
26 #include "delay.h"
27 #include "radio.h"
28 #include "sx1276-board.h"
29
30 /*!
31 * \brief Gets the board PA selection configuration
32 *
33 * \param [IN] power Selects the right PA according to the wanted power.
34 * \retval PaSelect RegPaConfig PaSelect value
35 */
36 static uint8_t SX1276GetPaSelect( int8_t power );
37
38 /*!
39 * Flag used to set the RF switch control pins in low power mode when the radio is not active.
40 */
41 static bool RadioIsActive = false;
42
43 /*!
44 * Radio driver structure initialization
45 */
46 const struct Radio_s Radio =
47 {
48 SX1276Init,
49 SX1276GetStatus,
50 SX1276SetModem,
51 SX1276SetChannel,
52 SX1276IsChannelFree,
53 SX1276Random,
54 SX1276SetRxConfig,
55 SX1276SetTxConfig,
56 SX1276CheckRfFrequency,
57 SX1276GetTimeOnAir,
58 SX1276Send,
59 SX1276SetSleep,
60 SX1276SetStby,
61 SX1276SetRx,
62 SX1276StartCad,
63 SX1276SetTxContinuousWave,
64 SX1276ReadRssi,
65 SX1276Write,
66 SX1276Read,
67 SX1276WriteBuffer,
68 SX1276ReadBuffer,
69 SX1276SetMaxPayloadLength,
70 SX1276SetPublicNetwork,
71 SX1276GetWakeupTime,
72 NULL, // void ( *IrqProcess )( void )
73 NULL, // void ( *RxBoosted )( uint32_t timeout ) - SX126x Only
74 NULL, // void ( *SetRxDutyCycle )( uint32_t rxTime, uint32_t sleepTime ) - SX126x Only
75 };
76
77 /*!
78 * TCXO power control pin
79 */
80 Gpio_t TcxoPower;
81
82 /*!
83 * Antenna switch GPIO pins objects
84 */
85 Gpio_t AntSwitchRx;
86 Gpio_t AntSwitchTxBoost;
87 Gpio_t AntSwitchTxRfo;
88
89 /*!
90 * Debug GPIO pins objects
91 */
92 #if defined( USE_RADIO_DEBUG )
93 Gpio_t DbgPinTx;
94 Gpio_t DbgPinRx;
95 #endif
96
SX1276IoInit(void)97 void SX1276IoInit( void )
98 {
99 GpioInit( &SX1276.Spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
100
101 GpioInit( &SX1276.DIO0, RADIO_DIO_0, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
102 GpioInit( &SX1276.DIO1, RADIO_DIO_1, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
103 GpioInit( &SX1276.DIO2, RADIO_DIO_2, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
104 GpioInit( &SX1276.DIO3, RADIO_DIO_3, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
105 GpioInit( &SX1276.DIO4, RADIO_DIO_4, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
106 GpioInit( &SX1276.DIO5, RADIO_DIO_5, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
107 }
108
SX1276IoIrqInit(DioIrqHandler ** irqHandlers)109 void SX1276IoIrqInit( DioIrqHandler **irqHandlers )
110 {
111 GpioSetInterrupt( &SX1276.DIO0, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[0] );
112 GpioSetInterrupt( &SX1276.DIO1, IRQ_RISING_FALLING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[1] );
113 GpioSetInterrupt( &SX1276.DIO2, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[2] );
114 GpioSetInterrupt( &SX1276.DIO3, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[3] );
115 GpioSetInterrupt( &SX1276.DIO4, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[4] );
116 GpioSetInterrupt( &SX1276.DIO5, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[5] );
117 }
118
SX1276IoDeInit(void)119 void SX1276IoDeInit( void )
120 {
121 GpioInit( &SX1276.Spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
122
123 GpioInit( &SX1276.DIO0, RADIO_DIO_0, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
124 GpioInit( &SX1276.DIO1, RADIO_DIO_1, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
125 GpioInit( &SX1276.DIO2, RADIO_DIO_2, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
126 GpioInit( &SX1276.DIO3, RADIO_DIO_3, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
127 GpioInit( &SX1276.DIO4, RADIO_DIO_4, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
128 GpioInit( &SX1276.DIO5, RADIO_DIO_5, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
129 }
130
SX1276IoDbgInit(void)131 void SX1276IoDbgInit( void )
132 {
133 #if defined( USE_RADIO_DEBUG )
134 GpioInit( &DbgPinTx, RADIO_DBG_PIN_TX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
135 GpioInit( &DbgPinRx, RADIO_DBG_PIN_RX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
136 #endif
137 }
138
SX1276IoTcxoInit(void)139 void SX1276IoTcxoInit( void )
140 {
141 GpioInit( &TcxoPower, RADIO_TCXO_POWER, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
142 }
143
SX1276SetBoardTcxo(uint8_t state)144 void SX1276SetBoardTcxo( uint8_t state )
145 {
146 if( state == true )
147 {
148 if( GpioRead( &TcxoPower ) == 0 )
149 { // TCXO OFF power it up.
150 // Power ON the TCXO
151 GpioWrite( &TcxoPower, 1 );
152 DelayMs( BOARD_TCXO_WAKEUP_TIME );
153 }
154 }
155 else
156 {
157 // Power OFF the TCXO
158 GpioWrite( &TcxoPower, 0 );
159 }
160 }
161
SX1276GetBoardTcxoWakeupTime(void)162 uint32_t SX1276GetBoardTcxoWakeupTime( void )
163 {
164 return BOARD_TCXO_WAKEUP_TIME;
165 }
166
SX1276Reset(void)167 void SX1276Reset( void )
168 {
169 // Enables the TCXO if available on the board design
170 SX1276SetBoardTcxo( true );
171
172 // Set RESET pin to 0
173 GpioInit( &SX1276.Reset, RADIO_RESET, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
174
175 // Wait 1 ms
176 DelayMs( 1 );
177
178 // Configure RESET as input
179 GpioInit( &SX1276.Reset, RADIO_RESET, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
180
181 // Wait 6 ms
182 DelayMs( 6 );
183 }
184
SX1276SetRfTxPower(int8_t power)185 void SX1276SetRfTxPower( int8_t power )
186 {
187 uint8_t paConfig = 0;
188 uint8_t paDac = 0;
189
190 paConfig = SX1276Read( REG_PACONFIG );
191 paDac = SX1276Read( REG_PADAC );
192
193 paConfig = ( paConfig & RF_PACONFIG_PASELECT_MASK ) | SX1276GetPaSelect( power );
194
195 if( ( paConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
196 {
197 if( power > 17 )
198 {
199 paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_ON;
200 }
201 else
202 {
203 paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_OFF;
204 }
205 if( ( paDac & RF_PADAC_20DBM_ON ) == RF_PADAC_20DBM_ON )
206 {
207 if( power < 5 )
208 {
209 power = 5;
210 }
211 if( power > 20 )
212 {
213 power = 20;
214 }
215 paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F );
216 }
217 else
218 {
219 if( power < 2 )
220 {
221 power = 2;
222 }
223 if( power > 17 )
224 {
225 power = 17;
226 }
227 paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F );
228 }
229 }
230 else
231 {
232 if( power > 0 )
233 {
234 if( power > 15 )
235 {
236 power = 15;
237 }
238 paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 7 << 4 ) | ( power );
239 }
240 else
241 {
242 if( power < -4 )
243 {
244 power = -4;
245 }
246 paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 0 << 4 ) | ( power + 4 );
247 }
248 }
249 SX1276Write( REG_PACONFIG, paConfig );
250 SX1276Write( REG_PADAC, paDac );
251 }
252
SX1276GetPaSelect(int8_t power)253 static uint8_t SX1276GetPaSelect( int8_t power )
254 {
255 if( power > 14 )
256 {
257 return RF_PACONFIG_PASELECT_PABOOST;
258 }
259 else
260 {
261 return RF_PACONFIG_PASELECT_RFO;
262 }
263 }
264
SX1276SetAntSwLowPower(bool status)265 void SX1276SetAntSwLowPower( bool status )
266 {
267 if( RadioIsActive != status )
268 {
269 RadioIsActive = status;
270
271 if( status == false )
272 {
273 SX1276AntSwInit( );
274 }
275 else
276 {
277 SX1276AntSwDeInit( );
278 }
279 }
280 }
281
SX1276AntSwInit(void)282 void SX1276AntSwInit( void )
283 {
284 GpioInit( &AntSwitchRx, RADIO_ANT_SWITCH_RX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
285 GpioInit( &AntSwitchTxBoost, RADIO_ANT_SWITCH_TX_BOOST, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
286 GpioInit( &AntSwitchTxRfo, RADIO_ANT_SWITCH_TX_RFO, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
287 }
288
SX1276AntSwDeInit(void)289 void SX1276AntSwDeInit( void )
290 {
291 GpioInit( &AntSwitchRx, RADIO_ANT_SWITCH_RX, PIN_ANALOGIC, PIN_OPEN_DRAIN, PIN_NO_PULL, 0 );
292 GpioInit( &AntSwitchTxBoost, RADIO_ANT_SWITCH_TX_BOOST, PIN_ANALOGIC, PIN_OPEN_DRAIN, PIN_NO_PULL, 0 );
293 GpioInit( &AntSwitchTxRfo, RADIO_ANT_SWITCH_TX_RFO, PIN_ANALOGIC, PIN_OPEN_DRAIN, PIN_NO_PULL, 0 );
294 }
295
SX1276SetAntSw(uint8_t opMode)296 void SX1276SetAntSw( uint8_t opMode )
297 {
298 uint8_t paConfig = SX1276Read( REG_PACONFIG );
299 switch( opMode )
300 {
301 case RFLR_OPMODE_TRANSMITTER:
302 if( ( paConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
303 {
304 GpioWrite( &AntSwitchTxBoost, 1 );
305 }
306 else
307 {
308 GpioWrite( &AntSwitchTxRfo, 1 );
309 }
310 break;
311 case RFLR_OPMODE_RECEIVER:
312 case RFLR_OPMODE_RECEIVER_SINGLE:
313 case RFLR_OPMODE_CAD:
314 default:
315 GpioWrite( &AntSwitchRx, 1 );
316 break;
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