A GPS Time and Frequency Reference Receiver with the NEO-7N
Quantumoptics - ahead of time. Looks like the frontpanel designer over-compensated
the ususal too optimistic schedules of our engineering team :-)
✈ The building Blocks • Functional Description
The mastermind of this design is of course the Arduino Nano Every. It displays the status on the 128 x 64 px oled display.
The Nano also decodes the dataflow f the U-Blox NEO-7N, which is the workhorse of this Reference Source.
The USB port of the u-blox module has - as protection - only twice those 100 Ω resistors,
as this port is used only once, during production. It is then covered with one of those
fancy 'hacked' stickers, beeing part of every genuine arduino.
We use the 1 PPS pin of the U-BLOX module to synchronize a VCXO, running at 10 MHz. This
is done by a ADF4002 (PLL). And yes, the NEO-7 has been re-programmed to output 10 kHz. (Details see below).
The 10 MHz is divided down to simultaneously generate the 1 pps pulse as well as a 1 MHz TTL pulse.
The device is powered by a 9 V, 800 mA Plug-in power supply. (Needs about 190 mA)
Dara [in Thai ดารา] means "Star" - unfortunately the celebrity one. We aimed for
the other one, namely this planet thing. Errors happen ...
✈ The workhorse : U-Blox's NEO-7N
Inside the module, courtesy of U-Blox,
"The NEO-7 series of standalone GNSS modules benefit from the exceptional performance of the u-blox 7
GNSS (GPS, GLONASS, QZSS and SBAS) engine. The NEO-7 series delivers high sensitivity and minimal
acquisition times in the industry-proven NEO form factor.
The NEO-7 series provides maximum sensitivity while maintaining low system power. The NEO-7M is optimized
for cost sensitive applications, while NEO-7N provides best performance and easy RF integration. The NEO
form factor allows easy migration from previous NEO generations. Sophisticated RF-architecture and
interference suppression ensure maximum performance even in GNSS-hostile environments.
The NEO-7 series combines a high level of integration capability with flexible connectivity options in a
miniature package. This makes it perfectly suited for industrial applications with strict size and cost
requirements. The I2C compatible DDC interface provides connectivity and enables synergies with u-blox
SARA, LEON and LISA cellular modules.".
Says the datasheet.
Possible (other) Candidates :
Module
Memory
Oscillator
Remarks
NEO-6T
ROM
TCXO
Needs Eeprom / Battery
NEO-7M
ROM
XCO
Needs Eeprom / Battery
NEO-7N
FLASH
TCXO
our selection
NEO-M8M
ROM
XCO
Needs Eeprom / Battery
NEO-M8N
FLASH
TCXO
NEO-M8Q
ROM
XCO
Needs Eeprom / Battery
Inside the predecessor module (6M), found at Ban Mo (บ้านหม้อ), Bangkok, Thailand.
Inside the case of the FuMu (Version 2). Some 'optimisations' were necessary.
Battery and Eeprom is not assembled here, as our NEO-7N module has a built-in Flash memory.
✈ Jitter cleaning PLL
Even so, the module is capable of outputting a 10 MHz squarewave signal,
there is a vcxo running at 10 MHz, controlled by an ADF4002. This is, because
the NEO-module is only precise on the long run. Compared to another trustworthy
reference, one can see, that the frequency jumps up and down. In order to
smoothen those jumps out, a jitter cleaning pll was introduced. For a low jitter,
a narrowband loopfilter is the order of the day. And that calls for a low phase
comparator frequency. With the ADF4002, we can program both, the integer-n value as well
as the output frequency of the gps module.
✈ Downloads
✈ Arduino Sketch - The Code
Double click on code to select ...
/* //////////////////////////////////////////////////////////////////
ARDUINO/Genuino Project "DARAMOD",
A GPS Time and Frequency Reference Receiver with the NEO-7N
https://www.changpuak.ch/electronics/Arduino-Daramod.php
Software Version 4.0 - 26.11.2021 by ALEXANDER SSE FRANK,
CREDITS :
https://simple-circuit.com/arduino-gps-clock-local-time-neo-6m/
////////////////////////////////////////////////////////////////// */
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
// DISPLAY
#define OLED_MOSI 7
#define OLED_CLK 8
#define OLED_DC 5
#define OLED_CS 4
#define OLED_RESET 6
Adafruit_SH1106 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
#if (SH1106_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SH1106.h!");
#endif
// VCXO
const int PLL_LOCK = A1 ;
const int PLL_LE = 10 ;
const int PLL_DATA = 11 ;
const int PLL_CLOCK = 12 ;
// GPS
const int NEO_RX = A3 ;
const int NEO_TX = A2 ;
#include <SoftwareSerial.h>
#include <TinyGPS++.h> // include TinyGPS++ library
#include <TimeLib.h> // include Arduino time library
TinyGPSPlus gps ;
SoftwareSerial ss(NEO_RX, NEO_TX) ;
// define a clock offset of 3600 seconds (1 hour) ==> UTC + 1
#define time_offset 3600
byte last_second, Second, Minute, Hour, Day, Month ;
int Year ;
static const int MAX_SATELLITES = 40 ;
// /////////////////////////////////////////////////////////////
// SUBROUTINES PLL ADF4002
// /////////////////////////////////////////////////////////////
void WriteADF4002(long payload)
{
digitalWrite(PLL_LE , LOW) ;
byte MSB = (payload & 0x00FF0000) >> 16 ;
byte ISB = (payload & 0x0000FF00) >> 8 ;
byte LSB = (payload & 0x000000FF) ;
shiftOut(PLL_DATA, PLL_CLOCK, MSBFIRST, MSB) ;
shiftOut(PLL_DATA, PLL_CLOCK, MSBFIRST, ISB) ;
shiftOut(PLL_DATA, PLL_CLOCK, MSBFIRST, LSB) ;
digitalWrite(PLL_LE , HIGH) ;
}
// /////////////////////////////////////////////////////////////
// SUBROUTINES DISPLAY.
// /////////////////////////////////////////////////////////////
unsigned long NumberSat = 0 ;
void UpdateDisplay()
{
display.clearDisplay() ;
display.setTextSize(3) ;
display.setTextColor(WHITE) ;
// --------------------------------------------
// TIME - UTC + TIMEZONE OFFSET
// --------------------------------------------
char TimeBuffer[3] = "" ;
display.setCursor(0,0) ;
sprintf(TimeBuffer, "%02d",hour()); display.print(TimeBuffer) ;
display.setCursor(32,0) ; display.print(":") ;
display.setCursor(46,0) ;
sprintf(TimeBuffer, "%02d",minute()) ; display.print(TimeBuffer) ;
display.setCursor(78,0) ; display.print(":") ;
display.setCursor(92,0) ;
sprintf(TimeBuffer, "%02d",second()) ; display.print(TimeBuffer) ;
// --------------------------------------------
// DAY OF THE WEEK
// --------------------------------------------
display.setTextSize(1) ;
display.setCursor(0,34);
switch(weekday())
{
case 1 : display.print("SUNDAY") ; break ;
case 2 : display.print("MONDAY") ; break ;
case 3 : display.print("TUESDAY") ; break ;
case 4 : display.print("WEDNESDAY") ; break ;
case 5 : display.print("THURSDAY") ; break ;
case 6 : display.print("FRIDAY") ; break ;
default : display.print("SATURDAY") ;
}
// --------------------------------------------
// DAY - MONTH - YEAR
// --------------------------------------------
display.setCursor(64,34);
sprintf(TimeBuffer, "%02d.%02d.%02d",day(),month(),year());
display.print(TimeBuffer) ;
// --------------------------------------------
// LOCKSTATUS
// --------------------------------------------
display.setCursor(0,48);
if(digitalRead(PLL_LOCK)) display.print("LOCKED");
else display.print("UNLOCKED");
if(NumberSat > 8) NumberSat = 8 ;
for(int i=0 ; i<NumberSat; i++)
{
display.fillRect(64+i*7,48,4,7, WHITE) ;
}
display.display();
}
// /////////////////////////////////////////////////////////////
// S E T U P
// /////////////////////////////////////////////////////////////
void setup()
{
Serial.begin(115200) ;
// INIT OLED
display.begin(SH1106_SWITCHCAPVCC);
// SHOW STARTUP SCREEN
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0); display.print("****");
display.setCursor(44,0); display.print("DARAMOD");
display.setCursor(104,0); display.print("****");
display.drawLine(0, 12, 128, 12, WHITE);
display.setTextSize(1);
display.setCursor(0, 21);
display.println("A GPS TIME FREQUENCY");
display.setCursor(0, 33);
display.println("REFERENCE RECEIVER.");
display.setCursor(0, 45);
display.println("(C) ETH QUANTUMOPTICS");
display.setCursor(0, 57);
display.println("BUILT 26.11.2021");
display.display();
delay(3999);
Serial.println("Setup ....... #1 completed") ;
// INIT SOFTWARE SERIAL
ss.begin(9600);
// INIT ADF4002
pinMode(PLL_LOCK, INPUT_PULLUP) ;
pinMode(PLL_LE, OUTPUT) ;
pinMode(PLL_DATA, OUTPUT) ;
pinMode(PLL_CLOCK, OUTPUT) ;
digitalWrite(PLL_LE , HIGH) ;
// Writing Initialization Latch
WriteADF4002(0x0D8093) ;
// Writing Function Latch
WriteADF4002(0x0D8092) ;
// Writing R Counter Latch
WriteADF4002(0x100004) ;
// Writing N Counter Latch
WriteADF4002(0x019001) ;
}
// /////////////////////////////////////////////////////////////
// M A I N L O O P
// /////////////////////////////////////////////////////////////
void loop()
{
while (ss.available() > 0)
{
if (gps.encode(ss.read()))
{
// get time from GPS module
if (gps.time.isValid())
{
Minute = gps.time.minute();
Second = gps.time.second();
Hour = gps.time.hour();
}
// get date from GPS module
if (gps.date.isValid())
{
Day = gps.date.day();
Month = gps.date.month();
Year = gps.date.year();
}
// update number of satellites
if (gps.satellites.isValid())
{
NumberSat = gps.satellites.value() ;
}
else
{
if(NumberSat > 0) NumberSat -= 1 ;
}
if(last_second != gps.time.second()) // if time has changed
{
last_second = gps.time.second();
// set current UTC time
setTime(Hour, Minute, Second, Day, Month, Year);
// add the offset to get local time
adjustTime(time_offset);
// show off the results
UpdateDisplay() ;
}
}
}
}
// /////////////////////////////////////////////////////////////
// END OF FILE.
// /////////////////////////////////////////////////////////////
✈ The Display
The display on such 'amateur' devices is very often straightforward. This is due to the fact,
that the used microprofessor does not have much time to draw fancy screens. The more
time spent on display-ing, the less time is available for decoding, as the NEO-7 transmits
data at 9600 Baud.
The Configuration is done with the u-center (V21.05) from
here.
Unzip and install it. Connect to the USB-B connector. (The micro-USB connector is for the Arduino Nano Every).
Select View / Configuration View.
Scroll down to TP5 (Timepulse 5)
Select Radiobutton Frequency and Duty-Cycle. Enter 25'000 ( = 25 kHz ) and 50% for the Dutycycle.
Both has to be entered twice. Once for the free-running case, once for the locked case.
Click on the button Send (bottom left).
From the top menue now select Receiver / Action / Save Config.
As we use a NEO-7 with Flash memory here, nothing more has to be done. Other types mayst need to
populate the batteries and / or the Eeprom.
✈ Share your thoughts
The webmaster does not read these comments regularely. Urgent questions should be send via email.
Ads or links to completely uncorrelated things will be removed.
Your Browser says that you allow tracking. Mayst we suggest that you check that DNT thing ?