#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 /**************************************************** AMS 5600 class for Arduino platform Author: Tom Denton Date: 15 Dec 2014 File: AMS_5600.cpp Version 1.00 www.ams.com Description: This class has been designed to access the AMS 5600 “potuino” shield. *****************************************************/ // updated jan 2022 by isc - read two bytes together // datasheet: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf #include "Arduino.h" #include "AS5600.h" #include "Wire.h" /**************************************************** Method: AMS_5600 In: none Out: none Description: constructor class for AMS 5600 *****************************************************/ AMS_5600::AMS_5600() { } /* mode = 0, output PWM, mode = 1 output analog (full range from 0% to 100% between GND and VDD */ void AMS_5600::setOutPut(uint8_t mode) { int _conf_lo = _addr_conf+1; // lower byte address uint8_t config_status; config_status = readOneByte(_conf_lo); if (mode == 1) { config_status = config_status & 0xcf; } else { uint8_t config_status; config_status = readOneByte(_conf_lo); if (mode == 1) config_status = config_status & 0xcf; else config_status = config_status & 0xef; writeOneByte(_conf_lo, lowByte(config_status)); } } /**************************************************** Method: AMS_5600 In: none Out: i2c address of AMS 5600 Description: returns i2c address of AMS 5600 ****************************************************/ int AMS_5600::getAddress() { return _ams5600_Address; } /******************************************************* Method: setMaxAngle In: new maximum angle to set OR none Out: value of max angle register Description: sets a value in maximum angle register. If no value is provided, method will read position of magnet. Setting this register zeros out max position register. *******************************************************/ word AMS_5600::setMaxAngle(word newMaxAngle) { word _maxAngle; if (newMaxAngle == -1) _maxAngle = getRawAngle(); else _maxAngle = newMaxAngle; writeOneByte(_addr_mang, highByte(_maxAngle)); delay(2); writeOneByte(_addr_mang+1, lowByte(_maxAngle)); delay(2); word retVal = readTwoBytesSeparately(_addr_mang); return retVal; } /******************************************************* Method: getMaxAngle In: none Out: value of max angle register Description: gets value of maximum angle register. *******************************************************/ word AMS_5600::getMaxAngle() { return readTwoBytesSeparately(_addr_mang); } /******************************************************* Method: setStartPosition In: new start angle position Out: value of start position register Description: sets a value in start position register. If no value is provided, method will read position of magnet. *******************************************************/ word AMS_5600::setStartPosition(word startAngle) { word _rawStartAngle; if (startAngle == -1) _rawStartAngle = getRawAngle(); else _rawStartAngle = startAngle; writeOneByte(_addr_zpos, highByte(_rawStartAngle)); delay(2); writeOneByte(_addr_zpos+1, lowByte(_rawStartAngle)); delay(2); word _zPosition = readTwoBytesSeparately(_addr_zpos); return (_zPosition); } /******************************************************* Method: getStartPosition In: none Out: value of start position register Description: gets value of start position register. *******************************************************/ word AMS_5600::getStartPosition() { return readTwoBytesSeparately(_addr_zpos); } /******************************************************* Method: setEndtPosition In: new end angle position Out: value of end position register Description: sets a value in end position register. If no value is provided, method will read position of magnet. *******************************************************/ word AMS_5600::setEndPosition(word endAngle) { word _rawEndAngle; if (endAngle == -1) _rawEndAngle = getRawAngle(); else _rawEndAngle = endAngle; writeOneByte(_addr_mpos, highByte(_rawEndAngle)); delay(2); writeOneByte(_addr_mpos+1, lowByte(_rawEndAngle)); delay(2); word _mPosition = readTwoBytesSeparately(_addr_mpos); return (_mPosition); } /******************************************************* Method: getEndPosition In: none Out: value of end position register Description: gets value of end position register. *******************************************************/ word AMS_5600::getEndPosition() { word retVal = readTwoBytesSeparately(_addr_mpos); return retVal; } /******************************************************* Method: getRawAngle In: none Out: value of raw angle register Description: gets raw value of magnet position. start, end, and max angle settings do not apply *******************************************************/ word AMS_5600::getRawAngle() { return readTwoBytesTogether(_addr_raw_angle); } /******************************************************* Method: getScaledAngle In: none Out: value of scaled angle register Description: gets scaled value of magnet position. start, end, or max angle settings are used to determine value *******************************************************/ word AMS_5600::getScaledAngle() { return readTwoBytesTogether(_addr_angle); } /******************************************************* Method: detectMagnet In: none Out: 1 if magnet is detected, 0 if not Description: reads status register and examines the MH bit *******************************************************/ int AMS_5600::detectMagnet() { int magStatus; int retVal = 0; /*0 0 MD ML MH 0 0 0*/ /* MD high = magnet detected*/ /* ML high = AGC Maximum overflow, magnet to weak*/ /* MH high = AGC minimum overflow, Magnet to strong*/ magStatus = readOneByte(_addr_status); if (magStatus & 0x20) retVal = 1; return retVal; } /******************************************************* Method: getMagnetStrength In: none Out: 0 if no magnet is detected 1 if magnet is to weak 2 if magnet is just right 3 if magnet is to strong Description: reads status register andexamins the MH,ML,MD bits *******************************************************/ int AMS_5600::getMagnetStrength() { int magStatus; int retVal = 0; /*0 0 MD ML MH 0 0 0*/ /* MD high = magnet detected */ /* ML high = AGC Maximum overflow, magnet to weak*/ /* MH high = AGC minimum overflow, Magnet to strong*/ magStatus = readOneByte(_addr_status); if (detectMagnet() == 1) { retVal = 2; /* just right */ if (magStatus & 0x10) retVal = 1; /* too weak */ else if (magStatus & 0x08) retVal = 3; /* too strong */ } return retVal; } /******************************************************* Method: get Agc In: none Out: value of AGC register Description: gets value of AGC register. *******************************************************/ int AMS_5600::getAgc() { return readOneByte(_addr_agc); } /******************************************************* Method: getMagnitude In: none Out: value of magnitude register Description: gets value of magnitude register. *******************************************************/ word AMS_5600::getMagnitude() { return readTwoBytesTogether(_addr_magnitude); } /******************************************************* Method: getConf In: none Out: value of CONF register Description: gets value of CONF register. *******************************************************/ word AMS_5600::getConf() { return readTwoBytesSeparately(_addr_conf); } /******************************************************* Method: setConf In: value of CONF register Out: none Description: sets value of CONF register. *******************************************************/ void AMS_5600::setConf(word _conf) { writeOneByte(_addr_conf, highByte(_conf)); delay(2); writeOneByte(_addr_conf+1, lowByte(_conf)); delay(2); } /******************************************************* Method: getBurnCount In: none Out: value of zmco register Description: determines how many times chip has been permanently written to. *******************************************************/ int AMS_5600::getBurnCount() { return readOneByte(_addr_zmco); } /******************************************************* Method: burnAngle In: none Out: 1 success -1 no magnet -2 burn limit exceeded -3 start and end positions not set (useless burn) Description: burns start and end positions to chip. THIS CAN ONLY BE DONE 3 TIMES *******************************************************/ int AMS_5600::burnAngle() { word _zPosition = getStartPosition(); word _mPosition = getEndPosition(); word _maxAngle = getMaxAngle(); int retVal = 1; if (detectMagnet() == 1) { if (getBurnCount() < 3) { if ((_zPosition == 0) && (_mPosition == 0)) retVal = -3; else writeOneByte(_addr_burn, 0x80); } else retVal = -2; } else retVal = -1; return retVal; } /******************************************************* Method: burnMaxAngleAndConfig In: none Out: 1 success -1 burn limit exceeded -2 max angle is to small, must be at or above 18 degrees Description: burns max angle and config data to chip. THIS CAN ONLY BE DONE 1 TIME *******************************************************/ int AMS_5600::burnMaxAngleAndConfig() { word _maxAngle = getMaxAngle(); int retVal = 1; if (getBurnCount() == 0) { if (_maxAngle * 0.087 < 18) retVal = -2; else writeOneByte(_addr_burn, 0x40); } else retVal = -1; return retVal; } /******************************************************* Method: readOneByte In: register to read Out: data read from i2c Description: reads one byte register from i2c *******************************************************/ int AMS_5600::readOneByte(int in_adr) { int retVal = -1; Wire.beginTransmission(_ams5600_Address); Wire.write(in_adr); Wire.endTransmission(); Wire.requestFrom(_ams5600_Address, (uint8_t) 1); /* while (Wire.available() == 0) ; retVal = Wire.read(); */ if(Wire.available() >= 1){ retVal = Wire.read(); } return retVal; } /******************************************************* Method: readTwoBytes In: two registers to read Out: data read from i2c as a word Description: reads two bytes register from i2c *******************************************************/ word AMS_5600::readTwoBytesTogether(int addr_in) { // use only for Angle, Raw Angle and Magnitude // read 2 bytes together to prevent getting inconsistent // data while the encoder is moving // according to the datasheet the address is automatically incremented // but only for Angle, Raw Angle and Magnitude // the title says it's auto, but the paragraph after it // says it does NOT // tested and it does auto increment // PAGE 13: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf // Automatic Increment of the Address Pointer for ANGLE, RAW ANGLE and MAGNITUDE Registers // These are special registers which suppress the automatic // increment of the address pointer on reads, so a re-read of these // registers requires no I²C write command to reload the address // pointer. This special treatment of the pointer is effective only if // the address pointer is set to the high byte of the register. /* Read 2 Bytes */ Wire.beginTransmission(_ams5600_Address); Wire.write(addr_in); Wire.endTransmission(); Wire.requestFrom(_ams5600_Address, (uint8_t) 2); /* while (Wire.available() < 2) ; int highByte = Wire.read(); int lowByte = Wire.read(); */ int highByte = 0; int lowByte = 0; if (Wire.available() >= 2){ highByte = Wire.read(); lowByte = Wire.read(); } // in case newer version of IC used the same address to // store something else, get only the 3 bits //return ( ( highByte & 0b111 ) << 8 ) | lowByte; // but in case newer version has higher resolution // we're good to go return ( highByte << 8 ) | lowByte; } /******************************************************* Method: readTwoBytes In: two registers to read Out: data read from i2c as a word Description: reads two bytes register from i2c *******************************************************/ word AMS_5600::readTwoBytesSeparately(int addr_in) { int highByte = readOneByte(addr_in ); int lowByte = readOneByte(addr_in+1); return ( highByte << 8 ) | lowByte; } /******************************************************* Method: writeOneByte In: address and data to write Out: none Description: writes one byte to a i2c register *******************************************************/ void AMS_5600::writeOneByte(int adr_in, int dat_in) { Wire.beginTransmission(_ams5600_Address); Wire.write(adr_in); Wire.write(dat_in); Wire.endTransmission(); } /********** END OF AMS 5600 CALSS *****************/ #endif