Author Topic: Arduino - Serial Read and Interrupt  (Read 7907 times)

0 Members and 1 Guest are viewing this topic.

Offline LeopoldoTopic starter

  • Contributor
  • Posts: 48
Arduino - Serial Read and Interrupt
« on: November 12, 2016, 11:45:32 pm »
Hi there,
I'm working on a project which uses a GPS and thus needs to acquire the data through the Serial port (software serial, in this case). I ran into a problem: since I'm doing other stuff inside the loop, which can take up to 350ms, sometimes the Serial buffer is not reached when the data comes from the GPS, and since the Serial buffer only holds up to 64B of memory, I end up losing most of the characters needed for the localization.
I've read online that there shouldn't be a phisical interrupt because I might lose incoming characters.
Also, the code is already quite efficent; the only "waste" of time is the refreshing of a display that is accomplished via I2C, and that's why it's so slow.
I was wondering if it could be possible to immediately read the port as soon as the GPS starts sending the data, but I have no clue how to do so.

To give you a rough idea how the loop is running, here's a brief explanation:

while(1){
  while(serial.available()){
    acquire_data;
  }
  calculations, variables updates, etc.
  draw char and shapes on LCD;
  draw char and shapes on LCD;
  ...
  various_functions();
 
  more LCD stuff;
  print_everything_on_LCD();

}

From "calculations, variables updates, etc."  to  "print_everything_on_LCD();"  it takes roughly 350ms. I'm explaining this because you can clearly see that I can't just use a goto or some sort of well-nested loop, there is just too much stuff....there are about 300 lines of code.

Thank you!
 

Offline obiwanjacobi

  • Super Contributor
  • ***
  • Posts: 1022
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Arduino - Serial Read and Interrupt
« Reply #1 on: November 13, 2016, 07:32:21 am »
since the Serial buffer only holds up to 64B of memory
If you're not able to stay ahead of 64 bytes of buffer, you are doing too much in the main loop. You need a faster MCU, or offload tasks to an external device (either receiving the GPS data or processing the LCD data).

I've read online that there shouldn't be a physical interrupt because I might lose incoming characters.
I think the standard Serial does use an interrupt and from what I understood that is also the only way NOT to lose data - assuming you have a main loop running.

I was wondering if it could be possible to immediately read the port as soon as the GPS starts sending the data
Yes, you could, but that would not fix your problem, I suspect it'll make it worse.

Realize that the Arduino libraries are not written for best performance - but for ease of access (easy to learn). So you can also think about ditching the Arduino libraries and write code directly on the MCUs registers. Get the datasheet for the MCU and lookup the peripherals you need. You can do this one "subject" at a time. If you are new to this, this can be a daunting task.

Hint: see my signature...
Wrong code should not compile!
 

Offline FreddyVictor

  • Regular Contributor
  • *
  • Posts: 164
  • Country: gb
Re: Arduino - Serial Read and Interrupt
« Reply #2 on: November 13, 2016, 08:14:57 am »
just knock up your own Serial code with bigger buffers - you'll learn something in the process

will also save a few bytes

I had to add i2c to a nearly full project - adding wiring took it way over the max
adaped an existing i2c library (Peter Fleurey) and it was half the size ....
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4283
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: Arduino - Serial Read and Interrupt
« Reply #3 on: November 14, 2016, 06:35:20 am »
From "calculations, variables updates, etc."  to  "print_everything_on_LCD();"  it takes roughly 350ms.
That is most likely because the LCD uses some kind of "delay()". Get those out of there.
 

Online 2N3055

  • Super Contributor
  • ***
  • Posts: 7788
  • Country: hr
"Just hard work is not enough - it must be applied sensibly."
Dr. Richard W. Hamming
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9987
  • Country: us
