Skip to content

Instantly share code, notes, and snippets.

@stephanschulz
Created November 19, 2019 20:16
Show Gist options
  • Select an option

  • Save stephanschulz/a691e956b84d0db5169bc2e44bab4173 to your computer and use it in GitHub Desktop.

Select an option

Save stephanschulz/a691e956b84d0db5169bc2e44bab4173 to your computer and use it in GitHub Desktop.
#include <Arduino.h>
#include <SPI.h>
#define CLOCK_SPEED 2'000'000 // 2.5 MHz SSI Clock
#define SCK_PIN 13 // SSI CLK line
#define SCK_PIN_13_INDEX 0
//#define SCK_PIN_14_INDEX 1
//#define SCK_PIN_27_INDEX 2
SPISettings settingsA(CLOCK_SPEED, MSBFIRST, SPI_MODE1);
uint8_t encoderBuf[2] = {0, 0};
void makeTransfer();
uint16_t decodeEncoderFrame();
void calculateAndPrintPosition(uint16_t& encoderData);
void setup()
{
SerialUSB.begin(9600);
SPI.begin(); // SPI.begin() will initialize the SPI port, as well as CLK pin
pinMode(SCK_PIN, OUTPUT); // pinMode() will initialize the CLK pin as output (SPI port can't use it now!)
digitalWriteFast(SCK_PIN, HIGH); // Set CLK line HIGH (to meet the requirements of SSI interface)
while (!SerialUSB) {}
SerialUSB.println("Started!");
}
void loop()
{
makeTransfer();
uint16_t encoderData = decodeEncoderFrame();
calculateAndPrintPosition(encoderData);
delay(200);
}
void makeTransfer()
{
digitalWriteFast(SCK_PIN, LOW); // Set CLK line LOW (to inform encoder -> latch data)
delayMicroseconds(1); // Running above 500kHz perform Delay First Clock function
// Before in setup() the pinMode() change the CLK pin function to output,
// now we have to enable usage of this pin by SPI port with calling SPI.begin():
// SPI.begin();
// Or use this one below - a bit faster but SPI port and SCK pin dependent option. I belive there is a more elegant and more
// scalable solution, maybe even supported by hardware for this purpose? - if anyone can point me it out I would be grateful:
uint8_t pinIndex = SCK_PIN_13_INDEX;
volatile uint32_t* reg = portConfigRegister(SPIClass::spi0_hardware.sck_pin[pinIndex]);
*reg = SPIClass::spi0_hardware.sck_mux[pinIndex];
SPI.beginTransaction(settingsA); // We use transactional API
for (int i = 0; i < 2; i++)
{
encoderBuf[i] = SPI.transfer(0xAA); // Transfer anything and read data back
}
SPI.endTransaction(); // We use transactional API
pinMode(SCK_PIN, OUTPUT); // A while before we set CLK pin to be used by SPI port, now we have to change it manually...
digitalWrite(SCK_PIN, HIGH); // ... back to idle HIGH
}
uint16_t decodeEncoderFrame()
{
// uint32_t data = static_cast<uint32_t>(encoderBuf[0] << 24) |
// static_cast<uint32_t>(encoderBuf[1] << 16) |
// static_cast<uint32_t>(encoderBuf[2] << 8) |
// static_cast<uint32_t>(encoderBuf[3]); // here transfer8 was made
uint16_t data = static_cast<uint16_t>(encoderBuf[0] << 8) |
static_cast<uint16_t>(encoderBuf[1]); // here transfer8 was made
Serial.println("data ");
Serial.print(data);
Serial.println();
// Shift one bit right - (MSB of position was placed on at MSB of uint32_t, so make it right and shift to make MSB position at 30'th bit):
data = data >> 1;
return data;
}
void calculateAndPrintPosition(uint16_t& encoderData)
{
// encoderPosition is placed in front (starting from MSB of uint32_t) so shift it for 11 bits to align position data right
uint16_t encoderPosition = (encoderData >> 9);
float angularAbsolutePosition = static_cast<float>(encoderPosition) / static_cast<float>(1 << 20) * 360.0F;
SerialUSB.println("Encoder Positon = " + String(encoderPosition) + " Angle = " + String(angularAbsolutePosition, 4));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment