1 #include "SX1280_Regs.h"
2 #include "SX1280_hal.h"
7 SX1280Driver
*SX1280Driver::instance
= NULL
;
9 //DEBUG_SX1280_OTA_TIMING
13 1. If not in STDBY_RC mode, then go to this mode by sending the command:
16 2. Define the LoRa® packet type by sending the command:
17 SetPacketType(PACKET_TYPE_LORA)
19 3. Define the RF frequency by sending the command:
20 SetRfFrequency(rfFrequency)
21 The LSB of rfFrequency is equal to the PLL step i.e. 52e6/2^18 Hz. SetRfFrequency() defines the Tx frequency.
23 4. Indicate the addresses where the packet handler will read (txBaseAddress in Tx) or write (rxBaseAddress in Rx) the first
24 byte of the data payload by sending the command:
25 SetBufferBaseAddress(txBaseAddress, rxBaseAddress)
27 txBaseAddress and rxBaseAddress are offset relative to the beginning of the data memory map.
29 5. Define the modulation parameter signal BW SF CR
32 #if defined(DEBUG_SX1280_OTA_TIMING)
33 static uint32_t beginTX
;
34 static uint32_t endTX
;
37 void ICACHE_RAM_ATTR
SX1280Driver::nullCallback(void) {}
39 SX1280Driver::SX1280Driver()
44 void SX1280Driver::End()
46 SetMode(SX1280_MODE_SLEEP
);
48 TXdoneCallback
= &nullCallback
; // remove callbacks
49 RXdoneCallback
= &nullCallback
;
52 bool SX1280Driver::Begin()
55 hal
.IsrCallback
= &SX1280Driver::IsrCallback
;
58 DBGLN("SX1280 Begin");
60 uint16_t firmwareRev
= (((hal
.ReadRegister(REG_LR_FIRMWARE_VERSION_MSB
)) << 8) | (hal
.ReadRegister(REG_LR_FIRMWARE_VERSION_MSB
+ 1)));
61 DBGLN("Read Vers: %d", firmwareRev
);
62 if ((firmwareRev
== 0) || (firmwareRev
== 65535))
64 // SPI communication failed, just return without configuration
68 SetMode(SX1280_MODE_STDBY_RC
); //Put in STDBY_RC mode
69 hal
.WriteCommand(SX1280_RADIO_SET_PACKETTYPE
, SX1280_PACKET_TYPE_LORA
); //Set packet type to LoRa
70 ConfigLoRaModParams(currBW
, currSF
, currCR
); //Configure Modulation Params
71 hal
.WriteCommand(SX1280_RADIO_SET_AUTOFS
, 0x01); //Enable auto FS
72 hal
.WriteRegister(0x0891, (hal
.ReadRegister(0x0891) | 0xC0)); //default is low power mode, switch to high sensitivity instead
73 SetPacketParams(12, SX1280_LORA_PACKET_IMPLICIT
, 8, SX1280_LORA_CRC_OFF
, SX1280_LORA_IQ_NORMAL
); //default params
74 SetFrequencyReg(currFreq
); //Set Freq
75 SetFIFOaddr(0x00, 0x00); //Config FIFO addr
76 SetDioIrqParams(SX1280_IRQ_RADIO_ALL
, SX1280_IRQ_TX_DONE
| SX1280_IRQ_RX_DONE
, SX1280_IRQ_RADIO_NONE
, SX1280_IRQ_RADIO_NONE
); //set IRQ to both RXdone/TXdone on DIO1
77 #if defined(USE_SX1280_DCDC)
78 hal
.WriteCommand(SX1280_RADIO_SET_REGULATORMODE
, 0x01); // Enable DCDC converter instead of LDO
83 void SX1280Driver::Config(SX1280_RadioLoRaBandwidths_t bw
, SX1280_RadioLoRaSpreadingFactors_t sf
, SX1280_RadioLoRaCodingRates_t cr
, uint32_t freq
, uint8_t PreambleLength
, bool InvertIQ
, uint8_t PayloadLength
)
85 PayloadLength
= PayloadLength
;
86 IQinverted
= InvertIQ
;
87 SetMode(SX1280_MODE_STDBY_XOSC
);
88 ConfigLoRaModParams(bw
, sf
, cr
);
89 SetPacketParams(PreambleLength
, SX1280_LORA_PACKET_IMPLICIT
, PayloadLength
, SX1280_LORA_CRC_OFF
, (SX1280_RadioLoRaIQModes_t
)((uint8_t)!IQinverted
<< 6)); // TODO don't make static etc. LORA_IQ_STD = 0x40, LORA_IQ_INVERTED = 0x00
90 SetFrequencyReg(freq
);
93 void SX1280Driver::SetOutputPower(int8_t power
)
95 if (power
< -18) power
= -18;
96 else if (13 < power
) power
= 13;
97 uint8_t buf
[2] = {(uint8_t)(power
+ 18), (uint8_t)SX1280_RADIO_RAMP_04_US
};
98 hal
.WriteCommand(SX1280_RADIO_SET_TXPARAMS
, buf
, sizeof(buf
));
99 DBGLN("SetPower: %d", buf
[0]);
103 void SX1280Driver::SetPacketParams(uint8_t PreambleLength
, SX1280_RadioLoRaPacketLengthsModes_t HeaderType
, uint8_t PayloadLength
, SX1280_RadioLoRaCrcModes_t crc
, SX1280_RadioLoRaIQModes_t InvertIQ
)
107 buf
[0] = PreambleLength
;
109 buf
[2] = PayloadLength
;
115 hal
.WriteCommand(SX1280_RADIO_SET_PACKETPARAMS
, buf
, sizeof(buf
));
118 void SX1280Driver::SetMode(SX1280_RadioOperatingModes_t OPmode
)
121 if (OPmode
== currOpmode
)
126 WORD_ALIGNED_ATTR
uint8_t buf
[3];
127 uint32_t switchDelay
= 0;
132 case SX1280_MODE_SLEEP
:
133 hal
.WriteCommand(SX1280_RADIO_SET_SLEEP
, 0x01);
136 case SX1280_MODE_CALIBRATION
:
139 case SX1280_MODE_STDBY_RC
:
140 hal
.WriteCommand(SX1280_RADIO_SET_STANDBY
, SX1280_STDBY_RC
);
144 case SX1280_MODE_STDBY_XOSC
:
145 hal
.WriteCommand(SX1280_RADIO_SET_STANDBY
, SX1280_STDBY_XOSC
);
150 hal
.WriteCommand(SX1280_RADIO_SET_FS
, 0x00);
155 buf
[0] = 0x00; // periodBase = 1ms, page 71 datasheet, set to FF for cont RX
158 hal
.WriteCommand(SX1280_RADIO_SET_RX
, buf
, sizeof(buf
));
163 //uses timeout Time-out duration = periodBase * periodBaseCount
164 buf
[0] = 0x00; // periodBase = 1ms, page 71 datasheet
165 buf
[1] = 0xFF; // no timeout set for now
166 buf
[2] = 0xFF; // TODO dynamic timeout based on expected onairtime
167 hal
.WriteCommand(SX1280_RADIO_SET_TX
, buf
, sizeof(buf
));
171 case SX1280_MODE_CAD
:
177 hal
.BusyDelay(switchDelay
);
182 void SX1280Driver::ConfigLoRaModParams(SX1280_RadioLoRaBandwidths_t bw
, SX1280_RadioLoRaSpreadingFactors_t sf
, SX1280_RadioLoRaCodingRates_t cr
)
184 // Care must therefore be taken to ensure that modulation parameters are set using the command
185 // SetModulationParam() only after defining the packet type SetPacketType() to be used
187 WORD_ALIGNED_ATTR
uint8_t rfparams
[3] = {0};
189 rfparams
[0] = (uint8_t)sf
;
190 rfparams
[1] = (uint8_t)bw
;
191 rfparams
[2] = (uint8_t)cr
;
193 hal
.WriteCommand(SX1280_RADIO_SET_MODULATIONPARAMS
, rfparams
, sizeof(rfparams
));
197 case SX1280_LORA_SF5
:
198 case SX1280_LORA_SF6
:
199 hal
.WriteRegister(0x925, 0x1E); // for SF5 or SF6
201 case SX1280_LORA_SF7
:
202 case SX1280_LORA_SF8
:
203 hal
.WriteRegister(0x925, 0x37); // for SF7 or SF8
206 hal
.WriteRegister(0x925, 0x32); // for SF9, SF10, SF11, SF12
210 void ICACHE_RAM_ATTR
SX1280Driver::SetFrequencyHz(uint32_t Reqfreq
)
212 WORD_ALIGNED_ATTR
uint8_t buf
[3] = {0};
214 uint32_t freq
= (uint32_t)((double)Reqfreq
/ (double)FREQ_STEP
);
215 buf
[0] = (uint8_t)((freq
>> 16) & 0xFF);
216 buf
[1] = (uint8_t)((freq
>> 8) & 0xFF);
217 buf
[2] = (uint8_t)(freq
& 0xFF);
219 hal
.WriteCommand(SX1280_RADIO_SET_RFFREQUENCY
, buf
, sizeof(buf
));
223 void ICACHE_RAM_ATTR
SX1280Driver::SetFrequencyReg(uint32_t freq
)
225 WORD_ALIGNED_ATTR
uint8_t buf
[3] = {0};
227 buf
[0] = (uint8_t)((freq
>> 16) & 0xFF);
228 buf
[1] = (uint8_t)((freq
>> 8) & 0xFF);
229 buf
[2] = (uint8_t)(freq
& 0xFF);
231 hal
.WriteCommand(SX1280_RADIO_SET_RFFREQUENCY
, buf
, sizeof(buf
));
235 int32_t ICACHE_RAM_ATTR
SX1280Driver::GetFrequencyError()
237 WORD_ALIGNED_ATTR
uint8_t efeRaw
[3] = {0};
241 efeRaw
[0] = hal
.ReadRegister(SX1280_REG_LR_ESTIMATED_FREQUENCY_ERROR_MSB
);
242 efeRaw
[1] = hal
.ReadRegister(SX1280_REG_LR_ESTIMATED_FREQUENCY_ERROR_MSB
+ 1);
243 efeRaw
[2] = hal
.ReadRegister(SX1280_REG_LR_ESTIMATED_FREQUENCY_ERROR_MSB
+ 2);
244 efe
= (efeRaw
[0] << 16) | (efeRaw
[1] << 8) | efeRaw
[2];
246 efe
&= SX1280_REG_LR_ESTIMATED_FREQUENCY_ERROR_MASK
;
248 //efeHz = 1.55 * (double)complement2(efe, 20) / (1600.0 / (double)GetLoRaBandwidth() * 1000.0);
252 void SX1280Driver::SetFIFOaddr(uint8_t txBaseAddr
, uint8_t rxBaseAddr
)
258 hal
.WriteCommand(SX1280_RADIO_SET_BUFFERBASEADDRESS
, buf
, sizeof(buf
));
261 void SX1280Driver::SetDioIrqParams(uint16_t irqMask
, uint16_t dio1Mask
, uint16_t dio2Mask
, uint16_t dio3Mask
)
265 buf
[0] = (uint8_t)((irqMask
>> 8) & 0x00FF);
266 buf
[1] = (uint8_t)(irqMask
& 0x00FF);
267 buf
[2] = (uint8_t)((dio1Mask
>> 8) & 0x00FF);
268 buf
[3] = (uint8_t)(dio1Mask
& 0x00FF);
269 buf
[4] = (uint8_t)((dio2Mask
>> 8) & 0x00FF);
270 buf
[5] = (uint8_t)(dio2Mask
& 0x00FF);
271 buf
[6] = (uint8_t)((dio3Mask
>> 8) & 0x00FF);
272 buf
[7] = (uint8_t)(dio3Mask
& 0x00FF);
274 hal
.WriteCommand(SX1280_RADIO_SET_DIOIRQPARAMS
, buf
, sizeof(buf
));
277 uint16_t ICACHE_RAM_ATTR
SX1280Driver::GetIrqStatus()
281 hal
.ReadCommand(SX1280_RADIO_GET_IRQSTATUS
, status
, 2);
282 return status
[0] << 8 | status
[1];
285 void ICACHE_RAM_ATTR
SX1280Driver::ClearIrqStatus(uint16_t irqMask
)
289 buf
[0] = (uint8_t)(((uint16_t)irqMask
>> 8) & 0x00FF);
290 buf
[1] = (uint8_t)((uint16_t)irqMask
& 0x00FF);
292 hal
.WriteCommand(SX1280_RADIO_CLR_IRQSTATUS
, buf
, sizeof(buf
));
295 void ICACHE_RAM_ATTR
SX1280Driver::TXnbISR()
297 currOpmode
= SX1280_MODE_FS
; // radio goes to FS after TX
298 #ifdef DEBUG_SX1280_OTA_TIMING
300 DBGLN("TOA: %d", endTX
- beginTX
);
305 uint8_t FIFOaddr
= 0;
307 void ICACHE_RAM_ATTR
SX1280Driver::TXnb()
309 if (currOpmode
== SX1280_MODE_TX
) //catch TX timeout
312 SetMode(SX1280_MODE_FS
);
316 hal
.TXenable(); // do first to allow PA stablise
317 hal
.WriteBuffer(0x00, TXdataBuffer
, PayloadLength
); //todo fix offset to equal fifo addr
318 instance
->SetMode(SX1280_MODE_TX
);
319 #ifdef DEBUG_SX1280_OTA_TIMING
324 void ICACHE_RAM_ATTR
SX1280Driver::RXnbISR()
326 // In continuous receive mode, the device stays in Rx mode
327 //currOpmode = SX1280_MODE_FS;
328 uint8_t FIFOaddr
= GetRxBufferAddr();
329 hal
.ReadBuffer(FIFOaddr
, RXdataBuffer
, PayloadLength
);
330 GetLastPacketStats();
334 void ICACHE_RAM_ATTR
SX1280Driver::RXnb()
337 SetMode(SX1280_MODE_RX
);
340 uint8_t ICACHE_RAM_ATTR
SX1280Driver::GetRxBufferAddr()
342 WORD_ALIGNED_ATTR
uint8_t status
[2] = {0};
343 hal
.ReadCommand(SX1280_RADIO_GET_RXBUFFERSTATUS
, status
, 2);
347 void ICACHE_RAM_ATTR
SX1280Driver::GetStatus()
350 hal
.ReadCommand(SX1280_RADIO_GET_STATUS
, (uint8_t *)&status
, 1);
351 DBGLN("Status: %x, %x, %x", (0b11100000 & status
) >> 5, (0b00011100 & status
) >> 2, 0b00000001 & status
);
354 bool ICACHE_RAM_ATTR
SX1280Driver::GetFrequencyErrorbool()
358 hal
.ReadRegister(SX1280_REG_LR_ESTIMATED_FREQUENCY_ERROR_MSB
, regEFI
, sizeof(regEFI
));
360 DBGLN("%d %d %d", regEFI
[0], regEFI
[1], regEFI
[2]);
362 //bool result = (val & 0b00001000) >> 3;
363 //return result; // returns true if pos freq error, neg if false
367 void ICACHE_RAM_ATTR
SX1280Driver::GetLastPacketStats()
371 hal
.ReadCommand(SX1280_RADIO_GET_PACKETSTATUS
, status
, 2);
372 LastPacketRSSI
= -(int8_t)(status
[0] / 2);
373 LastPacketSNR
= (int8_t)status
[1] / 4;
376 void ICACHE_RAM_ATTR
SX1280Driver::IsrCallback()
378 uint16_t irqStatus
= instance
->GetIrqStatus();
379 instance
->ClearIrqStatus(SX1280_IRQ_RADIO_ALL
);
380 if ((irqStatus
& SX1280_IRQ_TX_DONE
))
382 else if ((irqStatus
& SX1280_IRQ_RX_DONE
))