I'm trying to implement LoRa communications using an SX1276 module (DRF1276G) and an ATmega328P on a custom PCB. I've got it mostly working but I'm having a strange issue with the timeout interrupt. I've set it to use RX-Single mode, with a timeout for the full 1023-symbols, but SOMETIMES it times out before that.
EDIT: Note that for the tests i've shown below, SF=7 and BW=125kHz, so the symbol period is ~1.02ms, so timeout window should be ~1043ms. The reported timeout window in the screenshots in only an approximation, as i'm dividing these values with integers. No floating-points here. But you can assume that if it's something like 643ms or 27ms, it is a shorter amount of time before the timeout flag fired.
See the image below, where 1023 symbols is indicated by it taking "~1026 ms" to time out. Anything much less than that amount of time is a shorter period for the receive-function to return, indicated the RX-timeout flag was fired before the expected 1023sym/"~1026ms" window. [EDIT: Please ignore the "TX..." text, the program doesn't actually transmit anything, i just forgot to change that in my print-out]
My test setup is simply listening for incoming packets. No packets are being transmitted.
ONE TIME ONLY, in the (i'm estimating) 4 hours of total run-time of these boards, this happened...
Here's a summary of my testing:
- It happens on all my devices, so its not faulty hardware
- Testing Dragino boards in the same environment, the Draginos work perfectly. Indicates it's not environment noise/transmissions (though the Draginos use RX-continuous mode not RX-single).
- A program to output RSSI readings shows a constant ~-100dBm output. Doesn't look like it's environment noise.
- Adding 5-second delays between receive-function calls doesn't help.
- Changing settings such as data rate, frequency, coding rate, sync word, preamble length etc. don't affect its behaviour.
- Testing multiple power configurations and CRO testing show's it's not a power issue.
- Testing showed it's not noise on the SPI bus causing wrong reads of the interrupt flag register.
Googling hasn't yielded any answers, and the only thing in the datasheet I have to go off is the following snippet...
Thing is, I'm not transmitting anything for it to pick up.
Here is the relevant code.
Main loop
// main loop
while(1) {
USARTSendString("RX...\n");
rxPktNo = sx127X_RxPacket((uint8_t *)localDataBuffer);
USARTSendString("timeout: ~");
USARTSendString(itoa(sx127X_lastPacketDurationMilli(),string,10));
USARTSendString("ms\n");
// if data was received, print stuff
if (rxPktNo) {
printMessageContentsAndStats(rxPktNo);
resetContentsOfDataBuffer();
}
}
Receive Routine
/* ------------------------------------------/
Set to single receive mode and poll for
the reception of a single packet of data.
Upon reception write data from FIFO
buffer to the given array.
------------------------------------------*/
uint8_t sx127X_RxPacket(uint8_t* dataPtr) {
uint8_t var = 0; // dual-purpose variable
uint8_t returnValue = 0;
// Enter standby mode
setMode(MODE_STDBY);
// Configure for RX if not done already
if (rxtxConfig != CONFIGGED_FOR_RX) {
sx127X_ConfigRX();
}
// Poll for RX-ongoing status, wait till stopped
//while (sx127X_SPIReadReg(LR_RegModemStat) & 0x04);
// Clear interrupts
sx127X_ClearIrq();
// Set to receive mode
setMode(MODE_RXSINGLE);
// Start timer
TCNT1 = 0;
// Poll for timeout, sx127x will go to MODE_STDBY upon timeout
while (!(sx127X_SPIReadReg(LR_RegIrqFlags) & 0x80)) {
// Poll for the RX-done flag
if (sx127X_SPIReadReg(LR_RegIrqFlags) & 0x40) {
// Read starting address of the last received packet...
var = sx127X_SPIReadReg(LR_RegFifoRxCurrentaddr);
// ... Write it to the address pointer for the FIFO buffer
sx127X_SPIWriteReg(LR_RegFifoAddrPtr, var);
// Retrieve packet size of last received packet
var = sx127X_SPIReadReg(LR_RegRxNbBytes);
// Use packet size and FIFO to read RX packet
sx127X_SPIBurstRead(LR_RegFifo, dataPtr, var);
// If successfully retrieved a packet, return true with number of bytes
returnValue = var;
break;
}
}
// give timer value to global variable
lastTimeoutDuration = TCNT1;
// If no packet has been retrieved this call return false
return returnValue;
}
Settings
/* -------------------------------------------------------- /
Configuration settings common to both the receiver and
transmitter modes of operation.
------------------------------------------------------- */
void sx127X_ConfigCommon(void) {
/*------------ Hardware Settings ------------*/
// Set the access-shared-registers mode
sx127X_setASRMode(ASR_LORA);
// Set low or high frequency mode
sx127X_setFrequencyMode(LFM_HF);
// Set either PA_RFO (+14dB) or PA_BOOST (+20dB)
sx127X_setPaSelect(PA_BOOST);
// Set the output power in dBm (PA_BOOST 2 to 17)
sx127x_SetPowerDBm(14);
// Set the PA ramp-up time
sx127X_setPARampTime(RAMP_40US);
// Set overload current protection
sx127X_setOCP(OCP_ON);
// Set overload current protection limit
sx127X_setOCPLimit(OCP_100MA);
// Set the low noise amp gain
sx127X_setLNAGain(LNA_GAIN_G1);
// set LNA boost for low frequency
sx127X_setLNABoostLF(LNA_BOOST_LF_DEFAULT);
// set LNA boost for high frequency
sx127X_setLNABoostHF(LNA_BOOST_HF_DEFAULT);
// Set LNA gain manual or auto
sx127X_setLNAGainAuto(LNA_GAIN_AUTO_ON);
/*----------- Communication Settings -----------*/
// Set base frequency (channel) of the LoRa module
sx127X_setChannel(channel);
// Set the data rate (bandwidth and spreading factor) of the LoRa module
sx127X_setDataRate(dataRate);
// Set the coding rate of the LoRa module
sx127X_setCodeRate(CR_4OF8);
// Set the toggle for implicit header
sx127X_setImplHeaderMode(IHM_OFF); // Explicit
// Set TX continuous mode on or off(normal/packet mode)
sx127X_setTXContMode(TXCM_NORM);
// Set RX payload CRC mode on or off
sx127X_setRXPayloadCRC(RXPL_CRC_ON);
// Set the RX symbol timeout in symbols
sx127X_setRXSymbolTimeout(SYMB_TIMEOUT_1023SYM);
// Set preamble length in symbols
sx127X_setPreambleLength(8);
// Set the payload length in bytes
sx127X_setPayloadLength(0x01); // default
// Set payload maximum length in bytes
sx127X_setPayloadMaxLength(0x80);
// Set the frequency hopping period (0=disable)
sx127X_setFreqHopPeriod(0);
// Set Sync Word
sx127X_setSyncWord(0xF3);
// Select inversion of I and Q signals
sx127X_invertIQ(INVERT_IQ_OFF);
}
/* -------------------------------------------------------- /
Configure the sx127x module for receiver operation.
Use entire FIFO.
------------------------------------------------------- */
void sx127X_ConfigRX(void) {
uint8_t addr;
// Set DIO0 for the RX done flag
sx127X_SPIWriteReg(REG_LR_DIOMAPPING1, 0x00);
// Set interrupt mask for RX timeout and RX done
sx127X_SPIWriteReg(LR_RegIrqFlagsMask, 0x3F);
// Set the RX base address to bottom of FIFO
sx127X_SPIWriteReg(LR_RegFifoRxBaseAddr, 0x00);
// Set address pointer to bottom of FIFO as well
sx127X_SPIWriteReg(LR_RegFifoAddrPtr, 0x00);
// locally store RX mode config flag
rxtxConfig = CONFIGGED_FOR_RX;
}
If anyone knows what the issue might be, or can give me more ideas to test, it would be much appreciated.