2022-06-02 20:10:23 +02:00

412 lines
8.2 KiB
C++

//
// FILE: AS56000.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.2
// PURPOSE: Arduino library for AS5600 magnetic rotation meter
// DATE: 2022-05-28
// URL: https://github.com/RobTillaart/AS5600
// 0.1.0 2022-05-28 initial version
// 0.1.1 2022-05-31 Add readReg2() to speed up reading 2 byte values.
// Fix clock wise and counter clock wise
// Fix shift-direction @ getZPosition, getMPosition,
// getMaxAngle and getConfigure
// 0.1.2 2022-06-02 Add getAngularSpeed()
//
// TODO
// Power-up time 1 minute
// check Timing Characteristics
#include "AS5600.h"
// CONFIGURATION REGISTERS
#define AS5600_ZMCO 0x00
#define AS5600_ZPOS 0x01 // + 0x02
#define AS5600_MPOS 0x03 // + 0x04
#define AS5600_MANG 0x05 // + 0x06
#define AS5600_CONF 0x07 // + 0x08
// CONFIGURATION BIT MASKS - byte level
#define AS5600_CONF_POWER_MODE 0x03
#define AS5600_CONF_HYSTERESIS 0x0C
#define AS5600_CONF_OUTPUT_MODE 0x30
#define AS5600_CONF_PWM_FREQUENCY 0xC0
#define AS5600_CONF_SLOW_FILTER 0x03
#define AS5600_CONF_FAST_FILTER 0x1C
#define AS5600_CONF_WATCH_DOG 0x20
// UNKNOWN REGISTERS 0x09-0x0A
// OUTPUT REGISTERS
#define AS5600_RAW_ANGLE 0x0C // + 0x0D
#define AS5600_ANGLE 0x0E // + 0x0F
// STATUS REGISTERS
#define AS5600_STATUS 0x0B
#define AS5600_AGC 0x1A
#define AS5600_MAGNITUDE 0x1B // + 0x1C
#define AS5600_BURN 0xFF
// STATUS BITS
#define AS5600_MAGNET_HIGH 0x08
#define AS5600_MAGNET_LOW 0x10
#define AS5600_MAGNET_DETECT 0x20
AS5600::AS5600(TwoWire *wire)
{
_wire = wire;
}
#if defined (ESP8266) || defined(ESP32)
bool AS5600::begin(int dataPin, int clockPin, int directionPin)
{
_directionPin = directionPin;
pinMode(_directionPin, OUTPUT);
setDirection(AS5600_CLOCK_WISE);
_wire = &Wire;
if ((dataPin < 255) && (clockPin < 255))
{
_wire->begin(dataPin, clockPin);
} else {
_wire->begin();
}
if (! isConnected()) return false;
return true;
}
#endif
bool AS5600::begin(int directionPin)
{
_directionPin = directionPin;
pinMode(_directionPin, OUTPUT);
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)
{
digitalWrite(_directionPin, direction);
}
uint8_t AS5600::getDirection()
{
return digitalRead(_directionPin);
}
uint8_t AS5600::getZMCO()
{
uint8_t value = readReg(AS5600_ZMCO);
return value;
}
void AS5600::setZPosition(uint16_t value)
{
writeReg(AS5600_ZPOS, (value >> 8) & 0x0F);
writeReg(AS5600_ZPOS + 1, value & 0xFF);
}
uint16_t AS5600::getZPosition()
{
uint16_t value = (readReg(AS5600_ZPOS) & 0x0F) << 8;
value += readReg(AS5600_ZPOS + 1);
return value;
}
void AS5600::setMPosition(uint16_t value)
{
writeReg(AS5600_MPOS, (value >> 8) & 0x0F);
writeReg(AS5600_MPOS + 1, value & 0xFF);
}
uint16_t AS5600::getMPosition()
{
uint16_t value = (readReg(AS5600_MPOS) & 0x0F) << 8;
value += readReg(AS5600_MPOS + 1);
return value;
}
void AS5600::setMaxAngle(uint16_t value)
{
writeReg(AS5600_MANG, (value >> 8) & 0x0F);
writeReg(AS5600_MANG + 1, value & 0xFF);
}
uint16_t AS5600::getMaxAngle()
{
uint16_t value = (readReg(AS5600_MANG) & 0x0F) << 8;
value += readReg(AS5600_MANG + 1);
return value;
}
void AS5600::setConfigure(uint16_t value)
{
writeReg(AS5600_CONF, (value >> 8) & 0x0F);
writeReg(AS5600_CONF + 1, value & 0xFF);
}
uint16_t AS5600::getConfigure()
{
uint16_t value = (readReg(AS5600_CONF) & 0x2F) << 8;
value += readReg(AS5600_CONF + 1);
return value;
}
// details configure
void AS5600::setPowerMode(uint8_t powerMode)
{
if (powerMode > 3) return;
uint8_t value = readReg(AS5600_CONF + 1);
value &= ~AS5600_CONF_POWER_MODE;
value |= powerMode;
writeReg(AS5600_CONF + 1, value);
}
uint8_t AS5600::getPowerMode()
{
return readReg(AS5600_CONF + 1) & 0x03;
}
void AS5600::setHysteresis(uint8_t hysteresis)
{
if (hysteresis > 3) return;
uint8_t value = readReg(AS5600_CONF + 1);
value &= ~AS5600_CONF_HYSTERESIS;
value |= (hysteresis << 2);
writeReg(AS5600_CONF + 1, value);
}
uint8_t AS5600::getHysteresis()
{
return (readReg(AS5600_CONF + 1) >> 2) & 0x03;
}
void AS5600::setOutputMode(uint8_t outputMode)
{
if (outputMode > 2) return;
uint8_t value = readReg(AS5600_CONF + 1);
value &= ~AS5600_CONF_OUTPUT_MODE;
value |= (outputMode << 4);
writeReg(AS5600_CONF + 1, value);
}
uint8_t AS5600::getOutputMode()
{
return (readReg(AS5600_CONF + 1) >> 4) & 0x03;
}
void AS5600::setPWMFrequency(uint8_t pwmFreq)
{
if (pwmFreq > 3) return;
uint8_t value = readReg(AS5600_CONF + 1);
value &= ~AS5600_CONF_PWM_FREQUENCY;
value |= (pwmFreq << 6);
writeReg(AS5600_CONF + 1, value);
}
uint8_t AS5600::getPWMFrequency()
{
return (readReg(AS5600_CONF + 1) >> 6) & 0x03;
}
void AS5600::setSlowFilter(uint8_t mask)
{
if (mask > 3) return;
uint8_t value = readReg(AS5600_CONF);
value &= ~AS5600_CONF_SLOW_FILTER;
value |= mask;
writeReg(AS5600_CONF, value);
}
uint8_t AS5600::getSlowFilter()
{
return readReg(AS5600_CONF) & 0x03;
}
void AS5600::setFastFilter(uint8_t mask)
{
if (mask > 7) return;
uint8_t value = readReg(AS5600_CONF);
value &= ~AS5600_CONF_FAST_FILTER;
value |= (mask << 2);
writeReg(AS5600_CONF, value);
}
uint8_t AS5600::getFastFilter()
{
return (readReg(AS5600_CONF) >> 2) & 0x07;
}
void AS5600::setWatchDog(uint8_t mask)
{
if (mask > 1) return;
uint8_t value = readReg(AS5600_CONF);
value &= ~AS5600_CONF_WATCH_DOG;
value |= (mask << 5);
writeReg(AS5600_CONF, value);
}
uint8_t AS5600::getWatchDog()
{
return (readReg(AS5600_CONF) >> 5) & 0x01;
}
/////////////////////////////////////////////////////////
//
// OUTPUT REGISTERS
//
uint16_t AS5600::rawAngle()
{
uint16_t value = readReg2(AS5600_RAW_ANGLE) & 0x0FFF;
return value;
}
uint16_t AS5600::readAngle()
{
uint16_t value = readReg2(AS5600_ANGLE) & 0x0FFF;
return value;
}
/////////////////////////////////////////////////////////
//
// 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()
{
uint16_t value = readReg2(AS5600_MAGNITUDE) & 0x0FFF;
return value;
}
bool AS5600::detectMagnet()
{
return (readStatus() & AS5600_MAGNET_DETECT) > 1;
}
/////////////////////////////////////////////////////////
//
// 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);
// }
float AS5600::getAngularSpeed()
{
uint32_t now = micros();
int angle = readAngle();
uint32_t deltaT = now - _lastMeasurement;
int deltaA = angle - _lastAngle;
_lastMeasurement = now;
_lastAngle = angle;
return (deltaA * 1e6 * AS5600_RAW_TO_DEGREES) / deltaT;
}
/////////////////////////////////////////////////////////
//
// PRIVATE
//
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;
}
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;
}
uint8_t AS5600::writeReg(uint8_t reg, uint8_t value)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_wire->write(value);
_error = _wire->endTransmission();
return _error;
}
// -- END OF FILE --