Hello,
I’m experiencing an issue with UART communication in a tracker application using the Rak3172 module and Quectel L76 GNSS module, developed with RUI in the Arduino environment.
Problem Description:
- The UART1 hangs sporadically after 5-20 minutes of operation.
- Only the first character from the serial input is read (‘$’), and all subsequent characters are lost.
- This issue occurs more frequently when the GNSS module sends more messages.
- The GNSS module is connected to UART1.
- Changing the UART1 baud rate does not affect the behavior.
During the faulty operation, I used a logic analyzer to check the UART line and confirmed that the NMEA sentences were presented correctly. However, the Rak3172 only received the first character, suggesting a possible UART buffer overflow. This could be due to high interrupt load preventing the DMA buffer content from being copied to the UART RX buffer. I have not confirmed this with a debugger.
The issue is present in the following RUI versions: 3.5.6, 4.0.0, and 4.1.0 (tested only with these versions).
Workaround:
I modified the UART buffering in the BSP to use circular DMA mode. This change has resolved the issue, and I have not experienced the faulty behavior since. However, this workaround has a drawback: I can no longer reconfigure the UART baud rate after initialization.
The issue can be reproduced with the following application code
#include <TinyGPSPlus.h>
#define LogSerial Serial
#define GpsSerial Serial1
// LoRA parameters
#define CHANNEL_NUM 0
#define LORA_SF_RX 9
#define LORA_SF_TX 11
#define LORA_BW 1
#define LORA_CR 0
#define LORA_PREAMBLE 8
#define LORA_TX_POWER 14
#define SEND_PERIOD 45000
uint32_t channels[] = {868200000};
uint32_t myFreq; // Hz
uint16_t sf; // [SF7..SF12]
uint16_t bw; // kHz 0 = 125, 1 = 250, 2 = 500, 3 = 7.8, 4 = 10.4, 5 = 15.63, 6 = 20.83, 7 = 31.25, 8 = 41.67, 9 = 62.5
uint16_t cr; // 4/(cr+5)
uint16_t preamble; // Same for Tx and Rx
uint16_t txPower; // dBm
// The TinyGPSPlus object
TinyGPSPlus gps;
void recv_cb(rui_lora_p2p_recv_t data)
{
LogSerial.printf("Incoming message, length: %d, RSSI: %d, SNR: %d", data.BufferSize, data.Rssi, data.Snr);
}
void send_cb(void)
{
// After Tx set back to Rx mode
set_radio_sf_rx();
bool is_in_rx{false};
do{
is_in_rx = api.lorawan.precv(65534);
}
while(!is_in_rx);
}
void send_routine_periodic()
{
uint8_t payload[25] = {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4}; //dummy message
set_radio_sf_tx();
bool send_result = false;
while (!send_result) {
send_result = api.lorawan.psend(sizeof(payload), payload);
if (!send_result) {
api.lorawan.precv(0);
}
}
}
void routine_100ms()
{
listen_gps();
}
void listen_gps()
{
uint16_t cntr = 0U;
char c;
while(GpsSerial.available())
{
cntr++;
c = GpsSerial.read();
gps.encode(c);
}
LogSerial.printf("%d\r\n",cntr); //Logging number of received characters
}
void set_radio_sf_rx()
{
sf = LORA_SF_RX;
api.lorawan.psf.set(sf);
}
void set_radio_sf_tx()
{
sf = LORA_SF_TX;
api.lorawan.psf.set(sf);
}
void set_radio_rx_init()
{
myFreq = channels[CHANNEL_NUM];
sf = LORA_SF_RX;
bw = LORA_BW;
cr = LORA_CR;
preamble = LORA_PREAMBLE;
txPower = LORA_TX_POWER;
radio_init();
LogSerial.println(F("RX mode"));
}
void radio_init()
{
LogSerial.printf("Set P2P mode frequency %3.3f: %s\r\n", (myFreq / 1e6),
api.lorawan.pfreq.set(myFreq) ? "Success" : "Fail");
LogSerial.printf("Set P2P mode spreading factor %d: %s\r\n", sf,
api.lorawan.psf.set(sf) ? "Success" : "Fail"); //P2P Spreading Factor (6, 7, 8, 9, 10, 11, 12)
LogSerial.printf("Set P2P mode bandwidth %d: %s\r\n", bw,
api.lorawan.pbw.set(bw) ? "Success" : "Fail"); //P2P bandwidth in kHz (0 = 125, 1 = 250, 2 = 500, 3 = 7.8, 4 = 10.4, 5 = 15.63, 6 = 20.83, 7 = 31.25, 8 = 41.67, 9 = 62.5)
LogSerial.printf("Set P2P mode code rate 4/%d: %s\r\n", (cr + 5),
api.lorawan.pcr.set(cr) ? "Success" : "Fail");
LogSerial.printf("Set P2P mode preamble length %d: %s\r\n", preamble,
api.lorawan.ppl.set(preamble) ? "Success" : "Fail"); //P2P Preamble Length (2-65535)
LogSerial.printf("Set P2P mode tx power %d: %s\r\n", txPower,
api.lorawan.ptp.set(txPower) ? "Success" : "Fail"); //P2P TX Power (5-22)
}
void setup() {
LogSerial.begin(256000);
if(api.lorawan.nwm.get() != 0)
{
LogSerial.printf("Set Node device work mode %s\r\n",
api.lorawan.nwm.set(0) ? "Success" : "Fail"); // network working mode (0 = P2P, 1 = LoRaWAN, 2 = FSK)
api.system.reboot();
}
set_radio_rx_init();
api.lorawan.registerPRecvCallback(recv_cb);
api.lorawan.registerPSendCallback(send_cb);
bool is_in_rx = api.lorawan.precv(65534);
LogSerial.printf("P2P set Rx mode %s\r\n",
is_in_rx ? "Success" : "Fail");
GpsSerial.begin(9600);
if (api.system.timer.create(RAK_TIMER_0, (RAK_TIMER_HANDLER)send_routine_periodic, RAK_TIMER_PERIODIC) != true) {
LogSerial.println(F("LoRa - Creating timer failed."));
}
if (api.system.timer.start(RAK_TIMER_0, SEND_PERIOD, NULL) != true) {
LogSerial.println(F("LoRa - Starting timer failed."));
}
if (api.system.timer.create(RAK_TIMER_1, (RAK_TIMER_HANDLER)routine_100ms, RAK_TIMER_PERIODIC) != true) {
LogSerial.println(F("GPS - Creating timer failed."));
}
if (api.system.timer.start(RAK_TIMER_1, 100, NULL) != true) {
LogSerial.println(F("GPS - Starting timer failed."));
}
}
void loop()
{
api.system.sleep.cpu();
}
Application software operation:
- The application operates in P2P mode with continuous RX, switching to TX only while transmitting data.
- Different spreading factors are used for RX and TX, while other LoRa parameters remain the same.
- A 100ms timer is used to read the UART buffer and parse NMEA sentences.
- A 45-second timer is used to send a LoRa message.
Has anyone else experienced similar issues?