mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
412 lines
8.2 KiB
C++
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 --
|
|
|
|
|