Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 12 of 12

Thread: AMT203 Absolute encoder and Teensy 3.1

  1. #1
    Junior Member
    Join Date
    Apr 2015
    Posts
    1

    AMT203 Absolute encoder and Teensy 3.1

    I've used this code on an Arduino UNO and it works perfectly and outputs a 12 bit value from 0-4095 via serial.print.
    When I load it into my Teensy 3.1 I get a erratic stream of values, see screenshot.
    Click image for larger version. 

Name:	Screen Shot 2015-04-13 at 10.47.05 PM.png 
Views:	232 
Size:	34.2 KB 
ID:	4095
    Rotating the Encoder position doesn't affect the Serial.print values.

    CUI Amt203 datasheet.
    [URL="http://www.cui.com/product/resource/amt20.pdf"]

    Can someone please point out what I'm doing wrong???

    #include <SPI.h>

    const int CS = 15; //Chip or Slave select

    uint16_t ABSposition = 0;
    uint16_t ABSposition_last = 0;
    uint8_t temp[2];



    void setup()
    {
    pinMode(CS,OUTPUT);//Slave Select
    digitalWrite(CS,HIGH);
    SPI.begin();



    Serial.begin(9600);
    delay(1000);
    Serial.println("starting");
    }

    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 = 0xA5; //just a temp vairable
    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

    while (recieved != 0x10) //loop while encoder is not ready to send
    {
    recieved = SPI_T(0x00); //check again if encoder is still working
    delay(20); //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

    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

    Serial.println(ABSposition); //send position in degrees
    }

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

    }
    Attached Files Attached Files
    Last edited by Scott Atta; 04-16-2015 at 10:47 PM.

  2. #2
    Did you ever figure this out? Found your message today after traveling the same path from the same arduino script from elsewhere. UNO works perfect, Teensy not so much. I've been able to get garbage data returned by utilizing SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE0)); down in SPI_T() to set the clock speed. But like you, I get repeating readings but ABSposition is either 0,1, or 165. Rotating the encoder doesn't change the return. and there doesn't seem to be a pattern to the returns either. If I go to 4MHz I get an additional 16 thrown into the loop.

    Using T3.2 with a sparkfun level convertor https://www.sparkfun.com/products/12009 sometimes. Doesn't seem to change anything in or out of the loop though.

  3. #3
    OK, so I spent probably too much time on trying to get Teensy 3.2 to talk to this sensor. Fail fast and often. Time/money = use cheap Arduino as an intermediary since it works with the sensor. This allowed me to change the SPI 'sensor' into I2C comms and save a few wires in the process on the Teensy side. Kludged this through an Arduino Pro Mini 5V to the Teensy... my circuit is all the SPI and 5V/GND from the mini to the AMT203, then I2C from A4/A5 I2C on the mini to Teensy. I eventually picked up the 1per Z pin as an interrupt for my project as well. Make sure to have a ground going between Arduino and Teensy! I found the easytransfer library (and all it's limitations) and put it to work. http://www.billporter.info/2011/05/3...duino-library/

    These bits of code will get the absolute position counter and an error check to the Teensy. All the deg/RPM etc math needs to happen on the Teensy. I wish I could do all of that in the Arduino to make the timing/calculations more honest, but I can't figure out how to pass a float or unsigned long through easytransfer. Since the AMT203 doesn't timestamp it's output, I'm not sure that it will matter much realistically unless you are doing several RPM.

    Yes, I put a lot of notes in my code... hopefully I never have to see this again, but more then likely it will need changes in 5 years and I don't want to relearn it.

    Arduino Mini Pro:


    ============================================
    ============================================

    //arduino pro mini 5v 16Mhz coupled with AMT203 absolute position sensor
    //feeds into Teensy 3.2 with EasyTransfer I2C since I cannot figure out how to get
    //Teensy to communicate with the AMT203 directly. PITA!

    boolean verbose = 1;

    //sensor
    #include <SPI.h>
    #define CS 10 //Chip or Slave select
    long SPIspeed = 2000000; //2000000 stable // the orignal script was 4000000. I could not get reliable results at those speeds
    SPISettings AMT203(SPIspeed, MSBFIRST, SPI_MODE0); //set up SPI using transactions

    //transfer
    #include <Wire.h>
    #include <EasyTransferI2C.h>
    EasyTransferI2C ET;

    struct SEND_DATA_STRUCTURE {
    //put your variable definitions here for the data you want to send
    //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
    //unsigned long AMT_curTime; //couldn't get this to work in the library. uint32_t doesn't work either
    uint16_t AMT_ABSposition; // this is basically the only data type that works
    // float AMT_deg; //floats don't work in the library either
    uint16_t AMT_cycles; //pass some sort of errorchecking

    //uint8_t wouldn't work either. dunno why. seems basic enough.
    };

    //give a name to the group of data
    SEND_DATA_STRUCTURE mydata;

    //define slave i2c address
    #define I2C_SLAVE_ADDRESS 9


    //program
    uint16_t ABSposition = 0;
    uint16_t ABSposition_last = 0;
    uint8_t temp[2];
    float deg = 0.00;
    unsigned long curTime = millis();
    String NOTES; //goes at the end of the logging line for various references
    uint16_t cycles = 0;




    void setup()
    {
    delay(200); //init the sensor
    pinMode(CS, OUTPUT); //Slave Select
    digitalWrite(CS, HIGH);

    SPI.begin();
    Wire.begin();
    ET.begin(details(mydata), &Wire);
    if (verbose) {
    Serial.begin(115200);
    Serial.print("Starting Pro Mini 5V with AMT203 and Easy Transfer TX ");
    Serial.println(SPIspeed);
    Serial.flush();
    delay(5);
    }
    }

    void loop()
    {
    curTime = millis();
    //if (curTime % 25 == 0) { //do this bit every 25ms //commented out to just run full speed

    uint8_t recieved = 0xA5; //temp var
    ABSposition = 0; //reset position var
    SPI_T(0x10); //issue read command

    recieved = SPI_T(0x00); //issue NOP to check if encoder is ready to send
    delay (1);// 3 stable

    while (recieved != 0x10) //loop while encoder is not ready to send
    {
    recieved = SPI_T(0x00); //cleck again if encoder is still working
    delay(1);// 3 stable //wait a bit
    cycles++; //if something barfs on the SPI comms I want to know about it on the Teensy side. should = 2
    }

    temp[0] = SPI_T(0x00); //Recieve MSB
    temp[1] = SPI_T(0x00); // recieve LSB
    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


    //dont need this bit here, just send what you've got all the time regardless
    // if (ABSposition != ABSposition_last) { //if nothing has changed dont wast time sending position

    float deg = ABSposition * 0.087890625; // 360/4096

    ABSposition_last = ABSposition; //set last position to current position

    //blow data out to Teensy
    mydata.AMT_ABSposition = ABSposition;
    mydata.AMT_cycles = cycles;
    ET.sendData(I2C_SLAVE_ADDRESS);

    if (verbose) {
    //streamline output for serial in one print if needed
    NOTES += String (curTime, DEC);
    NOTES += " ";
    NOTES += ABSposition;
    NOTES += " ";
    NOTES += deg;
    NOTES += " ";
    // NOTES += ABSdistance;
    // NOTES += " ";
    // NOTES += RPM;
    // NOTES += " ";
    NOTES += cycles;
    Serial.println(NOTES);
    NOTES = "";
    }

    //} // if (ABSposition != ABSposition_last)
    cycles = 0;
    delay(1);

    //} //if (curTime % 25 == 0) {

    }

    uint8_t SPI_T (uint8_t msg) //Repetive SPI transmit sequence
    {
    uint8_t msg_temp = 0; //var to hold recieved data
    SPI.beginTransaction(AMT203);
    digitalWrite(CS, LOW); //select spi device
    msg_temp = SPI.transfer(msg); //send and receive
    digitalWrite(CS, HIGH); //deselect spi device
    SPI.endTransaction();
    return (msg_temp); //return received byte
    }


    ============================================
    ============================================
    and then on the Teesy side:
    ============================================
    ============================================

    #include <Wire.h>
    #include <EasyTransferI2C.h>

    //create object
    EasyTransferI2C ET;

    uint32_t curTime;
    uint16_t ABSposition;
    float deg;

    struct RECEIVE_DATA_STRUCTURE {
    //put your variable definitions here for the data you want to send
    //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
    uint16_t AMT_ABSposition;
    uint16_t AMT_cycles;
    };

    //give a name to the group of data
    RECEIVE_DATA_STRUCTURE mydata;

    //define slave i2c address
    #define I2C_SLAVE_ADDRESS 9


    String NOTES;

    void setup() {
    Serial.begin(115200);
    delay(3000);
    Serial.println("Starting");
    Wire.begin(I2C_SLAVE_ADDRESS);
    delay(100);
    //start the library, pass in the data details and the name of the serial port. Can be Serial, Serial1, Serial2, etc.
    ET.begin(details(mydata), &Wire);
    delay(100);
    //define handler function on receiving data
    Wire.onReceive(receive);

    }

    void loop() {
    curTime = millis();

    if (curTime % 25 == 0) { //do this bit every 25ms

    if (ET.receiveData()) { //check and see if a data packet has come in.
    ABSposition = mydata.AMT_ABSposition;
    }
    deg = ABSposition * 0.087890625; // 360/4096

    //just leaving this in here for future use
    //The equation for calculating speed is:
    //S = (C/PPR) / (T/60)
    //
    //Therefore if 60 pulses were counted in 10 seconds from a 250 PPR encoder, the speed can be calculated as
    //S = (60/250) / (10/60) = (0.24) / (0.1667) = 1.44 RPM



    NOTES += String (curTime, DEC);
    NOTES += " ";
    NOTES += ABSposition;
    NOTES += " ";
    NOTES += deg;
    NOTES += " ";
    NOTES += mydata.AMT_cycles; //show the errorchecking
    Serial.println(NOTES);
    NOTES = "";
    }

    }

    void receive(int numBytes) {}

    ============================================
    Remember if you are working with Arduino plugged into one USB and Teensy plugged into another and two IDEs open that you verify the board/port in Tools before trying to upload!!!!

  4. #4
    Junior Member
    Join Date
    Mar 2015
    Posts
    18

    Wink AMT-200 series Absolute Encoder interfacing

    OK. 4-year later reply to this thread... But this came up on Google for AMT encoders.

    A couple of things to note:

    1) From the datasheet these AMT-203/233 sensors are 1MHz SPI, 2MHz max. So use 1MHz maximum speed.

    2) These use a 5V level SPI interface. So your 3.3V clock at high speed may not work well. Also, you must power them with 5V not 3.3V.

    3) I used SPIMODE1 with an AMT-233B (14-bit) sensor recently and it works correctly.

    Happy Easter 2018!

  5. #5
    Hey ChrisBaron.

    Do you mind posting your working code. I am working with the same encoder on a teensy 3.2 and have not had any luck.
    Thank you.

  6. #6
    Junior Member
    Join Date
    Mar 2015
    Posts
    18
    Here you go. I know this could be cleaned up and a bunch of stuff combined but I do it this way so I can see each step during debugging and then clean up if I care later.

    Code:
    // *********************************************
    // ***** getAMT2xxPos()
    // Read AMT2xx Absolute Encoder - 14-bit
    // Uses SPI to read out the current encoder value
    uint16_t getAMT2xxPos(uint8_t cs_pin) {
      uint8_t high_byte, low_byte;
      uint16_t absvalue = 0;
        
      SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));  // 2Mhz max, 1Mhz typical from datasheet
    
      digitalWrite(cs_pin, LOW);  // select chip
      high_byte = SPI.transfer(0);
      low_byte = SPI.transfer(0);
      digitalWrite(cs_pin,HIGH); //end read sequence
     
      SPI.endTransaction();
    
      absvalue = (high_byte << 6) + (low_byte >> 2);  // 14-bits total for the "B" model
     
      return absvalue;
    }
    Quote Originally Posted by stephanschulz View Post
    Hey ChrisBaron.

    Do you mind posting your working code. I am working with the same encoder on a teensy 3.2 and have not had any luck.
    Thank you.

  7. #7
    Thanks for sharing. It's very much appreciated.

    Sorry to ask more question, but it's not yet working for me.

    Don't you have to do the 0xA5 and 0x10 stuff to query the sensor?

    I only get this print out all the time:
    absvalue 10560
    absvalue 10560
    absvalue 10560
    absvalue 10561

    I have tested the encoder with the regular teensy Encoder.h example and it works well.
    But the SPI seems not to respond correctly or at all. ???

    Here my testing code based on your code
    Code:
    //testinng this absolute encoder type: https://www.cui.com/product/resource/digikeypdf/amt20.pdf
    //specifiaclly AMT203-V
    
    #include <SPI.h>
    
    #define CS 10 //Chip or Slave select 
    
    void setup() {
    
      Serial.begin(9600);
      Serial.println("starting encoder_chrisBaron");
      Serial.flush();
      delay(2000);
    
      // put your setup code here, to run once:
      pinMode(CS, OUTPUT); //Slave Select
      digitalWrite(CS, HIGH);
    
      SPI.begin();
    
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      getAMT2xxPos(CS);
    }
    
    // *********************************************
    // ***** getAMT2xxPos()
    // Read AMT2xx Absolute Encoder - 14-bit
    // Uses SPI to read out the current encoder value
    uint16_t getAMT2xxPos(uint8_t cs_pin) {
      uint8_t high_byte, low_byte;
      uint16_t absvalue = 0;
    
      SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));  // 2Mhz max, 1Mhz typical from datasheet
    
      digitalWrite(cs_pin, LOW);  // select chip
      high_byte = SPI.transfer(0);
      low_byte = SPI.transfer(0);
      digitalWrite(cs_pin, HIGH); //end read sequence
    
      SPI.endTransaction();
    
      absvalue = (high_byte << 6) + (low_byte >> 2);  // 14-bits total for the "B" model
      Serial.print("absvalue ");
      Serial.print(absvalue);
      Serial.println();
      return absvalue;
    }

  8. #8
    Junior Member
    Join Date
    Mar 2015
    Posts
    18
    Are you doing 5V I/O for this? It needs 5V power and 5V SPI levels.

  9. #9
    yes I am using the Vin from the teensy to feed the encoder. Vin is 5 volts since it gets it from the USB power.
    I am using the standard SPI pins
    MISO 12
    MOSI 11
    CS 10
    SCK 13

    it's very strange.
    I tripple checked that I'm connected to the right pins on the encoder too.
    And the fact that the AB encoder method works confirms that I'm giving it power correctly.

    Here a photo of my setup. I realize it's not very helpful, but ...
    Click image for larger version. 

