ZED-F9P SPI: DSEL jumper has no effect

I would like to use SPI to communicate with my GPS-RTK2 (ZED-F9P). According to the hookup guide, this can be accomplished by closing the DSEL jumper on the back of the board, and doing so should disable the UART1 and I2C ports. This isn’t working.

I’ve soldered over the gap in the DSEL jumper, connected SCK, MISO, MOSI, and a CS pin to my micro, and I get nothing. This is the same SPI bus which hosts another working SPI device, so I know the bus works.

I modify the SparkFun_u-blox_GNSS_Arduino_Library code to enable debug logging via Serial and I see this, repeating:

Sending: CLS:CFG ID:RATE Len: 0x0 Payload:
sendSpiCommand: B5 62 6 8 0 0 E 30
sendCommand: Waiting for ACK response
waitForACKResponse: TIMEOUT after 1100 msec.

I hook up a logic analyzer and quickly realize that what I believe to be SPI MISO is still UART1 TX at 38,400 baud, reading out perfect NMEA sentences.

Does anyone know why closing the DSEL jumper did not switch the board to enable SPI and disable UART1? Do I need to also change something in the configuration?

It should just be the jumper…have you tried removing/re-soldering the blob on DSEL?

I haven’t completely removed and reapplied the solder, but I did reheat the solder to ensure that it had good contact that bridges both plates. I don’t see any traces or pins that are easily accessible with a multimeter probe so that I can verify a good connection. I can’t imagine there’s not a good connection there, but I’ll remove the solder, give it a good cleaning, and reapply.

Thanks for confirming this is all that should be necessary. If the above doesn’t work then I’ll assume my board is defective and probably just fall back to I2C.

Just providing some closure here: I cleaned it up and applied new solder and still no luck. Oh well, hopefully I2C will be fast enough for my needs.

Alrighty - if i2c doesn’t end up working out for your needs, head over to Return Policy - SparkFun Electronics and reference this forum post and we’ll get you squared away :wink:

Hi Scott,

Did you end up getting to the bottom of this one.

I have been trying for a few days now to get SPI working on my ZED F9P board with zero luck. I2C works ok but there appears to be timing issues. I really want to get SPI working.

Paul

No, I never got SPI working. I settled on using a combination of I2C and UART for that application - I2C for setup and control of the GPS, and UART for position updates. This worked well for me.

My goal was to minimize latency of the function calls into the SparkFun GPS library, and I found that UART was the lowest latency (likely even faster than SPI) because UART buffering was being performed by the hardware, completely asynchronous from the code. I also made a slight change to the library to only read from the UART buffer if Serial.available(), effectively making the library call non-blocking. IIRC this wasn’t possible in the I2C and SPI code paths, since in those protocols the line transmissions actually occur during the I2C or SPI calls to read or write.

Hi Scott / Paul,

We’re sorry you’re both having problems with SPI / DSEL… We don’t use SPI a lot, but it definitely works.

If you’re up for doing a little diagnostic work, and have a multimeter available, could you please try the following?

  • With the DSEL jumper open (not soldered)

  • With the board powered up (via Qwiic or USB)

  • Connect your meter’s COM (black) probe to one of the GND breakout pins

  • Use the V (red) probe to measure the DC voltage on each of the two halves of the DSEL jumper pads

One half is connected to GND, so you will see zero Volts on that. But, with the jumper open, you should see 3.3V on the other half. The ZED module has an internal pull-up-to-3.3V on the DSEL signal.

If you see zero Volts on both halves, it means you have a dry (open) solder joint under the ZED module on the DSEL signal. If that’s the case, go ahead and return the board and we’ll get a new one to you.

Apologies for the inconvenience,

Paul

I get 0V between GND and one half of DSEL, and 3.3V between GND and the other half of DSEL. The pullup appears to be working, so I don’t think it’s an open solder joint.

I’m guessing this is either a bug in the firmware, or user error - I have no idea what I could’ve done wrong, but I won’t rule it out!

Hi Scott,

Thanks for the reply. I’m afraid I don’t know what else to suggest. You do need to “turn it off and back on again” after changing the jumper, but I’m sure you would have done that? Maybe updating the firmware would help? We have a tutorial on that:

https://learn.sparkfun.com/tutorials/ho … s-receiver

