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

Thread: Troubles with the Teensy 3.2 and CUI AMT-203v encoder

  1. #1
    Junior Member
    Join Date
    Oct 2021
    Posts
    8

    Troubles with the Teensy 3.2 and CUI AMT-203v encoder

    Hi all, I am having troubles getting the CUI AMT-203v encoder to work with my teensy 3.2.

    I had previously been using the code, with no troubles at all on an Arduino Uno. However, when I try uploading the code to the 3.2 I get nothing popping up in the serial monitor.

    I've double checked all connection and I am using the VUSB pin on the 3.2 to supply 5V to my encoder.

    I'm using the sample code from the CUI website which can be found here: https://www.cuidevices.com/product/m...r/amt20-series

    I am pretty new to all of this so any help is appreciated. Thanks in advance.

    //include SPI library
    #include <SPI.h>

    //this is the serial baud rate for talking to the Arduino
    #define baudRate 9600

    //this will be our SPI timout limit
    #define timoutLimit 100

    //SPI commands used by the AMT20
    #define nop 0x00 //no operation
    #define rd_pos 0x10 //read position
    #define set_zero_point 0x70 //set zero point

    //set the chip select pin for the AMT20
    const int CS = 10;

    //Arduino uses a setup function for all program initializations
    void setup()
    {
    //Initialize the UART serial connection
    Serial.begin(baudRate);

    //Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
    //For our settings we will use a clock rate of 500kHz, and the standard SPI settings
    //of MSB First and SPI Mode 0
    SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));

    //Set I/O mode of all SPI pins.
    pinMode(SCK, OUTPUT);
    pinMode(MOSI, OUTPUT);
    pinMode(MISO, INPUT);
    pinMode(CS, OUTPUT);
    pinMode(3, OUTPUT);

    //Using SPI.beginTransaction seems to require explicitly setting the beginning state
    //of the CS pin as opposed to the SPI.begin() function that does this for us.
    digitalWrite(CS, HIGH);

    }

    //After the setup() method this loop gets entered and is the main() function for our program
    void loop()
    {
    uint8_t data; //this will hold our returned data from the AMT20
    uint8_t timeoutCounter; //our timeout incrementer
    uint32_t currentPosition; //this 16 bit variable will hold our 12-bit position

    while(true)
    {
    //reset the timoutCounter;
    timeoutCounter = 0;

    //send the rd_pos command to have the AMT20 begin obtaining the current position
    data = SPIWrite(rd_pos);

    //we need to send nop commands while the encoder processes the current position. We
    //will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
    while (data != rd_pos && timeoutCounter++ < timoutLimit)
    {
    data = SPIWrite(nop);
    }


    if (timeoutCounter < timoutLimit) //rd_pos echo received
    {
    //We received the rd_pos echo which means the next two bytes are the current encoder position.
    //Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.

    //Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
    //shift it left 8 bits to make room for the lower byte.
    currentPosition = (SPIWrite(nop)& 0x0F) << 8;

    //OR the next byte with the current position
    currentPosition |= SPIWrite(nop);
    }
    else //timeout reached
    {
    //This means we had a problem with the encoder, most likely a lost connection. For our
    //purposes we will alert the user via the serial connection, and then stay here forever.

    Serial.write("Error obtaining position.\n");
    Serial.write("Reset Arduino to restart program.\n");

    while(true);
    }

    Serial.write("Current position: ");
    Serial.print(currentPosition, DEC); //current position in decimal
    Serial.write("\t 0x");
    Serial.print(currentPosition, HEX); //current position in hexidecimal
    Serial.write("\t 0b");
    Serial.print(currentPosition, BIN); //current position in binary
    Serial.write("\t DEG: ");
    Serial.print(currentPosition*0.087890625); //current position in degrees
    Serial.write("\n");

    //Since we are displaying our position over the serial monitor we don't need updates that fast
    delay(250);

    analogWrite(3,currentPosition*0.0012207031);
    }
    }

    //We will use this function to handle transmitting SPI commands in order to keep our code clear and concise.
    //It will return the byte received from SPI.transfer()
    uint8_t SPIWrite(uint8_t sendByte)
    {
    //holder for the received over SPI
    uint8_t data;

    //the AMT20 requires the release of the CS line after each byte
    digitalWrite(CS, LOW);
    data = SPI.transfer(sendByte);
    digitalWrite(CS, HIGH);

    //we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
    delayMicroseconds(10);

    return data;
    }
    Attached Files Attached Files

  2. #2
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    464
    Please in future enclose your code with CODE tags using the # button above.
    This preserves the presentation of the code, as shown below, and makes it easier for someone to understand your code and potentially help you.
    I have pasted your code into this message below and I am sure that you can see the difference in presentation.

    Compared to the Uno the T3.2 is very fast.
    You need to allow time for the Serial usb port to initialise itself before continuing after a Serial.begin.
    Code:
        SerialUsb.begin(9600);
        while (!Serial && (millis() < 3000));
    The code above allows the Teensy to wait for up to 3 seconds before continuing.
    Code:
    //include SPI library
    #include <SPI.h>
    
    //this is the serial baud rate for talking to the Arduino
    #define baudRate 9600
    
    //this will be our SPI timout limit
    #define timoutLimit 100
    
    //SPI commands used by the AMT20
    #define nop 0x00 //no operation
    #define rd_pos 0x10 //read position
    #define set_zero_point 0x70 //set zero point
    
    //set the chip select pin for the AMT20
    const int CS = 10;
    
    //Arduino uses a setup function for all program initializations
    void setup()
    {
    	//Initialize the UART serial connection
    	Serial.begin(baudRate);
    
    	//Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
    	//For our settings we will use a clock rate of 500kHz, and the standard SPI settings
    	//of MSB First and SPI Mode 0
    	SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
    
    	//Set I/O mode of all SPI pins.
    	pinMode(SCK, OUTPUT);
    	pinMode(MOSI, OUTPUT);
    	pinMode(MISO, INPUT);
    	pinMode(CS, OUTPUT);
    	pinMode(3, OUTPUT);
    
    	//Using SPI.beginTransaction seems to require explicitly setting the beginning state
    	//of the CS pin as opposed to the SPI.begin() function that does this for us.
    	digitalWrite(CS, HIGH);
    
    }
    
    //After the setup() method this loop gets entered and is the main() function for our program
    void loop()
    {
    	uint8_t data; //this will hold our returned data from the AMT20
    	uint8_t timeoutCounter; //our timeout incrementer
    	uint32_t currentPosition; //this 16 bit variable will hold our 12-bit position
    
    	while (true)
    	{
    		//reset the timoutCounter;
    		timeoutCounter = 0;
    
    		//send the rd_pos command to have the AMT20 begin obtaining the current position
    		data = SPIWrite(rd_pos);
    
    		//we need to send nop commands while the encoder processes the current position. We
    		//will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
    		while (data != rd_pos && timeoutCounter++ < timoutLimit)
    		{
    			data = SPIWrite(nop);
    		}
    
    
    		if (timeoutCounter < timoutLimit) //rd_pos echo received
    		{
    			//We received the rd_pos echo which means the next two bytes are the current encoder position.
    			//Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.
    
    			//Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
    			//shift it left 8 bits to make room for the lower byte.
    			currentPosition = (SPIWrite(nop) & 0x0F) << 8;
    
    			//OR the next byte with the current position
    			currentPosition |= SPIWrite(nop);
    		}
    		else //timeout reached
    		{
    			//This means we had a problem with the encoder, most likely a lost connection. For our
    			//purposes we will alert the user via the serial connection, and then stay here forever.
    
    			Serial.write("Error obtaining position.\n");
    			Serial.write("Reset Arduino to restart program.\n");
    
    			while (true);
    		}
    
    		Serial.write("Current position: ");
    		Serial.print(currentPosition, DEC); //current position in decimal
    		Serial.write("\t 0x");
    		Serial.print(currentPosition, HEX); //current position in hexidecimal
    		Serial.write("\t 0b");
    		Serial.print(currentPosition, BIN); //current position in binary
    		Serial.write("\t DEG: ");
    		Serial.print(currentPosition * 0.087890625); //current position in degrees
    		Serial.write("\n");
    
    		//Since we are displaying our position over the serial monitor we don't need updates that fast
    		delay(250);
    
    		analogWrite(3, currentPosition * 0.0012207031);
    	}
    }
    
    //We will use this function to handle transmitting SPI commands in order to keep our code clear and concise.
    //It will return the byte received from SPI.transfer()
    uint8_t SPIWrite(uint8_t sendByte)
    {
    	//holder for the received over SPI
    	uint8_t data;
    
    	//the AMT20 requires the release of the CS line after each byte
    	digitalWrite(CS, LOW);
    	data = SPI.transfer(sendByte);
    	digitalWrite(CS, HIGH);
    
    	//we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
    	delayMicroseconds(10);
    
    	return data;
    }

  3. #3
    Junior Member
    Join Date
    Oct 2021
    Posts
    8
    So I tried putting in that while statement to no avail.

    Maybe I put it in the wrong location?

    Code:
    /*
     * AMT20_SPI_Sample_Code.ino
     * Company: CUI Inc.
     * Author: Jason Kelly
     * Version: 1.0.0.0
     * Date: August 8, 2016
     * 
     * This sample code can be used with the Arduino Uno to control the AMT20 encoder.
     * It uses SPI to control the encoder and the the Arduino UART to report back to the PC
     * via the Arduino Serial Monitor. Code can be modified for any Arduino with an SPI bus.
     * For more information or assistance contact CUI Inc for support.
     * 
     * After uploading code to Arduino UNO open the open the Serial Monitor under the Tools 
     * menu and set the baud rate to 115200 to view the serial stream the position from the AMT20.
     * 
     * Arduino Pin Connections
     * SPI Chip Select: Pin 10 (Green/Red)
     * SPI MOSI:        Pin 11 (Red/White)
     * SPI MISO:        Pin 12 (Brown/Black)
     * SPI Clock (SCK): Pin 13 (Orange/Black)
     * 
     * AMT20 Pin Connections
     * SPI Clock (SCK):       Pin 5
     * SPI MOSI:              Pin 7
     * SPI MISO:              PIN 3
     * SPI Chip Select (CSB): Pin 2
     * Vdd (5V):              Pin 6 (Red/Black)
     * GND:                   Pin 4 (Black/Red)
     * 
     * 
     * This is free and unencumbered software released into the public domain.
     * Anyone is free to copy, modify, publish, use, compile, sell, or
     * distribute this software, either in source code form or as a compiled
     * binary, for any purpose, commercial or non-commercial, and by any
     * means.
     * 
     * In jurisdictions that recognize copyright laws, the author or authors
     * of this software dedicate any and all copyright interest in the
     * software to the public domain. We make this dedication for the benefit
     * of the public at large and to the detriment of our heirs and
     * successors. We intend this dedication to be an overt act of
     * relinquishment in perpetuity of all present and future rights to this
     * software under copyright law.
     * 
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     */
    
    //include SPI library
    #include <SPI.h>
    
    //this is the serial baud rate for talking to the Arduino
    //#define baudRate 115200
    
    //this will be our SPI timout limit
    #define timoutLimit 100
    
    //SPI commands used by the AMT20
    #define nop 0x00            //no operation
    #define rd_pos 0x10         //read position
    #define set_zero_point 0x70 //set zero point
    
    //set the chip select pin for the AMT20
    const int CS = 10;
    
    #define SCK 14
    //Arduino uses a setup function for all program initializations
    void setup() 
    {
      //Initialize the UART serial connection
        Serial.begin(115200);  
        while (!Serial && (millis() < 3000));
    
      //Set I/O mode of all SPI pins.
      pinMode(SCK, OUTPUT);
      pinMode(MOSI, OUTPUT);
      pinMode(MISO, INPUT);
      pinMode(CS, OUTPUT);
      pinMode(3, OUTPUT);
    
      //Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
      //For our settings we will use a clock rate of 500kHz, and the standard SPI settings
      //of MSB First and SPI Mode 0
      SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
      
      //Using SPI.beginTransaction seems to require explicitly setting the beginning state
      //of the CS pin as opposed to the SPI.begin() function that does this for us.
      digitalWrite(CS, HIGH);
      
    }
    
    //After the setup() method this loop gets entered and is the main() function for our program
    void loop() 
    {
      uint8_t data;               //this will hold our returned data from the AMT20
      uint8_t timeoutCounter;     //our timeout incrementer
      uint16_t currentPosition;   //this 16 bit variable will hold our 12-bit position
    
      while(true)
      {
        //reset the timoutCounter;
        timeoutCounter = 0;
        
        //send the rd_pos command to have the AMT20 begin obtaining the current position
        data = SPIWrite(rd_pos);
      
        //we need to send nop commands while the encoder processes the current position. We
        //will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
        while (data != rd_pos && timeoutCounter++ < timoutLimit)
        {
          data = SPIWrite(nop);
        }
      
      
        if (timeoutCounter < timoutLimit) //rd_pos echo received
        {
          //We received the rd_pos echo which means the next two bytes are the current encoder position.
          //Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.
      
          //Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
          //shift it left 8 bits to make room for the lower byte.
          currentPosition = (SPIWrite(nop)& 0x0F) << 8;
      
          //OR the next byte with the current position
          currentPosition |= SPIWrite(nop);
        }
        else //timeout reached
        {
          //This means we had a problem with the encoder, most likely a lost connection. For our
          //purposes we will alert the user via the serial connection, and then stay here forever.
      
          Serial.write("Error obtaining position.\n");
          Serial.write("Reset Arduino to restart program.\n");
          
          while(true);
        }
    
        Serial.write("Current position: ");
        Serial.print(currentPosition, DEC); //current position in decimal
        Serial.write("\t 0x");
        Serial.print(currentPosition, HEX); //current position in hexidecimal
        Serial.write("\t 0b");
        Serial.print(currentPosition, BIN); //current position in binary
        Serial.write("\t DEG: ");
        Serial.print(currentPosition*0.087890625); //current position in degrees
        Serial.write("\n");
        
        //analogWrite(3, currentPosition*)
        
        //Since we are displaying our position over the serial monitor we don't need updates that fast
        delay(250);
      }
    }
    
    //We will use this function to handle transmitting SPI commands in order to keep our code clear and concise.
    //It will return the byte received from SPI.transfer()
    uint8_t SPIWrite(uint8_t sendByte)
    {
      //holder for the received over SPI
      uint8_t data;
    
      //the AMT20 requires the release of the CS line after each byte
      digitalWrite(CS, LOW);
      data = SPI.transfer(sendByte);
      digitalWrite(CS, HIGH);
    
      //we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
      delayMicroseconds(10);
      
      return data;
    }

  4. #4
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    464
    Ok, so I would suggest sprinkling some Serial.print statements to indicate where the code is going wrong.
    I have put some in your code below. You might want to change the text to something more meaningful to yourself.
    Code:
    /*
     * AMT20_SPI_Sample_Code.ino
     * Company: CUI Inc.
     * Author: Jason Kelly
     * Version: 1.0.0.0
     * Date: August 8, 2016
     *
     * This sample code can be used with the Arduino Uno to control the AMT20 encoder.
     * It uses SPI to control the encoder and the the Arduino UART to report back to the PC
     * via the Arduino Serial Monitor. Code can be modified for any Arduino with an SPI bus.
     * For more information or assistance contact CUI Inc for support.
     *
     * After uploading code to Arduino UNO open the open the Serial Monitor under the Tools
     * menu and set the baud rate to 115200 to view the serial stream the position from the AMT20.
     *
     * Arduino Pin Connections
     * SPI Chip Select: Pin 10 (Green/Red)
     * SPI MOSI:        Pin 11 (Red/White)
     * SPI MISO:        Pin 12 (Brown/Black)
     * SPI Clock (SCK): Pin 13 (Orange/Black)
     *
     * AMT20 Pin Connections
     * SPI Clock (SCK):       Pin 5
     * SPI MOSI:              Pin 7
     * SPI MISO:              PIN 3
     * SPI Chip Select (CSB): Pin 2
     * Vdd (5V):              Pin 6 (Red/Black)
     * GND:                   Pin 4 (Black/Red)
     *
     *
     * This is free and unencumbered software released into the public domain.
     * Anyone is free to copy, modify, publish, use, compile, sell, or
     * distribute this software, either in source code form or as a compiled
     * binary, for any purpose, commercial or non-commercial, and by any
     * means.
     *
     * In jurisdictions that recognize copyright laws, the author or authors
     * of this software dedicate any and all copyright interest in the
     * software to the public domain. We make this dedication for the benefit
     * of the public at large and to the detriment of our heirs and
     * successors. We intend this dedication to be an overt act of
     * relinquishment in perpetuity of all present and future rights to this
     * software under copyright law.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     */
    
     //include SPI library
    #include <SPI.h>
    
    //this is the serial baud rate for talking to the Arduino
    //#define baudRate 115200
    
    //debug below is simply to cause some debug print statements to be output.
    //to turn off simply comment uot the following line
    #define debug true
    
    //this will be our SPI timout limit
    #define timoutLimit 100
    
    //SPI commands used by the AMT20
    #define nop 0x00            //no operation
    #define rd_pos 0x10         //read position
    #define set_zero_point 0x70 //set zero point
    
    //set the chip select pin for the AMT20
    const int CS = 10;
    
    #define SCK 14
    //Arduino uses a setup function for all program initializations
    void setup()
    {
        //Initialize the UART serial connection
        Serial.begin(115200);
        while (!Serial && (millis() < 3000));
    
        //Set I/O mode of all SPI pins.
        pinMode(SCK, OUTPUT);
        pinMode(MOSI, OUTPUT);
        pinMode(MISO, INPUT);
        pinMode(CS, OUTPUT);
        pinMode(3, OUTPUT);
    
        //Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
        //For our settings we will use a clock rate of 500kHz, and the standard SPI settings
        //of MSB First and SPI Mode 0
        SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
    
        //Using SPI.beginTransaction seems to require explicitly setting the beginning state
        //of the CS pin as opposed to the SPI.begin() function that does this for us.
        digitalWrite(CS, HIGH);
    
    #ifdef debug
        Serial.println("Setup Complete");
    #endif
    }
    
    //After the setup() method this loop gets entered and is the main() function for our program
    void loop()
    {
        uint8_t data;               //this will hold our returned data from the AMT20
        uint8_t timeoutCounter;     //our timeout incrementer
        uint16_t currentPosition;   //this 16 bit variable will hold our 12-bit position
    
        while (true)
        {
            //reset the timoutCounter;
            timeoutCounter = 0;
    
            //send the rd_pos command to have the AMT20 begin obtaining the current position
            data = SPIWrite(rd_pos);
    
            //we need to send nop commands while the encoder processes the current position. We
            //will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
            while (data != rd_pos && timeoutCounter++ < timoutLimit)
            {
                data = SPIWrite(nop);
            }
    #ifdef debug
            Serial.println("Out of initial loop");
    #endif
    
    
            if (timeoutCounter < timoutLimit) //rd_pos echo received
            {
                //We received the rd_pos echo which means the next two bytes are the current encoder position.
                //Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.
    
                //Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
                //shift it left 8 bits to make room for the lower byte.
    #ifdef debug
                Serial.println("Got Position.\n");
    #endif
                currentPosition = (SPIWrite(nop) & 0x0F) << 8;
    
                //OR the next byte with the current position
                currentPosition |= SPIWrite(nop);
            }
            else //timeout reached
            {
                //This means we had a problem with the encoder, most likely a lost connection. For our
                //purposes we will alert the user via the serial connection, and then stay here forever.
    
                Serial.write("Error obtaining position.\n");
                Serial.write("Reset Arduino to restart program.\n");
    
                while (true);
            }
    
            Serial.write("Current position: ");
            Serial.print(currentPosition, DEC); //current position in decimal
            Serial.write("\t 0x");
            Serial.print(currentPosition, HEX); //current position in hexidecimal
            Serial.write("\t 0b");
            Serial.print(currentPosition, BIN); //current position in binary
            Serial.write("\t DEG: ");
            Serial.print(currentPosition * 0.087890625); //current position in degrees
            Serial.write("\n");
    
            //analogWrite(3, currentPosition*)
    
            //Since we are displaying our position over the serial monitor we don't need updates that fast
            delay(250);
        }
    }
    
    //We will use this function to handle transmitting SPI commands in order to keep our code clear and concise.
    //It will return the byte received from SPI.transfer()
    uint8_t SPIWrite(uint8_t sendByte)
    {
        //holder for the received over SPI
        uint8_t data;
    
        //the AMT20 requires the release of the CS line after each byte
        digitalWrite(CS, LOW);
        data = SPI.transfer(sendByte);
        digitalWrite(CS, HIGH);
    
        //we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
        delayMicroseconds(10);
    
        return data;
    }

  5. #5
    Junior Member
    Join Date
    Oct 2021
    Posts
    8
    Ok so over the weekend I was able to determine where the code stops writing to the serial monitor.

    It happens after the
    Code:
     SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
    So I think it has something to do with the SPISettings.

    I will read into this tonight. Any suggestion you may have would be helpful.

    Here is my updated code thus far.

    Code:
    /*
     * AMT20_SPI_Sample_Code.ino
     * Company: CUI Inc.
     * Author: Jason Kelly
     * Version: 1.0.0.0
     * Date: August 8, 2016
     * 
     * This sample code can be used with the Arduino Uno to control the AMT20 encoder.
     * It uses SPI to control the encoder and the the Arduino UART to report back to the PC
     * via the Arduino Serial Monitor. Code can be modified for any Arduino with an SPI bus.
     * For more information or assistance contact CUI Inc for support.
     * 
     * After uploading code to Arduino UNO open the open the Serial Monitor under the Tools 
     * menu and set the baud rate to 115200 to view the serial stream the position from the AMT20.
     * 
     * Arduino Pin Connections
     * SPI Chip Select: Pin 10 (Green/Red)
     * SPI MOSI:        Pin 11 (Red/White)
     * SPI MISO:        Pin 12 (Brown/Black)
     * SPI Clock (SCK): Pin 13 (Orange/Black)
     * 
     * AMT20 Pin Connections
     * SPI Clock (SCK):       Pin 5
     * SPI MOSI:              Pin 7
     * SPI MISO:              PIN 3
     * SPI Chip Select (CSB): Pin 2
     * Vdd (5V):              Pin 6 (Red/Black)
     * GND:                   Pin 4 (Black/Red)
     * 
     * 
     * This is free and unencumbered software released into the public domain.
     * Anyone is free to copy, modify, publish, use, compile, sell, or
     * distribute this software, either in source code form or as a compiled
     * binary, for any purpose, commercial or non-commercial, and by any
     * means.
     * 
     * In jurisdictions that recognize copyright laws, the author or authors
     * of this software dedicate any and all copyright interest in the
     * software to the public domain. We make this dedication for the benefit
     * of the public at large and to the detriment of our heirs and
     * successors. We intend this dedication to be an overt act of
     * relinquishment in perpetuity of all present and future rights to this
     * software under copyright law.
     * 
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     */
    
    //include SPI library
    #include <SPI.h>
    
    //this is the serial baud rate for talking to the Arduino
    //#define baudRate 115200
    
    //this will be our SPI timout limit
    #define timoutLimit 100
    
    //SPI commands used by the AMT20
    #define nop 0x00            //no operation
    #define rd_pos 0x10         //read position
    #define set_zero_point 0x70 //set zero point
    
    //set the chip select pin for the AMT20
    const int CS = 10;
    
    //Arduino uses a setup function for all program initializations
    void setup() 
    {
      //Initialize the UART serial connection
        Serial.begin(9600);  
        Serial.print("Hello World...");
        while (!Serial && (millis() < 3000));
    
      //Set I/O mode of all SPI pins.
      pinMode(SCK, OUTPUT);
      pinMode(MOSI, OUTPUT);
      pinMode(MISO, INPUT);
      pinMode(CS, OUTPUT);
      pinMode(1, OUTPUT);
    
      //Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
      //For our settings we will use a clock rate of 500kHz, and the standard SPI settings
      //of MSB First and SPI Mode 0
      
      Serial.print("Before SPI.beginTransaction");
      SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
      Serial.print("After SPI.beginTransaction");
      
      //Using SPI.beginTransaction seems to require explicitly setting the beginning state
      //of the CS pin as opposed to the SPI.begin() function that does this for us.
      digitalWrite(CS, HIGH);
    
    
      
    }
    
    //After the setup() method this loop gets entered and is the main() function for our program
    void loop() 
    {
      
      uint8_t data;               //this will hold our returned data from the AMT20
      uint8_t timeoutCounter;     //our timeout incrementer
      uint16_t currentPosition;   //this 16 bit variable will hold our 12-bit position
    
      while(true)
      {
        //reset the timoutCounter;
        timeoutCounter = 0;
        
        //send the rd_pos command to have the AMT20 begin obtaining the current position
        data = SPIWrite(rd_pos);
      
        //we need to send nop commands while the encoder processes the current position. We
        //will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
        while (data != rd_pos && timeoutCounter++ < timoutLimit)
        {
          data = SPIWrite(nop);
        }
      
      
        if (timeoutCounter < timoutLimit) //rd_pos echo received
        {
          //We received the rd_pos echo which means the next two bytes are the current encoder position.
          //Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.
      
          //Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
          //shift it left 8 bits to make room for the lower byte.
          currentPosition = (SPIWrite(nop)& 0x0F) << 8;
      
          //OR the next byte with the current position
          currentPosition |= SPIWrite(nop);
        }
        else //timeout reached
        {
          //This means we had a problem with the encoder, most likely a lost connection. For our
          //purposes we will alert the user via the serial connection, and then stay here forever.
      
          Serial.write("Error obtaining position.\n");
          Serial.write("Reset Arduino to restart program.\n");
          
          while(true);
        }
    
        Serial.write("Current position: ");
        Serial.print(currentPosition, DEC); //current position in decimal
        Serial.write("\t 0x");
        Serial.print(currentPosition, HEX); //current position in hexidecimal
        Serial.write("\t 0b");
        Serial.print(currentPosition, BIN); //current position in binary
        Serial.write("\t DEG: ");
        Serial.print(currentPosition*0.087890625); //current position in degrees
        Serial.write("\n");
        
        analogWrite(1, currentPosition*0.0012207031);
        
        //Since we are displaying our position over the serial monitor we don't need updates that fast
        delay(300);
      }
    }
    
    //We will use this function to handle transmitting SPI commands in order to keep our code clear and concise.
    //It will return the byte received from SPI.transfer()
    uint8_t SPIWrite(uint8_t sendByte)
    {
      //holder for the received over SPI
      uint8_t data;
    
      //the AMT20 requires the release of the CS line after each byte
      digitalWrite(CS, LOW);
      data = SPI.transfer(sendByte);
      digitalWrite(CS, HIGH);
    
      //we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
      delayMicroseconds(10);
      
      return data;
    }

  6. #6
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    464
    I believe that you need to call
    Code:
    SPI.begin()
    before calling
    Code:
    SPI.beginTransaction(SPISettings(clockspeed, MSBFIRST, SPI_MODE0))
    I am not sure if this will cure your problem, but certainly worth a try.

  7. #7
    Junior Member
    Join Date
    Oct 2021
    Posts
    8
    I do have an
    Code:
    SPI.begin()
    Line of code at the top of my Void Setup.
    Any other suggestions?

    Also thank you for your help on this thus far, it is appreciated.

  8. #8
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    464
    I am sorry but you don't. At least NOT in the code contained in your previous post. You have Serial.begin but NOT SPI.begin.

  9. #9
    Junior Member
    Join Date
    Oct 2021
    Posts
    8
    Ah I see that now, apologies. I will try this when I get home tonight.

  10. #10
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    464
    No problem.
    EDIT:
    I am no SPI expert, but I think you are using SPI.beginTransaction wrongly.
    Since you are only using one SPI device you do not need to preserve and reinstate SPI settings.
    That is what SPI.beginTransaction and it's paired SPI.endTransaction are meant to do.
    SPI.beginTransaction and SPI.endTransaction are supposed to be either side of your actual SPI transaction.

    So in your code they should be in your SPIWrite function as below
    Code:
    uint8_t SPIWrite(uint8_t sendByte)
    {
        //holder for the received over SPI
        uint8_t data;
    
        //the AMT20 requires the release of the CS line after each byte
        SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
        digitalWrite(CS, LOW);
        data = SPI.transfer(sendByte);
        digitalWrite(CS, HIGH);
        SPI.endTransaction();
    
        //we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
        delayMicroseconds(10);
    
        return data;
    }
    I believe SPI.beginTransaction does things to interrupts which might be what is stopping Serial.print from working.
    Last edited by BriComp; 10-25-2021 at 06:18 PM.

  11. #11
    Junior Member
    Join Date
    Oct 2021
    Posts
    8
    OK, so I've moved the SPI.beginTransaction() line down to the bottom of my code like you suggested, and closed it off with an SPI.endTransaction(). As well I added the SPI.begin() right under the Serial.begin() line.

    Now I am getting an error in my void loop. I believe it is happening somewhere in this portion of the code.
    Code:
     //reset the timoutCounter;
        timeoutCounter = 0;
        
        //send the rd_pos command to have the AMT20 begin obtaining the current position
        data = SPIWrite(rd_pos);
      
        //we need to send nop commands while the encoder processes the current position. We
        //will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
        while (data != rd_pos && timeoutCounter++ < timoutLimit)
        {
          data = SPIWrite(nop);
        }
      
      
        if (timeoutCounter < timoutLimit) //rd_pos echo received
        {
          //We received the rd_pos echo which means the next two bytes are the current encoder position.
          //Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.
      
          //Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
          //shift it left 8 bits to make room for the lower byte.
          currentPosition = (SPIWrite(nop)& 0x0F) << 8;
      
          //OR the next byte with the current position
          currentPosition |= SPIWrite(nop);
        }
        else //timeout reached
        {
          //This means we had a problem with the encoder, most likely a lost connection. For our
          //purposes we will alert the user via the serial connection, and then stay here forever.
      
          Serial.write("Error obtaining position.\n");
          Serial.write("Reset Arduino to restart program.\n");
          
          while(true);
        }
    When I comment out this section, the program runs and prints to the serial monitor, but all values are zero.

    Here is my code thus far:
    Code:
    /*
     * AMT20_SPI_Sample_Code.ino
     * Company: CUI Inc.
     * Author: Jason Kelly
     * Version: 1.0.0.0
     * Date: August 8, 2016
     * 
     * This sample code can be used with the Arduino Uno to control the AMT20 encoder.
     * It uses SPI to control the encoder and the the Arduino UART to report back to the PC
     * via the Arduino Serial Monitor. Code can be modified for any Arduino with an SPI bus.
     * For more information or assistance contact CUI Inc for support.
     * 
     * After uploading code to Arduino UNO open the open the Serial Monitor under the Tools 
     * menu and set the baud rate to 115200 to view the serial stream the position from the AMT20.
     * 
     * Arduino Pin Connections
     * SPI Chip Select: Pin 10 (Green/Red)
     * SPI MOSI:        Pin 11 (Red/White)
     * SPI MISO:        Pin 12 (Brown/Black)
     * SPI Clock (SCK): Pin 13 (Orange/Black)
     * 
     * AMT20 Pin Connections
     * SPI Clock (SCK):       Pin 5
     * SPI MOSI:              Pin 7
     * SPI MISO:              PIN 3
     * SPI Chip Select (CSB): Pin 2
     * Vdd (5V):              Pin 6 (Red/Black)
     * GND:                   Pin 4 (Black/Red)
     * 
     * 
     * This is free and unencumbered software released into the public domain.
     * Anyone is free to copy, modify, publish, use, compile, sell, or
     * distribute this software, either in source code form or as a compiled
     * binary, for any purpose, commercial or non-commercial, and by any
     * means.
     * 
     * In jurisdictions that recognize copyright laws, the author or authors
     * of this software dedicate any and all copyright interest in the
     * software to the public domain. We make this dedication for the benefit
     * of the public at large and to the detriment of our heirs and
     * successors. We intend this dedication to be an overt act of
     * relinquishment in perpetuity of all present and future rights to this
     * software under copyright law.
     * 
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     */
    
    //include SPI library
    #include <SPI.h>
    
    //this is the serial baud rate for talking to the Arduino
    //#define baudRate 115200
    
    //this will be our SPI timout limit
    #define timoutLimit 100
    
    //SPI commands used by the AMT20
    #define nop 0x00            //no operation
    #define rd_pos 0x10         //read position
    #define set_zero_point 0x70 //set zero point
    
    //set the chip select pin for the AMT20
    const int CS = 10;
    
    //Arduino uses a setup function for all program initializations
    void setup() 
    {
      //Initialize the UART serial connection
        Serial.begin(115200);
        SPI.begin();
        while (!Serial && (millis() < 3000));
    
      //Set I/O mode of all SPI pins.
      pinMode(SCK, OUTPUT);
      pinMode(MOSI, OUTPUT);
      pinMode(MISO, INPUT);
      pinMode(CS, OUTPUT);
      pinMode(1, OUTPUT);
    
      //Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
      //For our settings we will use a clock rate of 500kHz, and the standard SPI settings
      //of MSB First and SPI Mode 0
      
      Serial.println("Before SPI.beginTransaction");
      //SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
      Serial.println("After SPI.beginTransaction");
      
      //Using SPI.beginTransaction seems to require explicitly setting the beginning state
      //of the CS pin as opposed to the SPI.begin() function that does this for us.
      digitalWrite(CS, HIGH);
    
    
      
    }
    
    //After the setup() method this loop gets entered and is the main() function for our program
    void loop() 
    {
      
      uint8_t data;               //this will hold our returned data from the AMT20
      uint8_t timeoutCounter;     //our timeout incrementer
      uint16_t currentPosition;   //this 16 bit variable will hold our 12-bit position
    
      while(true)
      {
        //reset the timoutCounter;
        timeoutCounter = 0;
        
        //send the rd_pos command to have the AMT20 begin obtaining the current position
        data = SPIWrite(rd_pos);
      
        //we need to send nop commands while the encoder processes the current position. We
        //will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
        while (data != rd_pos && timeoutCounter++ < timoutLimit)
        {
          data = SPIWrite(nop);
        }
      
      
        if (timeoutCounter < timoutLimit) //rd_pos echo received
        {
          //We received the rd_pos echo which means the next two bytes are the current encoder position.
          //Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.
      
          //Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
          //shift it left 8 bits to make room for the lower byte.
          currentPosition = (SPIWrite(nop)& 0x0F) << 8;
      
          //OR the next byte with the current position
          currentPosition |= SPIWrite(nop);
        }
        else //timeout reached
        {
          //This means we had a problem with the encoder, most likely a lost connection. For our
          //purposes we will alert the user via the serial connection, and then stay here forever.
      
          Serial.write("Error obtaining position.\n");
          Serial.write("Reset Arduino to restart program.\n");
          
          while(true);
        }
    
        Serial.write("Current position: ");
        Serial.print(currentPosition, DEC); //current position in decimal
        Serial.write("\t 0x");
        Serial.print(currentPosition, HEX); //current position in hexidecimal
        Serial.write("\t 0b");
        Serial.print(currentPosition, BIN); //current position in binary
        Serial.write("\t DEG: ");
        Serial.print(currentPosition*0.087890625); //current position in degrees
        Serial.write("\n");
        
        analogWrite(1, currentPosition*0.0012207031);
        
        //Since we are displaying our position over the serial monitor we don't need updates that fast
        delay(300);
      }
    }
    
    //We will use this function to handle transmitting SPI commands in order to keep our code clear and concise.
    //It will return the byte received from SPI.transfer()
    uint8_t SPIWrite(uint8_t sendByte)
    {
      //holder for the received over SPI
      uint8_t data;
    
      //the AMT20 requires the release of the CS line after each byte
      SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
      digitalWrite(CS, LOW);
      data = SPI.transfer(sendByte);
      digitalWrite(CS, HIGH);
      SPI.endTransaction();
    
      //we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
      delayMicroseconds(10);
      
      return data;
    }

  12. #12
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    464
    When you say error, what sort of error? Is it the error message from your Serial.write, or some other error?

  13. #13
    Junior Member
    Join Date
    Oct 2021
    Posts
    8
    Sorry that was not the best phrasing. It is the error from my Serial.write.

  14. #14
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    464
    OK, I am afraid I won't be able to help you with that, I have never used SPI, so have no experience with it.
    Just a thought, it might be worth printing out the contents of data to see what is coming back, if anything.
    I might be tempted to put a Serial.print inside the while loop as a debug aid.

    EDIT: Did some reading and I think I read that the ports should be setup before calling SPI.begin.

    So try changing your setup routine like below.
    Code:
    void setup() 
    {
      //Initialize the UART serial connection
        Serial.begin(115200);
    //    SPI.begin();                           // Move from here to
        while (!Serial && (millis() < 3000));
    
      //Set I/O mode of all SPI pins.
      pinMode(SCK, OUTPUT);
      pinMode(MOSI, OUTPUT);
      pinMode(MISO, INPUT);
      pinMode(CS, OUTPUT);
      pinMode(1, OUTPUT);
    
      //Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
      //For our settings we will use a clock rate of 500kHz, and the standard SPI settings
      //of MSB First and SPI Mode 0
      
      Serial.println("Before SPI.beginTransaction");
      //SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
      Serial.println("After SPI.beginTransaction");
      
      //Using SPI.beginTransaction seems to require explicitly setting the beginning state
      //of the CS pin as opposed to the SPI.begin() function that does this for us.
      digitalWrite(CS, HIGH);
    
      SPI.begin();                           // TO HERE.
      
    }
    EDIT2:
    I don't know whether the 3.2 is being too fast but the DataSheet recommends
    It is recommended that the master leave a 20 μs delay between reads to avoid extending the read time by forcing wait sequences.
    It might be worth trying a small delay between read attempts.
    Last edited by BriComp; 10-26-2021 at 06:17 PM.

  15. #15
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    696
    Please have a look at the "Example using transactions" on this page.
    No need to set the SPI pins MOSI, MISO & CLK. The only SPI pin you have to take of yourself is the SlaveSelect aka ChipSelect pin.

    Paul

  16. #16
    Junior Member
    Join Date
    Oct 2021
    Posts
    8
    So a quick update for anyone following this thread.

    So after messing around with adding delays around my code where I thought it might need them. I just ended up slowing down the clock speed of my Teensy 3.2 to that of an Arduino Uno(16MHz). This does work, however the code does not write to the serial monitor, which I believe is because at a CPU speed of 16MHz, it also states no USB.

    I know this probably isn't the best solution, but it will work for me and hopefully others down the road.

    Thanks to everyone who posted on this thread giving suggestions.

    Here is my final code:
    Code:
    /*
     * AMT20_SPI_Sample_Code.ino
     * Company: CUI Inc.
     * Author: Jason Kelly
     * Version: 1.0.0.0
     * Date: August 8, 2016
     * 
     * This sample code can be used with the Arduino Uno to control the AMT20 encoder.
     * It uses SPI to control the encoder and the the Arduino UART to report back to the PC
     * via the Arduino Serial Monitor. Code can be modified for any Arduino with an SPI bus.
     * For more information or assistance contact CUI Inc for support.
     * 
     * After uploading code to Arduino UNO open the open the Serial Monitor under the Tools 
     * menu and set the baud rate to 115200 to view the serial stream the position from the AMT20.
     * 
     * Arduino Pin Connections
     * SPI Chip Select: Pin 10 (Green/Red)
     * SPI MOSI:        Pin 11 (Red/White)
     * SPI MISO:        Pin 12 (Brown/Black)
     * SPI Clock (SCK): Pin 13 (Orange/Black)
     * 
     * AMT20 Pin Connections
     * SPI Clock (SCK):       Pin 5
     * SPI MOSI:              Pin 7
     * SPI MISO:              PIN 3
     * SPI Chip Select (CSB): Pin 2
     * Vdd (5V):              Pin 6 (Red/Black)
     * GND:                   Pin 4 (Black/Red)
     * 
     * 
     * This is free and unencumbered software released into the public domain.
     * Anyone is free to copy, modify, publish, use, compile, sell, or
     * distribute this software, either in source code form or as a compiled
     * binary, for any purpose, commercial or non-commercial, and by any
     * means.
     * 
     * In jurisdictions that recognize copyright laws, the author or authors
     * of this software dedicate any and all copyright interest in the
     * software to the public domain. We make this dedication for the benefit
     * of the public at large and to the detriment of our heirs and
     * successors. We intend this dedication to be an overt act of
     * relinquishment in perpetuity of all present and future rights to this
     * software under copyright law.
     * 
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
     *
     *THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     */
    
    //include SPI library
    #include <SPI.h>
    
    //this is the serial baud rate for talking to the Arduino
    #define baudRate 115200
    
    //this will be our SPI timout limit
    #define timoutLimit 100
    
    //SPI commands used by the AMT20
    #define nop 0x00            //no operation
    #define rd_pos 0x10         //read position
    #define set_zero_point 0x70 //set zero point
    
    //set the chip select pin for the AMT20
    const int CS = 10;
    
    //Arduino uses a setup function for all program initializations
    void setup() 
    {
      //Initialize the UART serial connection
        Serial.begin(115200);
        while (!Serial && (millis() < 3000));
    
      //Set I/O mode of all SPI pins.
      pinMode(SCK, OUTPUT);
      pinMode(MOSI, OUTPUT);
      pinMode(MISO, INPUT);
      pinMode(CS, OUTPUT);
      pinMode(1, OUTPUT);
      pinMode(A14, OUTPUT);
    
      //Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
      //For our settings we will use a clock rate of 500kHz, and the standard SPI settings
      //of MSB First and SPI Mode 0
      
      //Serial.println("Before SPI.beginTransaction");
      //SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
      //Serial.println("After SPI.beginTransaction");
      
      //Using SPI.beginTransaction seems to require explicitly setting the beginning state
      //of the CS pin as opposed to the SPI.begin() function that does this for us.
      digitalWrite(CS, HIGH);
      SPI.begin();
    
      
    }
    
    //After the setup() method this loop gets entered and is the main() function for our program
    void loop() 
    {
      
      uint8_t data;               //this will hold our returned data from the AMT20
      uint8_t timeoutCounter;     //our timeout incrementer
      uint16_t currentPosition;   //this 16 bit variable will hold our 12-bit position
      //uint16_t analogPosition ;
      while(true)
      {
        //reset the timoutCounter;
        timeoutCounter = 0;
        
        //send the rd_pos command to have the AMT20 begin obtaining the current position
        data = SPIWrite(rd_pos);
        
        //we need to send nop commands while the encoder processes the current position. We
        //will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
        while (data != rd_pos && timeoutCounter++ < timoutLimit)
        {
          data = SPIWrite(nop);
        }
      
      
        if (timeoutCounter < timoutLimit) //rd_pos echo received
        {
          //We received the rd_pos echo which means the next two bytes are the current encoder position.
          //Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.
      
          //Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
          //shift it left 8 bits to make room for the lower byte.
          currentPosition = (SPIWrite(nop)& 0x0F) << 8;
    
          //OR the next byte with the current position
          currentPosition |= SPIWrite(nop);
        }
        else //timeout reached
        {
          //This means we had a problem with the encoder, most likely a lost connection. For our
          //purposes we will alert the user via the serial connection, and then stay here forever.
      
          Serial.write("Error obtaining position.\n");
          Serial.write("Reset Arduino to restart program.\n");
          
          while(true);
        }
    
        Serial.write("Current position: ");
        Serial.print(currentPosition, DEC); //current position in decimal
        Serial.write("\t 0x");
        Serial.print(currentPosition, HEX); //current position in hexidecimal
        Serial.write("\t 0b");
        Serial.print(currentPosition, BIN); //current position in binary
        Serial.write("\t DEG: ");
        Serial.print(currentPosition*0.087890625); //current position in degrees
        Serial.write("\n");
        //analogPosition=currentPosition*255/4096;
        analogWrite(A14, int(currentPosition*255/4096));
        
        //Since we are displaying our position over the serial monitor we don't need updates that fast
        delay(300);
      }
    }
    
    //We will use this function to handle transmitting SPI commands in order to keep our code clear and concise.
    //It will return the byte received from SPI.transfer()
    uint8_t SPIWrite(uint8_t sendByte)
    {
      //holder for the received over SPI
      uint8_t data;
    
      //the AMT20 requires the release of the CS line after each byte
      SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
      digitalWrite(CS, LOW);
      data = SPI.transfer(sendByte);
      digitalWrite(CS, HIGH);
      SPI.endTransaction();
    
      //we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
      delayMicroseconds(10);
      
      return data;
    }

  17. #17
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    464
    You might try NOT setting the SPI pins using pinMode as shown below.
    Code:
    /*
     * AMT20_SPI_Sample_Code.ino
     * Company: CUI Inc.
     * Author: Jason Kelly
     * Version: 1.0.0.0
     * Date: August 8, 2016
     *
     * This sample code can be used with the Arduino Uno to control the AMT20 encoder.
     * It uses SPI to control the encoder and the the Arduino UART to report back to the PC
     * via the Arduino Serial Monitor. Code can be modified for any Arduino with an SPI bus.
     * For more information or assistance contact CUI Inc for support.
     *
     * After uploading code to Arduino UNO open the open the Serial Monitor under the Tools
     * menu and set the baud rate to 115200 to view the serial stream the position from the AMT20.
     *
     * Arduino Pin Connections
     * SPI Chip Select: Pin 10 (Green/Red)
     * SPI MOSI:        Pin 11 (Red/White)
     * SPI MISO:        Pin 12 (Brown/Black)
     * SPI Clock (SCK): Pin 13 (Orange/Black)
     *
     * AMT20 Pin Connections
     * SPI Clock (SCK):       Pin 5
     * SPI MOSI:              Pin 7
     * SPI MISO:              PIN 3
     * SPI Chip Select (CSB): Pin 2
     * Vdd (5V):              Pin 6 (Red/Black)
     * GND:                   Pin 4 (Black/Red)
     *
     *
     * This is free and unencumbered software released into the public domain.
     * Anyone is free to copy, modify, publish, use, compile, sell, or
     * distribute this software, either in source code form or as a compiled
     * binary, for any purpose, commercial or non-commercial, and by any
     * means.
     *
     * In jurisdictions that recognize copyright laws, the author or authors
     * of this software dedicate any and all copyright interest in the
     * software to the public domain. We make this dedication for the benefit
     * of the public at large and to the detriment of our heirs and
     * successors. We intend this dedication to be an overt act of
     * relinquishment in perpetuity of all present and future rights to this
     * software under copyright law.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
     *
     *THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     */
    
     //include SPI library
    #include <SPI.h>
    
    //this is the serial baud rate for talking to the Arduino
    #define baudRate 115200
    
    //this will be our SPI timout limit
    #define timoutLimit 100
    
    //SPI commands used by the AMT20
    #define nop 0x00            //no operation
    #define rd_pos 0x10         //read position
    #define set_zero_point 0x70 //set zero point
    
    //set the chip select pin for the AMT20
    const int CS = 10;
    
    //Arduino uses a setup function for all program initializations
    void setup()
    {
        //Initialize the UART serial connection
        Serial.begin(115200);
        while (!Serial && (millis() < 3000));
    
        //Set I/O mode of all SPI pins.
    //    pinMode(SCK, OUTPUT);         NO NEED
    //    pinMode(MOSI, OUTPUT);        TO SET
    //    pinMode(MISO, INPUT);         THESE PINS
        pinMode(CS, OUTPUT);
        pinMode(1, OUTPUT);
        pinMode(A14, OUTPUT);
    
        //Initialize SPI using the SPISettings(speedMaxium, dataOrder, dataAMode) function
        //For our settings we will use a clock rate of 500kHz, and the standard SPI settings
        //of MSB First and SPI Mode 0
    
        //Serial.println("Before SPI.beginTransaction");
        //SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
        //Serial.println("After SPI.beginTransaction");
    
        //Using SPI.beginTransaction seems to require explicitly setting the beginning state
        //of the CS pin as opposed to the SPI.begin() function that does this for us.
        digitalWrite(CS, HIGH);
        SPI.begin();
    
    
    }
    
    //After the setup() method this loop gets entered and is the main() function for our program
    void loop()
    {
    
        uint8_t data;               //this will hold our returned data from the AMT20
        uint8_t timeoutCounter;     //our timeout incrementer
        uint16_t currentPosition;   //this 16 bit variable will hold our 12-bit position
        //uint16_t analogPosition ;
        while (true)
        {
            //reset the timoutCounter;
            timeoutCounter = 0;
    
            //send the rd_pos command to have the AMT20 begin obtaining the current position
            data = SPIWrite(rd_pos);
    
            //we need to send nop commands while the encoder processes the current position. We
            //will keep sending them until the AMT20 echos the rd_pos command, or our timeout is reached.
            while (data != rd_pos && timeoutCounter++ < timoutLimit)
            {
                data = SPIWrite(nop);
            }
    
    
            if (timeoutCounter < timoutLimit) //rd_pos echo received
            {
                //We received the rd_pos echo which means the next two bytes are the current encoder position.
                //Since the AMT20 is a 12 bit encoder we will throw away the upper 4 bits by masking.
    
                //Obtain the upper position byte. Mask it since we only need it's lower 4 bits, and then
                //shift it left 8 bits to make room for the lower byte.
                currentPosition = (SPIWrite(nop) & 0x0F) << 8;
    
                //OR the next byte with the current position
                currentPosition |= SPIWrite(nop);
            }
            else //timeout reached
            {
                //This means we had a problem with the encoder, most likely a lost connection. For our
                //purposes we will alert the user via the serial connection, and then stay here forever.
    
                Serial.write("Error obtaining position.\n");
                Serial.write("Reset Arduino to restart program.\n");
    
                while (true);
            }
    
            Serial.write("Current position: ");
            Serial.print(currentPosition, DEC); //current position in decimal
            Serial.write("\t 0x");
            Serial.print(currentPosition, HEX); //current position in hexidecimal
            Serial.write("\t 0b");
            Serial.print(currentPosition, BIN); //current position in binary
            Serial.write("\t DEG: ");
            Serial.print(currentPosition * 0.087890625); //current position in degrees
            Serial.write("\n");
            //analogPosition=currentPosition*255/4096;
            analogWrite(A14, int(currentPosition * 255 / 4096));
    
            //Since we are displaying our position over the serial monitor we don't need updates that fast
            delay(300);
        }
    }
    
    //We will use this function to handle transmitting SPI commands in order to keep our code clear and concise.
    //It will return the byte received from SPI.transfer()
    uint8_t SPIWrite(uint8_t sendByte)
    {
        //holder for the received over SPI
        uint8_t data;
    
        //the AMT20 requires the release of the CS line after each byte
        SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
        digitalWrite(CS, LOW);
        data = SPI.transfer(sendByte);
        digitalWrite(CS, HIGH);
        SPI.endTransaction();
    
        //we will delay here to prevent the AMT20 from having to prioritize SPI over obtaining our position
        delayMicroseconds(10);
    
        return data;
    }

  18. #18
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    696
    @Colt469198, since the encoder works OK with an Arduino Uno, I wonder if the issues you see are caused by the fact that the Teensy 3.2 SPI MOSI and SS pins are outputting at 3V3 levels. The encoder is a 5V device...

    You could consider a different option with this encoder though. According to the datasheet the quadrature outputs are also available on the connector of the encoder. Together with the Teensy Encoder library, this may be a viable solution?

    Paul

Posting Permissions

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