Hello guys, I am hoping you guys could help me out.
I am trying to interface a 17-bit resolution inductive encoder but have difficulty getting good results.
I have looked at previous examples and have managed to get a very rough reading using this thread as a guideline.
Looking at the datasheet i know that the setup is correct.
I believe that my issue resides in not reading the correct bits or data.
According to the data sheet the binary position resides on D29-D8.
Encoder Model: INC-11-58.120-171001-SPI1-RC2-5-S
Datasheet (4.6 Serial Peripheral Interface Protocol Definition):
Arduino Code:
#include <SPI.h>
#define CS 10 //Chip or Slave select
uint16_t ABSposition = 0;
uint16_t ABSposition_last = 0;
uint8_t temp[2];
float deg = 0.00;
void setup()
{
pinMode(CS,OUTPUT);//Slave Select
digitalWrite(CS,HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE1);
SPI.setClockDivider(SPI_CLOCK_DIV8);
Serial.begin(115200);
Serial.println("starting");
Serial.flush();
delay(2000);
SPI.end();
}
uint8_t SPI_T (uint8_t msg) //Repetive SPI transmit sequence
{
uint8_t msg_temp = 0; //vairable to hold recieved data
digitalWrite(CS,LOW); //select spi device
msg_temp = SPI.transfer(msg); //send and recieve
digitalWrite(CS,HIGH); //deselect spi device
return(msg_temp); //return recieved byte
}
void loop()
{
uint8_t recieved = 0x00; //just a temp vairable
ABSposition = 0; //reset position vairable
SPI.begin(); //start transmition
digitalWrite(CS,LOW);
SPI_T(0x00);
recieved = SPI_T(0x00); //issue NOP to check if encoder is ready to send
temp[0] = SPI_T(0); //Recieve MSB
temp[1] = SPI_T(0); // recieve LSB
digitalWrite(CS,HIGH);
SPI.end(); //end transmition
ABSposition = temp[0] << 9; //shift MSB to correct ABSposition in ABSposition message
ABSposition += temp[1] >> 0; // add LSB to ABSposition message to complete message
if (ABSposition != ABSposition_last) //if nothing has changed dont wast time sending position
{
ABSposition_last = ABSposition; //set last position to current position
deg = ABSposition;
deg = deg * 360/65536;
Serial.print(ABSposition); //raw value
Serial.print("\t");
Serial.println(deg,4); //send position in degrees
}
delay(10);
}
1.) Each message comes in a series of 6 bytes. This means you will need to call SPI_T(0); six times per sample
2.) You should be using all 6 of these bytes - not just the positional data bytes. The extra bytes give you status updates on the health of the encoder AND whether or not your received message is corrupt
3.) The positional data is in bits D29-D8 - the code you posted assumes the positional data is in bits D15:D0
4.) There is no difference between SPI_T(0); and SPI_T(0x00);
5.) Storing the pieces of data in an array as opposed to individual variables only makes sense if you are going to iterate through the array later in code
I have updated the code to account for the 6 bytes, the problem I'm now facing is outputting the data.
I've looked at various examples using smaller bit counts but I am not sure how to handle 6 bytes.
I used uint64_t but I ran into issues.
I am getting mostly stable data with some random readings.
I was also expecting to see higher resolution.
#include <SPI.h>
#define CS 10
uint8_t readbuf[6];
void setup()
{
Serial.begin(115200);
//initialise spi communication
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV16);
SPI.setDataMode(SPI_MODE1);
pinMode(CS, OUTPUT);
digitalWrite(CS, HIGH);
}
void loop(){
digitalWrite(CS, LOW);
uint8_t val = 0xFF;
for (int k=0; k <= 5; k++){
SPI.transfer(val);
}
digitalWrite(CS, HIGH);
digitalWrite(CS,LOW);
val = 0x00;
for (int i=0; i <= 5; i++){
readbuf[i]=SPI.transfer(val);
}
digitalWrite(CS, HIGH);
//Break down readbuf into its integer representation:
uint32_t encoderPosition = readbuf[0] << 40;
encoderPosition += readbuf[1] << 32;
encoderPosition += readbuf[2] << 24;
encoderPosition += readbuf[1] << 16;
encoderPosition += readbuf[2] << 8;
encoderPosition += readbuf[3];
Serial.println(encoderPosition);
delay(50); // delay in between reads for stability
}
No, no, no. You are still treating the positional data as being in the first bytes in the message when this is NOT the case. You need to become VERY familiar with the section labeled: Data Definition for IncOder SPI Protocol. Once you understand that section, you will know how to program the logic into your code.
Let me break it down for you a little more clearly:
First byte read --> 47 46 45 44 43 42 41 40 --- Bits 47 through 40 are all 0, always.
Second byte read --> 39 38 37 36 35 34 33 32 --- Bits 39 through 33 are all 0, always. Bit 32 is the Zero Point Default flag.
Third byte read --> 31 30 29 28 27 26 25 24 --- Bit 31 is the Position Valid flag. Bit 30 is the Position Synchronised flag. Bits 29 through 24 are the 6 most significant bits in the positional data.
Fourth byte read --> 23 22 21 20 19 18 17 16 --- Bits 23 through 16 are the next 8 most significant bits in the positional data.
Fifth byte read --> 15 14 13 12 11 10 9 8 --- Bits 15 through 8 are the 8 least significant bytes in the positional data
Sixth byte read --> 7 6 5 4 3 2 1 0 --- Bit 7 is the Stale Data flag. Bits 6 through 0 make up the Cyclic Redundancy Checksum (CRC)
I'm having a really hard time making sense of the logic here and highly doubt this solution is correct. I still thing you are misunderstanding what bits are and are not part of the positional data.
In order to more clearly explain the packet protocol, here is a more visual friendly breakdown of how the packet looks bit by bit: