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 all 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
3 changes: 3 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ end KEYWORD2
setI2CpollingWait KEYWORD2
setI2CTransactionSize KEYWORD2
getI2CTransactionSize KEYWORD2
setSpiTransactionSize KEYWORD2
getSpiTransactionSize KEYWORD2
isConnected KEYWORD2
enableDebugging KEYWORD2
disableDebugging KEYWORD2
Expand All @@ -66,6 +68,7 @@ disableUBX7Fcheck KEYWORD2
checkUblox KEYWORD2
checkUbloxI2C KEYWORD2
checkUbloxSerial KEYWORD2
checkUbloxSPI KEYWORD2

process KEYWORD2
processNMEA KEYWORD2
Expand Down
142 changes: 142 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 All @@ -473,6 +505,19 @@ uint8_t SFE_UBLOX_GNSS::getI2CTransactionSize(void)
return (i2cTransactionSize);
}

//Sets the global size for the SPI buffer/transactions.
//Call this before begin()!
//Note: if the buffer size is too small, incoming characters may be lost if the message sent
//is larger than this buffer. If too big, you may run out of SRAM on constrained architectures!
void SFE_UBLOX_GNSS::setSpiTransactionSize(uint8_t transactionSize)
{
spiTransactionSize = transactionSize;
}
uint8_t SFE_UBLOX_GNSS::getSpiTransactionSize(void)
{
return (spiTransactionSize);
}

//Returns true if I2C device ack's
boolean SFE_UBLOX_GNSS::isConnected(uint16_t maxWait)
{
Expand Down Expand Up @@ -598,6 +643,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 +802,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 +2748,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 +2858,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 ((spiBufferIndex < getSpiTransactionSize()) && (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[getSpiTransactionSize()];
}

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

// 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
27 changes: 26 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 All @@ -569,6 +576,11 @@ class SFE_UBLOX_GNSS
void setI2CTransactionSize(uint8_t bufferSize);
uint8_t getI2CTransactionSize(void);

//Control the size of the spi buffer. If the buffer isn't big enough, we'll start to lose bytes
//That we receive if the buffer is full!
void setSpiTransactionSize(uint8_t bufferSize);
uint8_t getSpiTransactionSize(void);

//Set the max number of bytes set in a given I2C transaction
uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit

Expand Down Expand Up @@ -612,6 +624,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 +635,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 +1249,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 +1290,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 +1313,10 @@ 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
uint8_t spiTransactionSize = SPI_BUFFER_SIZE; //Default size of 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