1 /*!
2 * \file sx126x.c
3 *
4 * \brief SX126x 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 <string.h>
24 #include "utilities.h"
25 #include "timer.h"
26 #include "radio.h"
27 #include "delay.h"
28 #include "sx126x.h"
29 #include "sx126x-board.h"
30
31 /*!
32 * \brief Internal frequency of the radio
33 */
34 #define SX126X_XTAL_FREQ 32000000UL
35
36 /*!
37 * \brief Scaling factor used to perform fixed-point operations
38 */
39 #define SX126X_PLL_STEP_SHIFT_AMOUNT ( 14 )
40
41 /*!
42 * \brief PLL step - scaled with SX126X_PLL_STEP_SHIFT_AMOUNT
43 */
44 #define SX126X_PLL_STEP_SCALED ( SX126X_XTAL_FREQ >> ( 25 - SX126X_PLL_STEP_SHIFT_AMOUNT ) )
45
46 /*!
47 * \brief Maximum value for parameter symbNum in \ref SX126xSetLoRaSymbNumTimeout
48 */
49 #define SX126X_MAX_LORA_SYMB_NUM_TIMEOUT 248
50
51 /*!
52 * \brief Radio registers definition
53 */
54 typedef struct
55 {
56 uint16_t Addr; //!< The address of the register
57 uint8_t Value; //!< The value of the register
58 }RadioRegisters_t;
59
60 /*!
61 * \brief Stores the current packet type set in the radio
62 */
63 static RadioPacketTypes_t PacketType;
64
65 /*!
66 * \brief Stores the current packet header type set in the radio
67 */
68 static volatile RadioLoRaPacketLengthsMode_t LoRaHeaderType;
69
70 /*!
71 * \brief Stores the last frequency error measured on LoRa received packet
72 */
73 volatile uint32_t FrequencyError = 0;
74
75 /*!
76 * \brief Hold the status of the Image calibration
77 */
78 static bool ImageCalibrated = false;
79
80 /*!
81 * \brief Get the number of PLL steps for a given frequency in Hertz
82 *
83 * \param [in] freqInHz Frequency in Hertz
84 *
85 * \returns Number of PLL steps
86 */
87 static uint32_t SX126xConvertFreqInHzToPllStep( uint32_t freqInHz );
88
89 /*
90 * SX126x DIO IRQ callback functions prototype
91 */
92
93 /*!
94 * \brief DIO 0 IRQ callback
95 */
96 void SX126xOnDioIrq( void );
97
98 /*!
99 * \brief DIO 0 IRQ callback
100 */
101 void SX126xSetPollingMode( void );
102
103 /*!
104 * \brief DIO 0 IRQ callback
105 */
106 void SX126xSetInterruptMode( void );
107
108 /*
109 * \brief Process the IRQ if handled by the driver
110 */
111 void SX126xProcessIrqs( void );
112
SX126xInit(DioIrqHandler dioIrq)113 void SX126xInit( DioIrqHandler dioIrq )
114 {
115 SX126xReset( );
116
117 SX126xIoIrqInit( dioIrq );
118
119 SX126xWakeup( );
120 SX126xSetStandby( STDBY_RC );
121
122 // Initialize TCXO control
123 SX126xIoTcxoInit( );
124
125 // Initialize RF switch control
126 SX126xIoRfSwitchInit( );
127
128 // Force image calibration
129 ImageCalibrated = false;
130
131 SX126xSetOperatingMode( MODE_STDBY_RC );
132 }
133
SX126xCheckDeviceReady(void)134 void SX126xCheckDeviceReady( void )
135 {
136 if( ( SX126xGetOperatingMode( ) == MODE_SLEEP ) || ( SX126xGetOperatingMode( ) == MODE_RX_DC ) )
137 {
138 SX126xWakeup( );
139 // Switch is turned off when device is in sleep mode and turned on is all other modes
140 SX126xAntSwOn( );
141 }
142 SX126xWaitOnBusy( );
143 }
144
SX126xSetPayload(uint8_t * payload,uint8_t size)145 void SX126xSetPayload( uint8_t *payload, uint8_t size )
146 {
147 SX126xWriteBuffer( 0x00, payload, size );
148 }
149
SX126xGetPayload(uint8_t * buffer,uint8_t * size,uint8_t maxSize)150 uint8_t SX126xGetPayload( uint8_t *buffer, uint8_t *size, uint8_t maxSize )
151 {
152 uint8_t offset = 0;
153
154 SX126xGetRxBufferStatus( size, &offset );
155 if( *size > maxSize )
156 {
157 return 1;
158 }
159 SX126xReadBuffer( offset, buffer, *size );
160 return 0;
161 }
162
SX126xSendPayload(uint8_t * payload,uint8_t size,uint32_t timeout)163 void SX126xSendPayload( uint8_t *payload, uint8_t size, uint32_t timeout )
164 {
165 SX126xSetPayload( payload, size );
166 SX126xSetTx( timeout );
167 }
168
SX126xSetSyncWord(uint8_t * syncWord)169 uint8_t SX126xSetSyncWord( uint8_t *syncWord )
170 {
171 SX126xWriteRegisters( REG_LR_SYNCWORDBASEADDRESS, syncWord, 8 );
172 return 0;
173 }
174
SX126xSetCrcSeed(uint16_t seed)175 void SX126xSetCrcSeed( uint16_t seed )
176 {
177 uint8_t buf[2];
178
179 buf[0] = ( uint8_t )( ( seed >> 8 ) & 0xFF );
180 buf[1] = ( uint8_t )( seed & 0xFF );
181
182 switch( SX126xGetPacketType( ) )
183 {
184 case PACKET_TYPE_GFSK:
185 SX126xWriteRegisters( REG_LR_CRCSEEDBASEADDR, buf, 2 );
186 break;
187
188 default:
189 break;
190 }
191 }
192
SX126xSetCrcPolynomial(uint16_t polynomial)193 void SX126xSetCrcPolynomial( uint16_t polynomial )
194 {
195 uint8_t buf[2];
196
197 buf[0] = ( uint8_t )( ( polynomial >> 8 ) & 0xFF );
198 buf[1] = ( uint8_t )( polynomial & 0xFF );
199
200 switch( SX126xGetPacketType( ) )
201 {
202 case PACKET_TYPE_GFSK:
203 SX126xWriteRegisters( REG_LR_CRCPOLYBASEADDR, buf, 2 );
204 break;
205
206 default:
207 break;
208 }
209 }
210
SX126xSetWhiteningSeed(uint16_t seed)211 void SX126xSetWhiteningSeed( uint16_t seed )
212 {
213 uint8_t regValue = 0;
214
215 switch( SX126xGetPacketType( ) )
216 {
217 case PACKET_TYPE_GFSK:
218 regValue = SX126xReadRegister( REG_LR_WHITSEEDBASEADDR_MSB ) & 0xFE;
219 regValue = ( ( seed >> 8 ) & 0x01 ) | regValue;
220 SX126xWriteRegister( REG_LR_WHITSEEDBASEADDR_MSB, regValue ); // only 1 bit.
221 SX126xWriteRegister( REG_LR_WHITSEEDBASEADDR_LSB, ( uint8_t )seed );
222 break;
223
224 default:
225 break;
226 }
227 }
228
SX126xGetRandom(void)229 uint32_t SX126xGetRandom( void )
230 {
231 uint32_t number = 0;
232 uint8_t regAnaLna = 0;
233 uint8_t regAnaMixer = 0;
234
235 regAnaLna = SX126xReadRegister( REG_ANA_LNA );
236 SX126xWriteRegister( REG_ANA_LNA, regAnaLna & ~( 1 << 0 ) );
237
238 regAnaMixer = SX126xReadRegister( REG_ANA_MIXER );
239 SX126xWriteRegister( REG_ANA_MIXER, regAnaMixer & ~( 1 << 7 ) );
240
241 // Set radio in continuous reception
242 SX126xSetRx( 0xFFFFFF ); // Rx Continuous
243
244 SX126xReadRegisters( RANDOM_NUMBER_GENERATORBASEADDR, ( uint8_t* )&number, 4 );
245
246 SX126xSetStandby( STDBY_RC );
247
248 SX126xWriteRegister( REG_ANA_LNA, regAnaLna );
249 SX126xWriteRegister( REG_ANA_MIXER, regAnaMixer );
250
251 return number;
252 }
253
SX126xSetSleep(SleepParams_t sleepConfig)254 void SX126xSetSleep( SleepParams_t sleepConfig )
255 {
256 SX126xAntSwOff( );
257
258 uint8_t value = ( ( ( uint8_t )sleepConfig.Fields.WarmStart << 2 ) |
259 ( ( uint8_t )sleepConfig.Fields.Reset << 1 ) |
260 ( ( uint8_t )sleepConfig.Fields.WakeUpRTC ) );
261
262 if( sleepConfig.Fields.WarmStart == 0 )
263 {
264 // Force image calibration
265 ImageCalibrated = false;
266 }
267 SX126xWriteCommand( RADIO_SET_SLEEP, &value, 1 );
268 SX126xSetOperatingMode( MODE_SLEEP );
269 }
270
SX126xSetStandby(RadioStandbyModes_t standbyConfig)271 void SX126xSetStandby( RadioStandbyModes_t standbyConfig )
272 {
273 SX126xWriteCommand( RADIO_SET_STANDBY, ( uint8_t* )&standbyConfig, 1 );
274 if( standbyConfig == STDBY_RC )
275 {
276 SX126xSetOperatingMode( MODE_STDBY_RC );
277 }
278 else
279 {
280 SX126xSetOperatingMode( MODE_STDBY_XOSC );
281 }
282 }
283
SX126xSetFs(void)284 void SX126xSetFs( void )
285 {
286 SX126xWriteCommand( RADIO_SET_FS, 0, 0 );
287 SX126xSetOperatingMode( MODE_FS );
288 }
289
SX126xSetTx(uint32_t timeout)290 void SX126xSetTx( uint32_t timeout )
291 {
292 uint8_t buf[3];
293
294 SX126xSetOperatingMode( MODE_TX );
295
296 buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF );
297 buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF );
298 buf[2] = ( uint8_t )( timeout & 0xFF );
299 SX126xWriteCommand( RADIO_SET_TX, buf, 3 );
300 }
301
SX126xSetRx(uint32_t timeout)302 void SX126xSetRx( uint32_t timeout )
303 {
304 uint8_t buf[3];
305
306 SX126xSetOperatingMode( MODE_RX );
307
308 SX126xWriteRegister( REG_RX_GAIN, 0x94 ); // default gain
309
310 buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF );
311 buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF );
312 buf[2] = ( uint8_t )( timeout & 0xFF );
313 SX126xWriteCommand( RADIO_SET_RX, buf, 3 );
314 }
315
SX126xSetRxBoosted(uint32_t timeout)316 void SX126xSetRxBoosted( uint32_t timeout )
317 {
318 uint8_t buf[3];
319
320 SX126xSetOperatingMode( MODE_RX );
321
322 SX126xWriteRegister( REG_RX_GAIN, 0x96 ); // max LNA gain, increase current by ~2mA for around ~3dB in sensitivity
323
324 buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF );
325 buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF );
326 buf[2] = ( uint8_t )( timeout & 0xFF );
327 SX126xWriteCommand( RADIO_SET_RX, buf, 3 );
328 }
329
SX126xSetRxDutyCycle(uint32_t rxTime,uint32_t sleepTime)330 void SX126xSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime )
331 {
332 uint8_t buf[6];
333
334 buf[0] = ( uint8_t )( ( rxTime >> 16 ) & 0xFF );
335 buf[1] = ( uint8_t )( ( rxTime >> 8 ) & 0xFF );
336 buf[2] = ( uint8_t )( rxTime & 0xFF );
337 buf[3] = ( uint8_t )( ( sleepTime >> 16 ) & 0xFF );
338 buf[4] = ( uint8_t )( ( sleepTime >> 8 ) & 0xFF );
339 buf[5] = ( uint8_t )( sleepTime & 0xFF );
340 SX126xWriteCommand( RADIO_SET_RXDUTYCYCLE, buf, 6 );
341 SX126xSetOperatingMode( MODE_RX_DC );
342 }
343
SX126xSetCad(void)344 void SX126xSetCad( void )
345 {
346 SX126xWriteCommand( RADIO_SET_CAD, 0, 0 );
347 SX126xSetOperatingMode( MODE_CAD );
348 }
349
SX126xSetTxContinuousWave(void)350 void SX126xSetTxContinuousWave( void )
351 {
352 SX126xWriteCommand( RADIO_SET_TXCONTINUOUSWAVE, 0, 0 );
353 SX126xSetOperatingMode( MODE_TX );
354 }
355
SX126xSetTxInfinitePreamble(void)356 void SX126xSetTxInfinitePreamble( void )
357 {
358 SX126xWriteCommand( RADIO_SET_TXCONTINUOUSPREAMBLE, 0, 0 );
359 SX126xSetOperatingMode( MODE_TX );
360 }
361
SX126xSetStopRxTimerOnPreambleDetect(bool enable)362 void SX126xSetStopRxTimerOnPreambleDetect( bool enable )
363 {
364 SX126xWriteCommand( RADIO_SET_STOPRXTIMERONPREAMBLE, ( uint8_t* )&enable, 1 );
365 }
366
SX126xSetLoRaSymbNumTimeout(uint8_t symbNum)367 void SX126xSetLoRaSymbNumTimeout( uint8_t symbNum )
368 {
369 uint8_t mant = ( ( ( symbNum > SX126X_MAX_LORA_SYMB_NUM_TIMEOUT ) ?
370 SX126X_MAX_LORA_SYMB_NUM_TIMEOUT :
371 symbNum ) + 1 ) >> 1;
372 uint8_t exp = 0;
373 uint8_t reg = 0;
374
375 while( mant > 31 )
376 {
377 mant = ( mant + 3 ) >> 2;
378 exp++;
379 }
380
381 reg = mant << ( 2 * exp + 1 );
382 SX126xWriteCommand( RADIO_SET_LORASYMBTIMEOUT, ®, 1 );
383
384 if( symbNum != 0 )
385 {
386 reg = exp + ( mant << 3 );
387 SX126xWriteRegister( REG_LR_SYNCH_TIMEOUT, reg );
388 }
389 }
390
SX126xSetRegulatorMode(RadioRegulatorMode_t mode)391 void SX126xSetRegulatorMode( RadioRegulatorMode_t mode )
392 {
393 SX126xWriteCommand( RADIO_SET_REGULATORMODE, ( uint8_t* )&mode, 1 );
394 }
395
SX126xCalibrate(CalibrationParams_t calibParam)396 void SX126xCalibrate( CalibrationParams_t calibParam )
397 {
398 uint8_t value = ( ( ( uint8_t )calibParam.Fields.ImgEnable << 6 ) |
399 ( ( uint8_t )calibParam.Fields.ADCBulkPEnable << 5 ) |
400 ( ( uint8_t )calibParam.Fields.ADCBulkNEnable << 4 ) |
401 ( ( uint8_t )calibParam.Fields.ADCPulseEnable << 3 ) |
402 ( ( uint8_t )calibParam.Fields.PLLEnable << 2 ) |
403 ( ( uint8_t )calibParam.Fields.RC13MEnable << 1 ) |
404 ( ( uint8_t )calibParam.Fields.RC64KEnable ) );
405
406 SX126xWriteCommand( RADIO_CALIBRATE, &value, 1 );
407 }
408
SX126xCalibrateImage(uint32_t freq)409 void SX126xCalibrateImage( uint32_t freq )
410 {
411 uint8_t calFreq[2];
412
413 if( freq > 900000000 )
414 {
415 calFreq[0] = 0xE1;
416 calFreq[1] = 0xE9;
417 }
418 else if( freq > 850000000 )
419 {
420 calFreq[0] = 0xD7;
421 calFreq[1] = 0xDB;
422 }
423 else if( freq > 770000000 )
424 {
425 calFreq[0] = 0xC1;
426 calFreq[1] = 0xC5;
427 }
428 else if( freq > 460000000 )
429 {
430 calFreq[0] = 0x75;
431 calFreq[1] = 0x81;
432 }
433 else if( freq > 425000000 )
434 {
435 calFreq[0] = 0x6B;
436 calFreq[1] = 0x6F;
437 }
438 SX126xWriteCommand( RADIO_CALIBRATEIMAGE, calFreq, 2 );
439 }
440
SX126xSetPaConfig(uint8_t paDutyCycle,uint8_t hpMax,uint8_t deviceSel,uint8_t paLut)441 void SX126xSetPaConfig( uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut )
442 {
443 uint8_t buf[4];
444
445 buf[0] = paDutyCycle;
446 buf[1] = hpMax;
447 buf[2] = deviceSel;
448 buf[3] = paLut;
449 SX126xWriteCommand( RADIO_SET_PACONFIG, buf, 4 );
450 }
451
SX126xSetRxTxFallbackMode(uint8_t fallbackMode)452 void SX126xSetRxTxFallbackMode( uint8_t fallbackMode )
453 {
454 SX126xWriteCommand( RADIO_SET_TXFALLBACKMODE, &fallbackMode, 1 );
455 }
456
SX126xSetDioIrqParams(uint16_t irqMask,uint16_t dio1Mask,uint16_t dio2Mask,uint16_t dio3Mask)457 void SX126xSetDioIrqParams( uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask )
458 {
459 uint8_t buf[8];
460
461 buf[0] = ( uint8_t )( ( irqMask >> 8 ) & 0x00FF );
462 buf[1] = ( uint8_t )( irqMask & 0x00FF );
463 buf[2] = ( uint8_t )( ( dio1Mask >> 8 ) & 0x00FF );
464 buf[3] = ( uint8_t )( dio1Mask & 0x00FF );
465 buf[4] = ( uint8_t )( ( dio2Mask >> 8 ) & 0x00FF );
466 buf[5] = ( uint8_t )( dio2Mask & 0x00FF );
467 buf[6] = ( uint8_t )( ( dio3Mask >> 8 ) & 0x00FF );
468 buf[7] = ( uint8_t )( dio3Mask & 0x00FF );
469 SX126xWriteCommand( RADIO_CFG_DIOIRQ, buf, 8 );
470 }
471
SX126xGetIrqStatus(void)472 uint16_t SX126xGetIrqStatus( void )
473 {
474 uint8_t irqStatus[2];
475
476 SX126xReadCommand( RADIO_GET_IRQSTATUS, irqStatus, 2 );
477 return ( irqStatus[0] << 8 ) | irqStatus[1];
478 }
479
SX126xSetDio2AsRfSwitchCtrl(uint8_t enable)480 void SX126xSetDio2AsRfSwitchCtrl( uint8_t enable )
481 {
482 SX126xWriteCommand( RADIO_SET_RFSWITCHMODE, &enable, 1 );
483 }
484
SX126xSetDio3AsTcxoCtrl(RadioTcxoCtrlVoltage_t tcxoVoltage,uint32_t timeout)485 void SX126xSetDio3AsTcxoCtrl( RadioTcxoCtrlVoltage_t tcxoVoltage, uint32_t timeout )
486 {
487 uint8_t buf[4];
488
489 buf[0] = tcxoVoltage & 0x07;
490 buf[1] = ( uint8_t )( ( timeout >> 16 ) & 0xFF );
491 buf[2] = ( uint8_t )( ( timeout >> 8 ) & 0xFF );
492 buf[3] = ( uint8_t )( timeout & 0xFF );
493
494 SX126xWriteCommand( RADIO_SET_TCXOMODE, buf, 4 );
495 }
496
SX126xSetRfFrequency(uint32_t frequency)497 void SX126xSetRfFrequency( uint32_t frequency )
498 {
499 uint8_t buf[4];
500
501 if( ImageCalibrated == false )
502 {
503 SX126xCalibrateImage( frequency );
504 ImageCalibrated = true;
505 }
506
507 uint32_t freqInPllSteps = SX126xConvertFreqInHzToPllStep( frequency );
508
509 buf[0] = ( uint8_t )( ( freqInPllSteps >> 24 ) & 0xFF );
510 buf[1] = ( uint8_t )( ( freqInPllSteps >> 16 ) & 0xFF );
511 buf[2] = ( uint8_t )( ( freqInPllSteps >> 8 ) & 0xFF );
512 buf[3] = ( uint8_t )( freqInPllSteps & 0xFF );
513 SX126xWriteCommand( RADIO_SET_RFFREQUENCY, buf, 4 );
514 }
515
SX126xSetPacketType(RadioPacketTypes_t packetType)516 void SX126xSetPacketType( RadioPacketTypes_t packetType )
517 {
518 // Save packet type internally to avoid questioning the radio
519 PacketType = packetType;
520 SX126xWriteCommand( RADIO_SET_PACKETTYPE, ( uint8_t* )&packetType, 1 );
521 }
522
SX126xGetPacketType(void)523 RadioPacketTypes_t SX126xGetPacketType( void )
524 {
525 return PacketType;
526 }
527
SX126xSetTxParams(int8_t power,RadioRampTimes_t rampTime)528 void SX126xSetTxParams( int8_t power, RadioRampTimes_t rampTime )
529 {
530 uint8_t buf[2];
531
532 if( SX126xGetDeviceId( ) == SX1261 )
533 {
534 if( power == 15 )
535 {
536 SX126xSetPaConfig( 0x06, 0x00, 0x01, 0x01 );
537 }
538 else
539 {
540 SX126xSetPaConfig( 0x04, 0x00, 0x01, 0x01 );
541 }
542 if( power >= 14 )
543 {
544 power = 14;
545 }
546 else if( power < -17 )
547 {
548 power = -17;
549 }
550 }
551 else // sx1262
552 {
553 // WORKAROUND - Better Resistance of the SX1262 Tx to Antenna Mismatch, see DS_SX1261-2_V1.2 datasheet chapter 15.2
554 SX126xWriteRegister( REG_TX_CLAMP_CFG, SX126xReadRegister( REG_TX_CLAMP_CFG ) | ( 0x0F << 1 ) );
555 // WORKAROUND END
556
557 SX126xSetPaConfig( 0x04, 0x07, 0x00, 0x01 );
558 if( power > 22 )
559 {
560 power = 22;
561 }
562 else if( power < -9 )
563 {
564 power = -9;
565 }
566 }
567 buf[0] = power;
568 buf[1] = ( uint8_t )rampTime;
569 SX126xWriteCommand( RADIO_SET_TXPARAMS, buf, 2 );
570 }
571
SX126xSetModulationParams(ModulationParams_t * modulationParams)572 void SX126xSetModulationParams( ModulationParams_t *modulationParams )
573 {
574 uint8_t n;
575 uint32_t tempVal = 0;
576 uint8_t buf[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
577
578 // Check if required configuration corresponds to the stored packet type
579 // If not, silently update radio packet type
580 if( PacketType != modulationParams->PacketType )
581 {
582 SX126xSetPacketType( modulationParams->PacketType );
583 }
584
585 switch( modulationParams->PacketType )
586 {
587 case PACKET_TYPE_GFSK:
588 n = 8;
589 tempVal = ( uint32_t )( 32 * SX126X_XTAL_FREQ / modulationParams->Params.Gfsk.BitRate );
590 buf[0] = ( tempVal >> 16 ) & 0xFF;
591 buf[1] = ( tempVal >> 8 ) & 0xFF;
592 buf[2] = tempVal & 0xFF;
593 buf[3] = modulationParams->Params.Gfsk.ModulationShaping;
594 buf[4] = modulationParams->Params.Gfsk.Bandwidth;
595 tempVal = SX126xConvertFreqInHzToPllStep( modulationParams->Params.Gfsk.Fdev );
596 buf[5] = ( tempVal >> 16 ) & 0xFF;
597 buf[6] = ( tempVal >> 8 ) & 0xFF;
598 buf[7] = ( tempVal& 0xFF );
599 SX126xWriteCommand( RADIO_SET_MODULATIONPARAMS, buf, n );
600 break;
601 case PACKET_TYPE_LORA:
602 n = 4;
603 buf[0] = modulationParams->Params.LoRa.SpreadingFactor;
604 buf[1] = modulationParams->Params.LoRa.Bandwidth;
605 buf[2] = modulationParams->Params.LoRa.CodingRate;
606 buf[3] = modulationParams->Params.LoRa.LowDatarateOptimize;
607
608 SX126xWriteCommand( RADIO_SET_MODULATIONPARAMS, buf, n );
609
610 break;
611 default:
612 case PACKET_TYPE_NONE:
613 return;
614 }
615 }
616
SX126xSetPacketParams(PacketParams_t * packetParams)617 void SX126xSetPacketParams( PacketParams_t *packetParams )
618 {
619 uint8_t n;
620 uint8_t crcVal = 0;
621 uint8_t buf[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
622
623 // Check if required configuration corresponds to the stored packet type
624 // If not, silently update radio packet type
625 if( PacketType != packetParams->PacketType )
626 {
627 SX126xSetPacketType( packetParams->PacketType );
628 }
629
630 switch( packetParams->PacketType )
631 {
632 case PACKET_TYPE_GFSK:
633 if( packetParams->Params.Gfsk.CrcLength == RADIO_CRC_2_BYTES_IBM )
634 {
635 SX126xSetCrcSeed( CRC_IBM_SEED );
636 SX126xSetCrcPolynomial( CRC_POLYNOMIAL_IBM );
637 crcVal = RADIO_CRC_2_BYTES;
638 }
639 else if( packetParams->Params.Gfsk.CrcLength == RADIO_CRC_2_BYTES_CCIT )
640 {
641 SX126xSetCrcSeed( CRC_CCITT_SEED );
642 SX126xSetCrcPolynomial( CRC_POLYNOMIAL_CCITT );
643 crcVal = RADIO_CRC_2_BYTES_INV;
644 }
645 else
646 {
647 crcVal = packetParams->Params.Gfsk.CrcLength;
648 }
649 n = 9;
650 buf[0] = ( packetParams->Params.Gfsk.PreambleLength >> 8 ) & 0xFF;
651 buf[1] = packetParams->Params.Gfsk.PreambleLength;
652 buf[2] = packetParams->Params.Gfsk.PreambleMinDetect;
653 buf[3] = ( packetParams->Params.Gfsk.SyncWordLength /*<< 3*/ ); // convert from byte to bit
654 buf[4] = packetParams->Params.Gfsk.AddrComp;
655 buf[5] = packetParams->Params.Gfsk.HeaderType;
656 buf[6] = packetParams->Params.Gfsk.PayloadLength;
657 buf[7] = crcVal;
658 buf[8] = packetParams->Params.Gfsk.DcFree;
659 break;
660 case PACKET_TYPE_LORA:
661 n = 6;
662 buf[0] = ( packetParams->Params.LoRa.PreambleLength >> 8 ) & 0xFF;
663 buf[1] = packetParams->Params.LoRa.PreambleLength;
664 buf[2] = LoRaHeaderType = packetParams->Params.LoRa.HeaderType;
665 buf[3] = packetParams->Params.LoRa.PayloadLength;
666 buf[4] = packetParams->Params.LoRa.CrcMode;
667 buf[5] = packetParams->Params.LoRa.InvertIQ;
668 break;
669 default:
670 case PACKET_TYPE_NONE:
671 return;
672 }
673 SX126xWriteCommand( RADIO_SET_PACKETPARAMS, buf, n );
674 }
675
SX126xSetCadParams(RadioLoRaCadSymbols_t cadSymbolNum,uint8_t cadDetPeak,uint8_t cadDetMin,RadioCadExitModes_t cadExitMode,uint32_t cadTimeout)676 void SX126xSetCadParams( RadioLoRaCadSymbols_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, RadioCadExitModes_t cadExitMode, uint32_t cadTimeout )
677 {
678 uint8_t buf[7];
679
680 buf[0] = ( uint8_t )cadSymbolNum;
681 buf[1] = cadDetPeak;
682 buf[2] = cadDetMin;
683 buf[3] = ( uint8_t )cadExitMode;
684 buf[4] = ( uint8_t )( ( cadTimeout >> 16 ) & 0xFF );
685 buf[5] = ( uint8_t )( ( cadTimeout >> 8 ) & 0xFF );
686 buf[6] = ( uint8_t )( cadTimeout & 0xFF );
687 SX126xWriteCommand( RADIO_SET_CADPARAMS, buf, 7 );
688 SX126xSetOperatingMode( MODE_CAD );
689 }
690
SX126xSetBufferBaseAddress(uint8_t txBaseAddress,uint8_t rxBaseAddress)691 void SX126xSetBufferBaseAddress( uint8_t txBaseAddress, uint8_t rxBaseAddress )
692 {
693 uint8_t buf[2];
694
695 buf[0] = txBaseAddress;
696 buf[1] = rxBaseAddress;
697 SX126xWriteCommand( RADIO_SET_BUFFERBASEADDRESS, buf, 2 );
698 }
699
SX126xGetStatus(void)700 RadioStatus_t SX126xGetStatus( void )
701 {
702 uint8_t stat = 0;
703 RadioStatus_t status = { .Value = 0 };
704
705 stat = SX126xReadCommand( RADIO_GET_STATUS, NULL, 0 );
706 status.Fields.CmdStatus = ( stat & ( 0x07 << 1 ) ) >> 1;
707 status.Fields.ChipMode = ( stat & ( 0x07 << 4 ) ) >> 4;
708 return status;
709 }
710
SX126xGetRssiInst(void)711 int8_t SX126xGetRssiInst( void )
712 {
713 uint8_t buf[1];
714 int8_t rssi = 0;
715
716 SX126xReadCommand( RADIO_GET_RSSIINST, buf, 1 );
717 rssi = -buf[0] >> 1;
718 return rssi;
719 }
720
SX126xGetRxBufferStatus(uint8_t * payloadLength,uint8_t * rxStartBufferPointer)721 void SX126xGetRxBufferStatus( uint8_t *payloadLength, uint8_t *rxStartBufferPointer )
722 {
723 uint8_t status[2];
724
725 SX126xReadCommand( RADIO_GET_RXBUFFERSTATUS, status, 2 );
726
727 // In case of LORA fixed header, the payloadLength is obtained by reading
728 // the register REG_LR_PAYLOADLENGTH
729 if( ( SX126xGetPacketType( ) == PACKET_TYPE_LORA ) && ( LoRaHeaderType == LORA_PACKET_FIXED_LENGTH ) )
730 {
731 *payloadLength = SX126xReadRegister( REG_LR_PAYLOADLENGTH );
732 }
733 else
734 {
735 *payloadLength = status[0];
736 }
737 *rxStartBufferPointer = status[1];
738 }
739
SX126xGetPacketStatus(PacketStatus_t * pktStatus)740 void SX126xGetPacketStatus( PacketStatus_t *pktStatus )
741 {
742 uint8_t status[3];
743
744 SX126xReadCommand( RADIO_GET_PACKETSTATUS, status, 3 );
745
746 pktStatus->packetType = SX126xGetPacketType( );
747 switch( pktStatus->packetType )
748 {
749 case PACKET_TYPE_GFSK:
750 pktStatus->Params.Gfsk.RxStatus = status[0];
751 pktStatus->Params.Gfsk.RssiSync = -status[1] >> 1;
752 pktStatus->Params.Gfsk.RssiAvg = -status[2] >> 1;
753 pktStatus->Params.Gfsk.FreqError = 0;
754 break;
755
756 case PACKET_TYPE_LORA:
757 pktStatus->Params.LoRa.RssiPkt = -status[0] >> 1;
758 // Returns SNR value [dB] rounded to the nearest integer value
759 pktStatus->Params.LoRa.SnrPkt = ( ( ( int8_t )status[1] ) + 2 ) >> 2;
760 pktStatus->Params.LoRa.SignalRssiPkt = -status[2] >> 1;
761 pktStatus->Params.LoRa.FreqError = FrequencyError;
762 break;
763
764 default:
765 case PACKET_TYPE_NONE:
766 // In that specific case, we set everything in the pktStatus to zeros
767 // and reset the packet type accordingly
768 memset( pktStatus, 0, sizeof( PacketStatus_t ) );
769 pktStatus->packetType = PACKET_TYPE_NONE;
770 break;
771 }
772 }
773
SX126xGetDeviceErrors(void)774 RadioError_t SX126xGetDeviceErrors( void )
775 {
776 uint8_t err[] = { 0, 0 };
777 RadioError_t error = { .Value = 0 };
778
779 SX126xReadCommand( RADIO_GET_ERROR, ( uint8_t* )err, 2 );
780 error.Fields.PaRamp = ( err[0] & ( 1 << 0 ) ) >> 0;
781 error.Fields.PllLock = ( err[1] & ( 1 << 6 ) ) >> 6;
782 error.Fields.XoscStart = ( err[1] & ( 1 << 5 ) ) >> 5;
783 error.Fields.ImgCalib = ( err[1] & ( 1 << 4 ) ) >> 4;
784 error.Fields.AdcCalib = ( err[1] & ( 1 << 3 ) ) >> 3;
785 error.Fields.PllCalib = ( err[1] & ( 1 << 2 ) ) >> 2;
786 error.Fields.Rc13mCalib = ( err[1] & ( 1 << 1 ) ) >> 1;
787 error.Fields.Rc64kCalib = ( err[1] & ( 1 << 0 ) ) >> 0;
788 return error;
789 }
790
SX126xClearDeviceErrors(void)791 void SX126xClearDeviceErrors( void )
792 {
793 uint8_t buf[2] = { 0x00, 0x00 };
794 SX126xWriteCommand( RADIO_CLR_ERROR, buf, 2 );
795 }
796
SX126xClearIrqStatus(uint16_t irq)797 void SX126xClearIrqStatus( uint16_t irq )
798 {
799 uint8_t buf[2];
800
801 buf[0] = ( uint8_t )( ( ( uint16_t )irq >> 8 ) & 0x00FF );
802 buf[1] = ( uint8_t )( ( uint16_t )irq & 0x00FF );
803 SX126xWriteCommand( RADIO_CLR_IRQSTATUS, buf, 2 );
804 }
805
SX126xConvertFreqInHzToPllStep(uint32_t freqInHz)806 static uint32_t SX126xConvertFreqInHzToPllStep( uint32_t freqInHz )
807 {
808 uint32_t stepsInt;
809 uint32_t stepsFrac;
810
811 // pllSteps = freqInHz / (SX126X_XTAL_FREQ / 2^19 )
812 // Get integer and fractional parts of the frequency computed with a PLL step scaled value
813 stepsInt = freqInHz / SX126X_PLL_STEP_SCALED;
814 stepsFrac = freqInHz - ( stepsInt * SX126X_PLL_STEP_SCALED );
815
816 // Apply the scaling factor to retrieve a frequency in Hz (+ ceiling)
817 return ( stepsInt << SX126X_PLL_STEP_SHIFT_AMOUNT ) +
818 ( ( ( stepsFrac << SX126X_PLL_STEP_SHIFT_AMOUNT ) + ( SX126X_PLL_STEP_SCALED >> 1 ) ) /
819 SX126X_PLL_STEP_SCALED );
820 }
821