Go Down

Topic: NeoHWSerial/interrupts (Read 2134 times) previous topic - next topic

-dev

Quote
What and why is RMC?
The GPS devices sends information in "sentences".

Different sentences contain different fields (see this table).  Since you are only using speed, you only need one of the sentences that contain speed: RMC or VTG.

Quote
If I turns off all sentences except the RMC, what impact will it have?
To reduce the number of RX char interrupts the Arduino has to handle, tell the GPS to send the fewest sentences possible.

To reduce the time that NeoGPS spends in recognizing different sentences, minimize the NMEAGPS_cfg.h configuration file as described above.  This also reduces RAM and program space.

To reduce the time that NeoGPS spends parsing fields that you don't use, minimize the GPSfix_cfg.h configuration file as described above.  This also reduces RAM and program space.

To configure the GPS to send only the RMC sentence, add these lines of code to your setup function:

Code: [Select]
 gps.send_P( &gpsPort, F("PUBX,40,GLL,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,GSV,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,GSA,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,VTG,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,ZDA,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,RMC,0,1,0,0,0,0") );  // <-- only enabled sentence
  gps.send_P( &gpsPort, F("PUBX,40,GGA,0,0,0,0,0,0") );

This matches the config files above.

To be even more efficient, you could try using just the VTG sentence.  Make these changes to NMEAGPS_cfg.h:

Code: [Select]
//#define NMEAGPS_PARSE_GGA
//#define NMEAGPS_PARSE_GLL
//#define NMEAGPS_PARSE_GSA
//#define NMEAGPS_PARSE_GSV
//#define NMEAGPS_PARSE_GST
//#define NMEAGPS_PARSE_RMC
#define NMEAGPS_PARSE_VTG
//#define NMEAGPS_PARSE_ZDA

#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_VTG

And send these commands in setup:

Code: [Select]
 gps.send_P( &gpsPort, F("PUBX,40,GLL,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,GSV,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,GSA,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,VTG,0,1,0,0,0,0") );  // <-- only enabled sentence
  gps.send_P( &gpsPort, F("PUBX,40,ZDA,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,RMC,0,0,0,0,0,0") );
  gps.send_P( &gpsPort, F("PUBX,40,GGA,0,0,0,0,0,0") );

Quote
How to configure that will run at 1.67Hz?
Start with these changes at 1Hz, as it will give the maximum amount of time for the OBD functions to complete.  It will also coordinate the OBD functions with the GPS quiet time.  No RX char interrupts will occur during the OBD functions.

Likewise, the OBD functions will have completed by the time a new GPS update begins (RX char interrupts).

