Skip to content

Add spi aberridg #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 27, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ disableUBX7Fcheck KEYWORD2
checkUblox KEYWORD2
checkUbloxI2C KEYWORD2
checkUbloxSerial KEYWORD2
checkUbloxSPI KEYWORD2

process KEYWORD2
processNMEA KEYWORD2
Expand Down
129 changes: 129 additions & 0 deletions src/SparkFun_u-blox_GNSS_Arduino_Library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,38 @@ boolean SFE_UBLOX_GNSS::begin(Stream &serialPort)
return (connected);
}

// Initialize for SPI
boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed)
{
commType = COMM_TYPE_SPI;
_spiPort = &spiPort;
_csPin = csPin;
_spiSpeed = spiSpeed;
// Initialize the chip select pin
pinMode(_csPin, OUTPUT);
digitalWrite(_csPin, HIGH);
//New in v2.0: allocate memory for the packetCfg payload here - if required. (The user may have called setPacketCfgPayloadSize already)
if (packetCfgPayloadSize == 0)
setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE);
Serial.println("Creating buffer");
createFileBuffer();
boolean connected = isConnected();
if (!connected)
connected = isConnected();

if (!connected)
connected = isConnected();

// Initialize/clear the SPI buffer - fill it with 0xFF as this is what is received from the UBLOX module if there's no data to be processed
for (uint8_t i = 0; i < 20; i++)
{
spiBuffer[i] = 0xFF;
}

return (connected);
}


// Allow the user to change I2C polling wait (the minimum interval between I2C data requests - to avoid pounding the bus)
// i2cPollingWait defaults to 100ms and is adjusted automatically when setNavigationFrequency()
// or setHNRNavigationRate() are called. But if the user is using callbacks, it might be advantageous
Expand Down Expand Up @@ -598,6 +630,8 @@ boolean SFE_UBLOX_GNSS::checkUbloxInternal(ubxPacket *incomingUBX, uint8_t reque
return (checkUbloxI2C(incomingUBX, requestedClass, requestedID));
else if (commType == COMM_TYPE_SERIAL)
return (checkUbloxSerial(incomingUBX, requestedClass, requestedID));
else if (commType == COMM_TYPE_SPI)
return (checkUbloxSpi(incomingUBX, requestedClass, requestedID));
return false;
}

Expand Down Expand Up @@ -755,6 +789,32 @@ boolean SFE_UBLOX_GNSS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t request

} //end checkUbloxSerial()


//Checks SPI for data, passing any new bytes to process()
boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID)
{
// Process the contents of the SPI buffer if not empty!
for (uint8_t i = 0; i < spiBufferIndex; i++) {
process(spiBuffer[i], incomingUBX, requestedClass, requestedID);
}
spiBufferIndex = 0;

SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0);
_spiPort->beginTransaction(settingsA);
digitalWrite(_csPin, LOW);
uint8_t byteReturned = _spiPort->transfer(0x0A);
while (byteReturned != 0xFF || currentSentence != NONE)
{
process(byteReturned, incomingUBX, requestedClass, requestedID);
byteReturned = _spiPort->transfer(0x0A);
}
digitalWrite(_csPin, HIGH);
_spiPort->endTransaction();
return (true);

} //end checkUbloxSpi()


//PRIVATE: Check if we have storage allocated for an incoming "automatic" message
boolean SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID)
{
Expand Down Expand Up @@ -2675,6 +2735,10 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendCommand(ubxPacket *outgoingUBX, uint16_t
{
sendSerialCommand(outgoingUBX);
}
else if (commType == COMM_TYPE_SPI)
{
sendSpiCommand(outgoingUBX);
}

if (maxWait > 0)
{
Expand Down Expand Up @@ -2781,6 +2845,71 @@ void SFE_UBLOX_GNSS::sendSerialCommand(ubxPacket *outgoingUBX)
_serialPort->write(outgoingUBX->checksumB);
}


// Transfer a byte to SPI. Also capture any bytes received from the UBLOX device during sending and capture them in a small buffer so that
// they can be processed later with process
void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer)
{
uint8_t returnedByte = _spiPort->transfer(byteToTransfer);
if (returnedByte != 0xFF || currentSentence != NONE)
{
spiBuffer[spiBufferIndex] = returnedByte;
spiBufferIndex++;
}
}

// Send a command via SPI
void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX)
{
if (spiBuffer == NULL) //Memory has not yet been allocated - so use new
{
spiBuffer = new uint8_t[SPI_BUFFER_SIZE];
}

if (spiBuffer == NULL) {
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
{
_debugSerial->print(F("process: memory allocation failed for SPI Buffer!"));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change process to sendSpiCommand.
(In other libraries, I've started using the full class::function name SFE_UBLOX_GNSS::sendSpiCommand just in case you have debug messages turned on in more than one library simultaneously. But no need to do that here.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Paul - done and done :-)

Please also check my other pull request - that one is much more involved and may need (yet more) tweaking! See comments therein.

And my pleasure - I really NEED this lib for my project, so happy to enhance it to meet my needs and to help others.

}
}

// Start at the beginning of the SPI buffer
spiBufferIndex = 0;

SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0);
_spiPort->beginTransaction(settingsA);
digitalWrite(_csPin, LOW);
//Write header bytes
spiTransfer(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on.
if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_1);
spiTransfer(UBX_SYNCH_2); //b
if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_2);

spiTransfer(outgoingUBX->cls);
if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->cls);
spiTransfer(outgoingUBX->id);
if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->id);
spiTransfer(outgoingUBX->len & 0xFF); //LSB
if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->len & 0xFF);
spiTransfer(outgoingUBX->len >> 8);
if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->len >> 8);

//Write payload.
for (uint16_t i = 0; i < outgoingUBX->len; i++)
{
spiTransfer(outgoingUBX->payload[i]);
if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->payload[i]);
}

//Write checksum
spiTransfer(outgoingUBX->checksumA);
if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->checksumA);
spiTransfer(outgoingUBX->checksumB);
if (_printDebug) _debugSerial->printf("%x \n", outgoingUBX->checksumB);
digitalWrite(_csPin, HIGH);
_spiPort->endTransaction();
}

//Pretty prints the current ubxPacket
void SFE_UBLOX_GNSS::printPacket(ubxPacket *packet, boolean alwaysPrintPayload)
{
Expand Down
21 changes: 20 additions & 1 deletion src/SparkFun_u-blox_GNSS_Arduino_Library.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@

#include <Wire.h>

#include <SPI.h>

#include "u-blox_config_keys.h"
#include "u-blox_structs.h"

Expand Down Expand Up @@ -492,6 +494,9 @@ enum sfe_ublox_ls_src_e
//#define MAX_PAYLOAD_SIZE 768 //Worst case: UBX_CFG_VALSET packet with 64 keyIDs each with 64 bit values
#endif

// For storing SPI bytes received during sendSpiCommand
#define SPI_BUFFER_SIZE 128

//-=-=-=-=- UBX binary specific variables
struct ubxPacket
{
Expand Down Expand Up @@ -560,6 +565,8 @@ class SFE_UBLOX_GNSS
boolean begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42); //Returns true if module is detected
//serialPort needs to be perviously initialized to correct baud rate
boolean begin(Stream &serialPort); //Returns true if module is detected
//SPI - supply instance of SPIClass, chip select pin and SPI speed (in Hz)
boolean begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed);

void end(void); //Stop all automatic message processing. Free all used RAM

Expand Down Expand Up @@ -612,6 +619,7 @@ class SFE_UBLOX_GNSS

boolean checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for I2C polling of data, passing any new bytes to process()
boolean checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for serial polling of data, passing any new bytes to process()
boolean checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for spi polling of data, passing any new bytes to process()

// Process the incoming data

Expand All @@ -622,12 +630,13 @@ class SFE_UBLOX_GNSS
void processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Given a character, file it away into the uxb packet structure
void processUBXpacket(ubxPacket *msg); //Once a packet has been received and validated, identify this packet's class/id and update internal flags

// Send I2C/Serial commands to the module
// Send I2C/Serial/SPI commands to the module

void calcChecksum(ubxPacket *msg); //Sets the checksumA and checksumB of a given messages
sfe_ublox_status_e sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait, boolean expectACKonly = false); //Given a packet and payload, send everything including CRC bytes, return true if we got a response
sfe_ublox_status_e sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait);
void sendSerialCommand(ubxPacket *outgoingUBX);
void sendSpiCommand(ubxPacket *outgoingUBX);

void printPacket(ubxPacket *packet, boolean alwaysPrintPayload = false); //Useful for debugging

Expand Down Expand Up @@ -1235,6 +1244,9 @@ class SFE_UBLOX_GNSS
//Calculate how much RAM is needed to store the payload for a given automatic message
uint16_t getMaxPayloadSize(uint8_t Class, uint8_t ID);

//Do the actual transfer to SPI
void spiTransfer(uint8_t byteToTransfer);

boolean initGeofenceParams(); // Allocate RAM for currentGeofenceParams and initialize it
boolean initModuleSWVersion(); // Allocate RAM for moduleSWVersion and initialize it

Expand Down Expand Up @@ -1273,6 +1285,10 @@ class SFE_UBLOX_GNSS
Stream *_nmeaOutputPort = NULL; //The user can assign an output port to print NMEA sentences if they wish
Stream *_debugSerial; //The stream to send debug messages to if enabled

SPIClass *_spiPort; //The instance of SPIClass
uint8_t _csPin; //The chip select pin
int _spiSpeed; //The speed to use for SPI (Hz)

uint8_t _gpsI2Caddress = 0x42; //Default 7-bit unshifted address of the ublox 6/7/8/M8/F9 series
//This can be changed using the ublox configuration software

Expand All @@ -1292,6 +1308,9 @@ class SFE_UBLOX_GNSS
uint8_t *payloadCfg = NULL;
uint8_t *payloadAuto = NULL;

uint8_t *spiBuffer = NULL; // A buffer to store any bytes being recieved back from the device while we are sending via SPI
uint8_t spiBufferIndex = 0; // Index into the SPI buffer

//Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays
ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
ubxPacket packetBuf = {0, 0, 0, 0, 0, payloadBuf, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
Expand Down