Name:	shot.jpg 
Views:	5 
Size:	116.1 KB 
ID:	17652

  10. #10
    Junior Member
    Join Date
    Mar 2015
    Posts
    18
    Hmmm. I don't have this still connected up. I know it worked properly with that code.

    Also, I remember now that I was using the Teensy 2.0++ CPU with the AMT233. So there may be some differences there. The AMT203 has both ABZ and the SPI mode. I didn't use that exact one so I don't know if you have to do something to switch modes or what.

    Without a level translator your SCK pin and MOSI pins will be at 3.3V which the AMT may or may not like. The datasheet doesn't specify SPI voltages but does mention CMOS levels.

    Also, it looks like you have to send the encoder the 0x10 command over SPI to read the position data out. Datasheet p9

  11. #11
    Thanks again for your input.
    I will try a 2.0 teensy too.

    Interesting to learn you used the AMT233 which uses SSI communication while the AMT203 used SPI. Aren't they different things?

    I think the teensy 3.2 should be able to handle 3.3 V and 5 V SPI signal.
    The SPI protocol allows for a range of transmission speeds ranging from 1Mhz to 100MHz. SPI slaves vary in the maximum speed at which they can reliably work. Slower speeds are usually needed when 5 volt signals are converted to 3 volts using only resistors.
    cheers

  12. #12
    An update.
    The AMT233A-V did not work with the mentioned code.
    But since the AMT233A-V use SSI for communication I was able to use this example to get good reading:
    https://github.com/heavydetail/EMS22A_Arduino

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •