2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
22 * Based on https://github.com/ExpressLRS/ExpressLRS
23 * Thanks to AlessandroAU, original creator of the ExpressLRS project.
35 #include "build/atomic.h"
36 #include "build/debug.h"
38 #include "drivers/bus_spi.h"
39 #include "drivers/io.h"
40 #include "drivers/io_impl.h"
41 #include "drivers/nvic.h"
42 #include "drivers/rx/rx_sx1280.h"
43 #include "drivers/rx/rx_spi.h"
44 #include "drivers/time.h"
46 #include "rx/rx_spi.h"
47 #include "rx/expresslrs.h"
48 #include "rx/expresslrs_common.h"
49 #include "rx/expresslrs_impl.h"
51 #define SX1280_MAX_SPI_MHZ 18000000
53 // The following global variables are accessed from interrupt context to process the sequence of steps in packet processing
54 // As there is only ever one device, no need to add a device context; globals will do
55 static volatile dioReason_e irqReason
; // Used to pass irq status from sx1280IrqStatusRead() to sx1280ProcessIrq()
56 static volatile uint8_t packetStats
[2];
57 static volatile uint8_t FIFOaddr
; // Used to pass data from sx1280GotFIFOAddr() to sx1280DoReadBuffer()
61 typedef struct busyIntContext_s
{
62 extiCallbackRec_t exti
;
65 static busyIntContext_t busyIntContext
;
67 static volatile timeUs_t sx1280Processing
;
69 static volatile bool pendingISR
= false;
70 static volatile bool pendingDoFHSS
= false;
72 #define SX1280_BUSY_TIMEOUT_US 1000
75 bool sx1280IsBusy(void)
80 FAST_CODE
static bool sx1280PollBusy(void)
82 uint32_t startTime
= micros();
83 while (IORead(busy
)) {
84 if ((micros() - startTime
) > SX1280_BUSY_TIMEOUT_US
) {
93 FAST_CODE
static bool sx1280MarkBusy(void)
95 // Check that there isn't already a sequence of accesses to the SX1280 in progress
96 ATOMIC_BLOCK(NVIC_PRIO_MAX
) {
97 if (sx1280Processing
) {
101 sx1280Processing
= micros();
107 static void sx1280ClearBusyFn(void)
112 // Switch to waiting for busy interrupt
113 FAST_CODE
static bool sx1280EnableBusy(void)
115 if (!sx1280MarkBusy()) {
119 /* Ensure BUSY EXTI is enabled
121 * This is needed because the BETAFPV F4SX1280 target defines the following resources which cannot be
122 * simultaneously used with the EXTI15_10_IRQHandler. Fortunately we can enable RX_SPI_EXTI until an
123 * interrupt is received, then enable RX_SPI_EXPRESSLRS_BUSY with the call below until data transfers
124 * are complete and then switch back with a call to sx1280EnableExti().
126 * resource RX_SPI_EXTI 1 C13
127 * resource RX_SPI_EXPRESSLRS_BUSY 1 A13
131 EXTIConfig(busy
, &busyIntContext
.exti
, NVIC_PRIO_RX_BUSY_EXTI
, IOCFG_IN_FLOATING
, BETAFLIGHT_EXTI_TRIGGER_FALLING
);
136 // waitingFn() must call sx1280ClearBusyFn() to prevent repeated calls
138 static void sx1280SetBusyFn(extiHandlerCallback
*waitingFn
)
142 ATOMIC_BLOCK(NVIC_PRIO_RX_BUSY_EXTI
) {
143 sx1280Busy
= IORead(busy
);
145 EXTIHandlerInit(&busyIntContext
.exti
, waitingFn
);
153 waitingFn(&busyIntContext
.exti
);
157 static void sx1280MarkFree(void)
159 // Mark that current sequence of accesses is concluded
160 sx1280Processing
= (timeUs_t
)0;
163 // Switch to waiting for EXTI interrupt
164 static void sx1280EnableExti(void)
170 // Unlikely as it is for the code to lock up waiting on a busy SX1280, we can't afford the risk
171 // If this routine is called twice in succession whilst waiting on the same busy, force the code to advance
172 // Called from the Tick timer
173 bool sx1280HandleFromTick(void)
175 // Grab a copy to prevent a race condition
176 timeUs_t startTime
= sx1280Processing
;
179 // No operation should take SX1280_BUSY_TIMEOUT_US us
180 if (cmpTimeUs(micros(), startTime
) > SX1280_BUSY_TIMEOUT_US
) {
181 // Brute force abandon the current sequence of operations
193 bool sx1280Init(IO_t resetPin
, IO_t busyPin
)
195 if (!rxSpiExtiConfigured()) {
199 rxSpiSetNormalSpeedMhz(SX1280_MAX_SPI_MHZ
);
203 IOInit(resetPin
, OWNER_RX_SPI_EXPRESSLRS_RESET
, 0);
204 IOConfigGPIO(resetPin
, IOCFG_OUT_PP
);
210 IOInit(busyPin
, OWNER_RX_SPI_EXPRESSLRS_BUSY
, 0);
211 IOConfigGPIO(busyPin
, IOCFG_IN_FLOATING
);
220 IOConfigGPIO(resetPin
, IOCFG_IN_FLOATING
); // leave floating, internal pullup on sx1280 side
223 uint16_t firmwareRev
= (((sx1280ReadRegister(REG_LR_FIRMWARE_VERSION_MSB
)) << 8) | (sx1280ReadRegister(REG_LR_FIRMWARE_VERSION_MSB
+ 1)));
225 if ((firmwareRev
== 0) || (firmwareRev
== 65535)) {
229 // Record the dev pointer for callbacks
230 extDevice_t
*dev
= rxSpiGetDevice();
231 dev
->callbackArg
= (uint32_t)dev
;
236 void sx1280WriteCommand(const uint8_t address
, const uint8_t data
)
239 rxSpiWriteCommand(address
, data
);
242 void sx1280WriteCommandBurst(const uint8_t address
, const uint8_t *data
, const uint8_t length
)
244 uint8_t outBuffer
[length
+ 1];
246 outBuffer
[0] = address
;
248 memcpy(outBuffer
+ 1, data
, length
);
251 rxSpiTransferCommandMulti(&outBuffer
[0], length
+ 1);
254 void sx1280ReadCommandBurst(const uint8_t address
, uint8_t *data
, const uint8_t length
)
256 uint8_t outBuffer
[length
+ 2];
258 outBuffer
[0] = address
;
261 memcpy(outBuffer
+ 2, data
, length
);
264 rxSpiTransferCommandMulti(&outBuffer
[0], length
+ 2);
265 memcpy(data
, outBuffer
+ 2, length
);
268 void sx1280WriteRegisterBurst(const uint16_t address
, const uint8_t *buffer
, const uint8_t size
)
270 uint8_t outBuffer
[size
+ 3];
272 outBuffer
[0] = (uint8_t) SX1280_RADIO_WRITE_REGISTER
;
273 outBuffer
[1] = ((address
& 0xFF00) >> 8);
274 outBuffer
[2] = (address
& 0x00FF);
276 memcpy(outBuffer
+ 3, buffer
, size
);
279 rxSpiTransferCommandMulti(&outBuffer
[0], size
+ 3);
282 void sx1280WriteRegister(const uint16_t address
, const uint8_t value
)
284 sx1280WriteRegisterBurst(address
, &value
, 1);
287 void sx1280ReadRegisterBurst(const uint16_t address
, uint8_t *buffer
, const uint8_t size
)
289 uint8_t outBuffer
[size
+ 4];
291 outBuffer
[0] = (uint8_t) SX1280_RADIO_READ_REGISTER
;
292 outBuffer
[1] = ((address
& 0xFF00) >> 8);
293 outBuffer
[2] = (address
& 0x00FF);
297 rxSpiTransferCommandMulti(&outBuffer
[0], size
+ 4);
298 memcpy(buffer
, outBuffer
+ 4, size
);
301 uint8_t sx1280ReadRegister(const uint16_t address
)
304 sx1280ReadRegisterBurst(address
, &data
, 1);
308 void sx1280WriteBuffer(const uint8_t offset
, const uint8_t *buffer
, const uint8_t size
)
310 uint8_t outBuffer
[size
+ 2];
312 outBuffer
[0] = (uint8_t) SX1280_RADIO_WRITE_BUFFER
;
313 outBuffer
[1] = offset
;
315 memcpy(outBuffer
+ 2, buffer
, size
);
318 rxSpiTransferCommandMulti(&outBuffer
[0], size
+ 2);
321 void sx1280ReadBuffer(const uint8_t offset
, uint8_t *buffer
, const uint8_t size
)
323 uint8_t outBuffer
[size
+ 3];
325 outBuffer
[0] = (uint8_t) SX1280_RADIO_READ_BUFFER
;
326 outBuffer
[1] = offset
;
330 rxSpiTransferCommandMulti(&outBuffer
[0], size
+ 3);
331 memcpy(buffer
, outBuffer
+ 3, size
);
334 uint8_t sx1280GetStatus(void)
336 uint8_t buffer
[3] = {(uint8_t) SX1280_RADIO_GET_STATUS
, 0, 0};
338 rxSpiTransferCommandMulti(&buffer
[0], 3);
342 void sx1280ConfigLoraDefaults(void)
344 sx1280SetMode(SX1280_MODE_STDBY_RC
); //step 1 put in STDBY_RC mode
345 sx1280WriteCommand(SX1280_RADIO_SET_PACKETTYPE
, SX1280_PACKET_TYPE_LORA
); //Step 2: set packet type to LoRa
346 sx1280ConfigLoraModParams(SX1280_LORA_BW_0800
, SX1280_LORA_SF6
, SX1280_LORA_CR_4_7
); //Step 5: Configure Modulation Params
347 sx1280WriteCommand(SX1280_RADIO_SET_AUTOFS
, 0x01); //enable auto FS
348 sx1280WriteRegister(0x0891, (sx1280ReadRegister(0x0891) | 0xC0)); //default is low power mode, switch to high sensitivity instead
349 sx1280SetPacketParams(12, SX1280_LORA_PACKET_IMPLICIT
, 8, SX1280_LORA_CRC_OFF
, SX1280_LORA_IQ_NORMAL
); //default params
350 sx1280SetFrequencyReg(fhssGetInitialFreq(0)); //Step 3: Set Freq
351 sx1280SetFifoAddr(0x00, 0x00); //Step 4: Config FIFO addr
352 sx1280SetDioIrqParams(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
355 void sx1280Config(const sx1280LoraBandwidths_e bw
, const sx1280LoraSpreadingFactors_e sf
, const sx1280LoraCodingRates_e cr
,
356 const uint32_t freq
, const uint8_t preambleLength
, const bool iqInverted
)
358 sx1280SetMode(SX1280_MODE_SLEEP
);
361 sx1280ConfigLoraDefaults();
362 sx1280SetOutputPower(13); //default is max power (12.5dBm for SX1280 RX)
363 sx1280SetMode(SX1280_MODE_STDBY_RC
);
364 sx1280ClearIrqStatus(SX1280_IRQ_RADIO_ALL
);
365 sx1280ConfigLoraModParams(bw
, sf
, cr
);
366 sx1280SetPacketParams(preambleLength
, SX1280_LORA_PACKET_IMPLICIT
, 8, SX1280_LORA_CRC_OFF
, (sx1280LoraIqModes_e
)((uint8_t)!iqInverted
<< 6)); // TODO don't make static etc.
367 sx1280SetFrequencyReg(freq
);
370 void sx1280SetOutputPower(const int8_t power
)
374 buf
[1] = (uint8_t) SX1280_RADIO_RAMP_04_US
;
375 sx1280WriteCommandBurst(SX1280_RADIO_SET_TXPARAMS
, buf
, 2);
378 void sx1280SetPacketParams(const uint8_t preambleLength
, const sx1280LoraPacketLengthsModes_e headerType
, const uint8_t payloadLength
,
379 const sx1280LoraCrcModes_e crc
, const sx1280LoraIqModes_e invertIQ
)
383 buf
[0] = preambleLength
;
385 buf
[2] = payloadLength
;
391 sx1280WriteCommandBurst(SX1280_RADIO_SET_PACKETPARAMS
, buf
, 7);
394 void sx1280SetMode(const sx1280OperatingModes_e opMode
)
399 case SX1280_MODE_SLEEP
:
400 sx1280WriteCommand(SX1280_RADIO_SET_SLEEP
, 0x01);
402 case SX1280_MODE_CALIBRATION
:
404 case SX1280_MODE_STDBY_RC
:
405 sx1280WriteCommand(SX1280_RADIO_SET_STANDBY
, SX1280_STDBY_RC
);
407 case SX1280_MODE_STDBY_XOSC
:
408 sx1280WriteCommand(SX1280_RADIO_SET_STANDBY
, SX1280_STDBY_XOSC
);
411 sx1280WriteCommand(SX1280_RADIO_SET_FS
, 0x00);
414 buf
[0] = 0x00; // periodBase = 1ms, page 71 datasheet, set to FF for cont RX
417 sx1280WriteCommandBurst(SX1280_RADIO_SET_RX
, buf
, 3);
420 //uses timeout Time-out duration = periodBase * periodBaseCount
421 buf
[0] = 0x00; // periodBase = 1ms, page 71 datasheet
422 buf
[1] = 0xFF; // no timeout set for now
423 buf
[2] = 0xFF; // TODO dynamic timeout based on expected onairtime
424 sx1280WriteCommandBurst(SX1280_RADIO_SET_TX
, buf
, 3);
426 case SX1280_MODE_CAD
: // not implemented yet
432 void sx1280ConfigLoraModParams(const sx1280LoraBandwidths_e bw
, const sx1280LoraSpreadingFactors_e sf
, const sx1280LoraCodingRates_e cr
)
434 // Care must therefore be taken to ensure that modulation parameters are set using the command
435 // SetModulationParam() only after defining the packet type SetPacketType() to be used
437 uint8_t rfparams
[3] = {0};
439 rfparams
[0] = (uint8_t)sf
;
440 rfparams
[1] = (uint8_t)bw
;
441 rfparams
[2] = (uint8_t)cr
;
443 sx1280WriteCommandBurst(SX1280_RADIO_SET_MODULATIONPARAMS
, rfparams
, 3);
446 case SX1280_LORA_SF5
:
447 case SX1280_LORA_SF6
:
448 sx1280WriteRegister(0x925, 0x1E); // for SF5 or SF6
450 case SX1280_LORA_SF7
:
451 case SX1280_LORA_SF8
:
452 sx1280WriteRegister(0x925, 0x37); // for SF7 or SF8
455 sx1280WriteRegister(0x925, 0x32); // for SF9, SF10, SF11, SF12
459 void sx1280SetFrequencyReg(const uint32_t freqReg
)
461 uint8_t buf
[3] = {0};
463 buf
[0] = (uint8_t)((freqReg
>> 16) & 0xFF);
464 buf
[1] = (uint8_t)((freqReg
>> 8) & 0xFF);
465 buf
[2] = (uint8_t)(freqReg
& 0xFF);
467 sx1280WriteCommandBurst(SX1280_RADIO_SET_RFFREQUENCY
, buf
, 3);
470 void sx1280AdjustFrequency(int32_t offset
, const uint32_t freq
)
472 // just a stub to show that frequency adjustment is not used on this chip as opposed to sx127x
477 void sx1280SetFifoAddr(const uint8_t txBaseAddr
, const uint8_t rxBaseAddr
)
483 sx1280WriteCommandBurst(SX1280_RADIO_SET_BUFFERBASEADDRESS
, buf
, 2);
486 void sx1280SetDioIrqParams(const uint16_t irqMask
, const uint16_t dio1Mask
, const uint16_t dio2Mask
, const uint16_t dio3Mask
)
490 buf
[0] = (uint8_t)((irqMask
>> 8) & 0x00FF);
491 buf
[1] = (uint8_t)(irqMask
& 0x00FF);
492 buf
[2] = (uint8_t)((dio1Mask
>> 8) & 0x00FF);
493 buf
[3] = (uint8_t)(dio1Mask
& 0x00FF);
494 buf
[4] = (uint8_t)((dio2Mask
>> 8) & 0x00FF);
495 buf
[5] = (uint8_t)(dio2Mask
& 0x00FF);
496 buf
[6] = (uint8_t)((dio3Mask
>> 8) & 0x00FF);
497 buf
[7] = (uint8_t)(dio3Mask
& 0x00FF);
499 sx1280WriteCommandBurst(SX1280_RADIO_SET_DIOIRQPARAMS
, buf
, 8);
502 void sx1280TransmitData(const uint8_t *data
, const uint8_t length
)
504 sx1280WriteBuffer(0x00, data
, length
);
505 sx1280SetMode(SX1280_MODE_TX
);
508 static uint8_t sx1280GetRxBufferAddr(void)
510 uint8_t status
[2] = {0};
511 sx1280ReadCommandBurst(SX1280_RADIO_GET_RXBUFFERSTATUS
, status
, 2);
515 void sx1280ReceiveData(uint8_t *data
, const uint8_t length
)
517 uint8_t FIFOaddr
= sx1280GetRxBufferAddr();
518 sx1280ReadBuffer(FIFOaddr
, data
, length
);
521 void sx1280StartReceiving(void)
523 if (sx1280MarkBusy()) {
524 sx1280SetMode(SX1280_MODE_RX
);
529 void sx1280GetLastPacketStats(int8_t *rssi
, int8_t *snr
)
531 *rssi
= -(int8_t)(packetStats
[0] / 2);
532 *snr
= (int8_t) packetStats
[1];
533 int8_t negOffset
= (*snr
< 0) ? (*snr
/ 4) : 0;
537 void sx1280DoFHSS(void)
542 void sx1280ClearIrqStatus(const uint16_t irqMask
)
546 buf
[0] = (uint8_t)(((uint16_t)irqMask
>> 8) & 0x00FF);
547 buf
[1] = (uint8_t)((uint16_t)irqMask
& 0x00FF);
549 sx1280WriteCommandBurst(SX1280_RADIO_CLR_IRQSTATUS
, buf
, 2);
552 // Forward Definitions for DMA Chain //
553 static void sx1280IrqGetStatus(extiCallbackRec_t
*cb
);
554 static busStatus_e
sx1280IrqStatusRead(uint32_t arg
);
555 static void sx1280IrqClearStatus(extiCallbackRec_t
*cb
);
556 static busStatus_e
sx1280IrqCmdComplete(uint32_t arg
);
557 static void sx1280ProcessIrq(extiCallbackRec_t
*cb
);
558 static busStatus_e
sx1280GotFIFOAddr(uint32_t arg
);
559 static void sx1280DoReadBuffer(extiCallbackRec_t
*cb
);
560 static busStatus_e
sx1280ReadBufferComplete(uint32_t arg
);
561 static void sx1280GetPacketStats(extiCallbackRec_t
*cb
);
562 static busStatus_e
sx1280GetStatsCmdComplete(uint32_t arg
);
563 static busStatus_e
sx1280IsFhssReq(uint32_t arg
);
564 static void sx1280SetFrequency(extiCallbackRec_t
*cb
);
565 static busStatus_e
sx1280SetFreqComplete(uint32_t arg
);
566 static void sx1280StartReceivingDMA(extiCallbackRec_t
*cb
);
567 static busStatus_e
sx1280EnableIRQs(uint32_t arg
);
568 static void sx1280SendTelemetryBuffer(extiCallbackRec_t
*cb
);
569 static busStatus_e
sx1280TelemetryComplete(uint32_t arg
);
570 static void sx1280StartTransmittingDMA(extiCallbackRec_t
*cb
);
572 FAST_IRQ_HANDLER
void sx1280ISR(void)
574 // Only attempt to access the SX1280 if it is currently idle to avoid any race condition
575 ATOMIC_BLOCK(NVIC_PRIO_RX_INT_EXTI
) {
576 if (sx1280EnableBusy()) {
578 sx1280SetBusyFn(sx1280IrqGetStatus
);
585 // Next, the reason for the IRQ must be read
587 FAST_IRQ_HANDLER
static void sx1280IrqGetStatus(extiCallbackRec_t
*cb
)
589 extDevice_t
*dev
= rxSpiGetDevice();
595 STATIC_DMA_DATA_AUTO
uint8_t irqStatusCmd
[] = {SX1280_RADIO_GET_IRQSTATUS
, 0, 0, 0};
596 STATIC_DMA_DATA_AUTO
uint8_t irqStatus
[sizeof(irqStatusCmd
)];
598 static busSegment_t segments
[] = {
599 {.u
.buffers
= {irqStatusCmd
, irqStatus
}, sizeof(irqStatusCmd
), true, sx1280IrqStatusRead
},
600 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
603 spiSequence(dev
, segments
);
606 // Read the IRQ status, and save it to irqStatus variable
608 FAST_IRQ_HANDLER
static busStatus_e
sx1280IrqStatusRead(uint32_t arg
)
610 extDevice_t
*dev
= (extDevice_t
*)arg
;
612 uint16_t irqStatus
= (dev
->bus
->curSegment
->u
.buffers
.rxData
[2] << 8) | dev
->bus
->curSegment
->u
.buffers
.rxData
[3];
614 if (irqStatus
& SX1280_IRQ_TX_DONE
) {
615 irqReason
= ELRS_DIO_TX_DONE
;
616 } else if (irqStatus
& SX1280_IRQ_RX_DONE
) {
617 irqReason
= ELRS_DIO_RX_DONE
;
619 irqReason
= ELRS_DIO_UNKNOWN
;
622 sx1280SetBusyFn(sx1280IrqClearStatus
);
626 // Clear the IRQ bit in the Radio registers
628 FAST_IRQ_HANDLER
static void sx1280IrqClearStatus(extiCallbackRec_t
*cb
)
630 extDevice_t
*dev
= rxSpiGetDevice();
636 STATIC_DMA_DATA_AUTO
uint8_t irqCmd
[] = {SX1280_RADIO_CLR_IRQSTATUS
, 0, 0};
638 irqCmd
[1] = (uint8_t)(((uint16_t)SX1280_IRQ_RADIO_ALL
>> 8) & 0x00FF);
639 irqCmd
[2] = (uint8_t)((uint16_t)SX1280_IRQ_RADIO_ALL
& 0x00FF);
641 static busSegment_t segments
[] = {
642 {.u
.buffers
= {irqCmd
, NULL
}, sizeof(irqCmd
), true, sx1280IrqCmdComplete
},
643 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
646 spiSequence(dev
, segments
);
649 // Callback follow clear of IRQ status
650 FAST_IRQ_HANDLER
static busStatus_e
sx1280IrqCmdComplete(uint32_t arg
)
654 sx1280SetBusyFn(sx1280ProcessIrq
);
659 // Process IRQ status
660 FAST_IRQ_HANDLER
static void sx1280ProcessIrq(extiCallbackRec_t
*cb
)
662 extDevice_t
*dev
= rxSpiGetDevice();
668 if (irqReason
== ELRS_DIO_RX_DONE
|| irqReason
== ELRS_DIO_UNKNOWN
) {
669 // Fire off the chain to read and decode the packet from the radio
670 // Get the buffer status to determine the FIFO address
671 STATIC_DMA_DATA_AUTO
uint8_t cmdBufStatusCmd
[] = {SX1280_RADIO_GET_RXBUFFERSTATUS
, 0, 0, 0};
672 STATIC_DMA_DATA_AUTO
uint8_t bufStatus
[sizeof(cmdBufStatusCmd
)];
674 static busSegment_t segments
[] = {
675 {.u
.buffers
= {cmdBufStatusCmd
, bufStatus
}, sizeof(cmdBufStatusCmd
), true, sx1280GotFIFOAddr
},
676 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
679 spiSequence(dev
, segments
);
682 // return to RX mode immediately, the next packet will be an RX and we won't need to FHSS
683 STATIC_DMA_DATA_AUTO
uint8_t irqSetRxCmd
[] = {SX1280_RADIO_SET_RX
, 0, 0xff, 0xff};
685 static busSegment_t segments
[] = {
686 {.u
.buffers
= {irqSetRxCmd
, NULL
}, sizeof(irqSetRxCmd
), true, sx1280EnableIRQs
},
687 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
690 spiSequence(dev
, segments
);
694 // First we read from the FIFO address register to determine the FIFO address
695 static busStatus_e
sx1280GotFIFOAddr(uint32_t arg
)
697 extDevice_t
*dev
= (extDevice_t
*)arg
;
699 FIFOaddr
= dev
->bus
->curSegment
->u
.buffers
.rxData
[3];
701 // Wait until no longer busy and read the buffer
702 sx1280SetBusyFn(sx1280DoReadBuffer
);
707 // Using the addr val stored to the global varable FIFOaddr, read the buffer
708 static void sx1280DoReadBuffer(extiCallbackRec_t
*cb
)
710 extDevice_t
*dev
= rxSpiGetDevice();
716 STATIC_DMA_DATA_AUTO
uint8_t cmdReadBuf
[] = {SX1280_RADIO_READ_BUFFER
, 0, 0};
718 cmdReadBuf
[1] = FIFOaddr
;
720 static busSegment_t segments
[] = {
721 {.u
.buffers
= {cmdReadBuf
, NULL
}, sizeof(cmdReadBuf
), false, NULL
},
722 {.u
.buffers
= {NULL
, NULL
}, ELRS_RX_TX_BUFF_SIZE
, true, sx1280ReadBufferComplete
},
723 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
726 segments
[1].u
.buffers
.rxData
= (uint8_t *)expressLrsGetRxBuffer();
728 spiSequence(dev
, segments
);
731 // Get the Packet Status and RSSI
732 static busStatus_e
sx1280ReadBufferComplete(uint32_t arg
)
736 sx1280SetBusyFn(sx1280GetPacketStats
);
741 // Save the Packet Stats to the global variables
742 static void sx1280GetPacketStats(extiCallbackRec_t
*cb
)
746 extDevice_t
*dev
= rxSpiGetDevice();
750 STATIC_DMA_DATA_AUTO
uint8_t getStatsCmd
[] = {SX1280_RADIO_GET_PACKETSTATUS
, 0, 0, 0};
751 STATIC_DMA_DATA_AUTO
uint8_t stats
[sizeof(getStatsCmd
)];
753 static busSegment_t segments
[] = {
754 {.u
.buffers
= {getStatsCmd
, stats
}, sizeof(getStatsCmd
), true, sx1280GetStatsCmdComplete
},
755 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
758 spiSequence(dev
, segments
);
761 // Process and decode the RF packet
762 static busStatus_e
sx1280GetStatsCmdComplete(uint32_t arg
)
764 extDevice_t
*dev
= (extDevice_t
*)arg
;
765 volatile uint8_t *payload
= expressLrsGetPayloadBuffer();
767 packetStats
[0] = dev
->bus
->curSegment
->u
.buffers
.rxData
[2];
768 packetStats
[1] = dev
->bus
->curSegment
->u
.buffers
.rxData
[3];
770 expressLrsSetRfPacketStatus(processRFPacket(payload
, rxSpiGetLastExtiTimeUs()));
772 return sx1280IsFhssReq(arg
);
775 void sx1280HandleFromTock(void)
777 ATOMIC_BLOCK(NVIC_PRIO_MAX
) {
778 if (expressLrsIsFhssReq()) {
779 if (sx1280EnableBusy()) {
780 pendingDoFHSS
= false;
781 sx1280SetBusyFn(sx1280SetFrequency
);
783 pendingDoFHSS
= true;
789 // Next we need to check if we need to FHSS and then do so if needed
790 static busStatus_e
sx1280IsFhssReq(uint32_t arg
)
794 if (expressLrsIsFhssReq()) {
795 sx1280SetBusyFn(sx1280SetFrequency
);
797 sx1280SetFreqComplete(arg
);
804 static void sx1280SetFrequency(extiCallbackRec_t
*cb
)
808 extDevice_t
*dev
= rxSpiGetDevice();
809 uint32_t currentFreq
= expressLrsGetCurrentFreq();
813 STATIC_DMA_DATA_AUTO
uint8_t setFreqCmd
[] = {SX1280_RADIO_SET_RFFREQUENCY
, 0, 0, 0};
814 setFreqCmd
[1] = (uint8_t)((currentFreq
>> 16) & 0xFF);
815 setFreqCmd
[2] = (uint8_t)((currentFreq
>> 8) & 0xFF);
816 setFreqCmd
[3] = (uint8_t)(currentFreq
& 0xFF);
818 static busSegment_t segments
[] = {
819 {.u
.buffers
= {setFreqCmd
, NULL
}, sizeof(setFreqCmd
), true, sx1280SetFreqComplete
},
820 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
823 spiSequence(dev
, segments
);
826 // Determine if we need to go back to RX or if we need to send TLM data
827 static busStatus_e
sx1280SetFreqComplete(uint32_t arg
)
831 if (expressLrsTelemRespReq()) {
833 // if it's time to do TLM and we have enough to do so
834 sx1280SetBusyFn(sx1280SendTelemetryBuffer
);
836 // we don't need to send TLM and we've already FHSS so just hop back into RX mode
837 sx1280SetBusyFn(sx1280StartReceivingDMA
);
843 // Go back into RX mode
844 static void sx1280StartReceivingDMA(extiCallbackRec_t
*cb
)
847 extDevice_t
*dev
= rxSpiGetDevice();
851 // Issue command to start receiving
852 // periodBase = 1ms, page 71 datasheet, set to FF for cont RX
853 STATIC_DMA_DATA_AUTO
uint8_t irqSetRxCmd
[] = {SX1280_RADIO_SET_RX
, 0, 0xff, 0xff};
855 static busSegment_t segments
[] = {
856 {.u
.buffers
= {irqSetRxCmd
, NULL
}, sizeof(irqSetRxCmd
), true, sx1280EnableIRQs
},
857 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
860 spiSequence(dev
, segments
);
863 static busStatus_e
sx1280EnableIRQs(uint32_t arg
)
867 // Handle any queued interrupt processing
870 sx1280SetBusyFn(sx1280IrqGetStatus
);
871 } else if (pendingDoFHSS
) {
872 pendingDoFHSS
= false;
873 sx1280SetBusyFn(sx1280SetFrequency
);
875 // Switch back to waiting for EXTI interrupt
883 // Send telemetry response
884 static void sx1280SendTelemetryBuffer(extiCallbackRec_t
*cb
)
887 extDevice_t
*dev
= rxSpiGetDevice();
891 STATIC_DMA_DATA_AUTO
uint8_t writeBufferCmd
[] = {SX1280_RADIO_WRITE_BUFFER
, 0};
893 static busSegment_t segments
[] = {
894 {.u
.buffers
= {writeBufferCmd
, NULL
}, sizeof(writeBufferCmd
), false, NULL
},
895 {.u
.buffers
= {NULL
, NULL
}, ELRS_RX_TX_BUFF_SIZE
, true, sx1280TelemetryComplete
},
896 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
899 segments
[1].u
.buffers
.txData
= (uint8_t *)expressLrsGetTelemetryBuffer();
901 spiSequence(dev
, segments
);
904 static busStatus_e
sx1280TelemetryComplete(uint32_t arg
)
908 sx1280SetBusyFn(sx1280StartTransmittingDMA
);
913 static void sx1280StartTransmittingDMA(extiCallbackRec_t
*cb
)
916 extDevice_t
*dev
= rxSpiGetDevice();
920 //uses timeout Time-out duration = periodBase * periodBaseCount
921 // periodBase = 1ms, page 71 datasheet
922 // no timeout set for now
923 // TODO dynamic timeout based on expected onairtime
924 STATIC_DMA_DATA_AUTO
uint8_t irqSetRxCmd
[] = {SX1280_RADIO_SET_TX
, 0, 0xff, 0xff};
926 static busSegment_t segments
[] = {
927 {.u
.buffers
= {irqSetRxCmd
, NULL
}, sizeof(irqSetRxCmd
), true, sx1280EnableIRQs
},
928 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
931 spiSequence(dev
, segments
);
933 #endif /* USE_RX_SX1280 */