unlimited packet length example for sx1272 or sx1276

Dependencies:   SX127x

operating

user button on MCU board toggles between receive operation on radio and transmit. (Latching PTT). Look at serial terminal at 9600 to see operation. User button is pressed once to start transmit, and again to end transmit: it doesnt need to be held down during TX.

example payload

The example payload is a continuously incrementing byte, with zero at start of packet.
End of packet is detected by four consecutive bytes which dont increment with expected value: background noise, this indicates transmitter has finished. This serves only as an example, because some other method would likely be needed in an application, such as unique data indicating end, or the length sent at begin of packet.

flow control

FifoThreshold is used for transmit flow control. With fifo is below threshold, bytes are send to the radio's fifo. While fifo is above threshold, nothing is sent until the fifo threshold pin returns low. AKA FifoLevel pin.

On receive, the packet reception is initialized by SyncAddress pin going high, indicating start of packet. Bytes are read from FIFO when the FifoEmpty pin is low.

The packet buffer (AKA FIFO) in sx127x is only 64 bytes, meaning the maximum time between FifoFull and FifoEmpty would be 512 bit periods. This needs to be considered: the MCU latency of servicing FifoLevel, FifoEmpty pins during packet, otherwise empty byte would be sent on transmit or byte missed on receiver.

FSK reception

The rxTrigger is used on preamble to enable start-of-frame detection, aka sync word. When end of packet is detected, the receiver is restarted. In this case, restarted with PLL when AFC is used, or without PLL when AFC not enabled.

The serial terminal will show when packet reception starts, and when there are incorrect bytes received over the air. This will always happen and end of packet for this example.

Files at this revision

API Documentation at this revision

Comitter:
dudmuck
Date:
Tue Sep 14 22:19:57 2021 +0000
Commit message:
commit initial

Changed in this revision

SX127x.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r df5ce1bc5036 SX127x.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SX127x.lib	Tue Sep 14 22:19:57 2021 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/dudmuck/code/SX127x/#af9b41b1e285
diff -r 000000000000 -r df5ce1bc5036 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Sep 14 22:19:57 2021 +0000
@@ -0,0 +1,399 @@
+#include "mbed.h"
+#include "sx127x_fsk.h"
+
+using namespace std::chrono;
+
+#define FSK_BIT_RATE                10000
+#define TX_FREQ_DEVIATION_HZ        20000
+#define RX_BW                       30000
+#define RX_BW_AFC                   30000
+#define START_OF_FRAME              0xd42d
+#define RADIO_FREQUENCY_MHZ         915.0
+//#define ENABLE_AFC
+
+SPI spi(D11, D12, D13); // mosi, miso, sclk
+//                  dio0, dio1, nss, spi, rst
+SX127x radio(  D2,   D3, D10, spi, A0); // sx127[62] arduino shield
+SX127x_fsk fsk(radio);
+DigitalInOut rfsw(A4);
+
+DigitalIn dio1(D3); // for FifoLevel
+InterruptIn dio2(D4); // for syncAddress
+DigitalIn dio3(D5); // for FifoEmpty
+
+DigitalIn button(/*USER_BUTTON*/ BUTTON1);
+bool button_pressed;
+#define BUTTON_DEBOUNCE_MS      10
+bool txing;
+bool end_tx;
+bool rxSync;
+
+typedef enum {
+    SHIELD_TYPE_NONE = 0,
+    SHIELD_TYPE_LAS,
+    SHIELD_TYPE_MAS,
+} shield_type_e;
+shield_type_e shield_type;
+
+void rfsw_callback()
+{
+    if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER)
+        rfsw = 1;
+    else
+        rfsw = 0;
+}
+
+void get_rf_board_type()
+{
+    rfsw.input();
+    if (rfsw.read()) {
+        shield_type = SHIELD_TYPE_LAS;
+        printf("LAS\r\n");
+    } else {
+        shield_type = SHIELD_TYPE_MAS;
+        printf("MAS\r\n");
+    }
+    
+    rfsw.output();
+}
+
+void ocp(uint8_t ma)
+{
+    if (ma < 130)
+        radio.RegOcp.bits.OcpTrim = (ma - 45) / 5;
+    else
+        radio.RegOcp.bits.OcpTrim = (ma + 30) / 10;
+    radio.write_reg(REG_OCP, radio.RegOcp.octet);
+   
+    radio.RegOcp.octet = radio.read_reg(REG_OCP);
+    if (radio.RegOcp.bits.OcpTrim < 16)
+        ma = 45 + (5 * radio.RegOcp.bits.OcpTrim);
+    else if (radio.RegOcp.bits.OcpTrim < 28)
+        ma = (10 * radio.RegOcp.bits.OcpTrim) - 30;
+    else
+        ma = 240;
+}
+
+void
+set_tx_dbm(int8_t dbm)
+{
+    RegPdsTrim1_t pds_trim;
+    uint8_t v, adr, pa_test_adr;
+ 
+    if (radio.type == SX1276) {
+        adr = REG_PDSTRIM1_SX1276;
+        pa_test_adr = REG_PATEST_SX1276;
+    } else {
+        adr = REG_PDSTRIM1_SX1272;
+        pa_test_adr = REG_PATEST_SX1272;
+    }
+       
+    v = radio.read_reg(pa_test_adr);
+    /*if (dbm == PA_OFF_DBM) {
+        // for bench testing: prevent overloading receiving station (very low TX power)
+        v &= ~0x20; // turn off pu_regpa_n: disable PA
+        radio.write_reg(pa_test_adr, v);
+        return;
+    } else if ((v & 0x20) == 0) {
+        v |= 0x20; // turn on pu_regpa_n: enable PA
+        radio.write_reg(pa_test_adr, v);
+    }*/
+ 
+    pds_trim.octet = radio.read_reg(adr);   
+ 
+    if (shield_type == SHIELD_TYPE_LAS)
+        radio.RegPaConfig.bits.PaSelect = 1;
+    else
+        radio.RegPaConfig.bits.PaSelect = 0;
+                
+    if (radio.RegPaConfig.bits.PaSelect) {
+        /* PABOOST used: +2dbm to +17, or +20 */
+        if (dbm > 17) {
+            if (dbm > 20)
+                dbm = 20;
+            dbm -= 3;
+            pds_trim.bits.prog_txdac = 7;
+            radio.write_reg(adr, pds_trim.octet);
+            ocp(150);
+        } else
+            ocp(120);
+ 
+        if (dbm > 1)
+                radio.RegPaConfig.bits.OutputPower = dbm - 2;
+    } else {
+        /* RFO used: -1 to +14dbm */
+        ocp(80);
+        if (dbm < 15)
+            radio.RegPaConfig.bits.OutputPower = dbm + 1;
+    }
+    radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
+ 
+    radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
+    if (radio.RegPaConfig.bits.PaSelect) {
+        dbm = radio.RegPaConfig.bits.OutputPower + pds_trim.bits.prog_txdac - 2;
+    } else {
+        dbm = radio.RegPaConfig.bits.OutputPower - 1;
+    }
+}
+
+void start_receive()
+{
+    fsk.RegRxConfig.octet = radio.read_reg(REG_FSK_RXCONFIG);
+    fsk.RegRxConfig.bits.RxTrigger = 6; // trigger receiver on preamble detect
+    fsk.RegRxConfig.bits.AgcAutoOn = 1; // radio controls its LNA
+#ifdef ENABLE_AFC    
+    fsk.RegRxConfig.bits.AfcAutoOn = 1;
+    fsk.RegRxConfig.bits.RestartRxWithPllLock = 1;      
+#endif /* ENABLE_AFC */              
+    radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet); 
+
+#ifdef ENABLE_AFC  
+    fsk.RegAfcFei.octet = radio.read_reg(REG_FSK_AFCFEI);
+    fsk.RegAfcFei.bits.AfcAutoClearOn = 1;
+    fsk.RegAfcFei.bits.AfcClear = 1;
+    radio.write_reg(REG_FSK_AFCFEI, fsk.RegAfcFei.octet);  
+#endif /* ENABLE_AFC */        
+
+    radio.set_opmode(RF_OPMODE_RECEIVER);
+}
+
+#define FIRST_PAYLOAD_BYTE      0
+uint8_t expected_rx;
+uint8_t rx_err_cnt;
+unsigned rx_bytes_ok;
+
+void dio2_callback()
+{
+    if (!txing) {
+        expected_rx = FIRST_PAYLOAD_BYTE;
+        rxSync = true;
+        rx_err_cnt = 0;
+        rx_bytes_ok = 0;
+    } else {
+        // fifoFull in TX
+    }
+
+}
+
+/* return non-zero at end of packet detection */
+int take_rx_byte(uint8_t in)
+{
+    int ret;
+
+    if (in != expected_rx) {
+        printf("(got %02x, wanted %02x)\r\n", in, expected_rx);
+        if (++rx_err_cnt == 4)
+            ret = -1; // too much consecutive noise
+        else
+            ret = 0;
+    } else {
+        rx_bytes_ok++;
+        rx_err_cnt = 0;
+        ret = 0;
+    }
+
+    expected_rx++;
+
+    return ret;
+}
+
+uint8_t tx_byte_cnt;
+uint8_t get_tx_byte()
+{
+    return tx_byte_cnt++;
+}
+
+void start_transmit()
+{
+    fsk.RegFifoThreshold.octet = radio.read_reg(REG_FSK_FIFOTHRESH);
+    fsk.RegFifoThreshold.bits.FifoThreshold = 48;
+    radio.write_reg(REG_FSK_FIFOTHRESH, fsk.RegFifoThreshold.octet);
+
+    tx_byte_cnt = FIRST_PAYLOAD_BYTE;
+    radio.set_opmode(RF_OPMODE_TRANSMITTER);
+}
+
+void end_transmit()
+{
+    printf("wait fifoEmpty...\r\n");
+    while (dio3.read() == 0)
+        ;
+    
+    radio.set_opmode(RF_OPMODE_STANDBY);
+    printf("tx-end\r\n");
+}
+
+int main()
+{
+    long button_release_start = -1;
+
+
+    radio.rf_switch = rfsw_callback;
+    get_rf_board_type();
+    ThisThread::sleep_for(30ms); // from cold power-up, both radio and mcu started
+
+    radio.hw_reset();
+
+    if (shield_type == SHIELD_TYPE_LAS)
+        set_tx_dbm(13);
+    else
+        set_tx_dbm(17);
+
+    radio.set_frf_MHz(RADIO_FREQUENCY_MHZ);
+
+    fsk.enable(true);
+    fsk.set_tx_fdev_hz(TX_FREQ_DEVIATION_HZ);
+ 
+    fsk.set_bitrate(FSK_BIT_RATE);
+ 
+    fsk.set_rx_dcc_bw_hz(RX_BW, 0);
+    fsk.set_rx_dcc_bw_hz(RX_BW_AFC, 1);
+
+    fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG);
+    fsk.RegSyncConfig.bits.SyncSize = 2 - 1;
+    radio.write_reg(REG_FSK_SYNCCONFIG, fsk.RegSyncConfig.octet);
+    radio.write_reg(REG_FSK_SYNCVALUE1, 0xd4);
+    radio.write_reg(REG_FSK_SYNCVALUE1, 0x2d);
+
+    // dio3 to FifoEmpty
+    // dio2 to syncAddress
+    // dio1 to FifoLevel
+    radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
+    radio.RegDioMapping1.bits.Dio3Mapping = 3;    // 
+    radio.RegDioMapping1.bits.Dio2Mapping = 3;    //
+    radio.RegDioMapping1.bits.Dio1Mapping = 0;    //
+    radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);  
+    dio2.rise(dio2_callback);  
+
+    fsk.RegPktConfig1.octet = radio.read_reg(REG_FSK_PACKETCONFIG1);
+    fsk.RegPktConfig1.bits.PacketFormatVariable = 0;
+    radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet);
+
+    // unlimited payload-length operation
+    fsk.RegPktConfig2.word = radio.read_u16(REG_FSK_PACKETCONFIG2);
+    fsk.RegPktConfig2.bits.PayloadLength = 0;
+    radio.write_u16(REG_FSK_PACKETCONFIG2, fsk.RegPktConfig2.word);    
+
+    fsk.RegPreambleDetect.octet = radio.read_reg(REG_FSK_PREAMBLEDETECT);   
+    fsk.RegPreambleDetect.bits.PreambleDetectorTol = 10;
+    fsk.RegPreambleDetect.bits.PreambleDetectorSize = 1;
+    fsk.RegPreambleDetect.bits.PreambleDetectorOn = 1;
+    radio.write_reg(REG_FSK_PREAMBLEDETECT, fsk.RegPreambleDetect.octet);
+
+    //printf("preamblesize: %02x ", radio.read_reg(REG_FSK_PREAMBLEMSB));
+    //printf("%02x\r\n", radio.read_reg(REG_FSK_PREAMBLELSB));
+    start_receive();
+
+    while (true) {
+        if (button_pressed) {
+            if (button.read()) {
+                // button released
+                button_pressed = false;
+                auto now_tp = time_point_cast<milliseconds>(Kernel::Clock::now());
+                button_release_start = now_tp.time_since_epoch().count();
+            }
+        } else {
+            if (!button.read()) {
+                // button pressed
+                button_pressed = true;
+                button_release_start = -1;
+            }            
+        }
+
+        if (button_release_start != -1) {
+            // debounce button
+            auto now_tp = time_point_cast<milliseconds>(Kernel::Clock::now());
+            long now_ms = now_tp.time_since_epoch().count();            
+            if ((now_ms - button_release_start) > BUTTON_DEBOUNCE_MS) {
+                // button released sufficiently long enough
+                button_release_start = -1;
+                if (txing) {
+                    printf("toRX\r\n");
+                    end_tx = true;
+                } else {
+                    printf("toTX\r\n");
+                    start_transmit();
+                    txing = true;
+                }
+            }
+        }
+        
+        if (txing) {
+            /* transmitting */
+            if (dio1) {
+                /* fifo above threshold, let the radio send it */
+                /* alternately, send until FifoFull */
+            } else {
+                /* fifo below threshold */
+                radio.m_cs = 0;
+                radio.m_spi.write(REG_FIFO | 0x80); // bit7 is high for writing to radio
+                while (dio1.read() == 0) {
+                    if (end_tx) {
+                        // something to send at end : radio.m_spi.write(<end-of-tx>);
+                        break;
+                    } else 
+                        radio.m_spi.write(get_tx_byte());
+                }
+
+                radio.m_cs = 1; 
+
+                if (end_tx) {
+                    end_transmit();
+                    txing = false;
+                    end_tx = false;
+                    start_receive();                 
+                }             
+            }
+        } else {
+            /* receving */
+            if (!dio3) {
+                bool restart_rx = false;
+                radio.m_cs = 0;
+                radio.m_spi.write(REG_FIFO);  // bit7 is low for reading from radio
+                while (dio3.read() == 0) {
+                    if (take_rx_byte(radio.m_spi.write(0)) != 0) {
+                        restart_rx = true;
+                        break;
+                    }
+
+                }
+                radio.m_cs = 1; 
+
+                if (restart_rx) {
+                    printf("rxRestart %u\r\n", rx_bytes_ok);
+                    fsk.RegRxConfig.octet = radio.read_reg(REG_FSK_RXCONFIG);
+                    #ifdef ENABLE_AFC
+                    fsk.RegRxConfig.bits.AfcAutoOn = 1;
+                    fsk.RegRxConfig.bits.RestartRxWithPllLock = 1;                    
+                    #else
+                    fsk.RegRxConfig.bits.RestartRxWithoutPllLock = 1;
+                    #endif
+                    radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet);
+
+                    if (!dio3) {
+                        /* dump whatever is remaining in fifo */
+                        radio.m_cs = 0;
+                        while (dio3.read() == 0) {
+                            radio.m_spi.write(0);
+                        }
+                        radio.m_cs = 1; 
+                    }
+
+/*
+                    fsk.RegAfcFei.octet = radio.read_reg(REG_FSK_AFCFEI);
+                    fsk.RegAfcFei.bits.AfcAutoClearOn = 1;
+                    fsk.RegAfcFei.bits.AfcClear = 1;
+                    radio.write_reg(REG_FSK_AFCFEI, fsk.RegAfcFei.octet);    
+                    */   
+                }
+            }
+
+            if (rxSync) {
+                rxSync = false;
+                printf("rxSync\r\n");
+            }
+        } // ..rxing
+
+
+    } // .. while(true)
+}
diff -r 000000000000 -r df5ce1bc5036 mbed-os.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Tue Sep 14 22:19:57 2021 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#b1796dedeb8accde1cbaecf136fab96895e23d81