Last active
November 19, 2019 21:54
-
-
Save stephanschulz/c2702d78ab67b0ef1613d9ab1d23947e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <Arduino.h> | |
| #include <SPI.h> | |
| #define CLOCK_SPEED 2'000'000 // 2.5 MHz SSI Clock | |
| #define CS_PIN 10 | |
| #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[4] = {0, 0, 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(CS_PIN, OUTPUT); | |
| 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) | |
| // digitalWriteFast(CS_PIN, LOW); | |
| while (!SerialUSB) {} | |
| SerialUSB.println("Started!"); | |
| } | |
| void loop() | |
| { | |
| makeTransfer(); | |
| uint16_t encoderData = decodeEncoderFrame(); | |
| calculateAndPrintPosition(encoderData); | |
| delay(200); | |
| } | |
| void makeTransfer() | |
| { | |
| digitalWrite(CS_PIN, HIGH); | |
| digitalWrite(CS_PIN, LOW); | |
| digitalWriteFast(SCK_PIN, HIGH); | |
| 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 | |
| Serial.print(i); | |
| Serial.print(" i "); | |
| Serial.print((int)encoderBuf[i]); | |
| Serial.println(); | |
| } | |
| 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... | |
| digitalWriteFast(SCK_PIN, LOW); | |
| digitalWriteFast(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(); | |
| data = data >> 6; // shift right to cut status and parity bits only 'position data' is in data variable now! | |
| 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 | |
| // no shifting needed (we done it in decodeEncoderFrame()) | |
| // int16_t encoderPosition = (encoderData >> 9); | |
| // you have 10 bits position data so max is 1 << 10 not 1 << 20 as in my case | |
| //float angularAbsolutePosition = static_cast<float>(encoderPosition) / static_cast<float>(1 << 20) * 360.0F; | |
| float angularAbsolutePosition = static_cast<float>(encoderData) / static_cast<float>(1 << 10) * 360.0F; | |
| SerialUSB.println("Encoder Positon = " + String(encoderData) + " Angle = " + String(angularAbsolutePosition, 4)); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment