In german language "Krimskrams".
Prologue:
My final goal is to have a stable time base to check accuracy of LSE circuit.
The solution can be a GPS receiver. Each of these boards have a 1PPS-output. That's the same output, where the blinking LED is connected.
So the easiest way would be to use this signal as interrupt. A small STM32C011 counts up to 30 or 60 and then send an interrupt to the STM32-board under test.
But I want more ...
Normally a GPS receiver sends NMEA-sentences via serial port. A modern receiver like uBlox NEO-M9N uses GPS, GLOSNASS, BEIDOO and GALILEO. Depending on which sentences you activate or deactivate, it will spit out a lot of data.
So I looked around for a library, which can use I²C instead of UART and found "SparkFun u-blox GNSS". You can install it by Arduino IDE library manager. If you have a NEO-9M or NEO-10 library version 3 is the right one for you. For older uBlox devices you have to choose version 2. SparFun wrote for their own GPS receiver, but it is public domain. And judging by all those Serial.println(F(...)) it was made for Arduino UNO etc. No information about tests with different MCUs. But it works flawless on a STM32G431!
Of course GPS needs free view to the sky, best would be a place with free view in each direction. I'm using a Mikroe GSSN 7 click. Even it sounds liek an older generation, it has a NEO-M9N module. The good thing is the SMA-socket on pcb. So receiver can stay inside and GPS antenna is outside. I²C lines have to short. It would be difficult to place whole GPS receiver outside. Long I²C lines may work with special line drivers.
BTW: I don't like these tiny u.FL-conncetors. You have to be careful not to damage them and they are made for only 30 connects/disconnects.
Because GPS antenna is at a fixed place, I don't want to know latitude, longitude and altitude. But you find teh methods outcommented in the sketch. I'm interested in:
- number of Satellites in view (SIV)
- dillution of precision (DOP)
If you want to more about it, please check at Wikipedia. From my experience on lot of hiking tours, I can tell you that values for horizontal DOP below 2 are good, close to 1 is excellent. Values below 1 are an effect of Multi-GNSS and a overdetermined system.
Also: you will have a fix with 3 satellites, but for acurate position you need 10 or more satellites. So forget all those marketing speech about a short cold start fix etc. Place a GPS receiver at a place with good sky view and let it "warm up" for 15 minutes!
Another hint: my GPS board has pin headers. Don't put the receiver into a breadboard. At EEV-Blog I read, that capacity between rows is only 2 pF. But 1PPS-line showed a awful jitter of 600 ns. May be TX-signal on next row influence signal? In datasheet you can see, that jitter should be only ±60 ns.
And for last: you can get GPS receivers for small money from chinese dealers. The chip may act like a uBlox. But when you want to upload a new firmware or make some settings, it may fail because it is a fake chip.
Deviation Map: left for the first 15 minutes, right 3 hours
It shows calculated positions in a latitude over longitude map. If GPS receiver sends exact same position all the time, you would see only a dot. So this kind of graphic is a visualisation of the position error.
For this first try I connected 3.3 V, GND, SCL and SDA from STM32G431 board to the GPS board with jumper cables.
Code: Select all
//-----------------------------------------------------------------------------
// Board: STM32G431CBU6 (WeactStudio "long type")
// https://github.com/stm32duino/Arduino_Core_STM32/blob/main/variants/STM32G4xx/G431C(6-8-B)U_G441CBU/PeripheralPins.c
// https://github.com/stm32duino/Arduino_Core_STM32/blob/main/variants/STM32G4xx/G431C(6-8-B)U_G441CBU/variant_generic.h
// DAC: PA4, PA5
// I2C: PA8 (SDA), PA9 (SCL)
// UART1: PA3 (RX), PA2 (TX)
// LED: PC6
//
// https://github.com/sparkfun/SparkFun_u-blox_GNSS_v3/tree/main (only uBlox M9/M10)
// code from Example4_CustomI2C.ino (V3) and Example15_GetDateTime.ino (V2)
// Example1_AutoPVT.ino genauere Prüfung auf valide Werte
//
// https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)
// - HDOP Horizontal DOP
// - PDOP 3D horizontal and vertical
// - GDOP Geometric DOP (3D and time)
//
// The fix type is as follows:
// 0 = no fix
// 1 = dead reckoning (requires external sensors)
// 2 = 2D (not quite enough satellites in view)
// 3 = 3D (the standard fix)
// 4 = GNSS + dead reckoning (requires external sensors)
// 5 = Time fix only
//-----------------------------------------------------------------------------
#include <Wire.h> // Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_v3.h> // SparkFun u-blox GNSS v3@3.1.5
SFE_UBLOX_GNSS myGNSS;
#define myWire Wire // Connect using the Wire (not Wire1) port. Change this if required
#define gnssAddress 0x42 // The default I2C address for u-blox modules is 0x42. Change this if required
void setup() {
Serial.begin(115200);
delay(2000);
Serial.printf("\n\n ----- u-blox NEO-9M (Time, Satellites and DOP) ----- \n");
myWire.begin(); // Start I2C
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
while (myGNSS.begin(myWire, gnssAddress) == false)
{
Serial.println("u-blox GNSS not detected. Retrying...");
delay (1000);
}
myGNSS.setI2COutput(COM_TYPE_UBX); // Set the I2C port to output UBX only (turn off NMEA noise)
//myGNSS.setNavigationFrequency(2); // Produce two solutions per second --- seems not to work
myGNSS.setAutoPVT(true); // Tell the GNSS to "send" each solution
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
}
void loop() {
uint8_t fix; // Fix-Type
uint8_t siv; // satellites in view (satellites in use would be better ...)
uint16_t gdop;
uint16_t hdop;
bool dop;
int32_t lat;
int32_t lon;
int32_t alt;
uint16_t year;
uint8_t mon;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint16_t ms;
// Request (poll) the position, velocity and time (PVT) information.
// The module only responds when a new position is available. Default is once per second.
// getPVT() returns true when new data is received.
if (myGNSS.getPVT() == true)
{
//lat = myGNSS.getLatitude();
//lon = myGNSS.getLongitude();
//alt = myGNSS.getAltitudeMSL();
year = myGNSS.getYear();
mon = myGNSS.getMonth();
day = myGNSS.getDay();
hour = myGNSS.getHour();
min = myGNSS.getMinute();
sec = myGNSS.getSecond();
ms = myGNSS.getMillisecond();
siv = myGNSS.getSIV();
dop = myGNSS.getDOP();
gdop = myGNSS.getGeometricDOP();
hdop = myGNSS.getHorizontalDOP();
fix = myGNSS.getFixType();
//Serial.printf("Lat = %d Lon = %d Alt = %d \n", lat,lon, alt);
Serial.printf(" %02d.%02d.%04d %02d:%02d:%02d.%03d UTC ",day,mon,year,hour,min,sec,ms);
Serial.printf("SIV = %d FIX = %d HDOP = %01d.%02d GDOP = %01d.%02d \n",siv, fix, hdop/100, hdop%100, gdop/100, gdop%100);
}
}
And here some output:
Code: Select all
11:49:23.421 -> ----- u-blox NEO-9M (Time, Satellites and DOP) -----
11:49:24.802 -> 09.07.2024 09:49:24.500 UTC SIV = 21 FIX = 3 HDOP = 0.77 GDOP = 1.46
11:49:25.825 -> 09.07.2024 09:49:25.500 UTC SIV = 21 FIX = 3 HDOP = 0.77 GDOP = 1.46
11:49:26.870 -> 09.07.2024 09:49:26.500 UTC SIV = 22 FIX = 3 HDOP = 0.77 GDOP = 1.46
11:49:27.909 -> 09.07.2024 09:49:27.500 UTC SIV = 21 FIX = 3 HDOP = 0.77 GDOP = 1.46
11:49:28.817 -> 09.07.2024 09:49:28.500 UTC SIV = 21 FIX = 3 HDOP = 0.77 GDOP = 1.46
11:49:29.845 -> 09.07.2024 09:49:29.500 UTC SIV = 21 FIX = 3 HDOP = 0.77 GDOP = 1.46
12:01:17.845 -> 09.07.2024 10:01:17.500 UTC SIV = 28 FIX = 3 HDOP = 0.53 GDOP = 1.02
[Update]
Somewhere in the library is a
Code: Select all
#define kUBLOXGNSSDefaultMaxWait 1100
An active
Code: Select all
myGNSS.setNavigationFrequency(2);
Is redefining of kUBLOXGNSSDefaultMaxWait to 300 ms a solution? No, one time it works, after the next power up anymore. So there is something, I don't really understand until now ...