I’m about to start on a GNSS SPI Logger example for some new hardware we’ve been developing. If I see anything unusual while I’m working on that, I’ll be sure to let you know.

Best wishes,

Paul

Hi Scott & Paul,

OK… Some updates for you…

I started writing the GNSS SPI logger example and couldn’t get the GNSS to begin on SPI. I started looking back through the SPI examples I wrote a while ago and found this cryptic “note to self”:

https://github.com/sparkfun/SparkFun_u- … no#L42-L45

The SPI examples themselves are here:

https://github.com/sparkfun/SparkFun_u- … amples/SPI

I configured my SPI logging example so it would keep attempting to begin:

  // Connect to the u-blox module using SPI port, csPin and speed setting
  // ublox devices generally work up to 5MHz. We'll use 4MHz for this example:
  bool begun = false;
  do
  {
    begun = myGNSS.begin(SPI, GNSS_CS, 4000000);
    if (!begun)
    {
      Serial.println(F("u-blox GNSS not detected on SPI bus. Please check wiring."));
      delay(1000);
    }
  }
  while (!begun);

I left that running while I connected to the ZED-F9P using u-center over USB.

I opened up “Messages View” and selected UBX \ CFG \ PRT (Ports).

I set Protocol In and Protocol Out to “None” on both 0-I2C and 1-UART1. (Click “Send” to apply each change.)

Still no joy.

I set Protocol In and Protocol Out to “0+1+5 UBX+NMEA+RTCM3” on 4-SPI…

Hey presto! The GNSS began and I could communicate with it.

So it appears that the SPI port needs a kick to enable the UBX messages / protocol.

I’ll try saving the configuration into BBR and see if I can still begin the GNSS after power-cycling it. It would be nice not to have to mess about with CFG PRT each time…! :smiley:

I’ll post an update later.

I hope this gets you going!

Paul

Hi Guys,

This is a puzzle. Once I got SPI working the first time, I can’t now make it not work… I’ve tried factory resetting the module, and re-burning the flash image, but it now stubbornly works every time. It’s almost as if once you’ve got SPI to work the first time, it keeps working…

I need to give up on this for now and get back to the day job, but if I discover anything else I’ll keep you posted.

Anyway, I hope this gets you going!

Best wishes,

Paul

Hi Scott and Paul,

So I managed to get the SPI comms working as well.

Only thing is the ZED F9P doesn’t seem to behave as nicely as other SPI devices I have used. It takes quite a while for comms to start. When they do the timing seems very erratic. I dont have a scope unfortunately (kind of need one). Tried alot of different settings and cant get a stable read time.

I would like to use the TX Ready feature but it appears pin 46 has not been made available on the board?

Paul.

I’m wondering if someone who has got SPI working could set up some code that times how long an GNSS read takes?

As with the I2C comms I get results anywhere between 10 and 100 microseconds. SPI should be alot more stable than that. I’m guessing this has something to do with how the ZED will only respond to a request when it has data available. Without the TX ready pin I dont know how to check if data is there prior to a read.

Any ideas?

Paul.

Hi Paul,

Yesterday, I wrote some new GNSS SPI logging code for a new board we have in the pipeline. I left it running for a few hours and it logged over 600MB of data completely glitch-free, no missing data, no checksum errors. It was logging RAWX, SFRBX and NMEA. RAWX was set to 20Hz. The new board has a full 4-bit SDIO interface to the SD card, which makes the logging much faster than conventional 1-bit SPI. The code is here if you want to take a look, but, like I say, you can’t buy the boards yet.

https://github.com/sparkfun/SparkFun_u- … I_SDIO.ino

Re the SPI timing:

The GNSS produces data at the navigation rate and it gets loaded into the SPI buffer. When data is waiting, you read it as a stream. If the buffer is empty, you get 0xFF’s. You just keep reading until you get something other than 0xFF… Our library does it that way.

We do implement an adjustable delay to prevent the library from pounding the bus:

https://github.com/sparkfun/SparkFun_u- … .cpp#L1291

You can adjust the delay by calling setSPIpollingWait:

https://github.com/sparkfun/SparkFun_u- … #L862-L865

The default delay is 9ms. Please see the note about waitForACKResponse adding another 1ms on top:

https://github.com/sparkfun/SparkFun_u- … ry.h#L1734