If this works very reliably, post your code and I can comment on changing the display update rate.
Quote
But still there are some "wrong" readings from OBD.
Explain this in more detail.
Really, I used to be /dev.  :(

gospod

To reduce the time that NeoGPS spends in recognizing different sentences, minimize the NMEAGPS_cfg.h configuration file as described above.  This also reduces RAM and program space.

To reduce the time that NeoGPS spends parsing fields that you don't use, minimize the GPSfix_cfg.h configuration file as described above.  This also reduces RAM and program space.

To be even more efficient, you could try using just the VTG sentence.
I have minimized the NMEAGPS_cfg.h and GPSfix_cfg.h configuration.
If use just RMC/VTG sentence, this will not affect from which satellites receive signal. Galileo or GPS, will use all of them?

Explain this in more detail.
LCDs sometimes show values other than the actual oil temperature. For example shows the value of 70 °C, next time show "random" value (negative, or more than 1000), and then next time it's right again 70 °C.

-dev

Quote from: gospod
If use just RMC/VTG sentence, this will not affect from which satellites receive signal. Galileo or GPS, will use all of them?
Correct.  From the M8 Protocol Specification:

  u-blox receivers generally try to combine information from
    all available GNSS to create the best possible navigation information. 

Quote
LCDs sometimes show values other than the actual oil temperature. For example shows the value of 70 °C, next time show "random" value (negative, or more than 1000), and then next time it's right again 70 °C.
I would suggest printing the complete response from the "22 19 4F" command.  Try something like:

Code: [Select]
Serial.println( prebralo_bo_sem );  // show the complete response buffer

    int temperatura = (readMultiAir(prebralo_bo_sem) - 40);

Then you can see why the temperature is not calculated correctly from those characters.
Really, I used to be /dev.  :(

gospod

#18
Feb 18, 2018, 08:09 pm Last Edit: Feb 18, 2018, 08:18 pm by gospod
I have record how looks reading when is not correct (different of: 62 19 4F ")https://www.dropbox.com/s/6v77nv9z0wz2k32/IMG_5453_2.mov?dl=0

I have tried with
Code: [Select]
Serial.println( prebralo_bo_sem ); and didn't work. Of course, I need to use NeoSerial. If I'm not wrong, USB works on (Neo)Serial? So I changed OBD on (Neo)Serial2. When I have changed OBD port from (Neo)Serial to (Neo)Serial2 the problem disappeared.

Question is why?


-dev

Quote
I have record how looks reading...
Just select the text in the Serial Monitor Window with your mouse, copy it (ctrl-C), and then paste it (ctrl-V) into your post, in code tags.  In the Serial Monitor Window, uncheck the Autoscroll box to make it easier to control what you select.

BTW, most people will not download from external sites, especially dropbox.  Don't post a screen image of the Serial Monitor window, either.

Quote
Of course, I need to use NeoSerial.
Only for the interrupt processing style.  You probably don't need to do that, but it's ok to try it.

Quote
USB works on (Neo)Serial?
Yes, on the Mega, the USB interface (an FTDI chip) is connected to pins 0 & 1.

Quote
When I have changed OBD port from (Neo)Serial to (Neo)Serial2 the problem disappeared.  Question is why?
Maybe the OBD adapter does not drive RX pin 0 "hard enough" to override the USB connection.  Sending data from the Serial Monitor window would also interfere with receiving the OBD response.

Be sure to post (or attach) your code, so others can benefit from your final solution.
Really, I used to be /dev.  :(

gospod

#20
Feb 19, 2018, 01:02 am Last Edit: Feb 19, 2018, 01:31 am by gospod
BTW, most people will not download from external sites, especially dropbox.  Don't post a screen image of the Serial Monitor window, either.
I have record a movie of print on LCD. You don't need to download, you can watch online.

Only for the interrupt processing style.  You probably don't need to do that, but it's ok to try it.
It means don't need to use NeoHWSerial.h?

Maybe the OBD adapter does not drive RX pin 0 "hard enough" to override the USB connection.  Sending data from the Serial Monitor window would also interfere with receiving the OBD response.
I guess can not be at the same time OBD connected on Serial(0) and computer on USB?



I have in code sleep function and want that GPS will go to sleep too. Will this work?

-dev

I have record a movie of print on LCD. You don't need to download, you can watch online.
"Watching" it effectively downloads the MOV file to your computer.  Uploading it to YouTube would be a "safe" alternative.

Quote
It means don't need to use NeoHWSerial.h?
Yes.  There two ways you can process characters (i.e., the "processing style"):

1)  By POLLING the Serial.available function in loop (or a function called from loop).  This does not require NeoHWSerial, and you should comment out the INTERRUPT define in NMEAGPS_cfg.h.

This is easiest to understand for most people.  The only disadvantage is that other functions can cause GPS data to be lost when the RX buffer overflows.  As long as other functions take less than 64 character times (5.55ms @ 115200), you will not lose GPS characters.  The OBD functions have a timeout of 300ms, so they could block for up to 600ms.  I do not know how long they actually take (without timeouts).

However, if you wait for the GPS to quit sending data until the next update period, you can try to perform the OBD functions during this "quiet time".  The loop structure in reply #11 will only call MultiAirTemp immediately after a fix is available.  That fix is the result of parsing the only sentence that is enabled (according to commands sent during setup).  The VTG sentence only contains ~50 characters, sent once per second.  It takes about 50*10/115200 = 4.35ms to send that sentence.  It will be 993.65ms until the GPS sends another VTG sentence.  This is long enough to complete the OBD transactions, even with the 600ms timeouts and LCD updates.

Therefore, the POLLING style should work for an update rate of 1Hz.

2)   By handling each character during the INTERRUPT.  If you cannot coordinate other functions with the GPS quiet time, or other parts of your sketch take longer than 5.55ms, you must use this processing style.  This requires NeoHWSerial, and you must uncomment the INTERRUPT define in NMEAGPS_cfg.h.

The main loop will still check for complete fixes to become available and will then read them.  The latest fix will always be available, even if older fixes were not read in time.  For example, if the OBD functions took 2 seconds to complete, you may have "lost" one complete fix while that was happening.  But the latest one will have been parsed during that time (by the ISR), and will be available immediately, the next time gps.available is checked.  NeoGPS holds on to the latest fix until it is read.  When a newer fix is available, the previous (unread) fix is discarded.  Your sketch will not care that a fix was lost.

Quote
I guess can not be at the same time OBD connected on Serial(0) and computer on USB?
Normally, it is ok.  You must disconnect 0 to upload new sketches, but you should be able to reconnect it after the upload.  If no characters are sent over the USB port to the Arduino, the OBD "should" be able to send data to the Arduino on pin 0.

Doesn't matter -- Serial2 is a better choice, anyway.

Quote
I have in code sleep function and want that GPS will go to sleep too. Will this work?
Yes.  Just write those bytes to the GPS port:

Code: [Select]
const uint8_t powerdown[] = { 0xB5, 0x62, 0x02, 0x41, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4D, 0x3B };

void sleep()
{
  lcd.noBacklight();
  lcd.noDisplay();

  gpsPort.write( powerdown, sizeof(powerdown) );
  gpsPort.flush();   // make sure the bytes are fully transmitted before sleeping

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here 
  sleep_enable();    // enables the sleep bit in the mcucr register
  sleep_mode();      // here the device is actually put to sleep!!
}

(not tested)

To wake the GPS device, send it a character:

    gpsPort.write( 0x00 ); // anything, really
Really, I used to be /dev.  :(

gospod

1)  By POLLING the Serial.available function in loop (or a function called from loop).  This does not require NeoHWSerial, and you should comment out the INTERRUPT define in NMEAGPS_cfg.h.
So, if INTERRUPT is not use, NeoHWSerial does not have the advantage of using it?


You must disconnect 0 to upload new sketches, but you should be able to reconnect it after the upload.  If no characters are sent over the USB port to the Arduino, the OBD "should" be able to send data to the Arduino on pin 0.
I thought OBD would read on serial(0) and then (at the same time) print it on USB. If this will work? Otherwise, I can not read in Serial Monitor Window.


Code: [Select]
const uint8_t powerdown[] = { 0xB5, 0x62, 0x02, 0x41, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4D, 0x3B };

It works. Is this the most power saving mode? I don't need hot start, I just want to turn off all I can when car is turned off.
Do you have any idea how to wake the whole system from sleep when I start the car? If is there any software "tweak"? I want to avoid additional cables/connections.

-dev

#23
Feb 22, 2018, 12:40 am Last Edit: Feb 22, 2018, 12:41 am by -dev
Quote
So, if INTERRUPT is not use, NeoHWSerial does not have the advantage of using it?
NeoHWSerial *is* HardwareSerial, with one addition: attachInterrupt.  I started with the Arduino core source code and made this modification.  If you don't need attachInterrupt, you might as well use the built-in HardwareSerial (i.e., Serial, Serial1, etc.).

Quote
I thought OBD would read on serial(0) and then (at the same time) print it on USB. If this will work? Otherwise, I can not read in Serial Monitor Window.
Yes, that will send debug messages to the OBD device as well as the Serial Monitor window.  Because the device requires a certain AT command format, it should ignore your debug messages... unless they start with "AT".  Then it tries to interpret your debug messages.  :P  Don't do that.

You will also see the AT commands in the Serial Monitor window.  But maybe you should connect the OBD device to Serial1, Serial2 or Serial3, like I suggested earlier.

You could put the GPS on Serial, if you want.  Again, Serial1, Serial2 or Serial3 would be more convenient, because you wouldn't have to disconnect pin 0 everytime you want to upload a new sketch.

Quote
It works. Is this the most power saving mode? I don't need hot start, I just want to turn off all I can when car is turned off.
Yes, this is the lowest power mode for the ublox devices: 35uA is a very small drain.  Other system components probably use more than this (e.g., regulators' quiescent currents).  You'll have to measure the actual usage of your system.

Be sure to read reply #5 and reply #20 in that other thread.

Quote
Do you have any idea how to wake the whole system from sleep when I start the car? If is there any software "tweak"? I want to avoid additional cables/connections.
No clue.  How would your system know the car is "on"?

Maybe a tilt switch or vibration/sound sensor hooked to a Pin Change Interrupt?  Sensing a voltage on something must be done very carefully, because automotive power if very noisy, even dangerous to the components.

The Watch Dog Timer can be used to periodically wake up, but it increases the sleep current.
Really, I used to be /dev.  :(

gospod

But maybe you should connect the OBD device to Serial1, Serial2 or Serial3, like I suggested earlier.
OBD is connected on Serial2 and wokrs. But I am trying to figure out why it does not work on Serial(0).

You could put the GPS on Serial, if you want.  
I would like OBD (not GPS), as I already wrote because of the length of the cables.

No clue.  How would your system know the car is "on"?

Maybe a tilt switch or vibration/sound sensor hooked to a Pin Change Interrupt?  Sensing a voltage on something must be done very carefully, because automotive power if very noisy, even dangerous to the components.

The Watch Dog Timer can be used to periodically wake up, but it increases the sleep current.
I was thinking about something like that. It could be watching for changes in motion (gyro in OBD adapter) or increased Voltage (also from OBD adapter - car battery voltage, not arduino VIN).

P.S. What I need to enable if I would like read number of seen satellites? Will this works if fix is not valid?
I have tried:
Code: [Select]
gps.send_P( &gpsPort, F("PUBX,40,GSA,0,1,0,0,0,0") );

in GPSfix_cfg.h enable
Code: [Select]
#define GPS_FIX_SATELLITES

in NMEAGPS_cfg.h enable:
Code: [Select]
#define NMEAGPS_PARSE_GSA
#define NMEAGPS_PARSE_SATELLITES

-dev

Quote
I am trying to figure out why it does not work on Serial(0).
Be sure to read my warning: don't print something that looks like an AT command to Serial for debugging.  It will also be sent to the OBD device.

Quote
What I need to enable if I would like read number of seen satellites?
Look at this table.  If you need speed and satellites, the RMC sentence would give you both.  That is the only sentence you would need to enable and parse.  Enable RMC (and set LAST_SENTENCE to RMC) in NMEAGPS_cfg and add SATELLITES to GPSfix_cfg.h.

All fields have a validity flag, so you can make sure the satellites field is valid with this:

    if (valid.satellites)

This can be valid even if other fields are not valid.  The RMC sentence may have a satellite count without a location or speed.
Really, I used to be /dev.  :(

gospod

Look at this table.  If you need speed and satellites, the RMC sentence would give you both.  That is the only sentence you would need to enable and parse.  Enable RMC (and set LAST_SENTENCE to RMC) in NMEAGPS_cfg and add SATELLITES to GPSfix_cfg.h.
In this table RMC sentence does not provide satellites data. Also until I enable GGA does not show satellites data.

-dev

Quote
until I enable GGA does not show satellites data.
LOL, double duh.  GGA + VTG would be the fewest number of characters.  Be sure to check which one is last, with the example NMEAorder.ino.
Really, I used to be /dev.  :(

gospod

The reason for which I want satellites data is because a places with bad signal (garage house, tunnel). I set the condition if the speed is not valid, than print  satellites. But it don't work. It show irregular speed (for example 20km/h) when the car is in fact standing in place.

-dev

Quote
It show irregular speed
Then the OBD functions may be taking too long, causing it to lose GPS characters.  You should try the INTERRUPT style (see Reply #4).  If the speed becomes reliable, then the OBD was taking too long.

Are the OBD temperatures good?
Really, I used to be /dev.  :(

Go Up