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

Status
Not open for further replies.
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/motion/rotary-encoders/absolute/modular/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;
}
 

Attachments

  • AMT20_SPI_Sample_Code_Uno_1.0.0.0.ino
    6.4 KB · Views: 23
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;
}
 
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;
}
 
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;
}
 
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;
}
 
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.
 
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.
 
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.
 
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:
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;
}
 
When you say error, what sort of error? Is it the error message from your Serial.write, or some other error?
 
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:
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
 
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;
}
 
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;
}
 
@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
 
Status
Not open for further replies.
Back
Top