CUI AMT203 Encoder Reading Jumps

Hi

I have a pretty strange problem with my AMT absolute encoder. For the most part it works great using the code I got from this forum. But for some reason the values jump every now and again. I have tried shaking the cable (1m) to see if that a loose connection or something causes it but it doesnt seem to have any correlation. It jumps randomly by up to 100 degrees in some cases (see image attached) .

I am not sure if anyone experienced anything similar.

My code is attached below. It uses an interrupt for the reading. I have also reduced the time to about 50ms interrupts which is the maximum I need for my application and it still jumps randomly. Could this be noise related ?

#include <SPI.h>

#define CS 10 //Chip or Slave select

uint16_t ABSposition = 0;
uint16_t ABSposition_last = 0;
uint8_t temp[2]; //This one.
uint8_t recieved = 0xA5; //just a temp vairable
float deg = 0.00;

void setup()
{
pinMode(CS,OUTPUT);//Slave Select
digitalWrite(CS,HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV32);
delay(2000);
SPI.end();

Serial.begin(115200);
Serial.println("starting");
Serial.flush();

read_encoder_position();
if ((deg < 358.0) && (deg > 2))
{ set_zero();}

noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0; //
OCR1A = 3125; // compare match register 16MHz/256/2Hz - 50ms
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}

ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine
{
read_encoder_position();
Serial.println(deg); //send position in degrees
}

uint8_t SPI_T (uint8_t msg) //Repetive SPI transmit sequence
{
uint8_t msg_temp = 0; //variable 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()
{
// Serial.println("Loop Started");
delay(1000); //wait a bit till next check

}

void read_encoder_position()
{
ABSposition = 0; //reset position vairable
SPI.begin(); //start transmition
//digitalWrite(CS,LOW);

SPI_T(0x10); //issue read command

recieved = SPI_T(0x00); //issue NOP to check if encoder is ready to send
// Serial.println("ChkPoint_1");
while (recieved != 0x10) //loop while encoder is not ready to send
{
recieved = SPI_T(0x00); //cleck again if encoder is still working
delay(2); //wait a bit
}

temp[0] = SPI_T(0x00); //Recieve MSB
temp[1] = SPI_T(0x00); // recieve LSB

digitalWrite(CS,HIGH); //just to make sure
SPI.end(); //end transmition
// Serial.println("ChkPoint_2");
temp[0] &=~ 0xF0; //mask out the first 4 bits

ABSposition = temp[0] << 8; //shift MSB to correct ABSposition in ABSposition message
ABSposition += temp[1]; // 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 * 0.08789; // aprox 360/4096
//}
}

bool set_zero()
{
uint8_t lcl_received;
int lcl_count = 1024;
SPI.begin(); //start transmition
digitalWrite(CS,LOW);

SPI_T(0x70); //issue zero point command

do
{
lcl_received = SPI_T(0x00);
lcl_count= lcl_count-1;
}
while(lcl_count>1 && lcl_received != 0x80);
digitalWrite(CS,HIGH); //just to make sur
SPI.end(); //start transmition
if (lcl_count>1)
{
Serial.println("Zero Position Set!");
}
else
{
Serial.println("Zero Position Set Failed!");
}
}

ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
  read_encoder_position();
  Serial.println(deg);     //send position in degrees
}

Never call the Serial object inside an interrupt handler as it depends on interrupts to work and interrupts are disabled inside ISRs.

    delay(2);    //wait a bit

Also an absolute no-go. ISRs must not call delay() as it depends on the timer 0 interrupt (millis()) to work.

Why do you need the interrupt at all? Why not just reading the value inside loop()?

noo .. it happens even if i dont use an isr and just put it in a normal loop as well.

#include <SPI.h>

#define CS 10 //Chip or Slave select

uint16_t ABSposition = 0;
uint16_t ABSposition_last = 0;
uint8_t temp[2]; //This one.
uint8_t recieved = 0xA5; //just a temp vairable

float deg = 0.00;

void setup()
{
pinMode(CS,OUTPUT);//Slave Select
digitalWrite(CS,HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV32);
Serial.begin(115200);
Serial.println("starting");
Serial.flush();
delay(2000);
SPI.end();

set_zero();
}

uint8_t SPI_T (uint8_t msg) //Repetive SPI transmit sequence
{
uint8_t msg_temp = 0; //variable 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()
{
// Serial.println("Loop Started");

ABSposition = 0; //reset position vairable

SPI.begin(); //start transmition
digitalWrite(CS,LOW);

SPI_T(0x10); //issue read command

recieved = SPI_T(0x00); //issue NOP to check if encoder is ready to send
// Serial.println("ChkPoint_1");
while (recieved != 0x10) //loop while encoder is not ready to send
{
recieved = SPI_T(0x00); //cleck again if encoder is still working
delay(2); //wait a bit
}

temp[0] = SPI_T(0x00); //Recieve MSB
temp[1] = SPI_T(0x00); // recieve LSB

digitalWrite(CS,HIGH); //just to make sure
SPI.end(); //end transmition
// Serial.println("ChkPoint_2");
temp[0] &=~ 0xF0; //mask out the first 4 bits

ABSposition = temp[0] << 8; //shift MSB to correct ABSposition in ABSposition message
ABSposition += temp[1]; // 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 * 0.08789; // aprox 360/4096
Serial.println(deg); //send position in degrees
}

delay(10); //wait a bit till next check

}

bool set_zero()
{
uint8_t lcl_received;
int lcl_count = 1024;
SPI.begin(); //start transmition
digitalWrite(CS,LOW);

SPI_T(0x70); //issue zero point command

do
{
lcl_received = SPI_T(0x00);
lcl_count= lcl_count-1;
}
while(lcl_count>1 && lcl_received != 0x80);
digitalWrite(CS,HIGH); //just to make sur
SPI.end(); //start transmition
if (lcl_count>1)
{
Serial.println("Zero Position Set!");
}
else
{
Serial.println("Zero Position Set Failed!");
}
}

Learn to use code tags. Edit your post and insert code tags to let use read what you wanted to show us (otherwise the forum system may mangle it).