0% found this document useful (0 votes)
15 views6 pages

Arduino AMT22 Encoder SPI Code

This document contains sample code for controlling the AMT22 encoder using an Arduino Uno via SPI communication. It includes setup instructions, pin connections, and functions for obtaining encoder position and handling errors. The code is released into the public domain and is provided without warranty.

Uploaded by

deepanryan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views6 pages

Arduino AMT22 Encoder SPI Code

This document contains sample code for controlling the AMT22 encoder using an Arduino Uno via SPI communication. It includes setup instructions, pin connections, and functions for obtaining encoder position and handling errors. The code is released into the public domain and is provided without warranty.

Uploaded by

deepanryan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

/*

* AMT22_SPI_Sample_Code.ino
* Company: CUI Inc.
* Author: Jason Kelly
* Version: [Link]
* Date: August 20, 2019
*
* This sample code can be used with the Arduino Uno to control the AMT22 encoder.
* It uses SPI to control the encoder and the the Arduino UART to report back to
the PC
* via the Arduino Serial Monitor.
* 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 AMT22.
*
* Arduino Pin Connections
* SPI Chip Select Enc 0: Pin 2
* SPI Chip Select Enc 1: Pin 3
* SPI MOSI Pin 11
* SPI MISO Pin 12
* SPI SCLK: Pin 13
*
*
* AMT22 Pin Connections
* Vdd (5V): Pin 1
* SPI SCLK: Pin 2
* SPI MOSI: Pin 3
* GND: Pin 4
* SPI MISO: Pin 5
* SPI Chip Select: Pin 6
*
*
* 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 the SPI library for the arduino boards */
#include <SPI.h>

/* Serial rates for UART */


#define BAUDRATE 115200

/* SPI commands */
#define AMT22_NOP 0x00
#define AMT22_RESET 0x60
#define AMT22_ZERO 0x70

/* Define special ascii characters */


#define NEWLINE 0x0A
#define TAB 0x09

/* We will use these define macros so we can write code once compatible with 12 or
14 bit encoders */
#define RES12 12
#define RES14 14

/* SPI pins */
#define ENC_0 2
#define ENC_1 3
#define SPI_MOSI 51
#define SPI_MISO 50
#define SPI_SCLK 52

void setup()
{
//Set the modes for the SPI IO
pinMode(SPI_SCLK, OUTPUT);
pinMode(SPI_MOSI, OUTPUT);
pinMode(SPI_MISO, INPUT);
pinMode(ENC_0, OUTPUT);
pinMode(ENC_1, OUTPUT);

//Initialize the UART serial connection for debugging


[Link](BAUDRATE);

//Get the CS line high which is the default inactive state


digitalWrite(ENC_0, HIGH);
digitalWrite(ENC_1, HIGH);

//set the clockrate. Uno clock rate is 16Mhz, divider of 32 gives 500 kHz.
//500 kHz is a good speed for our test environment
//[Link](SPI_CLOCK_DIV2); // 8 MHz
//[Link](SPI_CLOCK_DIV4); // 4 MHz
//[Link](SPI_CLOCK_DIV8); // 2 MHz
//[Link](SPI_CLOCK_DIV16); // 1 MHz
[Link](SPI_CLOCK_DIV32); // 500 kHz
//[Link](SPI_CLOCK_DIV64); // 250 kHz
//[Link](SPI_CLOCK_DIV128); // 125 kHz

//start SPI bus


[Link]();
}

void loop()
{
//create a 16 bit variable to hold the encoders position
uint16_t encoderPosition;
//let's also create a variable where we can count how many times we've tried to
obtain the position in case there are errors
uint8_t attempts;

//if you want to set the zero position before beggining uncomment the following
function call
//setZeroSPI(ENC_0);
//setZeroSPI(ENC_1);

//once we enter this loop we will run forever


while(1)
{
//set attemps counter at 0 so we can try again if we get bad position
attempts = 0;

//this function gets the encoder position and returns it as a uint16_t


//send the function either res12 or res14 for your encoders resolution
encoderPosition = getPositionSPI(ENC_0, RES14);

//if the position returned was 0xFFFF we know that there was an error
calculating the checksum
//make 3 attempts for position. we will pre-increment attempts because we'll
use the number later and want an accurate count
while (encoderPosition == 0xFFFF && ++attempts < 3)
{
encoderPosition = getPositionSPI(ENC_0, RES14); //try again
}

if (encoderPosition == 0xFFFF) //position is bad, let the user know how many
times we tried
{
[Link]("Encoder 0 error. Attempts: ");
[Link](attempts, DEC); //print out the number in decimal format.
attempts - 1 is used since we post incremented the loop
[Link](NEWLINE);
}
else //position was good, print to serial stream
{

[Link]("Encoder 0: ");
[Link](encoderPosition, DEC); //print the position in decimal format
[Link](NEWLINE);
}

//////////again for second encoder//////////////////////////////

//set attemps counter at 0 so we can try again if we get bad position


attempts = 0;

//this function gets the encoder position and returns it as a uint16_t


//send the function either res12 or res14 for your encoders resolution
encoderPosition = getPositionSPI(ENC_1, RES14);

//if the position returned was 0xFFFF we know that there was an error
calculating the checksum
//make 3 attempts for position. we will pre-increment attempts because we'll
use the number later and want an accurate count
while (encoderPosition == 0xFFFF && ++attempts < 3)
{
encoderPosition = getPositionSPI(ENC_1, RES14); //try again
}

if (encoderPosition == 0xFFFF) //position is bad, let the user know how many
times we tried
{
[Link]("Encoder 1 error. Attempts: ");
[Link](attempts, DEC); //print out the number in decimal format.
attempts - 1 is used since we post incremented the loop
[Link](NEWLINE);
}
else //position was good, print to serial stream
{

[Link]("Encoder 1: ");
[Link](encoderPosition, DEC); //print the position in decimal format
[Link](NEWLINE);
}

//For the purpose of this demo we don't need the position returned that quickly
so let's wait a half second between reads
//delay() is in milliseconds
delay(500);
}
}

/*
* This function gets the absolute position from the AMT22 encoder using the SPI
bus. The AMT22 position includes 2 checkbits to use
* for position verification. Both 12-bit and 14-bit encoders transfer position via
two bytes, giving 16-bits regardless of resolution.
* For 12-bit encoders the position is left-shifted two bits, leaving the right two
bits as zeros. This gives the impression that the encoder
* is actually sending 14-bits, when it is actually sending 12-bit values, where
every number is multiplied by 4.
* This function takes the pin number of the desired device as an input
* This funciton expects res12 or res14 to properly format position responses.
* Error values are returned as 0xFFFF
*/
uint16_t getPositionSPI(uint8_t encoder, uint8_t resolution)
{
uint16_t currentPosition; //16-bit response from encoder
bool binaryArray[16]; //after receiving the position we will populate
this array and use it for calculating the checksum

//get first byte which is the high byte, shift it 8 bits. don't release line for
the first byte
currentPosition = spiWriteRead(AMT22_NOP, encoder, false) << 8;

//this is the time required between bytes as specified in the datasheet.


//We will implement that time delay here, however the arduino is not the fastest
device so the delay
//is likely inherantly there already
delayMicroseconds(3);

//OR the low byte with the currentPosition variable. release line after second
byte
currentPosition |= spiWriteRead(AMT22_NOP, encoder, true);

//run through the 16 bits of position and put each bit into a slot in the array
so we can do the checksum calculation
for(int i = 0; i < 16; i++) binaryArray[i] = (0x01) & (currentPosition >> (i));

//using the equation on the datasheet we can calculate the checksums and then
make sure they match what the encoder sent
if ((binaryArray[15] == !(binaryArray[13] ^ binaryArray[11] ^ binaryArray[9] ^
binaryArray[7] ^ binaryArray[5] ^ binaryArray[3] ^ binaryArray[1]))
&& (binaryArray[14] == !(binaryArray[12] ^ binaryArray[10] ^
binaryArray[8] ^ binaryArray[6] ^ binaryArray[4] ^ binaryArray[2] ^
binaryArray[0])))
{
//we got back a good position, so just mask away the checkbits
currentPosition &= 0x3FFF;
}
else
{
currentPosition = 0xFFFF; //bad position
}

//If the resolution is 12-bits, and wasn't 0xFFFF, then shift position, otherwise
do nothing
if ((resolution == RES12) && (currentPosition != 0xFFFF)) currentPosition =
currentPosition >> 2;

return currentPosition;
}

/*
* This function does the SPI transfer. sendByte is the byte to transmit.
* Use releaseLine to let the spiWriteRead function know if it should release
* the chip select line after transfer.
* This function takes the pin number of the desired device as an input
* The received data is returned.
*/
uint8_t spiWriteRead(uint8_t sendByte, uint8_t encoder, uint8_t releaseLine)
{
//holder for the received over SPI
uint8_t data;

//set cs low, cs may already be low but there's no issue calling it again except
for extra time
setCSLine(encoder ,LOW);

//There is a minimum time requirement after CS goes low before data can be
clocked out of the encoder.
//We will implement that time delay here, however the arduino is not the fastest
device so the delay
//is likely inherantly there already
delayMicroseconds(3);

//send the command


data = [Link](sendByte);
delayMicroseconds(3); //There is also a minimum time after clocking that CS
should remain asserted before we release it
setCSLine(encoder, releaseLine); //if releaseLine is high set it high else it
stays low

return data;
}

/*
* This function sets the state of the SPI line. It isn't necessary but makes the
code more readable than having digitalWrite everywhere
* This function takes the pin number of the desired device as an input
*/
void setCSLine (uint8_t encoder, uint8_t csLine)
{
digitalWrite(encoder, csLine);
}

/*
* The AMT22 bus allows for extended commands. The first byte is 0x00 like a normal
position transfer, but the
* second byte is the command.
* This function takes the pin number of the desired device as an input
*/
void setZeroSPI(uint8_t encoder)
{
spiWriteRead(AMT22_NOP, encoder, false);

//this is the time required between bytes as specified in the datasheet.


//We will implement that time delay here, however the arduino is not the fastest
device so the delay
//is likely inherantly there already
delayMicroseconds(3);

spiWriteRead(AMT22_ZERO, encoder, true);


delay(250); //250 second delay to allow the encoder to reset
}

/*
* The AMT22 bus allows for extended commands. The first byte is 0x00 like a normal
position transfer, but the
* second byte is the command.
* This function takes the pin number of the desired device as an input
*/
void resetAMT22(uint8_t encoder)
{
spiWriteRead(AMT22_NOP, encoder, false);

//this is the time required between bytes as specified in the datasheet.


//We will implement that time delay here, however the arduino is not the fastest
device so the delay
//is likely inherantly there already
delayMicroseconds(3);

spiWriteRead(AMT22_RESET, encoder, true);

delay(250); //250 second delay to allow the encoder to start back up


}

You might also like