trailing whitespace removal (#14026)
[betaflight.git] / src / main / drivers / rx / rx_sx1280.c
blobd694e763b84c3e6e6f57c9cb1943acb39013a75e
1 /*
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)
8 * any later version.
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.
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
31 #include "platform.h"
33 #ifdef USE_RX_SX1280
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()
59 static IO_t busy;
61 typedef struct busyIntContext_s {
62 extiCallbackRec_t exti;
63 } busyIntContext_t;
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)
77 return IORead(busy);
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) {
85 return false;
86 } else {
87 __asm__("nop");
90 return true;
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) {
98 return false;
101 sx1280Processing = micros();
104 return true;
107 static void sx1280ClearBusyFn(void)
109 EXTIDisable(busy);
112 // Switch to waiting for busy interrupt
113 FAST_CODE_PREF static bool sx1280EnableBusy(void)
115 if (!sx1280MarkBusy()) {
116 return false;
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);
133 return true;
136 // waitingFn() must call sx1280ClearBusyFn() to prevent repeated calls
138 static void sx1280SetBusyFn(extiHandlerCallback *waitingFn)
140 bool sx1280Busy;
142 ATOMIC_BLOCK(NVIC_PRIO_RX_BUSY_EXTI) {
143 sx1280Busy = IORead(busy);
144 if (sx1280Busy) {
145 EXTIHandlerInit(&busyIntContext.exti, waitingFn);
146 EXTIEnable(busy);
147 } else {
148 EXTIDisable(busy);
152 if (!sx1280Busy) {
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)
166 sx1280MarkFree();
167 rxSpiEnableExti();
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;
178 if (startTime) {
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
182 sx1280ClearBusyFn();
183 // Renable EXTI
184 sx1280EnableExti();
186 return true;
190 return false;
193 bool sx1280Init(IO_t resetPin, IO_t busyPin)
195 if (!rxSpiExtiConfigured()) {
196 return false;
199 rxSpiSetNormalSpeedMhz(SX1280_MAX_SPI_MHZ);
200 rxSpiNormalSpeed();
202 if (resetPin) {
203 IOInit(resetPin, OWNER_RX_SPI_EXPRESSLRS_RESET, 0);
204 IOConfigGPIO(resetPin, IOCFG_OUT_PP);
205 } else {
206 resetPin = IO_NONE;
209 if (busyPin) {
210 IOInit(busyPin, OWNER_RX_SPI_EXPRESSLRS_BUSY, 0);
211 IOConfigGPIO(busyPin, IOCFG_IN_FLOATING);
212 } else {
213 busyPin = IO_NONE;
216 busy = busyPin;
218 IOLo(resetPin);
219 delay(50);
220 IOConfigGPIO(resetPin, IOCFG_IN_FLOATING); // leave floating, internal pullup on sx1280 side
221 delay(20);
223 uint16_t firmwareRev = (((sx1280ReadRegister(SX1280_REG_FIRMWARE_VERSION_MSB)) << 8) | (sx1280ReadRegister(SX1280_REG_FIRMWARE_VERSION_MSB + 1)));
224 if ((firmwareRev == 0) || (firmwareRev == 65535)) {
225 return false;
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
236 return true;
239 void sx1280WriteCommand(const uint8_t address, const uint8_t data)
241 sx1280PollBusy();
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);
253 sx1280PollBusy();
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;
262 outBuffer[1] = 0x00;
264 memcpy(outBuffer + 2, data, length);
266 sx1280PollBusy();
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);
281 sx1280PollBusy();
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);
297 outBuffer[3] = 0x00;
299 sx1280PollBusy();
300 rxSpiTransferCommandMulti(&outBuffer[0], size + 4);
301 memcpy(buffer, outBuffer + 4, size);
304 uint8_t sx1280ReadRegister(const uint16_t address)
306 uint8_t data;
307 sx1280ReadRegisterBurst(address, &data, 1);
308 return data;
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);
320 sx1280PollBusy();
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;
330 outBuffer[2] = 0x00;
332 sx1280PollBusy();
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};
340 sx1280PollBusy();
341 rxSpiTransferCommandMulti(&buffer[0], 3);
342 return buffer[0];
345 static void sx1280ConfigModParamsLora(const sx1280LoraBandwidths_e bw, const sx1280LoraSpreadingFactors_e sf, const sx1280LoraCodingRates_e cr)
347 uint8_t rfparams[3];
348 rfparams[0] = sf;
349 rfparams[1] = bw;
350 rfparams[2] = cr;
352 sx1280WriteCommandBurst(SX1280_RADIO_SET_MODULATIONPARAMS, rfparams, 3);
354 switch (sf) {
355 case SX1280_LORA_SF5:
356 case SX1280_LORA_SF6:
357 sx1280WriteRegister(SX1280_REG_SF_ADDITIONAL_CONFIG, 0x1E); // SF5 or SF6
358 break;
359 case SX1280_LORA_SF7:
360 case SX1280_LORA_SF8:
361 sx1280WriteRegister(SX1280_REG_SF_ADDITIONAL_CONFIG, 0x37); // SF7 or SF8
362 break;
363 default:
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)
371 uint8_t buf[7];
372 buf[0] = preambleLength;
373 buf[1] = headerType;
374 buf[2] = payloadLength;
375 buf[3] = crc;
376 buf[4] = invertIQ ? SX1280_LORA_IQ_INVERTED : SX1280_LORA_IQ_NORMAL;
377 buf[5] = 0x00;
378 buf[6] = 0x00;
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)
385 uint8_t rfparams[3];
386 rfparams[0] = bw;
387 rfparams[1] = cr;
388 rfparams[2] = 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)
397 PreambleLength = 8;
399 uint8_t buf[7];
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);
414 // Set SyncWord1
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];
424 buf[0] = buf[1];
425 buf[1] = temp;
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);
447 if (isFlrc) {
448 sx1280ConfigModParamsFlrc(bw, cr, sfbt);
449 sx1280SetPacketParamsFlrc(preambleLength, SX1280_FLRC_PACKET_FIXED_LENGTH, 8, flrcSyncWord, flrcCrcSeed, cr);
450 } else {
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)
468 uint8_t buf[2];
469 buf[0] = power + 18;
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)
476 uint8_t buf[3];
478 switch (opMode) {
479 case SX1280_MODE_SLEEP:
480 sx1280WriteCommand(SX1280_RADIO_SET_SLEEP, 0x01);
481 break;
482 case SX1280_MODE_CALIBRATION:
483 break;
484 case SX1280_MODE_STDBY_RC:
485 sx1280WriteCommand(SX1280_RADIO_SET_STANDBY, SX1280_STDBY_RC);
486 break;
487 case SX1280_MODE_STDBY_XOSC:
488 sx1280WriteCommand(SX1280_RADIO_SET_STANDBY, SX1280_STDBY_XOSC);
489 break;
490 case SX1280_MODE_FS:
491 sx1280WriteCommand(SX1280_RADIO_SET_FS, 0x00);
492 break;
493 case SX1280_MODE_RX:
494 buf[0] = 0x00; // periodBase = 1ms, page 71 datasheet, set to FF for cont RX
495 buf[1] = 0xFF;
496 buf[2] = 0xFF;
497 sx1280WriteCommandBurst(SX1280_RADIO_SET_RX, buf, 3);
498 break;
499 case SX1280_MODE_TX:
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);
505 break;
506 case SX1280_MODE_CAD: // not implemented yet
507 default:
508 break;
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)
525 UNUSED(offset);
526 UNUSED(freq);
529 void sx1280SetFifoAddr(const uint8_t txBaseAddr, const uint8_t rxBaseAddr)
531 uint8_t buf[2];
533 buf[0] = txBaseAddr;
534 buf[1] = 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)
540 uint8_t buf[8];
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);
564 return status[1];
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);
577 sx1280MarkFree();
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);
586 *snr = 0;
587 } else {
588 *rssi = -(int8_t)(packetStats[0] / 2);
589 *snr = (int8_t)packetStats[1];
590 int8_t negOffset = (*snr < 0) ? (*snr / 4) : 0;
591 *rssi += negOffset;
595 void sx1280DoFHSS(void)
597 return;
600 void sx1280ClearIrqStatus(const uint16_t irqMask)
602 uint8_t buf[2];
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();
646 UNUSED(cb);
648 sx1280ClearBusyFn();
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;
680 } else {
681 irqReason = ELRS_DIO_UNKNOWN;
684 sx1280SetBusyFn(sx1280IrqClearStatus);
685 return BUS_READY;
688 // Clear the IRQ bit in the Radio registers
690 FAST_IRQ_HANDLER static void sx1280IrqClearStatus(extiCallbackRec_t *cb)
692 extDevice_t *dev = rxSpiGetDevice();
694 UNUSED(cb);
696 sx1280ClearBusyFn();
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)
713 UNUSED(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);
720 return BUS_READY;
723 // Process IRQ status
724 FAST_IRQ_HANDLER static void sx1280ProcessIrq(extiCallbackRec_t *cb)
726 extDevice_t *dev = rxSpiGetDevice();
728 UNUSED(cb);
730 sx1280ClearBusyFn();
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);
745 } else {
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);
768 return BUS_READY;
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();
776 UNUSED(cb);
778 sx1280ClearBusyFn();
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)
798 UNUSED(arg);
800 sx1280SetBusyFn(sx1280GetPacketStats);
802 return BUS_READY;
805 // Save the Packet Stats to the global variables
806 static void sx1280GetPacketStats(extiCallbackRec_t *cb)
808 UNUSED(cb);
810 extDevice_t *dev = rxSpiGetDevice();
812 sx1280ClearBusyFn();
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);
846 } else {
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)
856 UNUSED(arg);
858 if (expressLrsIsFhssReq()) {
859 sx1280SetBusyFn(sx1280SetFrequency);
860 } else {
861 sx1280SetFreqComplete(arg);
864 return BUS_READY;
867 // Set the frequency
868 static void sx1280SetFrequency(extiCallbackRec_t *cb)
870 UNUSED(cb);
872 extDevice_t *dev = rxSpiGetDevice();
873 uint32_t currentFreq = expressLrsGetCurrentFreq();
875 sx1280ClearBusyFn();
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)
893 UNUSED(arg);
894 pendingDoFHSS = false;
896 if (expressLrsTelemRespReq()) {
897 expressLrsDoTelem();
898 // if it's time to do TLM and we have enough to do so
899 sx1280SetBusyFn(sx1280SendTelemetryBuffer);
900 } else {
901 // we don't need to send TLM and we've already FHSS so just hop back into RX mode
902 sx1280SetBusyFn(sx1280StartReceivingDMA);
905 return BUS_READY;
908 // Go back into RX mode
909 static void sx1280StartReceivingDMA(extiCallbackRec_t *cb)
911 UNUSED(cb);
912 extDevice_t *dev = rxSpiGetDevice();
914 sx1280ClearBusyFn();
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)
930 UNUSED(arg);
932 if (pendingDoFHSS) {
933 pendingDoFHSS = false;
934 sx1280SetBusyFn(sx1280SetFrequency);
935 } else {
936 // Switch back to waiting for EXTI interrupt
937 sx1280EnableExti();
940 return BUS_READY;
944 // Send telemetry response
945 static void sx1280SendTelemetryBuffer(extiCallbackRec_t *cb)
947 UNUSED(cb);
948 extDevice_t *dev = rxSpiGetDevice();
950 sx1280ClearBusyFn();
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)
967 UNUSED(arg);
969 sx1280SetBusyFn(sx1280StartTransmittingDMA);
971 return BUS_READY;
974 static void sx1280StartTransmittingDMA(extiCallbackRec_t *cb)
976 UNUSED(cb);
977 extDevice_t *dev = rxSpiGetDevice();
979 sx1280ClearBusyFn();
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 */