From the ZED-F9P integration manual: “To prevent the receiver from being busy parsing incoming data, the parsing process is stopped after 50 subsequent bytes containing 0xFF. The parsing process is re-enabled with the first byte not equal to 0xFF.”. I guess that may be responsible for some jitter?

The TX Ready pin is available on some of our boards, but not all. We’re usually stuck for board-edge space and that’s one of the first to go. Apologies for that.

Best wishes,

Paul

(Sorry. I had to edit the previous post. I was getting my interfaces mixed up… (It’s early here…))

Hi Paul,

I really appreciate you taking the time to assemble and share this information.

I am working through the links you have posted and will get back on here to discuss what I have come up with.

Paul.

Hi Paul,

I have been doing alot of testing this weekend trying to figure the SPI comms out.

Below is the best version of what I could come up with.

Nav rates, UBX config and SPI messages have been configured using ucentre.

I have turned the 0xff time out feature off as this seemed to help quite a bit.

It would be great if you could run this code on your ZED F9P and see what you get.

It seems to work ok but, there are things that make me realise I dont understand how the SPI comms on this thing work.

For example, Changing the GPS_Interval from 100 to 105ms messes the whole thing up and read times become unstable and very long. The same thing happens if I change the navigation rate from say 10 to 11hz. wouold have thought that a slight decrease in polling rate (increasing GPS_Interval) would have the opposite effect than what it does.

Another thing is how long the SPI comms take to begin and how long they take to become stable. Often it takes over 100 read cycles before things calm down. Read time will initially stabilize to say 40 ms then they will go down to 10ms. Almost like the bus is taking a while to “sync”. I need to work out how to sync from the get go.

It appears to me that I have to implement some kind of buffer check to ensure new data is ready to read. I cant work out how to do this.

Any thoughts?

  /* ZED F9P SPI testing

 
UBX-CFG(config)-RATE(Rates)
Period = 100ms
Freq = 10 Hz
Rate = 1 cyc
Nav Freq = 10Hz

UBX-CFG(config)-PRT(Ports)
4 -SPI
0_UBX
0_UBX
Max )xFF cnt = 0 (feature off)
0-CPOL=0
CHPA =0

UBX-CFG(config)-MSG(Messages)
Message = 01-07 NAV-PVT
SPI on
*/

  
  
  #include <SPI.h> 
  #include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
  SFE_UBLOX_GNSS myGNSS;
  
  #define spiPort SPI
  #define GNSS_CS 10 

  
  
  //-----------variables GPS Stuff----------------------//
  
  double  doublelatitude = 0.0, doublelongitude = 0.0;
  
  long spEed = 0.0, laTitude = 0.0, loNgitude = 0.0, heading = 0.0, GPS_Heading =0.0;
  float KPH = 0.0, RTK = 0.0;
  unsigned long GPSlastTime =0,GPS_Interval= 100, looptime, looptimelast,Readtime,Max;
  int Rate;
  long counter =0, TX_Counter =0;

  
  void setup() {
  Serial.begin(115200);
  while (!Serial); //Wait for user to open terminal
  Serial.println(F("SparkFun u-blox Example"));

  spiPort.begin();
  delay(50);
  // Do a fake transaction to initialize the SPI pins
  spiPort.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
  spiPort.transfer(0xff);
  spiPort.endTransaction();
  
  delay(50); 
  
  myGNSS.begin(spiPort, GNSS_CS, 4000000,20);
  delay(50);


}




//-------------------------------LOOP------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
void loop() {

looptime = millis() - looptimelast;
looptimelast = millis();


  //------------GPS  Read Values-------------------
  if ((millis() - GPSlastTime) >= GPS_Interval)  {// read GPS at given interval.
  GPSlastTime = millis(); //Update the timer
  
  
  TX_Counter++;
  
  LatLong();
  Heading();
  Speed();
  GPS_Solution_Type();
  
  
  if(TX_Counter >100){//let SPI comms stabalize before recording Max read GPS read time
  Readtime = millis() - GPSlastTime;
  if(Readtime > Max)
  Max = Readtime; //keep updating the max read time
  else
  Max = Max;  
  }
  counter ++;
  
  
  Serial.print("latitude- ");
  Serial.print(laTitude);
  Serial.print("   ");
  Serial.print("longitude- ");
  Serial.print(loNgitude);
  Serial.print("   ");
  Serial.print("Rate- ");
  Serial.print("Max- ");
  Serial.print(Max);
  Serial.print("   ");
  Serial.print("ReadTime- ");
  Serial.print(Readtime);
  Serial.print("   ");
  Serial.print("cnt- ");
  Serial.print(counter);
  Serial.println("   ");
  }
  
}

