Merge pull request #11494 from haslinghuis/dshot_gpio
[betaflight.git] / src / main / drivers / rx / rx_sx1280.c
blobe552106a4cb4a119491bcf833dbfc35250eb6e2b
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 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()
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 pendingISR = false;
70 static volatile bool pendingDoFHSS = false;
72 #define SX1280_BUSY_TIMEOUT_US 1000
75 bool sx1280IsBusy(void)
77 return IORead(busy);
80 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 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 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(REG_LR_FIRMWARE_VERSION_MSB)) << 8) | (sx1280ReadRegister(REG_LR_FIRMWARE_VERSION_MSB + 1)));
225 if ((firmwareRev == 0) || (firmwareRev == 65535)) {
226 return false;
229 // Record the dev pointer for callbacks
230 extDevice_t *dev = rxSpiGetDevice();
231 dev->callbackArg = (uint32_t)dev;
233 return true;
236 void sx1280WriteCommand(const uint8_t address, const uint8_t data)
238 sx1280PollBusy();
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);
250 sx1280PollBusy();
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;
259 outBuffer[1] = 0x00;
261 memcpy(outBuffer + 2, data, length);
263 sx1280PollBusy();
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);
278 sx1280PollBusy();
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);
294 outBuffer[3] = 0x00;
296 sx1280PollBusy();
297 rxSpiTransferCommandMulti(&outBuffer[0], size + 4);
298 memcpy(buffer, outBuffer + 4, size);
301 uint8_t sx1280ReadRegister(const uint16_t address)
303 uint8_t data;
304 sx1280ReadRegisterBurst(address, &data, 1);
305 return data;
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);
317 sx1280PollBusy();
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;
327 outBuffer[2] = 0x00;
329 sx1280PollBusy();
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};
337 sx1280PollBusy();
338 rxSpiTransferCommandMulti(&buffer[0], 3);
339 return buffer[0];
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);
359 sx1280PollBusy();
361 sx1280ConfigLoraDefaults();
362 sx1280SetOutputPower(13); //default is max power (12.5dBm for SX1280 RX)
363 sx1280SetMode(SX1280_MODE_STDBY_XOSC);
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)
372 uint8_t buf[2];
373 buf[0] = power + 18;
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)
381 uint8_t buf[7];
383 buf[0] = preambleLength;
384 buf[1] = headerType;
385 buf[2] = payloadLength;
386 buf[3] = crc;
387 buf[4] = invertIQ;
388 buf[5] = 0x00;
389 buf[6] = 0x00;
391 sx1280WriteCommandBurst(SX1280_RADIO_SET_PACKETPARAMS, buf, 7);
394 void sx1280SetMode(const sx1280OperatingModes_e opMode)
396 uint8_t buf[3];
398 switch (opMode) {
399 case SX1280_MODE_SLEEP:
400 sx1280WriteCommand(SX1280_RADIO_SET_SLEEP, 0x01);
401 break;
402 case SX1280_MODE_CALIBRATION:
403 break;
404 case SX1280_MODE_STDBY_RC:
405 sx1280WriteCommand(SX1280_RADIO_SET_STANDBY, SX1280_STDBY_RC);
406 break;
407 case SX1280_MODE_STDBY_XOSC:
408 sx1280WriteCommand(SX1280_RADIO_SET_STANDBY, SX1280_STDBY_XOSC);
409 break;
410 case SX1280_MODE_FS:
411 sx1280WriteCommand(SX1280_RADIO_SET_FS, 0x00);
412 break;
413 case SX1280_MODE_RX:
414 buf[0] = 0x00; // periodBase = 1ms, page 71 datasheet, set to FF for cont RX
415 buf[1] = 0xFF;
416 buf[2] = 0xFF;
417 sx1280WriteCommandBurst(SX1280_RADIO_SET_RX, buf, 3);
418 break;
419 case SX1280_MODE_TX:
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);
425 break;
426 case SX1280_MODE_CAD:
427 break;
428 default:
429 break;
433 void sx1280ConfigLoraModParams(const sx1280LoraBandwidths_e bw, const sx1280LoraSpreadingFactors_e sf, const sx1280LoraCodingRates_e cr)
435 // Care must therefore be taken to ensure that modulation parameters are set using the command
436 // SetModulationParam() only after defining the packet type SetPacketType() to be used
438 uint8_t rfparams[3] = {0};
440 rfparams[0] = (uint8_t)sf;
441 rfparams[1] = (uint8_t)bw;
442 rfparams[2] = (uint8_t)cr;
444 sx1280WriteCommandBurst(SX1280_RADIO_SET_MODULATIONPARAMS, rfparams, 3);
446 switch (sf) {
447 case SX1280_LORA_SF5:
448 case SX1280_LORA_SF6:
449 sx1280WriteRegister(0x925, 0x1E); // for SF5 or SF6
450 break;
451 case SX1280_LORA_SF7:
452 case SX1280_LORA_SF8:
453 sx1280WriteRegister(0x925, 0x37); // for SF7 or SF8
454 break;
455 default:
456 sx1280WriteRegister(0x925, 0x32); // for SF9, SF10, SF11, SF12
460 void sx1280SetFrequencyReg(const uint32_t freqReg)
462 uint8_t buf[3] = {0};
464 buf[0] = (uint8_t)((freqReg >> 16) & 0xFF);
465 buf[1] = (uint8_t)((freqReg >> 8) & 0xFF);
466 buf[2] = (uint8_t)(freqReg & 0xFF);
468 sx1280WriteCommandBurst(SX1280_RADIO_SET_RFFREQUENCY, buf, 3);
471 void sx1280AdjustFrequency(int32_t offset, const uint32_t freq)
473 // just a stub to show that frequency adjustment is not used on this chip as opposed to sx127x
474 UNUSED(offset);
475 UNUSED(freq);
478 void sx1280SetFifoAddr(const uint8_t txBaseAddr, const uint8_t rxBaseAddr)
480 uint8_t buf[2];
482 buf[0] = txBaseAddr;
483 buf[1] = rxBaseAddr;
484 sx1280WriteCommandBurst(SX1280_RADIO_SET_BUFFERBASEADDRESS, buf, 2);
487 void sx1280SetDioIrqParams(const uint16_t irqMask, const uint16_t dio1Mask, const uint16_t dio2Mask, const uint16_t dio3Mask)
489 uint8_t buf[8];
491 buf[0] = (uint8_t)((irqMask >> 8) & 0x00FF);
492 buf[1] = (uint8_t)(irqMask & 0x00FF);
493 buf[2] = (uint8_t)((dio1Mask >> 8) & 0x00FF);
494 buf[3] = (uint8_t)(dio1Mask & 0x00FF);
495 buf[4] = (uint8_t)((dio2Mask >> 8) & 0x00FF);
496 buf[5] = (uint8_t)(dio2Mask & 0x00FF);
497 buf[6] = (uint8_t)((dio3Mask >> 8) & 0x00FF);
498 buf[7] = (uint8_t)(dio3Mask & 0x00FF);
500 sx1280WriteCommandBurst(SX1280_RADIO_SET_DIOIRQPARAMS, buf, 8);
503 void sx1280TransmitData(const uint8_t *data, const uint8_t length)
505 sx1280WriteBuffer(0x00, data, length);
506 sx1280SetMode(SX1280_MODE_TX);
509 static uint8_t sx1280GetRxBufferAddr(void)
511 uint8_t status[2] = {0};
512 sx1280ReadCommandBurst(SX1280_RADIO_GET_RXBUFFERSTATUS, status, 2);
513 return status[1];
516 void sx1280ReceiveData(uint8_t *data, const uint8_t length)
518 uint8_t FIFOaddr = sx1280GetRxBufferAddr();
519 sx1280ReadBuffer(FIFOaddr, data, length);
522 void sx1280StartReceiving(void)
524 if (sx1280MarkBusy()) {
525 sx1280SetMode(SX1280_MODE_RX);
526 sx1280MarkFree();
530 void sx1280GetLastPacketStats(int8_t *rssi, int8_t *snr)
532 *rssi = -(int8_t)(packetStats[0] / 2);
533 *snr = ((int8_t) packetStats[1]) / 4;
534 int8_t negOffset = (*snr < 0) ? *snr : 0;
535 *rssi += negOffset;
538 void sx1280DoFHSS(void)
540 return;
543 void sx1280ClearIrqStatus(const uint16_t irqMask)
545 uint8_t buf[2];
547 buf[0] = (uint8_t)(((uint16_t)irqMask >> 8) & 0x00FF);
548 buf[1] = (uint8_t)((uint16_t)irqMask & 0x00FF);
550 sx1280WriteCommandBurst(SX1280_RADIO_CLR_IRQSTATUS, buf, 2);
553 // Forward Definitions for DMA Chain //
554 static void sx1280IrqGetStatus(extiCallbackRec_t *cb);
555 static busStatus_e sx1280IrqStatusRead(uint32_t arg);
556 static void sx1280IrqClearStatus(extiCallbackRec_t *cb);
557 static busStatus_e sx1280IrqCmdComplete(uint32_t arg);
558 static void sx1280ProcessIrq(extiCallbackRec_t *cb);
559 static busStatus_e sx1280GotFIFOAddr(uint32_t arg);
560 static void sx1280DoReadBuffer(extiCallbackRec_t *cb);
561 static busStatus_e sx1280ReadBufferComplete(uint32_t arg);
562 static void sx1280GetPacketStats(extiCallbackRec_t *cb);
563 static busStatus_e sx1280GetStatsCmdComplete(uint32_t arg);
564 static busStatus_e sx1280IsFhssReq(uint32_t arg);
565 static void sx1280SetFrequency(extiCallbackRec_t *cb);
566 static busStatus_e sx1280SetFreqComplete(uint32_t arg);
567 static void sx1280StartReceivingDMA(extiCallbackRec_t *cb);
568 static busStatus_e sx1280EnableIRQs(uint32_t arg);
569 static void sx1280SendTelemetryBuffer(extiCallbackRec_t *cb);
570 static busStatus_e sx1280TelemetryComplete(uint32_t arg);
571 static void sx1280StartTransmittingDMA(extiCallbackRec_t *cb);
573 void sx1280ISR(void)
575 // Only attempt to access the SX1280 if it is currently idle to avoid any race condition
576 ATOMIC_BLOCK(NVIC_PRIO_MAX) {
577 if (sx1280EnableBusy()) {
578 pendingISR = false;
579 sx1280SetBusyFn(sx1280IrqGetStatus);
580 } else {
581 pendingISR = true;
586 // Next, the reason for the IRQ must be read
588 static void sx1280IrqGetStatus(extiCallbackRec_t *cb)
590 extDevice_t *dev = rxSpiGetDevice();
592 UNUSED(cb);
594 sx1280ClearBusyFn();
596 STATIC_DMA_DATA_AUTO uint8_t irqStatusCmd[] = {SX1280_RADIO_GET_IRQSTATUS, 0, 0, 0};
597 STATIC_DMA_DATA_AUTO uint8_t irqStatus[sizeof(irqStatusCmd)];
599 static busSegment_t segments[] = {
600 {.u.buffers = {irqStatusCmd, irqStatus}, sizeof(irqStatusCmd), false, sx1280IrqStatusRead},
601 {.u.link = {NULL, NULL}, 0, true, NULL},
604 spiSequence(dev, segments);
607 // Read the IRQ status, and save it to irqStatus variable
609 static busStatus_e sx1280IrqStatusRead(uint32_t arg)
611 extDevice_t *dev = (extDevice_t *)arg;
613 uint16_t irqStatus = (dev->bus->curSegment->u.buffers.rxData[2] << 8) | dev->bus->curSegment->u.buffers.rxData[3];
615 if (irqStatus & SX1280_IRQ_TX_DONE) {
616 irqReason = ELRS_DIO_TX_DONE;
617 } else if (irqStatus & SX1280_IRQ_RX_DONE) {
618 irqReason = ELRS_DIO_RX_DONE;
619 } else {
620 irqReason = ELRS_DIO_UNKNOWN;
623 sx1280SetBusyFn(sx1280IrqClearStatus);
624 return BUS_READY;
627 // Clear the IRQ bit in the Radio registers
629 static void sx1280IrqClearStatus(extiCallbackRec_t *cb)
631 extDevice_t *dev = rxSpiGetDevice();
633 UNUSED(cb);
635 sx1280ClearBusyFn();
637 STATIC_DMA_DATA_AUTO uint8_t irqCmd[] = {SX1280_RADIO_CLR_IRQSTATUS, 0, 0};
639 irqCmd[1] = (uint8_t)(((uint16_t)SX1280_IRQ_RADIO_ALL >> 8) & 0x00FF);
640 irqCmd[2] = (uint8_t)((uint16_t)SX1280_IRQ_RADIO_ALL & 0x00FF);
642 static busSegment_t segments[] = {
643 {.u.buffers = {irqCmd, NULL}, sizeof(irqCmd), false, sx1280IrqCmdComplete},
644 {.u.link = {NULL, NULL}, 0, true, NULL},
647 spiSequence(dev, segments);
650 // Callback follow clear of IRQ status
651 static busStatus_e sx1280IrqCmdComplete(uint32_t arg)
653 UNUSED(arg);
655 sx1280SetBusyFn(sx1280ProcessIrq);
657 return BUS_READY;
660 // Process IRQ status
661 static void sx1280ProcessIrq(extiCallbackRec_t *cb)
663 extDevice_t *dev = rxSpiGetDevice();
665 UNUSED(cb);
667 sx1280ClearBusyFn();
669 if (irqReason == ELRS_DIO_RX_DONE || irqReason == ELRS_DIO_UNKNOWN) {
670 // Fire off the chain to read and decode the packet from the radio
671 // Get the buffer status to determine the FIFO address
672 STATIC_DMA_DATA_AUTO uint8_t cmdBufStatusCmd[] = {SX1280_RADIO_GET_RXBUFFERSTATUS, 0, 0, 0};
673 STATIC_DMA_DATA_AUTO uint8_t bufStatus[sizeof(cmdBufStatusCmd)];
675 static busSegment_t segments[] = {
676 {.u.buffers = {cmdBufStatusCmd, bufStatus}, sizeof(cmdBufStatusCmd), false, sx1280GotFIFOAddr},
677 {.u.link = {NULL, NULL}, 0, true, NULL},
680 spiSequence(dev, segments);
682 } else {
683 // return to RX mode immediately, the next packet will be an RX and we won't need to FHSS
684 STATIC_DMA_DATA_AUTO uint8_t irqSetRxCmd[] = {SX1280_RADIO_SET_RX, 0, 0xff, 0xff};
686 static busSegment_t segments[] = {
687 {.u.buffers = {irqSetRxCmd, NULL}, sizeof(irqSetRxCmd), false, sx1280EnableIRQs},
688 {.u.link = {NULL, NULL}, 0, true, NULL},
691 spiSequence(dev, segments);
695 // First we read from the FIFO address register to determine the FIFO address
696 static busStatus_e sx1280GotFIFOAddr(uint32_t arg)
698 extDevice_t *dev = (extDevice_t *)arg;
700 FIFOaddr = dev->bus->curSegment->u.buffers.rxData[3];
702 // Wait until no longer busy and read the buffer
703 sx1280SetBusyFn(sx1280DoReadBuffer);
705 return BUS_READY;
708 // Using the addr val stored to the global varable FIFOaddr, read the buffer
709 static void sx1280DoReadBuffer(extiCallbackRec_t *cb)
711 extDevice_t *dev = rxSpiGetDevice();
713 UNUSED(cb);
715 sx1280ClearBusyFn();
717 STATIC_DMA_DATA_AUTO uint8_t cmdReadBuf[] = {SX1280_RADIO_READ_BUFFER, 0, 0};
719 cmdReadBuf[1] = FIFOaddr;
721 static busSegment_t segments[] = {
722 {.u.buffers = {cmdReadBuf, NULL}, sizeof(cmdReadBuf), false, NULL},
723 {.u.buffers = {NULL, NULL}, ELRS_RX_TX_BUFF_SIZE, true, sx1280ReadBufferComplete},
724 {.u.link = {NULL, NULL}, 0, true, NULL},
727 segments[1].u.buffers.rxData = (uint8_t *)expressLrsGetRxBuffer();
729 spiSequence(dev, segments);
732 // Get the Packet Status and RSSI
733 static busStatus_e sx1280ReadBufferComplete(uint32_t arg)
735 UNUSED(arg);
737 sx1280SetBusyFn(sx1280GetPacketStats);
739 return BUS_READY;
742 // Save the Packet Stats to the global variables
743 static void sx1280GetPacketStats(extiCallbackRec_t *cb)
745 UNUSED(cb);
747 extDevice_t *dev = rxSpiGetDevice();
749 sx1280ClearBusyFn();
751 STATIC_DMA_DATA_AUTO uint8_t getStatsCmd[] = {SX1280_RADIO_GET_PACKETSTATUS, 0, 0, 0};
752 STATIC_DMA_DATA_AUTO uint8_t stats[sizeof(getStatsCmd)];
754 static busSegment_t segments[] = {
755 {.u.buffers = {getStatsCmd, stats}, sizeof(getStatsCmd), false, sx1280GetStatsCmdComplete},
756 {.u.link = {NULL, NULL}, 0, true, NULL},
759 spiSequence(dev, segments);
762 // Process and decode the RF packet
763 static busStatus_e sx1280GetStatsCmdComplete(uint32_t arg)
765 extDevice_t *dev = (extDevice_t *)arg;
766 volatile uint8_t *payload = expressLrsGetPayloadBuffer();
768 packetStats[0] = dev->bus->curSegment->u.buffers.rxData[2];
769 packetStats[1] = dev->bus->curSegment->u.buffers.rxData[3];
771 expressLrsSetRfPacketStatus(processRFPacket(payload, rxSpiGetLastExtiTimeUs()));
773 return sx1280IsFhssReq(arg);
776 void sx1280HandleFromTock(void)
778 ATOMIC_BLOCK(NVIC_PRIO_MAX) {
779 if (expressLrsIsFhssReq()) {
780 if (sx1280EnableBusy()) {
781 pendingDoFHSS = false;
782 sx1280SetBusyFn(sx1280SetFrequency);
783 } else {
784 pendingDoFHSS = true;
790 // Next we need to check if we need to FHSS and then do so if needed
791 static busStatus_e sx1280IsFhssReq(uint32_t arg)
793 UNUSED(arg);
795 if (expressLrsIsFhssReq()) {
796 sx1280SetBusyFn(sx1280SetFrequency);
797 } else {
798 sx1280SetFreqComplete(arg);
801 return BUS_READY;
804 // Set the frequency
805 static void sx1280SetFrequency(extiCallbackRec_t *cb)
807 UNUSED(cb);
809 extDevice_t *dev = rxSpiGetDevice();
810 uint32_t currentFreq = expressLrsGetCurrentFreq();
812 sx1280ClearBusyFn();
814 STATIC_DMA_DATA_AUTO uint8_t setFreqCmd[] = {SX1280_RADIO_SET_RFFREQUENCY, 0, 0, 0};
815 setFreqCmd[1] = (uint8_t)((currentFreq >> 16) & 0xFF);
816 setFreqCmd[2] = (uint8_t)((currentFreq >> 8) & 0xFF);
817 setFreqCmd[3] = (uint8_t)(currentFreq & 0xFF);
819 static busSegment_t segments[] = {
820 {.u.buffers = {setFreqCmd, NULL}, sizeof(setFreqCmd), false, sx1280SetFreqComplete},
821 {.u.link = {NULL, NULL}, 0, true, NULL},
824 spiSequence(dev, segments);
827 // Determine if we need to go back to RX or if we need to send TLM data
828 static busStatus_e sx1280SetFreqComplete(uint32_t arg)
830 UNUSED(arg);
832 if (expressLrsTelemRespReq()) {
833 expressLrsDoTelem();
834 // if it's time to do TLM and we have enough to do so
835 sx1280SetBusyFn(sx1280SendTelemetryBuffer);
836 } else {
837 // we don't need to send TLM and we've already FHSS so just hop back into RX mode
838 sx1280SetBusyFn(sx1280StartReceivingDMA);
841 return BUS_READY;
844 // Go back into RX mode
845 static void sx1280StartReceivingDMA(extiCallbackRec_t *cb)
847 UNUSED(cb);
848 extDevice_t *dev = rxSpiGetDevice();
850 sx1280ClearBusyFn();
852 // Issue command to start receiving
853 // periodBase = 1ms, page 71 datasheet, set to FF for cont RX
854 STATIC_DMA_DATA_AUTO uint8_t irqSetRxCmd[] = {SX1280_RADIO_SET_RX, 0, 0xff, 0xff};
856 static busSegment_t segments[] = {
857 {.u.buffers = {irqSetRxCmd, NULL}, sizeof(irqSetRxCmd), false, sx1280EnableIRQs},
858 {.u.link = {NULL, NULL}, 0, true, NULL},
861 spiSequence(dev, segments);
864 static busStatus_e sx1280EnableIRQs(uint32_t arg)
866 UNUSED(arg);
868 // Handle any queued interrupt processing
869 if (pendingISR) {
870 pendingISR = false;
871 sx1280SetBusyFn(sx1280IrqGetStatus);
872 } else if (pendingDoFHSS) {
873 pendingDoFHSS = false;
874 sx1280SetBusyFn(sx1280SetFrequency);
875 } else {
876 // Switch back to waiting for EXTI interrupt
877 sx1280EnableExti();
880 return BUS_READY;
884 // Send telemetry response
885 static void sx1280SendTelemetryBuffer(extiCallbackRec_t *cb)
887 UNUSED(cb);
888 extDevice_t *dev = rxSpiGetDevice();
890 sx1280ClearBusyFn();
892 STATIC_DMA_DATA_AUTO uint8_t writeBufferCmd[] = {SX1280_RADIO_WRITE_BUFFER, 0};
894 static busSegment_t segments[] = {
895 {.u.buffers = {writeBufferCmd, NULL}, sizeof(writeBufferCmd), false, NULL},
896 {.u.buffers = {NULL, NULL}, ELRS_RX_TX_BUFF_SIZE, true, sx1280TelemetryComplete},
897 {.u.link = {NULL, NULL}, 0, true, NULL},
900 segments[1].u.buffers.txData = (uint8_t *)expressLrsGetTelemetryBuffer();
902 spiSequence(dev, segments);
905 static busStatus_e sx1280TelemetryComplete(uint32_t arg)
907 UNUSED(arg);
909 sx1280SetBusyFn(sx1280StartTransmittingDMA);
911 return BUS_READY;
914 static void sx1280StartTransmittingDMA(extiCallbackRec_t *cb)
916 UNUSED(cb);
917 extDevice_t *dev = rxSpiGetDevice();
919 sx1280ClearBusyFn();
921 //uses timeout Time-out duration = periodBase * periodBaseCount
922 // periodBase = 1ms, page 71 datasheet
923 // no timeout set for now
924 // TODO dynamic timeout based on expected onairtime
925 STATIC_DMA_DATA_AUTO uint8_t irqSetRxCmd[] = {SX1280_RADIO_SET_TX, 0, 0xff, 0xff};
927 static busSegment_t segments[] = {
928 {.u.buffers = {irqSetRxCmd, NULL}, sizeof(irqSetRxCmd), false, sx1280EnableIRQs},
929 {.u.link = {NULL, NULL}, 0, true, NULL},
932 spiSequence(dev, segments);
934 #endif /* USE_RX_SX1280 */