Compare commits

..

8 commits

Author SHA1 Message Date
Jeff Epler
c86e552d7f Allow a jumper to enable booting directly to passthrough mode
Connect the SDA/SCL pins with a jumper or low value (e.g., 1K)
resistor to enable passthrough mode.  Disconnect the jumper to return
to normal mode.  These are pins 7/8 on the 10-pin connector, so they
are convenient to short with a standard .100 jumper block.
2018-07-06 20:36:44 -05:00
Jeff Epler
16df1ad584 Support setting frequency via serial
To set the frequency, connect via serial and enter e.g.,:
    F1M
followed by enter/return to set the frequency to 1000000Hz (1MHz)

Frequency can be set as a whole number, a whole number of kHz, or a
whole number of MHz.  The commands are case insensitive.  So all
the following set the frequency to 1MHz:
    F1000000
    F1000k
    F1M

No validation is performed and nonsensical things can be requested,
so for example if you enter the nonsensical "F9MMM", you get
"GPS Initialized to output RF at 3800301568"  This specific number
results from overflow of integer arithmetic and is also way out of
spec for the board, since the actual value requested is around 3.8GHz.
2018-07-06 17:21:37 -05:00
Jeff Epler
c241ed1444 Use the same checksum computing code in ACK 2018-07-06 17:21:37 -05:00
5f5ca8af1c Support setting arbitrary frequencies 2018-07-06 17:21:37 -05:00
0284dc50b5 Consistently use F-strings for serial prints 2018-07-06 07:11:54 -05:00
Jeff Epler
70c9003b5e Implement 'switch to passthrough' mode 2018-07-06 07:11:54 -05:00
Zachtek
4806e86c09
Merge pull request #2 from jepler/travis
travis-ci: build the latest version & (if tagged) upload hex to github
2018-07-03 08:23:05 +02:00
8191e4b027 travis-ci: build the latest version & (if tagged) upload hex to github 2018-07-02 22:21:43 -05:00
2 changed files with 180 additions and 89 deletions

35
.travis.yml Normal file
View file

@ -0,0 +1,35 @@
dist: trusty
language: bash
cache:
directories:
- "${HOME}/persist"
addons:
apt:
packages:
- build-essential
- curl
- xvfb
install:
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
- sleep 3
- export DISPLAY=:1.0
- test -e "${HOME}/persist/arduino.tar.xz" || curl -o "${HOME}/persist/arduino.tar.xz" https://downloads.arduino.cc/arduino-1.8.5-linux64.tar.xz
- mkdir $HOME/arduino_ide
- tar -C $HOME/arduino_ide --strip-components=1 -xaf "${HOME}/persist/arduino.tar.xz"
- export PATH="$HOME/arduino_ide:$PATH"
- arduino --install-library "NeoGPS" || arduino --install-library "NeoGPS"
- mkdir -p artifacts
script:
- arduino --pref "build.path=$(pwd)/artifacts" --pref "arduino:avr:pro:cpu=8MHzatmega328" --pref "compiler.warning_level=all" --preserve-temp-files --verbose-build --verify "$(pwd)/RFout1MHzV1_05/RFout1MHzV1_05.ino"
deploy:
provider: releases
api_key:
secure: eUTHqMZp7e4eASS4GXx/qbmO71MNp1KbaQU9kQeFgXFxbOL60bOQJu7KHJUlLsmpipNZs098XRGpEcIIR6EhQ5A+28F1k8X/QClrScV2sn4BiXoXpHCQHPmhzySaLN1U5u/nTAQvZeUX5E6Or5N9NpvPtADoKKVn00bBuStM/ItH15/10RFUmJ8MMpczTvcFb+LHpFZksGJaQPxDVqXiVnyP+v9dnASdGWtqWPMUt6IaVhH13lE0eoY6AyOYozINPzsORb8JLOC8a3m7v5o1I9hlhpr3/oWhdqy0eDu+5QAOtBmZi7udr0gutnHlq/AkQkLFZvHZotRgMMqCBXQm3OAubDoxZ1aHX8KzKvjnFLvCjX8+gLDiDkiF3RQMJ21yIl1x+C6Dy0FAb/OvkWPQW1TqZPSdoMeNv6L/M4r9OdMHxqx38DuewhLkGfnVpGffo1PmK12uJ9z3qWYW2X/d5VyLzJgdU1tCOc9VjKT5QquZS5Qcy+gbIkbuLmWISN2TWZ4wPnbsm/OX8hfnODg4MbZhXDJoXpWXXDy3jVaiWqUji4MQmxBeIeWZ/vkygXhL0ez506qxC6meZedDcuqC87JhuSqFF/ou/IybfOpoOip+ovaWFwddkkm/RvOIyAKPnjyFD17e8IGzF0cYJ6mhYH3fOVwqe83+8rpJbrbWrWw=
file_glob: true
file: "artifacts/*.ino.hex"
on:
repo: jepler/1009-GPS_Derived_RF_Generator
tags: true
skip_cleanup: true