Re: Arduino - Serial Read and Interrupt
« Reply #5 on: November 14, 2016, 08:14:29 pm »
If you have space for another 'sentence assembly buffer', you can call the 'acquire' routine several times in the super-loop to grab chars and put them in the 'assembly buffer'.
You might be able to add flow control to the serial loop such that it only sends data when you are ready to accept it.
The 'right' way to do it is to have the serial port generate interrupts and allow the interrupt routine to put the chars in a circular queue.  Obviously, the queue needs to be long enough to hold however many characters might be received before you get back to fetching them.
If you have enough RAM, you can have the main code empty out the circular buffer periodically (perhaps several times in the super-loop) and put the chars in the 'sentence assembly buffer'.

When things happen asynchronous to the CPU and can't be controlled (flow control in this case), the only way to synchronize things is via interrupts.  I really don't know where you read that interrupts shouldn't be used but the source is wrong!
 

Offline slashdev

  • Contributor
  • Posts: 10
Re: Arduino - Serial Read and Interrupt
« Reply #6 on: November 15, 2016, 01:56:55 pm »
Lots of people also have trouble when logging to an SD card, because an atomic write operation can take up to 100ms.  This causes the same input buffer overflow (GPS character loss) that you are seeing.

I developed my library, NeoGPS, to overcome this issue, among others.  There's even a section about parsing during the RX char interrupt, which avoids the whole buffer size question.  This requires using some alternative serial libraries that are drop-in replacements for the standard HardwareSerial, SoftwareSerial and AltSoftSerial libraries.

NeoGPS is smaller, faster and more accurate than all other libraries, and you can edit the configuration files to ignore fields and sentences that you don't really use.  For example, if you only need the time, you can configure the library to only parse the time from a ZDA message.  This makes the library even smaller and faster.

The other thing to note is that NeoGPS parses characters and emits a complete "fix".  The fix structure contains all the fields from all the sentences received in one second (i.e., each update interval).  This is unlike other libraries that parse characters and emit one sentence.  Your main loop would look something like this:

Code: [Select]
gps_fix latest_fix; // a structure containing GPS fields
while(1){
  while (gps.available( gpsSerialPort )){
    latest_fix = gps.read();
  }
  calculations, variables updates, etc.
  draw char and shapes on LCD;
  if (latest_fix.valid.time)
    draw latest_fix.dateTime.seconds on LCD;
  ...
  various_functions();
 
  more LCD stuff;
  print_everything_on_LCD();

}

However, this appears to be constantly updating the LCD.  If the LCD is only displaying GPS information, or your calculations only need to be performed with the GPS information changes, you might want to restructure your loop like this:

Code: [Select]
gps_fix latest_fix; // a structure containing GPS fields
while(1){
  while (gps.available( gpsSerialPort )){
    latest_fix = gps.read(); // new info!

    calculations, variables updates, etc.
    draw char and shapes on LCD;
    if (latest_fix.valid.time)
      draw latest_fix.dateTime.seconds on LCD;
    ...
    various_functions();
 
    more LCD stuff;
    print_everything_on_LCD();
  }

  other_non_GPS functions()

}

NeoGPS is available from the Library Manager if you're using a current version of the IDE, or you can get it from the link above.  Be sure to check out the examples.

Cheers,
/dev
 

Offline @rt

  • Super Contributor
  • ***
  • Posts: 1076
Re: Arduino - Serial Read and Interrupt
« Reply #7 on: November 18, 2016, 07:36:48 pm »
Serial isn't the only interrupt source.
Don't forget if you're using a UBlox or anything else with
frequency/PPS output, the serial data is sent immediately
following the rising or falling edge of the pulse, so the pulse
could be used to trigger spin interrupt to read the serial.
 

Offline retrolefty

  • Super Contributor
  • ***
  • Posts: 1648
  • Country: us
  • measurement changes behavior
Re: Arduino - Serial Read and Interrupt
« Reply #8 on: November 18, 2016, 11:22:08 pm »
The arduino serial library source is supplied as part of the IDE distribution. One can very easily change the buffer size to what one might require, larger or smaller. Keep in mind the SRAM limitations you might have and that buffer size defines two seperate buffers, one for send and one for receive data.

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf