4 years, 10 months ago.

Unable to read serial data from GPS

Goodmorning I'm trying to develop an application with the B-L072Z-LRWAN1 LoRa®Discovery kit which has to get the location from a GPS module and sent it in LoRaWAN network. The GPS module that I'm using is a Microstack GPS (https://www.element14.com/community/docs/DOC-68898) but I have the same issue with an Adafruit Ultimate GPS.

The problem is that even if the GPS module has a fix on satellites I'm not able to read any string from serial pins, with Adafruit nothing at all, with Microstack sometimes it prints random and incomplete data, even when not requested, and only if the serial object is set to PB_9 and PB_8 pins. The other variation of what I consider an unpredictable behavior is that sometimes the board get stucked in a deadlock, usually caused by a single getc() call.

Moreover, seems that the interrupt on serial read is never thrown because the debug function is never executed; it executes only when Serial is open on PA_2, PA_3 pins when press "ENTER" on my pc.

IMPORTANT: I'm trying to debug this application with this command: mbed sterm port /dev/ttyACM0 baud 9600

Here my code:

GPS read issue

#include "mbed.h"
#include <string.h>

#define SERIAL_TX   PB_6
#define SERIAL_RX   PB_7
 
Serial gps(SERIAL_TX,SERIAL_RX,9600);

DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
 
InterruptIn mybutton(USER_BUTTON);
 
double tempo = 0.3; // LED blinking delay

const int MAXLENGTH = 100;
int i =0;
char buffer[MAXLENGTH];

void debug(){
     
    //printf("Interrupt ");

    if(i<MAXLENGTH){
         buffer[i++] = gps.getc();
    }
    
    if(i==MAXLENGTH){
        printf("\n%s\n",buffer);
        i=0;
    }
}
 
// Change LEDs blinking frequency
void change_blinking_frequency() {
    if (tempo == 0.3) // If leds have low frequency
        tempo = 0.1;  // Set the fast frequency
    else              // If leds have fast frequency
        tempo = 0.3;  // Set the low frequency
        
        printf("Buffer length: %d\n",strlen(buffer));
}
 
int main() {
    // All LEDs are OFF
    myled1 = 0;
    myled2 = 0;
    myled3 = 0;
    myled4 = 0;
 
    // Change LEDs blinking frequency when button is pressed
    mybutton.fall(&change_blinking_frequency);
    
    gps.attach(&debug,Serial::RxIrq);
    
    printf("Starting loop\n\n");
 
    while(1) {
        
        //char c = gps.getc();
        myled2 = 1;   // LED2 is ON
        wait(tempo);  // wait tempo
        myled2 = 0;   // LED2 is OFF
        myled1 = 1;   // LED1 is ON
        wait(tempo);  // wait tempo
        myled1 = 0;   // LED1 is OFF
        myled3 = 1;   // LED3 is ON
        wait(tempo);  // wait tempo
        myled3 = 0;   // LED3 is OFF
        myled4 = 1;   // LED4 is ON
        wait(tempo);  // wait tempo
        myled4 = 0;   // LED4 is OFF
        
    }
}

I've maintained leds blinking in order to detect when the software get stucked. I'm trying to solve this issue since 2 days but I'm not undestanding what mistake I'm making, does someone of you had a similar issue and was able to solve it?

What is your wiring like? Can you post a picture or diagram of how things are connected up? It could be a power or grounding issue.

posted by Andy A 24 Jun 2019

I've uploaded a couple of images of the wiring. Basically GPS 3,3V is wired to 3,3 output pin, GND to GND, PB6 to GPS RX pin and PB7 to GPS TX.

posted by Marco Zanetti 24 Jun 2019

In the pictures it looks like you have the TX and Rx pins the wrong way around. The data Tx from the module is on the yellow wire which you have going to PB6 which is defined in your code as serial Tx when data from the module should go in on serial Rx.

posted by Andy A 24 Jun 2019

Pins were wrongly connected but the problem persists. Sometimes it get stucked and sometimes it seems not to receive any input from serial that raise the interrupt function

posted by Marco Zanetti 24 Jun 2019

2 Answers

4 years, 10 months ago.

Marco -

Assuming that Andy's suggestion solved any hardware problem you were having, it sounds like the interrupt is not getting attached. I have seen similar behavior on a couple of different STM boards when I try to read serial connections at high rates. I think it has to do with a combination of the small buffer size of STM UARTs and the fact that your GPS is continuously sending packets (that are not being flushed) at the same time you are trying to attach the callback.

I have had good luck solving this using two different approaches:

1) Call the USART callback function immediately before attaching the interrupt. This is a simple way to clear the USART buffer and any pending interrupts.

2) Disable RX interrupts for the USART by re-setting its RX Interrupt Enable bit, attach the callback function and then re-enable RX interrupts for the USART by setting its RX Interrupt Enable bit. This approach is MCU dependent and should be documented in its Reference Manual. This bit is probably in the USART's CR1 register, based on my experience with other STM boards.

Also, keep in mind that you are printing inside of your callback function, which blocks code execution until the printing is complete. You would be better off replacing the printf call in the callback function with a "data_ready" flag. Set the data_ready flag when the RX buffer is full. Move the printf statements into the while() loop and read them when the data_ready flag indicates that a full buffer of new data is available. Don't forget to clear the data_ready flag after you have read the buffer.

You may want to use a ping-pong buffer and some of your variables may have to be declared as volatile. Andy has written some good notes on these issues - check his Activity thread.

4 years, 10 months ago.

Check your schematics for the board. See here. The user LEDs are connected to the same pins as used for your GPS serial port. LED3 = PB_6 and LED4 = PB_7. The serial GPS is basically just disabled by the declaration of the DigitalOut for the LEDs.

You should try using a different serial port if you want to use the LEDs for debugging.