View file

@ -14,12 +14,25 @@ SoftwareSerial gpsPort(2, 3); // RX, TX
#define LEDIndicator1 5 //LED indicator for GPS Lock on pin A3
#define FIXOut 4 //Pin Out at IDC. Indicator for GPS Lock on pin 4
#define LDO_Enable A3 //GPS Voltage regulator Enable on pin A3
boolean GPSOK;
const char softwareversion[] = "1.05" ; //Version of this program, sent to serialport at startup
boolean GPSOK, passthrough;
int state; // serial command state machine
uint32_t freq; // Frequency in Hz commanded via serial
#define softwareversion "1.05" //Version of this program, sent to serialport at startup
NMEAGPS gps; // This parses the GPS characters
gps_fix fix; // This holds on to the latest values
constexpr auto MHz = 1000000lu;
constexpr auto KHz = 1000lu;
constexpr auto Hz = 1lu;
// This is a little bit arcane but it just lets you keep the user string
// and the actual value in synch automatically
#define SPEED 1
#define UNITS MHz
#define STRINGIFY1(x) #x
#define STRINGIFY(x) STRINGIFY1(x)
#define SPEED_STR STRINGIFY(SPEED) STRINGIFY(UNITS)
#define SPEED_ARG (UINT32_C(SPEED) * UNITS)
//-------------------------- SETUP -----------------------
@ -27,9 +40,18 @@ void setup()
{
Serial.begin(9600);
while (!Serial);
Serial.println("");
Serial.print(F("Zachtek GPS referenced RF, Software version: "));
Serial.println(softwareversion);
Serial.println(F(""));
Serial.println(F("Zachtek GPS referenced RF, Software version: " softwareversion));
if(strapped_for_passthrough()) {
pinMode(LDO_Enable, OUTPUT); // Set Voltage Regulator Enable pin as output.
digitalWrite(LDO_Enable, HIGH); //Turn on 3.1V Power supply for the Ublox GPS module
gpsPort.begin(9600);
passthrough = 1;
Serial.println(F("Strapped for passthrough. Disconnect jumper between SDA/SCL for normal operation"));
return;
}
pinMode(LDO_Enable, OUTPUT); // Set Voltage Regulator Enable pin as output.
@ -58,15 +80,15 @@ void setup()
delay(500);//Wait for GPSmodule to complete it's power on.
//Program GPS to output RF
if (setGPS_OutputFreq1MHz()) {
Serial.println ("GPS Initialized to output RF at 1MHz");
if (setGPS_OutputFreq(SPEED_ARG)) {
Serial.println ("GPS Initialized to output RF at " SPEED_STR);
Serial.println ("Initialization is complete.");
Serial.println ("");
GPSOK = true;
}
else
{
Serial.println ("Error! Could not program GPS!");
Serial.println (F("Error! Could not program GPS!"));
GPSOK = false;
}
}
@ -74,11 +96,59 @@ void setup()
//--------------------------
// Handle serial commands
void handle_serial() {
int c = Serial.read();
if(c == 'P') {
Serial.println(F("Entering passthrough mode -- reset microcontroller to return to normal mode\n"));
passthrough = true;
}
else if(c == 'F' || c == 'f') {
Serial.print(F("Frequency?"));
state = 1; freq = 0;
}
else if(state == 1) {
if(c >= '0' && c <= '9') {
Serial.write(c);
freq = freq * 10 + c - '0';
} else if (c == 'M' || c == 'm') {
Serial.write(c);
freq *= 1000000lu;
} else if (c == 'K' || c == 'k') {
Serial.write(c);
freq *= 1000lu;
} else if (c == '\n' || c == '\r') {
Serial.println(F(""));
if (setGPS_OutputFreq(freq)) {
Serial.print ("GPS Initialized to output RF at " );
Serial.println (freq);
Serial.println ("Initialization is complete.");
Serial.println ("");
GPSOK = true;
}
else
{
Serial.println (F("Error! Could not program GPS!"));
GPSOK = false;
}
state = 0;
}
}
}
//-------------------------- Main loop -----------------------
void loop()
{
if(passthrough) {
if(gpsPort.available()) Serial.write(gpsPort.read());
if(Serial.available()) gpsPort.write(Serial.read());
return;
}
if(Serial.available()) {
handle_serial();
}
if(state != 0) return;
while (gps.available( gpsPort )) {
fix = gps.read();
if (fix.valid.location && fix.valid.date && fix.valid.time)
@ -108,81 +178,68 @@ void loop()
//--------------------------
bool setGPS_OutputFreq100kHz()
{
int gps_set_sucess = 0;
uint8_t setOutputFreq[] = {
0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0xA0, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x20, 0x1B
};
// For details of the UBX protocol, see
// https://www.u-blox.com/sites/default/files/products/documents/u-blox7-V14_ReceiverDescriptionProtocolSpec_%28GPS.G7-SW-12001%29_Public.pdf
// Documentation of this packet is under the heading CFG-TP5 (35.19.2) in the current documentation.
uint8_t setOutputFreq[] = {
0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0xA0, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x20, 0x1B
};
#define OFFSET_FREQUENCY_LOCKED (18)
#define OFFSET_CKSUM (38)
// Note: Normally payload_start is 2 bytes past the start of buf, because the first two bytes
// are the message type and are not checksummed.
void ubx_compute_checksum(uint8_t *payload_start, uint8_t *payload_end, uint8_t *cksum) {
uint8_t ck_a=0, ck_b=0;
for(const uint8_t *p = payload_start; p != payload_end; p++)
{
ck_a += *p;
ck_b += ck_a;
}
cksum[0] = ck_a;
cksum[1] = ck_b;
}
bool setGPS_OutputFreq(uint32_t freq) {
for(int i=0; i<4; i++) {
setOutputFreq[OFFSET_FREQUENCY_LOCKED+i] = freq & 0xff;
freq >>= 8;
}
ubx_compute_checksum(setOutputFreq+2, setOutputFreq+38, setOutputFreq+38);
sendUBX(setOutputFreq, sizeof(setOutputFreq) / sizeof(uint8_t));
gps_set_sucess = getUBX_ACK(setOutputFreq);
//Serial.println("Set output Freq Done");
bool gps_set_sucess = getUBX_ACK(setOutputFreq);
// Serial.println(F("Set output Freq Done"));
return gps_set_sucess;
}
bool setGPS_OutputFreq1Kz()
{
return setGPS_OutputFreq(1*KHz);
}
bool setGPS_OutputFreq1MHz()
{
int gps_set_sucess = 0;
uint8_t setOutputFreq[] = {
0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x8A, 0x8B
};
sendUBX(setOutputFreq, sizeof(setOutputFreq) / sizeof(uint8_t));
gps_set_sucess = getUBX_ACK(setOutputFreq);
//Serial.println("Set output Freq Done");
return gps_set_sucess;
return setGPS_OutputFreq(1*MHz);
}
bool setGPS_OutputFreq2MHz()
{
int gps_set_sucess = 0;
uint8_t setOutputFreq[] = {
0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x80, 0x84, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x1B, 0x7F
};
sendUBX(setOutputFreq, sizeof(setOutputFreq) / sizeof(uint8_t));
gps_set_sucess = getUBX_ACK(setOutputFreq);
//Serial.println("Set output Freq Done");
return gps_set_sucess;
return setGPS_OutputFreq(2*MHz);
}
bool setGPS_OutputFreq4MHz()
{
int gps_set_sucess = 0;
uint8_t setOutputFreq[] = {
0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x09, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x3F, 0x8C
};
sendUBX(setOutputFreq, sizeof(setOutputFreq) / sizeof(uint8_t));
gps_set_sucess = getUBX_ACK(setOutputFreq);
//Serial.println("Set output Freq Done");
return gps_set_sucess;
return setGPS_OutputFreq(4*MHz);
}
//8MHz is the highest low-jitter frequency possible
bool setGPS_OutputFreq8MHz()
{
int gps_set_sucess = 0;
uint8_t setOutputFreq[] = {
0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x12, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xD4, 0x28
};
sendUBX(setOutputFreq, sizeof(setOutputFreq) / sizeof(uint8_t));
gps_set_sucess = getUBX_ACK(setOutputFreq);
//Serial.println("Set output Freq Done");
return gps_set_sucess;
return setGPS_OutputFreq(8*MHz);
}
//10 MHz is very jittery. Numbers that can be done with an integer division from 48MHz will produce
@ -190,34 +247,14 @@ bool setGPS_OutputFreq8MHz()
//If 10MHz low jitter is needed then one option is to output 2MHz and then filter out the 5th overtone arriving at 10MHz in that way.
bool setGPS_OutputFreq10MHz()
{
int gps_set_sucess = 0;
uint8_t setOutputFreq[] = {
0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x80, 0x96, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xF6, 0x10
};
sendUBX(setOutputFreq, sizeof(setOutputFreq) / sizeof(uint8_t));
gps_set_sucess = getUBX_ACK(setOutputFreq);
//Serial.println("Set output Freq Done");
return gps_set_sucess;
return setGPS_OutputFreq(10*MHz);
}
//16MHz is above the specs for lUblox Neo-6, only included for experiments.
//This will not produce as clean Square wave.
bool setGPS_OutputFreq16MHz()
{
int gps_set_sucess = 0;
uint8_t setOutputFreq[] = {
0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x24, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x60, 0x12
};
sendUBX(setOutputFreq, sizeof(setOutputFreq) / sizeof(uint8_t));
gps_set_sucess = getUBX_ACK(setOutputFreq);
//Serial.println("Set output Freq Done");
return gps_set_sucess;
return setGPS_OutputFreq(16*MHz);
}
@ -249,10 +286,7 @@ boolean getUBX_ACK(uint8_t *MSG) {
ackPacket[9] = 0; // CK_B
// Calculate the checksums
for (uint8_t ubxi = 2; ubxi < 8; ubxi++) {
ackPacket[8] = ackPacket[8] + ackPacket[ubxi];
ackPacket[9] = ackPacket[9] + ackPacket[8];
}
ubx_compute_checksum(ackPacket+2, ackPacket+8, ackPacket+8);
while (1) { // Test for success
if (ackByteID > 9) {
@ -277,4 +311,26 @@ boolean getUBX_ACK(uint8_t *MSG) {
}//else
}//If
}//While
}//getUBX_ACK
}//getUBX_ACK
// If pins 7/8 on the 10-pin header are bridged, this is "strapped for passthrough"
// Detect this by driving one pin high and checking the other pin, then driving low and repeating
// set pins back to inputs before returning
bool strapped_for_passthrough() {
bool result = true;
pinMode(A4, OUTPUT);
digitalWrite(A4, HIGH);
delay(1);
if(!digitalRead(A5)) result = false;
digitalWrite(A4, LOW);
pinMode(A5, INPUT_PULLUP);
delay(1);
if(digitalRead(A5)) result = false;
pinMode(A4, INPUT);
pinMode(A5, INPUT);
return result;
}