Sunday, July 28, 2019

Programing TP5 (time pulse) on the Ublox NEO-7M via Arduino

I needed to program the time pulse (TP-5) output on a Ublox NEO-7M GPS module, that is strait forward with the U-center software (connect serial and power betwen PC and GPS module), only problem is that software only runs on Windows and I'm more a Linux user.

The module can also be programed via the Arduino or any device with a serial port as long as you know the u-blox programing specification/protocol.
For the correct command to be sent you can either read the u-blox programing/documentation manual and calculate/generate the string plus the crc or you deploy U-center software on Windows, take the hex output for your needed output and program that on Arduino.

I started to read the specs and try to recreate the command but half way trough it just decided to boot a Windows and deploy U-center and then get the needed outputs, example here:

The two Hex lines are is in the bottom right.

Most of the details on how to accomplish this here were taken from a nice tutorial from "iforce2d" channel at:

 https://www.youtube.com/watch?v=ylxwOg2pXrc

Have a go there, it's very well explained from someone who really knows what is doing.... not my case :)

The output of some of the frequencies tested with the module directly at the "PPS" output pin (not the internal blinking LED).

 2Mhz
 2.5Mhz, all the ones that are not integer division of 48Mhz appear with some jitter.
 24Mhz is not the most square, also due to probes.
The module used is one like the above.
Vcc is 5v, txd and rxd to Arduino softserial 3,4 and PPS is the output.

In the code are 2Mhz, 2.5Mhz, 10Mhz and 24Mhz output examples, all with 1Hz timepulse if not enough satelites to provide a precise frequency are avaiable.
If other frequencies are needed I suggest installing U-center and then generate the needed Hex code and insert it on the code bellow.

The code also includes one output for I2C LCD, serial and LED to indicate status, it can be removed, if you just need to program the module. I added it as part of some experiemtes, don't expect to be perfect was mostly for troubleshooting some GPS modules I have.

Arduino code bellow:
/////////////////////
// programing of the u-blox 7m module from Arduino for timepulse TP-5
// hex was taken from u-center software configuration view
//
//
// plus, flashing LED connected to pin 10 indicates when enough sat's in view
// u-blox module to connect o 3 and 4 for using soft serial of Arduino
// CT2GQV 2019 mixing multiple libs and examples.

// copy code from the image because blogger screws completely any attempt of including the includes...





const char UBLOX_INIT[] PROGMEM = { 
 
// the actual programing string, uncoment for the one needed. 10Mhz, 2.5Mhz, 24Mhz or 2Mhz
// any frequency not integer divide of 48Mhz will have some jitter since module reference is 48. Best use is for 24 or 2 Mhz

/*
 // CFG-TP5 1Hz / 10Mhz sync
  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, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x08, 0x00, 0x00, 0x7E, 0xA8,
*/

/*
  // CFG-TP5 1Hz / 10Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x96, 0x98, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xA8, 0x08,
*/

/*
  // CFG-TP5 1Hz / 24 Mhz no sync 0ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6E, 0x01,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6D, 0x8D,
*/

/*
  // CFG-TP5 1Hz / 2.5Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x25, 0x26, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xE5, 0x21,
*/

  // CFG-TP5 1Hz / 2 Mhz no sync 50ms cable delay
  0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x84, 0x1E, 0x00,
  0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x1C, 0x1E,


/* 
  // UBX-CFG-TP5 parameters (not fully complete)
  0xB5, 0x62, // header
  0x06, 0x31, // time pulse get/set
  0x20,  // lenght 32
  0x00, // tpIdx time pulse selection = 0 = timepulse, 1 = timepulse2  (U1 Char)
  0x00,  // reserved0 U1
  0x01, 0x00, // reserved1 U2
  0x00, 0x32, // antCableDelay ns
  0x00, 0x00, // rf group delay I2
  0x00, 0x90, 0xD0, 0x03, // freqPeriod
  0x00, 0x40, 0x42, 0x0F, // freqPeriodLoc
  0x00, 0xF0, 0x49, 0x02, // pulselenRatio
  0x00, 0x60, 0xAE, 0x0A, // pulselenRatio
  0x00, 0x00, 0x00, 0x00, // userConfigDelay ns
  0x00, 0x77, 0x00, 0x00, // flags - page 135 u-blox 7 Receiver Description Including Protocol Specification V14.pdf
  0x00, 0x48, 0x65,
*/ 

};

int SATLED = 10;  // for showing we have satelites

TinyGPS gps;
// SoftwareSerial ss(4, 3);
SoftwareSerial ss(3, 4);
int sats = 0 ;

void setup()

  lcd.begin(16, 2);                           // LCD set for 16 by 2 display
  lcd.setBacklightPin(3,POSITIVE);            // (BL, BL_POL)
  lcd.setBacklight(HIGH);                     // LCD backlight turned ON
 
  lcd.setCursor(0, 0);                        //
  lcd.print("Booting...");    
  ss.begin(9600);

  pinMode(SATLED, OUTPUT); // to indicate we have enough satelites
  digitalWrite(SATLED, HIGH);
  delay(2000);
  digitalWrite(SATLED, LOW);

// actual u-blox 7m programing 
   for(int i = 0; i < sizeof(UBLOX_INIT); i++) {                       
    ss.write( pgm_read_byte(UBLOX_INIT+i) );
    delay(5); // simulating a 38400baud pace (or less), otherwise commands are not accepted by the device.
  }
// ends here  
  
  Serial.begin(9600);
  Serial.println("= sent init string to GPS =");
  lcd.setCursor(0, 0); lcd.print("NO DATA   ");
}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
    sats = gps.satellites();
    lcd.setCursor(0, 0); lcd.print("Satelites:");lcd.print(sats);
    if (sats >= 3){digitalWrite(SATLED, HIGH); delay(20);digitalWrite(SATLED, LOW );};
    //if (sats < 3 ){digitalWrite(SATLED, LOW );};
    Serial.print(" PREC=");
    Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
  }
 
  gps.stats(&chars, &sentences, &failed);
 if (chars == 0)
    Serial.println("** No characters received from GPS: check wiring **");
}


////////////////////
..code ended.

Have a nice week!