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 dioReasonFlags_e irqReason
; // Used to pass irq status from sx1280IrqStatusRead() to sx1280ProcessIrq()
56 static volatile uint8_t packetStats
[2];
57 static 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 pendingDoFHSS
= false;
70 static sx1280PacketTypes_e sx1280PacketMode
;
72 #define SX1280_BUSY_TIMEOUT_US 1000
75 bool sx1280IsBusy(void)
80 FAST_CODE_PREF
static bool sx1280PollBusy(void)
82 uint32_t startTime
= micros();
83 while (IORead(busy
)) {
84 if ((micros() - startTime
) > SX1280_BUSY_TIMEOUT_US
) {
93 FAST_CODE_PREF
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_PREF
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(SX1280_REG_FIRMWARE_VERSION_MSB
)) << 8) | (sx1280ReadRegister(SX1280_REG_FIRMWARE_VERSION_MSB
+ 1)));
224 if ((firmwareRev
== 0) || (firmwareRev
== 65535)) {
228 // Record the dev pointer for callbacks
229 extDevice_t
*dev
= rxSpiGetDevice();
230 dev
->callbackArg
= (uint32_t)dev
;
232 sx1280SetMode(SX1280_MODE_STDBY_RC
);
233 sx1280WriteCommand(SX1280_RADIO_SET_AUTOFS
, 0x01);
234 sx1280WriteRegister(SX1280_REG_RX_GAIN_REGIME
, sx1280ReadRegister(SX1280_REG_RX_GAIN_REGIME
) | 0xC0); //default is low power mode, switch to high sensitivity instead
239 void sx1280WriteCommand(const uint8_t address
, const uint8_t data
)
242 rxSpiWriteCommand(address
, data
);
245 void sx1280WriteCommandBurst(const uint8_t address
, const uint8_t *data
, const uint8_t length
)
247 uint8_t outBuffer
[length
+ 1];
249 outBuffer
[0] = address
;
251 memcpy(outBuffer
+ 1, data
, length
);
254 rxSpiTransferCommandMulti(&outBuffer
[0], length
+ 1);
257 void sx1280ReadCommandBurst(const uint8_t address
, uint8_t *data
, const uint8_t length
)
259 uint8_t outBuffer
[length
+ 2];
261 outBuffer
[0] = address
;
264 memcpy(outBuffer
+ 2, data
, length
);
267 rxSpiTransferCommandMulti(&outBuffer
[0], length
+ 2);
268 memcpy(data
, outBuffer
+ 2, length
);
271 void sx1280WriteRegisterBurst(const uint16_t address
, const uint8_t *buffer
, const uint8_t size
)
273 uint8_t outBuffer
[size
+ 3];
275 outBuffer
[0] = (uint8_t) SX1280_RADIO_WRITE_REGISTER
;
276 outBuffer
[1] = ((address
& 0xFF00) >> 8);
277 outBuffer
[2] = (address
& 0x00FF);
279 memcpy(outBuffer
+ 3, buffer
, size
);
282 rxSpiTransferCommandMulti(&outBuffer
[0], size
+ 3);
285 void sx1280WriteRegister(const uint16_t address
, const uint8_t value
)
287 sx1280WriteRegisterBurst(address
, &value
, 1);
290 void sx1280ReadRegisterBurst(const uint16_t address
, uint8_t *buffer
, const uint8_t size
)
292 uint8_t outBuffer
[size
+ 4];
294 outBuffer
[0] = (uint8_t) SX1280_RADIO_READ_REGISTER
;
295 outBuffer
[1] = ((address
& 0xFF00) >> 8);
296 outBuffer
[2] = (address
& 0x00FF);
300 rxSpiTransferCommandMulti(&outBuffer
[0], size
+ 4);
301 memcpy(buffer
, outBuffer
+ 4, size
);
304 uint8_t sx1280ReadRegister(const uint16_t address
)
307 sx1280ReadRegisterBurst(address
, &data
, 1);
311 void sx1280WriteBuffer(const uint8_t offset
, const uint8_t *buffer
, const uint8_t size
)
313 uint8_t outBuffer
[size
+ 2];
315 outBuffer
[0] = (uint8_t) SX1280_RADIO_WRITE_BUFFER
;
316 outBuffer
[1] = offset
;
318 memcpy(outBuffer
+ 2, buffer
, size
);
321 rxSpiTransferCommandMulti(&outBuffer
[0], size
+ 2);
324 void sx1280ReadBuffer(const uint8_t offset
, uint8_t *buffer
, const uint8_t size
)
326 uint8_t outBuffer
[size
+ 3];
328 outBuffer
[0] = (uint8_t) SX1280_RADIO_READ_BUFFER
;
329 outBuffer
[1] = offset
;
333 rxSpiTransferCommandMulti(&outBuffer
[0], size
+ 3);
334 memcpy(buffer
, outBuffer
+ 3, size
);
337 uint8_t sx1280GetStatus(void)
339 uint8_t buffer
[3] = {(uint8_t) SX1280_RADIO_GET_STATUS
, 0, 0};
341 rxSpiTransferCommandMulti(&buffer
[0], 3);
345 static void sx1280ConfigModParamsLora(const sx1280LoraBandwidths_e bw
, const sx1280LoraSpreadingFactors_e sf
, const sx1280LoraCodingRates_e cr
)
352 sx1280WriteCommandBurst(SX1280_RADIO_SET_MODULATIONPARAMS
, rfparams
, 3);
355 case SX1280_LORA_SF5
:
356 case SX1280_LORA_SF6
:
357 sx1280WriteRegister(SX1280_REG_SF_ADDITIONAL_CONFIG
, 0x1E); // SF5 or SF6
359 case SX1280_LORA_SF7
:
360 case SX1280_LORA_SF8
:
361 sx1280WriteRegister(SX1280_REG_SF_ADDITIONAL_CONFIG
, 0x37); // SF7 or SF8
364 sx1280WriteRegister(SX1280_REG_SF_ADDITIONAL_CONFIG
, 0x32); // SF9, SF10, SF11, SF12
368 static void sx1280SetPacketParamsLora(const uint8_t preambleLength
, const sx1280LoraPacketLengthsModes_e headerType
, const uint8_t payloadLength
,
369 const sx1280LoraCrcModes_e crc
, const bool invertIQ
)
372 buf
[0] = preambleLength
;
374 buf
[2] = payloadLength
;
376 buf
[4] = invertIQ
? SX1280_LORA_IQ_INVERTED
: SX1280_LORA_IQ_NORMAL
;
380 sx1280WriteCommandBurst(SX1280_RADIO_SET_PACKETPARAMS
, buf
, 7);
383 static void sx1280ConfigModParamsFlrc(const SX1280_RadioFlrcBandwidths_t bw
, const SX1280_RadioFlrcCodingRates_t cr
, const SX1280_RadioFlrcGaussianFilter_t bt
)
390 sx1280WriteCommandBurst(SX1280_RADIO_SET_MODULATIONPARAMS
, rfparams
, 3);
393 static void sx1280SetPacketParamsFlrc(uint8_t PreambleLength
, uint8_t HeaderType
,
394 uint8_t PayloadLength
, uint32_t syncWord
, uint16_t crcSeed
, uint8_t cr
)
396 if (PreambleLength
< 8)
400 buf
[0] = ((PreambleLength
/ 4) - 1) << 4; // AGCPreambleLength
401 buf
[1] = SX1280_FLRC_SYNC_WORD_LEN_P32S
; // SyncWordLength
402 buf
[2] = SX1280_FLRC_RX_MATCH_SYNC_WORD_1
; // SyncWordMatch
403 buf
[3] = HeaderType
; // PacketType
404 buf
[4] = PayloadLength
; // PayloadLength
405 buf
[5] = SX1280_FLRC_CRC_3_BYTE
; // CrcLength
406 buf
[6] = SX1280_FLRC_WHITENING_DISABLE
; // Must be whitening disabled
407 sx1280WriteCommandBurst(SX1280_RADIO_SET_PACKETPARAMS
, buf
, 7);
409 // CRC seed (use dedicated cipher)
410 buf
[0] = (uint8_t)(crcSeed
>> 8);
411 buf
[1] = (uint8_t)crcSeed
;
412 sx1280WriteRegisterBurst(SX1280_REG_FLRC_CRC_SEED
, buf
, 2);
415 buf
[0] = (uint8_t)(syncWord
>> 24);
416 buf
[1] = (uint8_t)(syncWord
>> 16);
417 buf
[2] = (uint8_t)(syncWord
>> 8);
418 buf
[3] = (uint8_t)syncWord
;
420 // DS_SX1280-1_V3.2.pdf - 16.4 FLRC Modem: Increased PER in FLRC Packets with Synch Word
421 if (((cr
== SX1280_FLRC_CR_1_2
) || (cr
== SX1280_FLRC_CR_3_4
)) &&
422 ((buf
[0] == 0x8C && buf
[1] == 0x38) || (buf
[0] == 0x63 && buf
[1] == 0x0E))) {
423 uint8_t temp
= buf
[0];
426 // For SX1280_FLRC_CR_3_4 the datasheet also says
427 // "In addition to this the two LSB values XX XX must not be in the range 0x0000 to 0x3EFF"
428 if (cr
== SX1280_FLRC_CR_3_4
&& buf
[3] <= 0x3e)
429 buf
[3] |= 0x80; // 0x80 or 0x40 would work
432 sx1280WriteRegisterBurst(SX1280_REG_FLRC_SYNC_WORD
, buf
, 4);
434 // Set permissible sync errors = 0
435 sx1280WriteRegister(SX1280_REG_FLRC_SYNC_ADDR_CTRL
, sx1280ReadRegister(SX1280_REG_FLRC_SYNC_ADDR_CTRL
) & 0xf0);
438 void sx1280Config(const uint8_t bw
, const uint8_t sfbt
, const uint8_t cr
,
439 const uint32_t freq
, const uint8_t preambleLength
, const bool iqInverted
,
440 const uint32_t flrcSyncWord
, const uint16_t flrcCrcSeed
, const bool isFlrc
)
442 sx1280SetMode(SX1280_MODE_STDBY_RC
);
444 sx1280PacketMode
= (isFlrc
) ? SX1280_PACKET_TYPE_FLRC
: SX1280_PACKET_TYPE_LORA
;
445 sx1280WriteCommand(SX1280_RADIO_SET_PACKETTYPE
, sx1280PacketMode
);
448 sx1280ConfigModParamsFlrc(bw
, cr
, sfbt
);
449 sx1280SetPacketParamsFlrc(preambleLength
, SX1280_FLRC_PACKET_FIXED_LENGTH
, 8, flrcSyncWord
, flrcCrcSeed
, cr
);
451 sx1280ConfigModParamsLora(bw
, sfbt
, cr
);
452 sx1280SetPacketParamsLora(preambleLength
, SX1280_LORA_PACKET_FIXED_LENGTH
, 8, SX1280_LORA_CRC_OFF
, iqInverted
);
455 sx1280SetDioIrqParams(
456 SX1280_IRQ_TX_DONE
| SX1280_IRQ_RX_DONE
| SX1280_IRQ_SYNCWORD_VALID
| SX1280_IRQ_SYNCWORD_ERROR
| SX1280_IRQ_CRC_ERROR
, // irqMask
457 SX1280_IRQ_TX_DONE
| SX1280_IRQ_RX_DONE
, // dio1Mask
458 SX1280_IRQ_RADIO_NONE
,
459 SX1280_IRQ_RADIO_NONE
462 sx1280SetOutputPower(13); //default is max power (12.5dBm for SX1280 RX)
463 sx1280SetFrequencyReg(freq
);
466 void sx1280SetOutputPower(const int8_t power
)
470 buf
[1] = (uint8_t) SX1280_RADIO_RAMP_04_US
;
471 sx1280WriteCommandBurst(SX1280_RADIO_SET_TXPARAMS
, buf
, 2);
474 void sx1280SetMode(const sx1280OperatingModes_e opMode
)
479 case SX1280_MODE_SLEEP
:
480 sx1280WriteCommand(SX1280_RADIO_SET_SLEEP
, 0x01);
482 case SX1280_MODE_CALIBRATION
:
484 case SX1280_MODE_STDBY_RC
:
485 sx1280WriteCommand(SX1280_RADIO_SET_STANDBY
, SX1280_STDBY_RC
);
487 case SX1280_MODE_STDBY_XOSC
:
488 sx1280WriteCommand(SX1280_RADIO_SET_STANDBY
, SX1280_STDBY_XOSC
);
491 sx1280WriteCommand(SX1280_RADIO_SET_FS
, 0x00);
494 buf
[0] = 0x00; // periodBase = 1ms, page 71 datasheet, set to FF for cont RX
497 sx1280WriteCommandBurst(SX1280_RADIO_SET_RX
, buf
, 3);
500 //uses timeout Time-out duration = periodBase * periodBaseCount
501 buf
[0] = 0x00; // periodBase = 1ms, page 71 datasheet
502 buf
[1] = 0xFF; // no timeout set for now
503 buf
[2] = 0xFF; // TODO dynamic timeout based on expected onairtime
504 sx1280WriteCommandBurst(SX1280_RADIO_SET_TX
, buf
, 3);
506 case SX1280_MODE_CAD
: // not implemented yet
512 void sx1280SetFrequencyReg(const uint32_t freqReg
)
514 uint8_t buf
[3] = {0};
516 buf
[0] = (uint8_t)((freqReg
>> 16) & 0xFF);
517 buf
[1] = (uint8_t)((freqReg
>> 8) & 0xFF);
518 buf
[2] = (uint8_t)(freqReg
& 0xFF);
520 sx1280WriteCommandBurst(SX1280_RADIO_SET_RFFREQUENCY
, buf
, 3);
523 void sx1280AdjustFrequency(int32_t *offset
, const uint32_t freq
)
529 void sx1280SetFifoAddr(const uint8_t txBaseAddr
, const uint8_t rxBaseAddr
)
535 sx1280WriteCommandBurst(SX1280_RADIO_SET_BUFFERBASEADDRESS
, buf
, 2);
538 void sx1280SetDioIrqParams(const uint16_t irqMask
, const uint16_t dio1Mask
, const uint16_t dio2Mask
, const uint16_t dio3Mask
)
542 buf
[0] = (uint8_t)((irqMask
>> 8) & 0x00FF);
543 buf
[1] = (uint8_t)(irqMask
& 0x00FF);
544 buf
[2] = (uint8_t)((dio1Mask
>> 8) & 0x00FF);
545 buf
[3] = (uint8_t)(dio1Mask
& 0x00FF);
546 buf
[4] = (uint8_t)((dio2Mask
>> 8) & 0x00FF);
547 buf
[5] = (uint8_t)(dio2Mask
& 0x00FF);
548 buf
[6] = (uint8_t)((dio3Mask
>> 8) & 0x00FF);
549 buf
[7] = (uint8_t)(dio3Mask
& 0x00FF);
551 sx1280WriteCommandBurst(SX1280_RADIO_SET_DIOIRQPARAMS
, buf
, 8);
554 void sx1280TransmitData(const uint8_t *data
, const uint8_t length
)
556 sx1280WriteBuffer(0x00, data
, length
);
557 sx1280SetMode(SX1280_MODE_TX
);
560 static uint8_t sx1280GetRxBufferAddr(void)
562 uint8_t status
[2] = {0};
563 sx1280ReadCommandBurst(SX1280_RADIO_GET_RXBUFFERSTATUS
, status
, 2);
567 void sx1280ReceiveData(uint8_t *data
, const uint8_t length
)
569 uint8_t FIFOaddr
= sx1280GetRxBufferAddr();
570 sx1280ReadBuffer(FIFOaddr
, data
, length
);
573 void sx1280StartReceiving(void)
575 if (sx1280MarkBusy()) {
576 sx1280SetMode(SX1280_MODE_RX
);
581 void sx1280GetLastPacketStats(int8_t *rssi
, int8_t *snr
)
583 if (sx1280PacketMode
== SX1280_PACKET_TYPE_FLRC
) {
584 // No SNR in FLRC mode
585 *rssi
= -(int8_t)(packetStats
[1] / 2);
588 *rssi
= -(int8_t)(packetStats
[0] / 2);
589 *snr
= (int8_t)packetStats
[1];
590 int8_t negOffset
= (*snr
< 0) ? (*snr
/ 4) : 0;
595 void sx1280DoFHSS(void)
600 void sx1280ClearIrqStatus(const uint16_t irqMask
)
604 buf
[0] = (uint8_t)(((uint16_t)irqMask
>> 8) & 0x00FF);
605 buf
[1] = (uint8_t)((uint16_t)irqMask
& 0x00FF);
607 sx1280WriteCommandBurst(SX1280_RADIO_CLR_IRQSTATUS
, buf
, 2);
610 // Forward Definitions for DMA Chain //
611 static void sx1280IrqGetStatus(extiCallbackRec_t
*cb
);
612 static busStatus_e
sx1280IrqStatusRead(uint32_t arg
);
613 static void sx1280IrqClearStatus(extiCallbackRec_t
*cb
);
614 static busStatus_e
sx1280IrqCmdComplete(uint32_t arg
);
615 static void sx1280ProcessIrq(extiCallbackRec_t
*cb
);
616 static busStatus_e
sx1280GotFIFOAddr(uint32_t arg
);
617 static void sx1280DoReadBuffer(extiCallbackRec_t
*cb
);
618 static busStatus_e
sx1280ReadBufferComplete(uint32_t arg
);
619 static void sx1280GetPacketStats(extiCallbackRec_t
*cb
);
620 static busStatus_e
sx1280GetStatsCmdComplete(uint32_t arg
);
621 static busStatus_e
sx1280IsFhssReq(uint32_t arg
);
622 static void sx1280SetFrequency(extiCallbackRec_t
*cb
);
623 static busStatus_e
sx1280SetFreqComplete(uint32_t arg
);
624 static void sx1280StartReceivingDMA(extiCallbackRec_t
*cb
);
625 static busStatus_e
sx1280EnableIRQs(uint32_t arg
);
626 static void sx1280SendTelemetryBuffer(extiCallbackRec_t
*cb
);
627 static busStatus_e
sx1280TelemetryComplete(uint32_t arg
);
628 static void sx1280StartTransmittingDMA(extiCallbackRec_t
*cb
);
630 FAST_IRQ_HANDLER
void sx1280ISR(void)
632 // Only attempt to access the SX1280 if it is currently idle to avoid any race condition
633 ATOMIC_BLOCK(NVIC_PRIO_RX_INT_EXTI
) {
634 if (sx1280EnableBusy()) {
635 sx1280SetBusyFn(sx1280IrqGetStatus
);
640 // Next, the reason for the IRQ must be read
642 FAST_IRQ_HANDLER
static void sx1280IrqGetStatus(extiCallbackRec_t
*cb
)
644 extDevice_t
*dev
= rxSpiGetDevice();
650 STATIC_DMA_DATA_AUTO
uint8_t irqStatusCmd
[] = {SX1280_RADIO_GET_IRQSTATUS
, 0, 0, 0};
651 STATIC_DMA_DATA_AUTO
uint8_t irqStatus
[sizeof(irqStatusCmd
)];
653 static busSegment_t segments
[] = {
654 {.u
.buffers
= {irqStatusCmd
, irqStatus
}, sizeof(irqStatusCmd
), true, sx1280IrqStatusRead
},
655 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
658 spiSequence(dev
, segments
);
661 // Read the IRQ status, and save it to irqStatus variable
662 FAST_IRQ_HANDLER
static busStatus_e
sx1280IrqStatusRead(uint32_t arg
)
664 extDevice_t
*dev
= (extDevice_t
*)arg
;
666 uint16_t irqStatus
= (dev
->bus
->curSegment
->u
.buffers
.rxData
[2] << 8) | dev
->bus
->curSegment
->u
.buffers
.rxData
[3];
668 if (irqStatus
& SX1280_IRQ_TX_DONE
) {
669 irqReason
= ELRS_DIO_TX_DONE
;
670 } else if (irqStatus
& SX1280_IRQ_RX_DONE
) {
671 irqReason
= ELRS_DIO_RX_DONE
;
673 if (sx1280PacketMode
== SX1280_PACKET_TYPE_FLRC
) {
674 // Reject the packet early if CRC/Syncword error or syncword valid not set
675 if ((irqStatus
& (SX1280_IRQ_CRC_ERROR
| SX1280_IRQ_SYNCWORD_ERROR
)) ||
676 !(irqStatus
& SX1280_IRQ_SYNCWORD_VALID
)) {
677 irqReason
|= ELRS_DIO_HWERROR
;
681 irqReason
= ELRS_DIO_UNKNOWN
;
684 sx1280SetBusyFn(sx1280IrqClearStatus
);
688 // Clear the IRQ bit in the Radio registers
690 FAST_IRQ_HANDLER
static void sx1280IrqClearStatus(extiCallbackRec_t
*cb
)
692 extDevice_t
*dev
= rxSpiGetDevice();
697 STATIC_DMA_DATA_AUTO
uint8_t irqCmd
[] = {SX1280_RADIO_CLR_IRQSTATUS
, 0, 0};
699 irqCmd
[1] = (uint8_t)(((uint16_t)SX1280_IRQ_RADIO_ALL
>> 8) & 0x00FF);
700 irqCmd
[2] = (uint8_t)((uint16_t)SX1280_IRQ_RADIO_ALL
& 0x00FF);
702 static busSegment_t segments
[] = {
703 {.u
.buffers
= {irqCmd
, NULL
}, sizeof(irqCmd
), true, sx1280IrqCmdComplete
},
704 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
707 spiSequence(dev
, segments
);
710 // Callback follow clear of IRQ status
711 FAST_IRQ_HANDLER
static busStatus_e
sx1280IrqCmdComplete(uint32_t arg
)
715 // If HWERROR reported on RX, just do nothing and wait for the timer to expire
716 if (!(irqReason
& ELRS_DIO_HWERROR
)) {
717 sx1280SetBusyFn(sx1280ProcessIrq
);
723 // Process IRQ status
724 FAST_IRQ_HANDLER
static void sx1280ProcessIrq(extiCallbackRec_t
*cb
)
726 extDevice_t
*dev
= rxSpiGetDevice();
732 if (irqReason
& ELRS_DIO_RX_DONE
) {
733 // Fire off the chain to read and decode the packet from the radio
734 // Get the buffer status to determine the FIFO address
735 STATIC_DMA_DATA_AUTO
uint8_t cmdBufStatusCmd
[] = {SX1280_RADIO_GET_RXBUFFERSTATUS
, 0, 0, 0};
736 STATIC_DMA_DATA_AUTO
uint8_t bufStatus
[sizeof(cmdBufStatusCmd
)];
738 static busSegment_t segments
[] = {
739 {.u
.buffers
= {cmdBufStatusCmd
, bufStatus
}, sizeof(cmdBufStatusCmd
), true, sx1280GotFIFOAddr
},
740 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
743 spiSequence(dev
, segments
);
746 // return to RX mode immediately, the next packet will be an RX and we won't need to FHSS
747 STATIC_DMA_DATA_AUTO
uint8_t irqSetRxCmd
[] = {SX1280_RADIO_SET_RX
, 0, 0xff, 0xff};
749 static busSegment_t segments
[] = {
750 {.u
.buffers
= {irqSetRxCmd
, NULL
}, sizeof(irqSetRxCmd
), true, sx1280EnableIRQs
},
751 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
754 spiSequence(dev
, segments
);
758 // First we read from the FIFO address register to determine the FIFO address
759 static busStatus_e
sx1280GotFIFOAddr(uint32_t arg
)
761 extDevice_t
*dev
= (extDevice_t
*)arg
;
763 FIFOaddr
= dev
->bus
->curSegment
->u
.buffers
.rxData
[3];
765 // Wait until no longer busy and read the buffer
766 sx1280SetBusyFn(sx1280DoReadBuffer
);
771 // Using the addr val stored to the global varable FIFOaddr, read the buffer
772 static void sx1280DoReadBuffer(extiCallbackRec_t
*cb
)
774 extDevice_t
*dev
= rxSpiGetDevice();
780 STATIC_DMA_DATA_AUTO
uint8_t cmdReadBuf
[] = {SX1280_RADIO_READ_BUFFER
, 0, 0};
782 cmdReadBuf
[1] = FIFOaddr
;
784 static busSegment_t segments
[] = {
785 {.u
.buffers
= {cmdReadBuf
, NULL
}, sizeof(cmdReadBuf
), false, NULL
},
786 {.u
.buffers
= {NULL
, NULL
}, ELRS_RX_TX_BUFF_SIZE
, true, sx1280ReadBufferComplete
},
787 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
790 segments
[1].u
.buffers
.rxData
= (uint8_t *)expressLrsGetRxBuffer();
792 spiSequence(dev
, segments
);
795 // Get the Packet Status and RSSI
796 static busStatus_e
sx1280ReadBufferComplete(uint32_t arg
)
800 sx1280SetBusyFn(sx1280GetPacketStats
);
805 // Save the Packet Stats to the global variables
806 static void sx1280GetPacketStats(extiCallbackRec_t
*cb
)
810 extDevice_t
*dev
= rxSpiGetDevice();
814 STATIC_DMA_DATA_AUTO
uint8_t getStatsCmd
[] = {SX1280_RADIO_GET_PACKETSTATUS
, 0, 0, 0};
815 STATIC_DMA_DATA_AUTO
uint8_t stats
[sizeof(getStatsCmd
)];
817 static busSegment_t segments
[] = {
818 {.u
.buffers
= {getStatsCmd
, stats
}, sizeof(getStatsCmd
), true, sx1280GetStatsCmdComplete
},
819 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
822 spiSequence(dev
, segments
);
825 // Process and decode the RF packet
826 static busStatus_e
sx1280GetStatsCmdComplete(uint32_t arg
)
828 extDevice_t
*dev
= (extDevice_t
*)arg
;
829 volatile uint8_t *payload
= expressLrsGetPayloadBuffer();
831 packetStats
[0] = dev
->bus
->curSegment
->u
.buffers
.rxData
[2];
832 packetStats
[1] = dev
->bus
->curSegment
->u
.buffers
.rxData
[3];
834 expressLrsSetRfPacketStatus(processRFPacket(payload
, rxSpiGetLastExtiTimeUs()));
836 return sx1280IsFhssReq(arg
);
839 void sx1280HandleFromTock(void)
841 ATOMIC_BLOCK(NVIC_PRIO_MAX
) {
842 if (expressLrsIsFhssReq()) {
843 if (sx1280EnableBusy()) {
844 pendingDoFHSS
= false;
845 sx1280SetBusyFn(sx1280SetFrequency
);
847 pendingDoFHSS
= true;
853 // Next we need to check if we need to FHSS and then do so if needed
854 static busStatus_e
sx1280IsFhssReq(uint32_t arg
)
858 if (expressLrsIsFhssReq()) {
859 sx1280SetBusyFn(sx1280SetFrequency
);
861 sx1280SetFreqComplete(arg
);
868 static void sx1280SetFrequency(extiCallbackRec_t
*cb
)
872 extDevice_t
*dev
= rxSpiGetDevice();
873 uint32_t currentFreq
= expressLrsGetCurrentFreq();
877 STATIC_DMA_DATA_AUTO
uint8_t setFreqCmd
[] = {SX1280_RADIO_SET_RFFREQUENCY
, 0, 0, 0};
878 setFreqCmd
[1] = (uint8_t)((currentFreq
>> 16) & 0xFF);
879 setFreqCmd
[2] = (uint8_t)((currentFreq
>> 8) & 0xFF);
880 setFreqCmd
[3] = (uint8_t)(currentFreq
& 0xFF);
882 static busSegment_t segments
[] = {
883 {.u
.buffers
= {setFreqCmd
, NULL
}, sizeof(setFreqCmd
), true, sx1280SetFreqComplete
},
884 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
887 spiSequence(dev
, segments
);
890 // Determine if we need to go back to RX or if we need to send TLM data
891 static busStatus_e
sx1280SetFreqComplete(uint32_t arg
)
894 pendingDoFHSS
= false;
896 if (expressLrsTelemRespReq()) {
898 // if it's time to do TLM and we have enough to do so
899 sx1280SetBusyFn(sx1280SendTelemetryBuffer
);
901 // we don't need to send TLM and we've already FHSS so just hop back into RX mode
902 sx1280SetBusyFn(sx1280StartReceivingDMA
);
908 // Go back into RX mode
909 static void sx1280StartReceivingDMA(extiCallbackRec_t
*cb
)
912 extDevice_t
*dev
= rxSpiGetDevice();
916 // Issue command to start receiving
917 // periodBase = 1ms, page 71 datasheet, set to FF for cont RX
918 STATIC_DMA_DATA_AUTO
uint8_t irqSetRxCmd
[] = {SX1280_RADIO_SET_RX
, 0, 0xff, 0xff};
920 static busSegment_t segments
[] = {
921 {.u
.buffers
= {irqSetRxCmd
, NULL
}, sizeof(irqSetRxCmd
), true, sx1280EnableIRQs
},
922 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
925 spiSequence(dev
, segments
);
928 static busStatus_e
sx1280EnableIRQs(uint32_t arg
)
933 pendingDoFHSS
= false;
934 sx1280SetBusyFn(sx1280SetFrequency
);
936 // Switch back to waiting for EXTI interrupt
944 // Send telemetry response
945 static void sx1280SendTelemetryBuffer(extiCallbackRec_t
*cb
)
948 extDevice_t
*dev
= rxSpiGetDevice();
952 STATIC_DMA_DATA_AUTO
uint8_t writeBufferCmd
[] = {SX1280_RADIO_WRITE_BUFFER
, 0};
954 static busSegment_t segments
[] = {
955 {.u
.buffers
= {writeBufferCmd
, NULL
}, sizeof(writeBufferCmd
), false, NULL
},
956 {.u
.buffers
= {NULL
, NULL
}, ELRS_RX_TX_BUFF_SIZE
, true, sx1280TelemetryComplete
},
957 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
960 segments
[1].u
.buffers
.txData
= (uint8_t *)expressLrsGetTelemetryBuffer();
962 spiSequence(dev
, segments
);
965 static busStatus_e
sx1280TelemetryComplete(uint32_t arg
)
969 sx1280SetBusyFn(sx1280StartTransmittingDMA
);
974 static void sx1280StartTransmittingDMA(extiCallbackRec_t
*cb
)
977 extDevice_t
*dev
= rxSpiGetDevice();
981 //uses timeout Time-out duration = periodBase * periodBaseCount
982 // periodBase = 1ms, page 71 datasheet
983 // no timeout set for now
984 // TODO dynamic timeout based on expected onairtime
985 STATIC_DMA_DATA_AUTO
uint8_t irqSetRxCmd
[] = {SX1280_RADIO_SET_TX
, 0, 0xff, 0xff};
987 static busSegment_t segments
[] = {
988 {.u
.buffers
= {irqSetRxCmd
, NULL
}, sizeof(irqSetRxCmd
), true, sx1280EnableIRQs
},
989 {.u
.link
= {NULL
, NULL
}, 0, false, NULL
},
992 spiSequence(dev
, segments
);
994 #endif /* USE_RX_SX1280 */