GY-63_MS5611/libraries/AS5600/AS5600.cpp

536 lines
10 KiB
C++
Raw Normal View History

2022-05-29 16:07:48 -04:00
//
// FILE: AS56000.cpp
// AUTHOR: Rob Tillaart
2022-10-17 03:48:27 -04:00
// VERSION: 0.3.2
2022-05-29 16:07:48 -04:00
// PURPOSE: Arduino library for AS5600 magnetic rotation meter
// DATE: 2022-05-28
// URL: https://github.com/RobTillaart/AS5600
2022-09-01 05:31:32 -04:00
//
2022-10-17 03:48:27 -04:00
// HISTORY: see changelog.md
2022-05-29 16:07:48 -04:00
#include "AS5600.h"
// CONFIGURATION REGISTERS
2022-06-27 05:27:48 -04:00
const uint8_t AS5600_ZMCO = 0x00;
const uint8_t AS5600_ZPOS = 0x01; // + 0x02
const uint8_t AS5600_MPOS = 0x03; // + 0x04
const uint8_t AS5600_MANG = 0x05; // + 0x06
const uint8_t AS5600_CONF = 0x07; // + 0x08
2022-05-29 16:07:48 -04:00
// CONFIGURATION BIT MASKS - byte level
2022-06-27 05:27:48 -04:00
const uint8_t AS5600_CONF_POWER_MODE = 0x03;
const uint8_t AS5600_CONF_HYSTERESIS = 0x0C;
const uint8_t AS5600_CONF_OUTPUT_MODE = 0x30;
const uint8_t AS5600_CONF_PWM_FREQUENCY = 0xC0;
const uint8_t AS5600_CONF_SLOW_FILTER = 0x03;
const uint8_t AS5600_CONF_FAST_FILTER = 0x1C;
const uint8_t AS5600_CONF_WATCH_DOG = 0x20;
2022-05-29 16:07:48 -04:00
// UNKNOWN REGISTERS 0x09-0x0A
// OUTPUT REGISTERS
2022-06-27 05:27:48 -04:00
const uint8_t AS5600_RAW_ANGLE = 0x0C; // + 0x0D
const uint8_t AS5600_ANGLE = 0x0E; // + 0x0F
2022-05-29 16:07:48 -04:00
2022-09-01 05:31:32 -04:00
// I2C_ADDRESS REGISTERS (AS5600L)
const uint8_t AS5600_I2CADDR = 0x20;
const uint8_t AS5600_I2CUPDT = 0x21;
2022-05-29 16:07:48 -04:00
// STATUS REGISTERS
2022-06-27 05:27:48 -04:00
const uint8_t AS5600_STATUS = 0x0B;
const uint8_t AS5600_AGC = 0x1A;
const uint8_t AS5600_MAGNITUDE = 0x1B; // + 0x1C
const uint8_t AS5600_BURN = 0xFF;
2022-05-29 16:07:48 -04:00
// STATUS BITS
2022-06-27 05:27:48 -04:00
const uint8_t AS5600_MAGNET_HIGH = 0x08;
const uint8_t AS5600_MAGNET_LOW = 0x10;
const uint8_t AS5600_MAGNET_DETECT = 0x20;
2022-05-29 16:07:48 -04:00
AS5600::AS5600(TwoWire *wire)
{
2022-06-02 06:07:52 -04:00
_wire = wire;
2022-05-29 16:07:48 -04:00
}
#if defined (ESP8266) || defined(ESP32)
2022-06-27 05:27:48 -04:00
bool AS5600::begin(int dataPin, int clockPin, uint8_t directionPin)
2022-05-29 16:07:48 -04:00
{
_directionPin = directionPin;
2022-07-04 06:10:00 -04:00
if (_directionPin != 255)
{
pinMode(_directionPin, OUTPUT);
}
2022-05-29 16:07:48 -04:00
setDirection(AS5600_CLOCK_WISE);
2022-06-02 06:07:52 -04:00
_wire = &Wire;
2022-05-29 16:07:48 -04:00
if ((dataPin < 255) && (clockPin < 255))
{
_wire->begin(dataPin, clockPin);
} else {
_wire->begin();
}
if (! isConnected()) return false;
return true;
}
#endif
2022-06-27 05:27:48 -04:00
bool AS5600::begin(uint8_t directionPin)
2022-05-29 16:07:48 -04:00
{
_directionPin = directionPin;
2022-07-04 06:10:00 -04:00
if (_directionPin != 255)
{
pinMode(_directionPin, OUTPUT);
}
2022-05-29 16:07:48 -04:00
setDirection(AS5600_CLOCK_WISE);
_wire->begin();
if (! isConnected()) return false;
return true;
}
bool AS5600::isConnected()
{
_wire->beginTransmission(_address);
return ( _wire->endTransmission() == 0);
}
/////////////////////////////////////////////////////////
//
// CONFIGURATION REGISTERS + direction pin
//
void AS5600::setDirection(uint8_t direction)
{
2022-07-04 06:10:00 -04:00
_direction = direction;
if (_directionPin != 255)
{
digitalWrite(_directionPin, _direction);
}
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getDirection()
{
2022-07-04 06:10:00 -04:00
if (_directionPin != 255)
{
_direction = digitalRead(_directionPin);
}
return _direction;
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getZMCO()
{
uint8_t value = readReg(AS5600_ZMCO);
return value;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setZPosition(uint16_t value)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (value > 0x0FFF) return false;
writeReg2(AS5600_ZPOS, value);
return true;
2022-05-29 16:07:48 -04:00
}
uint16_t AS5600::getZPosition()
{
2022-06-27 05:27:48 -04:00
uint16_t value = readReg2(AS5600_ZPOS) & 0x0FFF;
2022-05-29 16:07:48 -04:00
return value;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setMPosition(uint16_t value)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (value > 0x0FFF) return false;
writeReg2(AS5600_MPOS, value);
return true;
2022-05-29 16:07:48 -04:00
}
uint16_t AS5600::getMPosition()
{
2022-06-27 05:27:48 -04:00
uint16_t value = readReg2(AS5600_MPOS) & 0x0FFF;
2022-05-29 16:07:48 -04:00
return value;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setMaxAngle(uint16_t value)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (value > 0x0FFF) return false;
writeReg2(AS5600_MANG, value);
return true;
2022-05-29 16:07:48 -04:00
}
uint16_t AS5600::getMaxAngle()
{
2022-06-27 05:27:48 -04:00
uint16_t value = readReg2(AS5600_MANG) & 0x0FFF;
2022-05-29 16:07:48 -04:00
return value;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setConfigure(uint16_t value)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (value > 0x3FFF) return false;
writeReg2(AS5600_CONF, value);
return true;
2022-05-29 16:07:48 -04:00
}
uint16_t AS5600::getConfigure()
{
2022-07-07 06:53:02 -04:00
uint16_t value = readReg2(AS5600_CONF) & 0x3FFF;
2022-05-29 16:07:48 -04:00
return value;
}
// details configure
2022-07-07 06:53:02 -04:00
bool AS5600::setPowerMode(uint8_t powerMode)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (powerMode > 3) return false;
2022-05-29 16:07:48 -04:00
uint8_t value = readReg(AS5600_CONF + 1);
value &= ~AS5600_CONF_POWER_MODE;
value |= powerMode;
writeReg(AS5600_CONF + 1, value);
2022-07-07 06:53:02 -04:00
return true;
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getPowerMode()
{
return readReg(AS5600_CONF + 1) & 0x03;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setHysteresis(uint8_t hysteresis)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (hysteresis > 3) return false;
2022-05-29 16:07:48 -04:00
uint8_t value = readReg(AS5600_CONF + 1);
value &= ~AS5600_CONF_HYSTERESIS;
value |= (hysteresis << 2);
writeReg(AS5600_CONF + 1, value);
2022-07-07 06:53:02 -04:00
return true;
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getHysteresis()
{
return (readReg(AS5600_CONF + 1) >> 2) & 0x03;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setOutputMode(uint8_t outputMode)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (outputMode > 2) return false;
2022-05-29 16:07:48 -04:00
uint8_t value = readReg(AS5600_CONF + 1);
value &= ~AS5600_CONF_OUTPUT_MODE;
value |= (outputMode << 4);
writeReg(AS5600_CONF + 1, value);
2022-07-07 06:53:02 -04:00
return true;
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getOutputMode()
{
return (readReg(AS5600_CONF + 1) >> 4) & 0x03;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setPWMFrequency(uint8_t pwmFreq)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (pwmFreq > 3) return false;
2022-05-29 16:07:48 -04:00
uint8_t value = readReg(AS5600_CONF + 1);
value &= ~AS5600_CONF_PWM_FREQUENCY;
value |= (pwmFreq << 6);
writeReg(AS5600_CONF + 1, value);
2022-07-07 06:53:02 -04:00
return true;
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getPWMFrequency()
{
return (readReg(AS5600_CONF + 1) >> 6) & 0x03;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setSlowFilter(uint8_t mask)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (mask > 3) return false;
2022-05-29 16:07:48 -04:00
uint8_t value = readReg(AS5600_CONF);
value &= ~AS5600_CONF_SLOW_FILTER;
value |= mask;
writeReg(AS5600_CONF, value);
2022-07-07 06:53:02 -04:00
return true;
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getSlowFilter()
{
return readReg(AS5600_CONF) & 0x03;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setFastFilter(uint8_t mask)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (mask > 7) return false;
2022-05-29 16:07:48 -04:00
uint8_t value = readReg(AS5600_CONF);
value &= ~AS5600_CONF_FAST_FILTER;
value |= (mask << 2);
writeReg(AS5600_CONF, value);
2022-07-07 06:53:02 -04:00
return true;
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getFastFilter()
{
return (readReg(AS5600_CONF) >> 2) & 0x07;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setWatchDog(uint8_t mask)
2022-05-29 16:07:48 -04:00
{
2022-07-07 06:53:02 -04:00
if (mask > 1) return false;
2022-05-29 16:07:48 -04:00
uint8_t value = readReg(AS5600_CONF);
value &= ~AS5600_CONF_WATCH_DOG;
value |= (mask << 5);
writeReg(AS5600_CONF, value);
2022-07-07 06:53:02 -04:00
return true;
2022-05-29 16:07:48 -04:00
}
uint8_t AS5600::getWatchDog()
{
return (readReg(AS5600_CONF) >> 5) & 0x01;
}
/////////////////////////////////////////////////////////
//
// OUTPUT REGISTERS
//
uint16_t AS5600::rawAngle()
{
2022-06-02 06:07:52 -04:00
uint16_t value = readReg2(AS5600_RAW_ANGLE) & 0x0FFF;
2022-07-04 06:10:00 -04:00
if (_offset > 0) value = (value + _offset) & 0x0FFF;
if ((_directionPin == 255) && (_direction == AS5600_COUNTERCLOCK_WISE))
{
value = (4096 - value) & 4095;
}
2022-05-29 16:07:48 -04:00
return value;
}
uint16_t AS5600::readAngle()
{
2022-06-02 06:07:52 -04:00
uint16_t value = readReg2(AS5600_ANGLE) & 0x0FFF;
2022-07-04 06:10:00 -04:00
if (_offset > 0) value = (value + _offset) & 0x0FFF;
2022-07-07 06:53:02 -04:00
2022-07-04 06:10:00 -04:00
if ((_directionPin == 255) && (_direction == AS5600_COUNTERCLOCK_WISE))
{
value = (4096 - value) & 4095;
}
2022-05-29 16:07:48 -04:00
return value;
}
2022-07-07 06:53:02 -04:00
bool AS5600::setOffset(float degrees)
2022-07-04 06:10:00 -04:00
{
2022-07-07 06:53:02 -04:00
// expect loss of precision.
if (abs(degrees) > 36000) return false;
bool neg = (degrees < 0);
if (neg) degrees = -degrees;
2022-07-04 06:10:00 -04:00
uint16_t offset = round(degrees * (4096 / 360.0));
offset &= 4095;
if (neg) offset = 4096 - offset;
2022-07-07 06:53:02 -04:00
_offset = offset;
return true;
2022-07-04 06:10:00 -04:00
}
float AS5600::getOffset()
{
return _offset * AS5600_RAW_TO_DEGREES;
}
2022-05-29 16:07:48 -04:00
/////////////////////////////////////////////////////////
//
// STATUS REGISTERS
//
uint8_t AS5600::readStatus()
{
uint8_t value = readReg(AS5600_STATUS);
return value;
}
uint8_t AS5600::readAGC()
{
uint8_t value = readReg(AS5600_AGC);
return value;
}
uint16_t AS5600::readMagnitude()
{
2022-06-02 06:07:52 -04:00
uint16_t value = readReg2(AS5600_MAGNITUDE) & 0x0FFF;
2022-05-29 16:07:48 -04:00
return value;
}
bool AS5600::detectMagnet()
{
return (readStatus() & AS5600_MAGNET_DETECT) > 1;
}
2022-09-01 05:31:32 -04:00
bool AS5600::magnetTooStrong()
{
return (readStatus() & AS5600_MAGNET_HIGH) > 1;
}
bool AS5600::magnetTooWeak()
{
return (readStatus() & AS5600_MAGNET_LOW) > 1;
}
2022-05-29 16:07:48 -04:00
/////////////////////////////////////////////////////////
//
// BURN COMMANDS
//
// DO NOT UNCOMMENT - USE AT OWN RISK - READ DATASHEET
//
// void AS5600::burnAngle()
// {
// writeReg(AS5600_BURN, x0x80);
// }
//
//
// void AS5600::burnSetting()
// {
// writeReg(AS5600_BURN, x0x40);
// }
2022-06-26 07:58:33 -04:00
float AS5600::getAngularSpeed(uint8_t mode)
2022-06-02 14:10:23 -04:00
{
uint32_t now = micros();
int angle = readAngle();
uint32_t deltaT = now - _lastMeasurement;
int deltaA = angle - _lastAngle;
2022-07-04 06:10:00 -04:00
// assumption is that there is no more than 180° rotation
// between two consecutive measurements.
// => at least two measurements per rotation (preferred 4).
if (deltaA > 2048) deltaA -= 4096;
if (deltaA < -2048) deltaA += 4096;
2022-06-26 07:58:33 -04:00
float speed = (deltaA * 1e6) / deltaT;
2022-07-04 06:10:00 -04:00
2022-06-26 07:58:33 -04:00
// remember last time & angle
2022-06-02 14:10:23 -04:00
_lastMeasurement = now;
_lastAngle = angle;
2022-06-26 07:58:33 -04:00
// return degrees or radians
2022-06-27 05:27:48 -04:00
if (mode == AS5600_MODE_RADIANS)
{
return speed * AS5600_RAW_TO_RADIANS;
}
// default return degrees
2022-06-26 07:58:33 -04:00
return speed * AS5600_RAW_TO_DEGREES;
2022-06-02 14:10:23 -04:00
}
2022-05-29 16:07:48 -04:00
/////////////////////////////////////////////////////////
//
2022-09-01 05:31:32 -04:00
// PRIVATE AS5600
2022-05-29 16:07:48 -04:00
//
uint8_t AS5600::readReg(uint8_t reg)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_error = _wire->endTransmission();
_wire->requestFrom(_address, (uint8_t)1);
uint8_t _data = _wire->read();
return _data;
}
2022-06-02 06:07:52 -04:00
uint16_t AS5600::readReg2(uint8_t reg)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_error = _wire->endTransmission();
_wire->requestFrom(_address, (uint8_t)2);
uint16_t _data = _wire->read();
_data <<= 8;
_data += _wire->read();
return _data;
}
2022-05-29 16:07:48 -04:00
uint8_t AS5600::writeReg(uint8_t reg, uint8_t value)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_wire->write(value);
_error = _wire->endTransmission();
return _error;
}
2022-06-27 05:27:48 -04:00
uint8_t AS5600::writeReg2(uint8_t reg, uint16_t value)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_wire->write(value >> 8);
_wire->write(value & 0xFF);
_error = _wire->endTransmission();
return _error;
}
2022-09-01 05:31:32 -04:00
/////////////////////////////////////////////////////////////////////////////
//
// AS5600L
//
AS5600L::AS5600L(uint8_t address, TwoWire *wire) : AS5600(wire)
{
_address = address;; // 0x40 = default address AS5600L.
}
bool AS5600L::setAddress(uint8_t address)
{
// skip reserved I2C addresses
if ((address < 8) || (address > 119)) return false;
// note address need to be shifted 1 bit.
writeReg(AS5600_I2CADDR, address << 1);
writeReg(AS5600_I2CUPDT, address << 1);
// remember new address.
_address = address;
return true;
}
bool AS5600L::setI2CUPDT(uint8_t address)
{
// skip reserved I2C addresses
if ((address < 8) || (address > 119)) return false;
writeReg(AS5600_I2CUPDT, address << 1);
return true;
}
uint8_t AS5600L::getI2CUPDT()
{
return (readReg(AS5600_I2CUPDT) >> 1);
}
2022-05-29 16:07:48 -04:00
// -- END OF FILE --