Merge pull request #43 from aberridg/add-spi-aberridg
Add support for SPI communication - thank you @aberridg !
This commit is contained in:
@@ -55,6 +55,8 @@ end KEYWORD2
|
|||||||
setI2CpollingWait KEYWORD2
|
setI2CpollingWait KEYWORD2
|
||||||
setI2CTransactionSize KEYWORD2
|
setI2CTransactionSize KEYWORD2
|
||||||
getI2CTransactionSize KEYWORD2
|
getI2CTransactionSize KEYWORD2
|
||||||
|
setSpiTransactionSize KEYWORD2
|
||||||
|
getSpiTransactionSize KEYWORD2
|
||||||
isConnected KEYWORD2
|
isConnected KEYWORD2
|
||||||
enableDebugging KEYWORD2
|
enableDebugging KEYWORD2
|
||||||
disableDebugging KEYWORD2
|
disableDebugging KEYWORD2
|
||||||
@@ -66,6 +68,7 @@ disableUBX7Fcheck KEYWORD2
|
|||||||
checkUblox KEYWORD2
|
checkUblox KEYWORD2
|
||||||
checkUbloxI2C KEYWORD2
|
checkUbloxI2C KEYWORD2
|
||||||
checkUbloxSerial KEYWORD2
|
checkUbloxSerial KEYWORD2
|
||||||
|
checkUbloxSPI KEYWORD2
|
||||||
|
|
||||||
process KEYWORD2
|
process KEYWORD2
|
||||||
processNMEA KEYWORD2
|
processNMEA KEYWORD2
|
||||||
|
|||||||
@@ -451,6 +451,38 @@ boolean SFE_UBLOX_GNSS::begin(Stream &serialPort)
|
|||||||
return (connected);
|
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)
|
// 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()
|
// 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
|
// or setHNRNavigationRate() are called. But if the user is using callbacks, it might be advantageous
|
||||||
@@ -473,6 +505,19 @@ uint8_t SFE_UBLOX_GNSS::getI2CTransactionSize(void)
|
|||||||
return (i2cTransactionSize);
|
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
|
//Returns true if I2C device ack's
|
||||||
boolean SFE_UBLOX_GNSS::isConnected(uint16_t maxWait)
|
boolean SFE_UBLOX_GNSS::isConnected(uint16_t maxWait)
|
||||||
{
|
{
|
||||||
@@ -598,6 +643,8 @@ boolean SFE_UBLOX_GNSS::checkUbloxInternal(ubxPacket *incomingUBX, uint8_t reque
|
|||||||
return (checkUbloxI2C(incomingUBX, requestedClass, requestedID));
|
return (checkUbloxI2C(incomingUBX, requestedClass, requestedID));
|
||||||
else if (commType == COMM_TYPE_SERIAL)
|
else if (commType == COMM_TYPE_SERIAL)
|
||||||
return (checkUbloxSerial(incomingUBX, requestedClass, requestedID));
|
return (checkUbloxSerial(incomingUBX, requestedClass, requestedID));
|
||||||
|
else if (commType == COMM_TYPE_SPI)
|
||||||
|
return (checkUbloxSpi(incomingUBX, requestedClass, requestedID));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,6 +802,32 @@ boolean SFE_UBLOX_GNSS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t request
|
|||||||
|
|
||||||
} //end checkUbloxSerial()
|
} //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
|
//PRIVATE: Check if we have storage allocated for an incoming "automatic" message
|
||||||
boolean SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID)
|
boolean SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID)
|
||||||
{
|
{
|
||||||
@@ -2675,6 +2748,10 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendCommand(ubxPacket *outgoingUBX, uint16_t
|
|||||||
{
|
{
|
||||||
sendSerialCommand(outgoingUBX);
|
sendSerialCommand(outgoingUBX);
|
||||||
}
|
}
|
||||||
|
else if (commType == COMM_TYPE_SPI)
|
||||||
|
{
|
||||||
|
sendSpiCommand(outgoingUBX);
|
||||||
|
}
|
||||||
|
|
||||||
if (maxWait > 0)
|
if (maxWait > 0)
|
||||||
{
|
{
|
||||||
@@ -2781,6 +2858,71 @@ void SFE_UBLOX_GNSS::sendSerialCommand(ubxPacket *outgoingUBX)
|
|||||||
_serialPort->write(outgoingUBX->checksumB);
|
_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
|
//Pretty prints the current ubxPacket
|
||||||
void SFE_UBLOX_GNSS::printPacket(ubxPacket *packet, boolean alwaysPrintPayload)
|
void SFE_UBLOX_GNSS::printPacket(ubxPacket *packet, boolean alwaysPrintPayload)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,6 +51,8 @@
|
|||||||
|
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
#include "u-blox_config_keys.h"
|
#include "u-blox_config_keys.h"
|
||||||
#include "u-blox_structs.h"
|
#include "u-blox_structs.h"
|
||||||
|
|
||||||
@@ -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
|
//#define MAX_PAYLOAD_SIZE 768 //Worst case: UBX_CFG_VALSET packet with 64 keyIDs each with 64 bit values
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// For storing SPI bytes received during sendSpiCommand
|
||||||
|
#define SPI_BUFFER_SIZE 128
|
||||||
|
|
||||||
//-=-=-=-=- UBX binary specific variables
|
//-=-=-=-=- UBX binary specific variables
|
||||||
struct ubxPacket
|
struct ubxPacket
|
||||||
{
|
{
|
||||||
@@ -560,6 +565,8 @@ public:
|
|||||||
boolean begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42); //Returns true if module is detected
|
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
|
//serialPort needs to be perviously initialized to correct baud rate
|
||||||
boolean begin(Stream &serialPort); //Returns true if module is detected
|
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
|
void end(void); //Stop all automatic message processing. Free all used RAM
|
||||||
|
|
||||||
@@ -569,6 +576,11 @@ public:
|
|||||||
void setI2CTransactionSize(uint8_t bufferSize);
|
void setI2CTransactionSize(uint8_t bufferSize);
|
||||||
uint8_t getI2CTransactionSize(void);
|
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
|
//Set the max number of bytes set in a given I2C transaction
|
||||||
uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit
|
uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit
|
||||||
|
|
||||||
@@ -612,6 +624,7 @@ public:
|
|||||||
|
|
||||||
boolean checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for I2C polling of data, passing any new bytes to process()
|
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 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
|
// Process the incoming data
|
||||||
|
|
||||||
@@ -622,12 +635,13 @@ public:
|
|||||||
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 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
|
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
|
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 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);
|
sfe_ublox_status_e sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait);
|
||||||
void sendSerialCommand(ubxPacket *outgoingUBX);
|
void sendSerialCommand(ubxPacket *outgoingUBX);
|
||||||
|
void sendSpiCommand(ubxPacket *outgoingUBX);
|
||||||
|
|
||||||
void printPacket(ubxPacket *packet, boolean alwaysPrintPayload = false); //Useful for debugging
|
void printPacket(ubxPacket *packet, boolean alwaysPrintPayload = false); //Useful for debugging
|
||||||
|
|
||||||
@@ -1235,6 +1249,9 @@ private:
|
|||||||
//Calculate how much RAM is needed to store the payload for a given automatic message
|
//Calculate how much RAM is needed to store the payload for a given automatic message
|
||||||
uint16_t getMaxPayloadSize(uint8_t Class, uint8_t ID);
|
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 initGeofenceParams(); // Allocate RAM for currentGeofenceParams and initialize it
|
||||||
boolean initModuleSWVersion(); // Allocate RAM for moduleSWVersion and initialize it
|
boolean initModuleSWVersion(); // Allocate RAM for moduleSWVersion and initialize it
|
||||||
|
|
||||||
@@ -1273,6 +1290,10 @@ private:
|
|||||||
Stream *_nmeaOutputPort = NULL; //The user can assign an output port to print NMEA sentences if they wish
|
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
|
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
|
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
|
//This can be changed using the ublox configuration software
|
||||||
|
|
||||||
@@ -1292,6 +1313,10 @@ private:
|
|||||||
uint8_t *payloadCfg = NULL;
|
uint8_t *payloadCfg = NULL;
|
||||||
uint8_t *payloadAuto = 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
|
//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 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};
|
ubxPacket packetBuf = {0, 0, 0, 0, 0, payloadBuf, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
|
||||||
|
|||||||
Reference in New Issue
Block a user