//------ Latitude and Longitude-----------------------------------------------------------------
void LatLong() {
  laTitude = myGNSS.getLatitude();
  doublelatitude = laTitude / 10000000.0L; //have to declare the variable as a double and put an L after the constant. This makes compiler treat both as double precision (65 bit) floats.
  loNgitude = myGNSS.getLongitude(10);
  doublelongitude = loNgitude / 10000000.0L; //have to declare the variable as a double and put an L after the constant. This makes compiler treat both as double precision (65 bit) floats.


}


//------ GPS Navigation Rate-----------------------------------------------------------------
void Nav_Rate() {
  Rate = myGNSS.getNavigationFrequency();
   
}

//------ GPS carrier solution type-----------------------------------------------------------------
void GPS_Solution_Type() {
  RTK = myGNSS.getCarrierSolutionType();
   
}
 
//------ Get the ground speed-----------------------------------------------------------------
void Speed() {
  spEed = myGNSS.getGroundSpeed();
  KPH = spEed / 277.777; //convert mm/s to KPH
}

//------ GPS Heading-----------------------------------------------------------------
void Heading() {
  GPS_Heading = myGNSS.getHeading();
 }

Hi Paul,

OK. This could be your issue. If I understand correctly, you’ve used u-center to set the rate for the UBX NAV PVT message on SPI (with CFG MSG). BUT the library is unaware that the messages are being produced “automatically”. The way you have your code configured, the library is still polling (requesting) each message. The messages are only output at the navigation rate, so if you request one just after the previous one was produced, it will be a full nav interval before the message is returned.

Please have a look at the “auto” SPI example:

https://github.com/sparkfun/SparkFun_u- … utoPVT.ino

Specifically this line:

https://github.com/sparkfun/SparkFun_u- … VT.ino#L88

It is possible to tell the library to expect the messages to be delivered automatically, without calling setAutoPVT and without sending the CFG MSG for NAV PVT. It doesn’t get used much but myGNSS.assumeAutoPVT() should do exactly what you need. It calls initPacketUBXNAVPVT to create storage for the NAV PVT message, and sets the automaticFlags so getPVT will no longer poll the PVT message. Yes, I think that’ll work for you… Fingers crossed!

Just FYI: getLatitude etc. will then return immediately if there’s no data waiting in the SPI buffer to be processed. They return the previous (stale) data, replacing it with fresh when it arrives. If you want to wait for fresh data, call getPVT and wait for it to return true.

The other way to do this is with callbacks. The callback gets called once fresh data has arrived. Please see the following example. packetUBXNAVPVT is public, so you could set myGNSS.packetUBXNAVPVT->callbackPointer manually, without going through setAutoPVTcallbackPtr, but that’s pretty advanced stuff. Your mileage may vary! :wink:

https://github.com/sparkfun/SparkFun_u- … AV_PVT.ino

I hope this helps,

Paul

Hi Paul,

I am happy to report that I got things working.

I wouldn’t have been able to do this without your help.

Setting auto PVT to true fixed the problem. In hindsight it was I guess obvious the mistake I was making… oh well.

I left the GPS running for about 24 hours. During this time it was polled over SPI some 750k times (10hz). There wasnt a single pole that took over 1 millisecond. Compare that to before where I was getting hundreds of 100 millisecond plus per hours.

I am so bloody relieved I have solved this issue.

Thanks again for your time and patience. It really means alot.

So to put things into context, I am building a autonomous lawnmower. It works pretty well so far apart from the GPS time outs I was getting. Now that is solved its onwards and upwards… woohoo

https://scontent.fper6-1.fna.fbcdn.net/ … e=635D856A

https://www.facebook.com/10000014418604 … 4522077610

