├── ino.ini ├── README.md ├── .gitignore ├── src └── sketch.ino ├── LICENSE └── lib └── AS5048A ├── AS5048A.h └── AS5048A.cpp /ino.ini: -------------------------------------------------------------------------------- 1 | board-model = uno 2 | serial-port = /dev/ttyACM0 3 | baud-rate = 19200 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AS5048A-Arduino 2 | =============== 3 | 4 | A simple SPI library to interface with Austria Microsystem's AS5048A angle sensor with an Arduino. 5 | 6 | The sensor should be connected to the hardware SPI pins (MISO, MOSI, SCK). The CS pin can be connected to any GPIO pin but should be passed to the constructor. 7 | 8 | The angle sensor is described in more detail [here](zoetrope.io/AS5048) 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | #Vim 32 | *.swp 33 | *.swo 34 | -------------------------------------------------------------------------------- /src/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | AS5048A angleSensor(10); 5 | 6 | void setup() 7 | { 8 | Serial.begin(19200); 9 | angleSensor.init(); 10 | } 11 | 12 | void loop() 13 | { 14 | delay(1000); 15 | 16 | word val = angleSensor.getRawRotation(); 17 | Serial.print("Got rotation of: 0x"); 18 | Serial.println(val, HEX); 19 | Serial.print("State: "); 20 | angleSensor.printState(); 21 | Serial.print("Errors: "); 22 | Serial.println(angleSensor.getErrors()); 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /lib/AS5048A/AS5048A.h: -------------------------------------------------------------------------------- 1 | #ifndef as5048_h 2 | #define as5048_h 3 | #define LIBRARY_VERSION 1.0.1 4 | 5 | #include 6 | 7 | class AS5048A{ 8 | 9 | bool errorFlag; 10 | byte _cs; 11 | byte cs; 12 | byte dout; 13 | byte din; 14 | byte clk; 15 | word position; 16 | word transaction(word data); 17 | 18 | SPISettings settings; 19 | 20 | public: 21 | 22 | /** 23 | * Constructor 24 | */ 25 | AS5048A(byte arg_cs); 26 | 27 | /** 28 | * Initialiser 29 | * Sets up the SPI interface 30 | */ 31 | void init(); 32 | 33 | /** 34 | * Closes the SPI connection 35 | */ 36 | void close(); 37 | 38 | /* 39 | * Read a register from the sensor 40 | * Takes the address of the register as a 16 bit word 41 | * Returns the value of the register 42 | */ 43 | word read(word registerAddress); 44 | 45 | /* 46 | * Write to a register 47 | * Takes the 16-bit address of the target register and the 16 bit word of data 48 | * to be written to that register 49 | * Returns the value of the register after the write has been performed. This 50 | * is read back from the sensor to ensure a sucessful write. 51 | */ 52 | word write(word registerAddress, word data); 53 | 54 | /** 55 | * Get the rotation of the sensor relative to the zero position. 56 | * 57 | * @return {int} between -2^13 and 2^13 58 | */ 59 | int getRotation(); 60 | 61 | /** 62 | * Returns the raw angle directly from the sensor 63 | */ 64 | word getRawRotation(); 65 | 66 | 67 | /** 68 | * returns the value of the state register 69 | * @return 16 bit word containing flags 70 | */ 71 | word getState(); 72 | 73 | /** 74 | * Print the diagnostic register of the sensor 75 | */ 76 | void printState(); 77 | 78 | /** 79 | * Returns the value used for Automatic Gain Control (Part of diagnostic 80 | * register) 81 | */ 82 | byte getGain(); 83 | 84 | /* 85 | * Get and clear the error register by reading it 86 | */ 87 | word getErrors(); 88 | 89 | /* 90 | * Set the zero position 91 | */ 92 | void setZeroPosition(word arg_position); 93 | 94 | /* 95 | * Returns the current zero position 96 | */ 97 | word getZeroPosition(); 98 | 99 | /* 100 | * Check if an error has been encountered. 101 | */ 102 | bool error(); 103 | 104 | private: 105 | 106 | byte spiCalcEvenParity(word); 107 | }; 108 | #endif 109 | -------------------------------------------------------------------------------- /lib/AS5048A/AS5048A.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | 3 | #include 4 | 5 | //#define AS5048A_DEBUG 6 | 7 | const int AS5048A_CLEAR_ERROR_FLAG = 0x0001; 8 | const int AS5048A_PROGRAMMING_CONTROL = 0x0003; 9 | const int AS5048A_OTP_REGISTER_ZERO_POS_HIGH = 0x0016; 10 | const int AS5048A_OTP_REGISTER_ZERO_POS_LOW = 0x0017; 11 | const int AS5048A_DIAG_AGC = 0x3FFD; 12 | const int AS5048A_MAGNITUDE = 0x3FFE; 13 | const int AS5048A_ANGLE = 0x3FFF; 14 | 15 | /** 16 | * Constructor 17 | */ 18 | AS5048A::AS5048A(byte arg_cs){ 19 | _cs = arg_cs; 20 | errorFlag = false; 21 | position = 0; 22 | } 23 | 24 | 25 | /** 26 | * Initialiser 27 | * Sets up the SPI interface 28 | */ 29 | void AS5048A::init(){ 30 | // 1MHz clock (AMS should be able to accept up to 10MHz) 31 | settings = SPISettings(1000000, MSBFIRST, SPI_MODE1); 32 | 33 | //setup pins 34 | pinMode(_cs, OUTPUT); 35 | 36 | //SPI has an internal SPI-device counter, it is possible to call "begin()" from different devices 37 | SPI.begin(); 38 | } 39 | 40 | /** 41 | * Closes the SPI connection 42 | * SPI has an internal SPI-device counter, for each init()-call the close() function must be called exactly 1 time 43 | */ 44 | void AS5048A::close(){ 45 | SPI.end(); 46 | } 47 | 48 | /** 49 | * Utility function used to calculate even parity of word 50 | */ 51 | byte AS5048A::spiCalcEvenParity(word value){ 52 | byte cnt = 0; 53 | byte i; 54 | 55 | for (i = 0; i < 16; i++) 56 | { 57 | if (value & 0x1) 58 | { 59 | cnt++; 60 | } 61 | value >>= 1; 62 | } 63 | return cnt & 0x1; 64 | } 65 | 66 | 67 | 68 | /** 69 | * Get the rotation of the sensor relative to the zero position. 70 | * 71 | * @return {int} between -2^13 and 2^13 72 | */ 73 | int AS5048A::getRotation(){ 74 | word data; 75 | int rotation; 76 | 77 | data = AS5048A::getRawRotation(); 78 | rotation = (int)data - (int)position; 79 | if(rotation > 8191) rotation = -((0x3FFF)-rotation); //more than -180 80 | //if(rotation < -0x1FFF) rotation = rotation+0x3FFF; 81 | 82 | return rotation; 83 | } 84 | 85 | /** 86 | * Returns the raw angle directly from the sensor 87 | */ 88 | word AS5048A::getRawRotation(){ 89 | return AS5048A::read(AS5048A_ANGLE); 90 | } 91 | 92 | /** 93 | * returns the value of the state register 94 | * @return 16 bit word containing flags 95 | */ 96 | word AS5048A::getState(){ 97 | return AS5048A::read(AS5048A_DIAG_AGC); 98 | } 99 | 100 | /** 101 | * Print the diagnostic register of the sensor 102 | */ 103 | void AS5048A::printState(){ 104 | word data; 105 | 106 | data = AS5048A::getState(); 107 | if(AS5048A::error()){ 108 | Serial.print("Error bit was set!"); 109 | } 110 | Serial.println(data, BIN); 111 | } 112 | 113 | /** 114 | * Returns the value used for Automatic Gain Control (Part of diagnostic 115 | * register) 116 | */ 117 | byte AS5048A::getGain(){ 118 | word data = AS5048A::getState(); 119 | return (byte) data & 0xFF; 120 | } 121 | 122 | /* 123 | * Get and clear the error register by reading it 124 | */ 125 | word AS5048A::getErrors(){ 126 | return AS5048A::read(AS5048A_CLEAR_ERROR_FLAG); 127 | } 128 | 129 | /* 130 | * Set the zero position 131 | */ 132 | void AS5048A::setZeroPosition(word arg_position){ 133 | position = arg_position % 0x3FFF; 134 | } 135 | 136 | /* 137 | * Returns the current zero position 138 | */ 139 | word AS5048A::getZeroPosition(){ 140 | return position; 141 | } 142 | 143 | /* 144 | * Check if an error has been encountered. 145 | */ 146 | bool AS5048A::error(){ 147 | return errorFlag; 148 | } 149 | 150 | /* 151 | * Read a register from the sensor 152 | * Takes the address of the register as a 16 bit word 153 | * Returns the value of the register 154 | */ 155 | word AS5048A::read(word registerAddress){ 156 | word command = 0b0100000000000000; // PAR=0 R/W=R 157 | command = command | registerAddress; 158 | 159 | //Add a parity bit on the the MSB 160 | command |= ((word)spiCalcEvenParity(command)<<15); 161 | 162 | //Split the command into two bytes 163 | byte right_byte = command & 0xFF; 164 | byte left_byte = ( command >> 8 ) & 0xFF; 165 | 166 | #ifdef AS5048A_DEBUG 167 | Serial.print("Read (0x"); 168 | Serial.print(registerAddress, HEX); 169 | Serial.print(") with command: 0b"); 170 | Serial.println(command, BIN); 171 | #endif 172 | 173 | //SPI - begin transaction 174 | SPI.beginTransaction(settings); 175 | 176 | //Send the command 177 | digitalWrite(_cs, LOW); 178 | SPI.transfer(left_byte); 179 | SPI.transfer(right_byte); 180 | digitalWrite(_cs,HIGH); 181 | 182 | //Now read the response 183 | digitalWrite(_cs, LOW); 184 | left_byte = SPI.transfer(0x00); 185 | right_byte = SPI.transfer(0x00); 186 | digitalWrite(_cs, HIGH); 187 | 188 | //SPI - end transaction 189 | SPI.endTransaction(); 190 | 191 | #ifdef AS5048A_DEBUG 192 | Serial.print("Read returned: "); 193 | Serial.print(left_byte, BIN); 194 | Serial.print(" "); 195 | Serial.println(right_byte, BIN); 196 | #endif 197 | 198 | //Check if the error bit is set 199 | if (left_byte & 0x40) { 200 | Serial.println("Setting Error bit"); 201 | errorFlag = true; 202 | } 203 | else { 204 | errorFlag = false; 205 | } 206 | 207 | //Return the data, stripping the parity and error bits 208 | return (( ( left_byte & 0xFF ) << 8 ) | ( right_byte & 0xFF )) & ~0xC000; 209 | } 210 | 211 | 212 | /* 213 | * Write to a register 214 | * Takes the 16-bit address of the target register and the 16 bit word of data 215 | * to be written to that register 216 | * Returns the value of the register after the write has been performed. This 217 | * is read back from the sensor to ensure a sucessful write. 218 | */ 219 | word AS5048A::write(word registerAddress, word data) { 220 | 221 | word command = 0b0000000000000000; // PAR=0 R/W=W 222 | command |= registerAddress; 223 | 224 | //Add a parity bit on the the MSB 225 | command |= ((word)spiCalcEvenParity(command)<<15); 226 | 227 | //Split the command into two bytes 228 | byte right_byte = command & 0xFF; 229 | byte left_byte = ( command >> 8 ) & 0xFF; 230 | 231 | #ifdef AS5048A_DEBUG 232 | Serial.print("Write (0x"); 233 | Serial.print(registerAddress, HEX); 234 | Serial.print(") with command: 0b"); 235 | Serial.println(command, BIN); 236 | #endif 237 | 238 | //SPI - begin transaction 239 | SPI.beginTransaction(settings); 240 | 241 | //Start the write command with the target address 242 | digitalWrite(_cs, LOW); 243 | SPI.transfer(left_byte); 244 | SPI.transfer(right_byte); 245 | digitalWrite(_cs,HIGH); 246 | 247 | word dataToSend = 0b0000000000000000; 248 | dataToSend |= data; 249 | 250 | //Craft another packet including the data and parity 251 | dataToSend |= ((word)spiCalcEvenParity(dataToSend)<<15); 252 | right_byte = dataToSend & 0xFF; 253 | left_byte = ( dataToSend >> 8 ) & 0xFF; 254 | 255 | #ifdef AS5048A_DEBUG 256 | Serial.print("Sending data to write: "); 257 | Serial.println(dataToSend, BIN); 258 | #endif 259 | 260 | //Now send the data packet 261 | digitalWrite(_cs,LOW); 262 | SPI.transfer(left_byte); 263 | SPI.transfer(right_byte); 264 | digitalWrite(_cs,HIGH); 265 | 266 | //Send a NOP to get the new data in the register 267 | digitalWrite(_cs, LOW); 268 | left_byte =-SPI.transfer(0x00); 269 | right_byte = SPI.transfer(0x00); 270 | digitalWrite(_cs, HIGH); 271 | 272 | //SPI - end transaction 273 | SPI.endTransaction(); 274 | 275 | //Return the data, stripping the parity and error bits 276 | return (( ( left_byte & 0xFF ) << 8 ) | ( right_byte & 0xFF )) & ~0xC000; 277 | } 278 | --------------------------------------------------------------------------------