1
1
/* *********************************************************************************************************
2
- STM32 GPSDO v0.05e by André Balsa, February 2022
2
+ STM32 GPSDO v0.05f by André Balsa, February 2022
3
3
GPLV3 license
4
4
Reuses small bits of the excellent GPS checker code Arduino sketch by Stuart Robinson - 05/04/20
5
5
From version 0.03 includes a command parser, so the GPSDO can receive commands from the USB serial or
126
126
// 2. Refactor the setup and main loop functions to make them as simple as possible.
127
127
128
128
#define Program_Name " GPSDO"
129
- #define Program_Version " v0.05e "
129
+ #define Program_Version " v0.05f "
130
130
#define Author_Name " André Balsa"
131
131
132
132
// Debug options
@@ -391,17 +391,20 @@ volatile bool force_armpicDIV_flag = true; // indicates picDIV must be armed
391
391
volatile bool force_calibration_flag = true ; // indicates GPSDO should start calibration sequence
392
392
393
393
volatile bool ocxo_needs_warming = true ; // indicates OCXO needs to warm up a few minutes after power on
394
+
394
395
#ifdef FastBootMode
395
396
const uint16_t ocxo_warmup_time = 15 ; // ocxo warmup time in seconds; 15s for testing
397
+ const uint16_t ocxo_calib_time = 15 ; // 15s fast calibration countdown time (for each calibration step)
396
398
#else
397
399
const uint16_t ocxo_warmup_time = 300 ; // ocxo warmup time in seconds; 300s or 600s normal use
400
+ const uint16_t ocxo_calib_time = 60 ; // 60s normal calibration countdown time (for each calibration step)
398
401
#endif // FastBootMode
399
402
400
403
volatile bool tunnel_mode_flag = false ; // the GPSDO relays the information directly to and from the GPS module to the USB serial
401
404
#ifdef TunnelModeTesting
402
405
const uint16_t tunnelSecs = 15 ; // tunnel mode timeout in seconds; 15s for testing, 300s or 600s normal use
403
406
#else
404
- const uint16_t tunnelSecs = 300 ; // tunnel mode timeout in seconds; 15s for testing, 300s or 600s normal use
407
+ const uint16_t tunnelSecs = 300 ; // tunnel mode timeout in seconds; 15s for testing, 300s or 600s normal use
405
408
#endif // TunnelModeTesting
406
409
407
410
// Miscellaneous functions
@@ -880,10 +883,13 @@ boolean getUBX_ACK(uint8_t *MSG) {
880
883
}
881
884
#endif // UBX_CONFIG
882
885
886
+ // ---------------------------------------------------------------------------------------------
887
+ // GPSDO tunnel mode (GPS serial is relayed to Bluetooth serial or USB serial)
888
+ // ---------------------------------------------------------------------------------------------
883
889
void tunnelgps ()
884
890
// GPSDO tunnel mode operation
885
891
{
886
- #ifdef GPSDO_BLUETOOTH // print calibrating started message to either
892
+ #ifdef GPSDO_BLUETOOTH // print entering tunnel mode message to either
887
893
Serial2.println (); // Bluetooth serial xor USB serial
888
894
Serial2.print (F (" Entering tunnel mode..." ));
889
895
Serial2.println ();
@@ -893,7 +899,7 @@ void tunnelgps()
893
899
Serial.println ();
894
900
#endif // BLUETOOTH
895
901
896
- // tunnel mode operation goes here
902
+ // tunnel mode operation starts here
897
903
uint32_t endtunnelmS = millis () + (tunnelSecs * 1000 );
898
904
uint8_t GPSchar;
899
905
uint8_t PCchar;
@@ -902,17 +908,29 @@ void tunnelgps()
902
908
if (Serial1.available () > 0 )
903
909
{
904
910
GPSchar = Serial1.read ();
905
- Serial.write (GPSchar); // echo NMEA stream to USB serial
911
+ #ifdef GPSDO_BLUETOOTH
912
+ Serial2.write (GPSchar); // echo GPS NMEA serial stream to Bluetooth serial
913
+ #else
914
+ Serial.write (GPSchar); // echo GPS NMEA serial stream to USB serial
915
+ #endif // BLUETOOTH
906
916
}
917
+ #ifdef GPSDO_BLUETOOTH
918
+ if (Serial2.available () > 0 )
919
+ #else
907
920
if (Serial.available () > 0 )
921
+ #endif // BLUETOOTH
908
922
{
923
+ #ifdef GPSDO_BLUETOOTH
924
+ PCchar = Serial2.read ();
925
+ #else
909
926
PCchar = Serial.read ();
910
- Serial1.write (PCchar); // echo PC stream to GPS serial
927
+ #endif // BLUETOOTH
928
+ Serial1.write (PCchar); // echo USB serial stream to GPS serial
911
929
}
912
930
}
913
931
// tunnel mode operation ends here
914
932
915
- #ifdef GPSDO_BLUETOOTH // print calibrating started message to either
933
+ #ifdef GPSDO_BLUETOOTH // print exiting tunnel mode message to either
916
934
Serial2.println (); // Bluetooth serial xor USB serial
917
935
Serial2.print (F (" Tunnel mode exited." ));
918
936
Serial2.println ();
@@ -923,20 +941,21 @@ void tunnelgps()
923
941
#endif // BLUETOOTH
924
942
925
943
tunnel_mode_flag = false ; // reset flag, exit tunnel mode
926
- }
927
- void docalibration ()
928
- // OCXO Vctl calibration routine: find an approximate value for Vctl
944
+ } // end of tunnel mode routine
945
+
946
+ // ---------------------------------------------------------------------------------------------
947
+ // OCXO warmup delay routine (only needed during a GPSDO "cold start")
948
+ // ---------------------------------------------------------------------------------------------
949
+ void doocxowarmup ()
929
950
{
930
951
unsigned long startWarmup = millis (); // we need a rough timer
931
- if (ocxo_needs_warming) {
932
- // spend a few seconds/minutes here waiting for the OCXO to warm
933
- // show countdown timer on OLED display
934
- // and report on either USB serial or Bluetooth serial
935
- // Note: during calibration the GPSDO does not accept any commands
936
- uint16_t countdown = ocxo_warmup_time;
937
- while (countdown) {
938
- yellow_led_state = 2 ; // blink yellow LED
939
-
952
+ // spend a few seconds/minutes here waiting for the OCXO to warm
953
+ // show countdown timer on OLED display
954
+ // and report on either USB serial or Bluetooth serial
955
+ // Note: during warmup the GPSDO does not accept any commands
956
+ uint16_t countdown = ocxo_warmup_time;
957
+ while (countdown) {
958
+
940
959
#ifdef GPSDO_OLED
941
960
disp.clear (); // display warmup message on OLED
942
961
disp.setCursor (0 , 0 );
@@ -982,11 +1001,22 @@ void docalibration()
982
1001
// do nothing for 1s
983
1002
delay (1000 );
984
1003
countdown--;
985
- }
986
- ocxo_needs_warming = false ; // reset flag, next "hot" calibration skips ocxo warmup
987
1004
}
988
- // proceed with calibration
989
- #ifdef GPSDO_BLUETOOTH // print calibrating started message to either
1005
+ ocxo_needs_warming = false ; // reset flag, next "hot" calibration skips ocxo warmup
1006
+ } // end of OCXO warmup routine
1007
+
1008
+ // ---------------------------------------------------------------------------------------------
1009
+ // GPSDO calibration routine
1010
+ // ---------------------------------------------------------------------------------------------
1011
+ void docalibration ()
1012
+ // OCXO Vctl calibration: find an approximate value for Vctl
1013
+ {
1014
+ yellow_led_state = 2 ; // blink yellow LED (handled by 2Hz ISR)
1015
+
1016
+ if (ocxo_needs_warming) doocxowarmup ();
1017
+
1018
+ // Note: during calibration the GPSDO does not accept any commands
1019
+ #ifdef GPSDO_BLUETOOTH // print calibration started message to either
990
1020
Serial2.println (); // Bluetooth serial xor USB serial
991
1021
Serial2.print (F (" Calibrating..." ));
992
1022
Serial2.println ();
@@ -1039,27 +1069,56 @@ void docalibration()
1039
1069
// 1.5V for PWM = 65536 x (1.5 / 3.2) = 30720 results in frequency f1 = 10MHz + e1
1040
1070
// 2.5V for PWM = 65536 x (2.5 / 3.2) = 51200 results in frequency f2 = 10MHz + e2
1041
1071
// where f2 > f1 (most OCXOs have positive slope).
1072
+
1042
1073
double f1, f2, e1 , e2 ;
1074
+
1043
1075
// make sure we have a fix and data
1044
- while (!cbTen_full) delay (1000 );
1076
+ while (!cbTen_full) delay (1000 ); // note there is a small chance that we lose PPS during calibration
1077
+ // resulting in completely wrong calibration value
1078
+
1045
1079
// measure frequency for Vctl=1.5V
1046
- Serial.println (F (" set PWM 1.5V, wait 15s" ));
1080
+ Serial.println (F (" Measure frequency for Vctl=1.5V" ));
1081
+ Serial.print (F (" Set PWM Vctl to 1.5V, wait " )); Serial.print (ocxo_calib_time); Serial.println (F (" s" ));
1047
1082
analogWrite (VctlPWMOutputPin, 30720 );
1048
- delay (15000 );
1049
- Serial.print (F (" f1 (average frequency for 1.5V Vctl): " ));
1083
+
1084
+ uint16_t calib_countdown = ocxo_calib_time; // note there are two possible values depending on FastBootMode setting
1085
+ while (calib_countdown > 0 )
1086
+ {
1087
+ calib_countdown--;
1088
+ Serial.print (calib_countdown); Serial.print (F (" s " ));
1089
+ delay (1000 );
1090
+ }
1091
+
1092
+ Serial.println ();
1093
+ Serial.print (F (" f1 (average frequency for Vctl=1.5V): " ));
1050
1094
f1 = avgften;
1051
1095
Serial.print (f1,1 );
1052
1096
Serial.println (F (" Hz" ));
1097
+ Serial.println ();
1098
+
1053
1099
// make sure we have a fix and data again
1054
1100
while (!cbTen_full) delay (1000 );
1101
+
1055
1102
// measure frequency for Vctl=2.5V
1056
- Serial.println (F (" set PWM 2.5V, wait 15s" ));
1103
+ Serial.println (F (" Measure frequency for Vctl=2.5V" ));
1104
+ Serial.println (F (" Set PWM Vctl to 2.5V, wait " )); Serial.print (ocxo_calib_time); Serial.println (F (" s" ));
1057
1105
analogWrite (VctlPWMOutputPin, 51200 );
1058
- delay (15000 );
1106
+
1107
+ calib_countdown = ocxo_calib_time; // no need to declare variable again
1108
+ while (calib_countdown > 0 )
1109
+ {
1110
+ calib_countdown--;
1111
+ Serial.print (calib_countdown); Serial.print (F (" s " ));
1112
+ delay (1000 );
1113
+ }
1114
+
1115
+ Serial.println ();
1059
1116
Serial.print (F (" f2 (average frequency for 2.5V Vctl): " ));
1060
1117
f2 = avgften;
1061
1118
Serial.print (f2,1 );
1062
1119
Serial.println (F (" Hz" ));
1120
+ Serial.println ();
1121
+
1063
1122
// slope s is (f2-f1) / (51200-30720) for PWM
1064
1123
// So F=10MHz +/- 0.1Hz for PWM = 30720 - (e1 / s)
1065
1124
// set Vctl
@@ -1088,9 +1147,14 @@ void docalibration()
1088
1147
disp.fillScreen (ST7735_BLACK);
1089
1148
#endif // LCD_ST7735
1090
1149
1150
+ yellow_led_state = 0 ; // turn off yellow LED (handled by 2Hz ISR)
1091
1151
force_calibration_flag = false ; // reset flag, calibration done
1092
- } // end of docalibration()
1152
+ } // end of GPSDO calibration routine
1093
1153
1154
+
1155
+ // ---------------------------------------------------------------------------------------------
1156
+ // Adjust Vctl DAC routine
1157
+ // ---------------------------------------------------------------------------------------------
1094
1158
#ifdef GPSDO_MCP4725
1095
1159
void adjustVctlDAC ()
1096
1160
// This should reach a stable DAC output value / a stable 10000000.00 frequency
@@ -1123,6 +1187,9 @@ void adjustVctlDAC()
1123
1187
}
1124
1188
#endif // MCP4725
1125
1189
1190
+ // ---------------------------------------------------------------------------------------------
1191
+ // Adjust Vctl PWM routine
1192
+ // ---------------------------------------------------------------------------------------------
1126
1193
#ifdef GPSDO_PWM_DAC
1127
1194
void adjustVctlPWM ()
1128
1195
// This should reach a stable PWM output value / a stable 10000000.00 frequency
@@ -1748,6 +1815,9 @@ void uptimetostrings() {
1748
1815
}
1749
1816
}
1750
1817
1818
+ // ---------------------------------------------------------------------------------------------
1819
+ // setup routine, prepares the hardware for normal operation
1820
+ // ---------------------------------------------------------------------------------------------
1751
1821
void setup ()
1752
1822
{
1753
1823
// Wait 1 second for things to stabilize
@@ -1961,9 +2031,11 @@ void setup()
1961
2031
avgVcc = avg_adcVcc.reading (adcVcc);
1962
2032
# endif // VCC
1963
2033
2034
+ #ifdef GPSDO_MCP4725
1964
2035
avg_dacVctl.begin ();
1965
2036
dacVctl = analogRead (VctlInputPin);
1966
2037
avgdacVctl = avg_dacVctl.reading (dacVctl);
2038
+ # endif // MCP4725
1967
2039
1968
2040
avg_pwmVctl.begin ();
1969
2041
pwmVctl = analogRead (VctlPWMInputPin);
@@ -1974,6 +2046,9 @@ void setup()
1974
2046
// setup done
1975
2047
}
1976
2048
2049
+ // ---------------------------------------------------------------------------------------------
2050
+ // loop routine: this is the main loop
2051
+ // ---------------------------------------------------------------------------------------------
1977
2052
void loop ()
1978
2053
{
1979
2054
serial_commands_.ReadSerial (); // process any command from either USB serial (usually
0 commit comments