I’m no programmer but here is the code if anyone is interested -

 /* ZED F9P SPI testing

//Thanks to Paul from Sparkfun for helping me get this code working. 

UBX-CFG(config)-RATE(Rates)
Period = 100ms
Freq = 10 Hz
Rate = 1 cyc
Nav Freq = 10Hz

UBX-CFG(config)-PRT(Ports)
4 -SPI
0_UBX
0_UBX
Max )xFF cnt = 0 (feature off)
0-CPOL=0
CHPA =0

UBX-CFG(config)-MSG(Messages)
Message = 01-07 NAV-PVT
SPI on
*/

  
  
  #include <SPI.h> 
  #include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
  SFE_UBLOX_GNSS myGNSS;
  
  #define spiPort SPI
  #define GNSS_CS 10 

  #include <movingAvg.h>                  // https://github.com/JChristensen/movingAvg

  movingAvg timeaverage(200);  

  
  
  //-----------variables GPS Stuff----------------------//
  
  double  doublelatitude = 0.0, doublelongitude = 0.0;
  
  long spEed = 0.0, laTitude = 0.0, loNgitude = 0.0, heading = 0.0, GPS_Heading =0.0;
  float KPH = 0.0, RTK = 0.0;
  unsigned long GPSlastTime =0,GPS_Interval= 50, looptime, looptimelast,Readtime,Max,entrymillis;
  int Rate, avg=200;
  long counter =0, TX_Counter =0;
  
  void setup() {
  Serial.begin(115200);
  
  spiPort.begin();
  delay(50);
  // Do a fake transaction to initialize the SPI pins
  spiPort.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
  spiPort.transfer(0xff);
  spiPort.endTransaction();
  
  delay(50); 
  
  while(! myGNSS.begin(spiPort, GNSS_CS, 4000000,20)){
  delay(50);
  Serial.println("Waiting for ZED F9P to connect over SPI");}
  
  timeaverage.begin();

  myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution
}




//-------------------------------LOOP------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
void loop() {

looptime = millis() - looptimelast;
looptimelast = millis();


  //------------GPS  Read Values-------------------
  if ((millis() - GPSlastTime) >= GPS_Interval)  {// read GPS at given interval.
  GPSlastTime = millis(); //Update the timer

   if (myGNSS.getPVT())
  {
  entrymillis = millis();
  TX_Counter++;
  
  LatLong();
  Heading();
  Speed();
  GPS_Solution_Type();

 
  if(TX_Counter >100){//let SPI comms stabalize before recording Max read GPS read time
  Readtime = millis() - entrymillis;
  if(Readtime > Max)
  Max = Readtime; //keep updating the max read time
  else
  Max = Max;  
  avg = timeaverage.reading(Readtime); 
  }
  counter ++;
  
  }
  

  
  Serial.print("latitude- ");
  Serial.print(laTitude);
  Serial.print("   ");
  Serial.print("longitude- ");
  Serial.print(loNgitude);
  Serial.print("   ");
  Serial.print("Max- ");
  Serial.print(Max);
  Serial.print("   ");
  Serial.print("ReadTime- ");
  Serial.print(Readtime);
  Serial.print("   ");
   Serial.print("Avg- ");
  Serial.print(avg);
  Serial.print("   ");
  Serial.print("cnt- ");
  Serial.print(counter);
  Serial.println("   ");
  }
  
}

//------ Latitude and Longitude-----------------------------------------------------------------
void LatLong() {
  laTitude = myGNSS.getLatitude();
  doublelatitude = laTitude / 10000000.0L; //have to declare the variable as a double and put an L after the constant. This makes compiler treat both as double precision (65 bit) floats.
  loNgitude = myGNSS.getLongitude(10);
  doublelongitude = loNgitude / 10000000.0L; //have to declare the variable as a double and put an L after the constant. This makes compiler treat both as double precision (65 bit) floats.


}


//------ GPS Navigation Rate-----------------------------------------------------------------
void Nav_Rate() {
  Rate = myGNSS.getNavigationFrequency();
   
}

//------ GPS carrier solution type-----------------------------------------------------------------
void GPS_Solution_Type() {
  RTK = myGNSS.getCarrierSolutionType();
   
}
 
//------ Get the ground speed-----------------------------------------------------------------
void Speed() {
  spEed = myGNSS.getGroundSpeed();
  KPH = spEed / 277.777; //convert mm/s to KPH
}

//------ GPS Heading-----------------------------------------------------------------
void Heading() {
  GPS_Heading = myGNSS.getHeading();
 }