From 67bc9511aa659438feefb4ce1d0803bdf84cd524 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Mon, 4 Jul 2022 12:01:32 +0200 Subject: [PATCH] Add software direction control (#12) * fix #6 add software direction control * fix #14 getAngularSpeed() * fix #13 add offset functions * fix conversion constant * fix readAngle() rawAngle() * add examples * update unit test * update readme.md --- AS5600.cpp | 73 ++++++++- AS5600.h | 81 ++++++--- README.md | 154 +++++++++++------- .../AS5600_demo_offset/AS5600_demo_offset.ino | 48 ++++++ .../AS5600_demo_software_direction.ino | 51 ++++++ .../AS5600_outmode_pwm_interrupt.ino | 60 +++++++ keywords.txt | 19 +++ library.json | 2 +- library.properties | 2 +- test/unit_test_001.cpp | 70 +++++++- 10 files changed, 469 insertions(+), 91 deletions(-) create mode 100644 examples/AS5600_demo_offset/AS5600_demo_offset.ino create mode 100644 examples/AS5600_demo_software_direction/AS5600_demo_software_direction.ino create mode 100644 examples/AS5600_outmode_pwm_interrupt/AS5600_outmode_pwm_interrupt.ino diff --git a/AS5600.cpp b/AS5600.cpp index 4f988bc..e121ac4 100644 --- a/AS5600.cpp +++ b/AS5600.cpp @@ -1,7 +1,7 @@ // // FILE: AS56000.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.1.3 +// VERSION: 0.2.0 // PURPOSE: Arduino library for AS5600 magnetic rotation meter // DATE: 2022-05-28 // URL: https://github.com/RobTillaart/AS5600 @@ -15,11 +15,16 @@ // 0.1.3 2022-06-26 Add AS5600_RAW_TO_RADIANS. // Add getAngularSpeed() mode parameter. // Fix #8 bug in configure. -// 0.1.4 2022-06-xx Fix #7 use readReg2() to improve I2C performance. +// 0.1.4 2022-06-27 Fix #7 use readReg2() to improve I2C performance. // define constants for configuration functions. // add examples - especially OUT pin related. // Fix default parameter of the begin function. - +// +// 0.2.0 2022-06-28 add software based direction control. +// add examples +// define constants for configuration functions. +// fix conversion constants (4096 based) +// add get- setOffset(degrees) functions. (no radians yet) // TODO // Power-up time 1 minute @@ -74,7 +79,10 @@ AS5600::AS5600(TwoWire *wire) bool AS5600::begin(int dataPin, int clockPin, uint8_t directionPin) { _directionPin = directionPin; - pinMode(_directionPin, OUTPUT); + if (_directionPin != 255) + { + pinMode(_directionPin, OUTPUT); + } setDirection(AS5600_CLOCK_WISE); _wire = &Wire; @@ -93,7 +101,10 @@ bool AS5600::begin(int dataPin, int clockPin, uint8_t directionPin) bool AS5600::begin(uint8_t directionPin) { _directionPin = directionPin; - pinMode(_directionPin, OUTPUT); + if (_directionPin != 255) + { + pinMode(_directionPin, OUTPUT); + } setDirection(AS5600_CLOCK_WISE); _wire->begin(); @@ -115,13 +126,21 @@ bool AS5600::isConnected() // void AS5600::setDirection(uint8_t direction) { - digitalWrite(_directionPin, direction); + _direction = direction; + if (_directionPin != 255) + { + digitalWrite(_directionPin, _direction); + } } uint8_t AS5600::getDirection() { - return digitalRead(_directionPin); + if (_directionPin != 255) + { + _direction = digitalRead(_directionPin); + } + return _direction; } @@ -291,6 +310,12 @@ uint8_t AS5600::getWatchDog() uint16_t AS5600::rawAngle() { uint16_t value = readReg2(AS5600_RAW_ANGLE) & 0x0FFF; + if (_offset > 0) value = (value + _offset) & 0x0FFF; + + if ((_directionPin == 255) && (_direction == AS5600_COUNTERCLOCK_WISE)) + { + value = (4096 - value) & 4095; + } return value; } @@ -298,10 +323,37 @@ uint16_t AS5600::rawAngle() uint16_t AS5600::readAngle() { uint16_t value = readReg2(AS5600_ANGLE) & 0x0FFF; + if (_offset > 0) value = (value + _offset) & 0x0FFF; + + if ((_directionPin == 255) && (_direction == AS5600_COUNTERCLOCK_WISE)) + { + value = (4096 - value) & 4095; + } return value; } +void AS5600::setOffset(float degrees) +{ + bool neg = false; + if (degrees < 0) + { + neg = true; + degrees = -degrees; + } + uint16_t offset = round(degrees * (4096 / 360.0)); + offset &= 4095; + if (neg) offset = 4096 - offset; + _offset = offset; +} + + +float AS5600::getOffset() +{ + return _offset * AS5600_RAW_TO_DEGREES; +} + + ///////////////////////////////////////////////////////// // // STATUS REGISTERS @@ -357,7 +409,14 @@ float AS5600::getAngularSpeed(uint8_t mode) int angle = readAngle(); uint32_t deltaT = now - _lastMeasurement; int deltaA = angle - _lastAngle; + + // 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; float speed = (deltaA * 1e6) / deltaT; + // remember last time & angle _lastMeasurement = now; _lastAngle = angle; diff --git a/AS5600.h b/AS5600.h index 96ed0c5..d2a9a0d 100644 --- a/AS5600.h +++ b/AS5600.h @@ -2,7 +2,7 @@ // // FILE: AS5600.h // AUTHOR: Rob Tillaart -// VERSION: 0.1.4 +// VERSION: 0.2.0 // PURPOSE: Arduino library for AS5600 magnetic rotation meter // DATE: 2022-05-28 // URL: https://github.com/RobTillaart/AS5600 @@ -12,21 +12,24 @@ #include "Wire.h" -#define AS5600_LIB_VERSION (F("0.1.4")) +#define AS5600_LIB_VERSION (F("0.2.0")) // setDirection const uint8_t AS5600_CLOCK_WISE = 0; // LOW const uint8_t AS5600_COUNTERCLOCK_WISE = 1; // HIGH -// 0.0879120879120879121; -const float AS5600_RAW_TO_DEGREES = 360.0 / 4095.0; -// 0.00153435538636864138630654133494; -const float AS5600_RAW_TO_RADIANS = PI * 2.0 / 4095.0; +// 0.087890625; +const float AS5600_RAW_TO_DEGREES = 360.0 / 4096; +// 0.00153398078788564122971808758949; +const float AS5600_RAW_TO_RADIANS = PI * 2.0 / 4096; // getAngularSpeed const uint8_t AS5600_MODE_DEGREES = 0; const uint8_t AS5600_MODE_RADIANS = 1; +// CONFIGURE CONSTANTS +// check datasheet for details + // setOutputMode const uint8_t AS5600_OUTMODE_ANALOG_100 = 0; const uint8_t AS5600_OUTMODE_ANALOG_90 = 1; @@ -44,6 +47,28 @@ const uint8_t AS5600_PWM_230 = 1; const uint8_t AS5600_PWM_460 = 2; const uint8_t AS5600_PWM_920 = 3; +// setHysteresis +const uint8_t AS5600_HYST_OFF = 0; +const uint8_t AS5600_HYST_LSB1 = 1; +const uint8_t AS5600_HYST_LSB2 = 2; +const uint8_t AS5600_HYST_LSB3 = 3; + +// setSlowFilter +const uint8_t AS5600_SLOW_FILT_16X = 0; +const uint8_t AS5600_SLOW_FILT_8X = 1; +const uint8_t AS5600_SLOW_FILT_4X = 2; +const uint8_t AS5600_SLOW_FILT_2X = 3; + +// setFastFilter +const uint8_t AS5600_FAST_FILT_NONE = 0; +const uint8_t AS5600_FAST_FILT_LSB6 = 1; +const uint8_t AS5600_FAST_FILT_LSB7 = 2; +const uint8_t AS5600_FAST_FILT_LSB9 = 3; +const uint8_t AS5600_FAST_FILT_LSB18 = 4; +const uint8_t AS5600_FAST_FILT_LSB21 = 5; +const uint8_t AS5600_FAST_FILT_LSB24 = 6; +const uint8_t AS5600_FAST_FILT_LSB10 = 7; + // setWatchDog const uint8_t AS5600_WATCHDOG_OFF = 0; const uint8_t AS5600_WATCHDOG_ON = 1; @@ -56,9 +81,11 @@ class AS5600 AS5600(TwoWire *wire = &Wire); #if defined (ESP8266) || defined(ESP32) - bool begin(int sda, int scl, uint8_t directionPin); + // 255 is software controlled direction pin + bool begin(int sda, int scl, uint8_t directionPin = 255); #endif - bool begin(uint8_t directionPin); + // 255 is software controlled direction pin + bool begin(uint8_t directionPin = 255); bool isConnected(); uint8_t getAddress() { return _address; }; // 0x36 @@ -81,38 +108,42 @@ class AS5600 uint16_t getMaxAngle(); // access the whole configuration register + // check datasheet for bit fields void setConfigure(uint16_t value); uint16_t getConfigure(); // access details of the configuration register // 0 = Normal // 1,2,3 are low power mode - check datasheet - void setPowerMode(uint8_t powerMode); // 0..3 + void setPowerMode(uint8_t powerMode); uint8_t getPowerMode(); - // hysteresis = nr of LSB - void setHysteresis(uint8_t hysteresis); // 0..3 + // 0 = off 1 = lsb1 2 = lsb2 3 = lsb3 + void setHysteresis(uint8_t hysteresis); uint8_t getHysteresis(); // 0 = analog 0-100% // 1 = analog 10-90% // 2 = PWM - void setOutputMode(uint8_t outputMode); // 0..2 + void setOutputMode(uint8_t outputMode); uint8_t getOutputMode(); // 0 = 115 1 = 230 2 = 460 3 = 920 (Hz) - void setPWMFrequency(uint8_t pwmFreq); // 0..3 + void setPWMFrequency(uint8_t pwmFreq); uint8_t getPWMFrequency(); - void setSlowFilter(uint8_t mask); // 0..3 + // 0 = 16x 1 = 8x 2 = 4x 3 = 2x + void setSlowFilter(uint8_t mask); uint8_t getSlowFilter(); - void setFastFilter(uint8_t mask); // 0..7 + // 0 = none 1 = LSB6 2 = LSB7 3 = LSB9 + // 4 = LSB18 5 = LSB21 6 = LSB24 7 = LSB10 + void setFastFilter(uint8_t mask); uint8_t getFastFilter(); // 0 = OFF // 1 = ON (auto low power mode) - void setWatchDog(uint8_t mask); // 0..1 + void setWatchDog(uint8_t mask); uint8_t getWatchDog(); @@ -120,6 +151,10 @@ class AS5600 uint16_t rawAngle(); uint16_t readAngle(); + // software based offset. + void setOffset(float degrees); + float getOffset(); + // READ STATUS REGISTERS uint8_t readStatus(); @@ -135,7 +170,8 @@ class AS5600 // void burnAngle(); // void burnSetting(); - // experimental 0.1.2 - to be tested. + + // Experimental 0.1.2 - to be tested. // approximation of the angular speed in rotations per second. // mode == 1: radians /second // mode == 0: degrees /second (default) @@ -149,13 +185,18 @@ class AS5600 uint8_t writeReg2(uint8_t reg, uint16_t value); const uint8_t _address = 0x36; - uint8_t _directionPin; - uint8_t _error = 0; + uint8_t _directionPin = 255; + uint8_t _direction = AS5600_CLOCK_WISE; + uint8_t _error = 0; TwoWire* _wire; + // for getAngularSpeed() uint32_t _lastMeasurement = 0; - uint16_t _lastAngle = 0; + int16_t _lastAngle = 0; + + // for readAngle() and rawAngle() + uint16_t _offset = 0; }; diff --git a/README.md b/README.md index 18cbc7a..20966f3 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,6 @@ To use more than one **AS5600** on one I2C bus, see Multiplexing below. ### OUT pin -Not tested. - The sensor has an output pin named **OUT**. This pin can be used for an analogue or PWM output signal. Examples are added to show how to use this pin with **setOutputMode()**. @@ -60,14 +58,17 @@ See also **Make configuration persistent** below. The sensor should connect the I2C lines SDA and SCL and the VCC and GND to communicate with the processor. The DIR (direction) pin of the sensor should be connected to: -- GND = fixed clockwise -- VCC = fixed counter clock wise +- **GND** = fixed clockwise(\*) +- **VCC** = fixed counter clock wise - a free IO pin of the processor = library control. -In the latter setup the library can control the direction of counting by initializing this pin in **begin(pin)**, followed by **setDirection(direction)**. For the direction the library defines two constants named: +In the latter setup the library can control the direction of counting by initializing this pin in **begin(directionPin)**, followed by **setDirection(direction)**. For the direction the library defines two constants named: - **AS5600_CLOCK_WISE (0)** - **AS5600_COUNTERCLOCK_WISE (1)** +(\*) if **begin()** is called without **directionPin** or with this parameter set to **255**, software direction control is enabled. +See below for more information. + ## Interface @@ -76,63 +77,52 @@ The I2C address of the **AS5600** is always 0x36. ### Constants -**NOT** to be adjusted. +Most important are: ```cpp // setDirection const uint8_t AS5600_CLOCK_WISE = 0; // LOW const uint8_t AS5600_COUNTERCLOCK_WISE = 1; // HIGH -const float AS5600_RAW_TO_DEGREES = 360.0 / 4095.0; // 0.0879120879120879121; -const float AS5600_RAW_TO_RADIANS = 2 * PI / 4095.0; // 0.00153435538636864138630654133494; +// 0.087890625; +const float AS5600_RAW_TO_DEGREES = 360.0 / 4096; +// 0.00153398078788564122971808758949; +const float AS5600_RAW_TO_RADIANS = PI * 2.0 / 4096; // getAngularSpeed const uint8_t AS5600_MODE_DEGREES = 0; const uint8_t AS5600_MODE_RADIANS = 1; - -// setOutputMode -const uint8_t AS5600_OUTMODE_ANALOG_100 = 0; -const uint8_t AS5600_OUTMODE_ANALOG_90 = 1; -const uint8_t AS5600_OUTMODE_PWM = 2; - -// setPowerMode -const uint8_t AS5600_POWERMODE_NOMINAL = 0; -const uint8_t AS5600_POWERMODE_LOW1 = 1; -const uint8_t AS5600_POWERMODE_LOW2 = 2; -const uint8_t AS5600_POWERMODE_LOW3 = 3; - -// setPWMFrequency -const uint8_t AS5600_PWM_115 = 0; -const uint8_t AS5600_PWM_230 = 1; -const uint8_t AS5600_PWM_460 = 2; -const uint8_t AS5600_PWM_920 = 3; - -// setWatchDog -const uint8_t AS5600_WATCHDOG_OFF = 0; -const uint8_t AS5600_WATCHDOG_ON = 1; ``` +See AS5600.h file (and datasheet) for all constants. +Also Configuration bits below for configuration related ones. + ### Constructor + I2C - **AS5600(TwoWire \*wire = &Wire)** Constructor with optional Wire interface as parameter. -- **bool begin(uint8_t directionPin = AS5600_CLOCK_WISE)** set the value for the directionPin. -- **bool begin(int sda, int scl, uint8_t directionPin = AS5600_CLOCK_WISE)** idem, for the ESP32 where one can choose the I2C pins. -- **bool isConnected()** checks if the fixed address 0x36 is on the I2C bus. -- **uint8_t getAddress()** returns the device address. +- **bool begin(uint8_t directionPin = 255)** set the value for the directionPin. +If the pin is set to 255, the default value, there will be software direction control instead of hardware control. +See below. +- **bool begin(int sda, int scl, uint8_t directionPin = 255)** idem, for the ESP32 where one can choose the I2C pins. +If the pin is set to 255, the default value, there will be software direction control instead of hardware control. +See below. +- **bool isConnected()** checks if the address 0x36 is on the I2C bus. +- **uint8_t getAddress()** returns the fixed device address 0x36. ### Direction To define in which way the sensor counts up. -- **void setDirection(uint8_t direction = AS5600_CLOCK_WISE)** -- **uint8_t getDirection()** +- **void setDirection(uint8_t direction = AS5600_CLOCK_WISE)** idem. +- **uint8_t getDirection()** returns AS5600_CLOCK_WISE (0) or +AS5600_COUNTERCLOCK_WISE (1). ### Configuration registers -Please read datasheet for details. +Please read the datasheet for details. - **void setZPosition(uint16_t value)** set start position for limited range. - **uint16_t getZPosition()** get current start position. @@ -141,6 +131,8 @@ Please read datasheet for details. - **void setMaxAngle(uint16_t value)** set limited range. See datasheet **Angle Programming** - **uint16_t getMaxAngle()** get limited range. + + - **void setConfigure(uint16_t value)** - **uint16_t getConfigure()** @@ -163,20 +155,32 @@ Please read datasheet for details. ### Read Angle -- **uint16_t rawAngle()** idem. returns 0 .. 4095. -Conversion factor to degrees = 360 / 4095 = 0.0879121 +- **uint16_t rawAngle()** idem. returns 0 .. 4095. (12 bits) +Conversion factor AS5600_RAW_TO_DEGREES = 360 / 4096 = 0.087890625 +or use AS5600_RAW_TO_RADIANS if needed. - **uint16_t readAngle()** read the angle from the sensor. This is the one most used. +- **void setOffset(float degrees)** sets an offset in degrees, +e.g. to calibrate the sensor after mounting. +Typical values are -359.99 - 359.99 probably smaller. +Larger values will be mapped back to this interval. +Be aware that larger values will affect / decrease the precision of the measurements as floats have only 7 significant digits. +Verify this for your application. +- **float getOffset()** returns offset in degrees. + +In #14 there is a discussion about **setOffset()**. +A possible implementation is to ignore all values outside the +-359.99 - 359.99 range. +This would help to keep the precision high. ### Angular Speed -- **getAngularSpeed(uint8_t mode = AS5600_MODE_DEGREES)** is an experimental function that returns +- **float getAngularSpeed(uint8_t mode = AS5600_MODE_DEGREES)** is an experimental function that returns an approximation of the angular speed in rotations per second. The function needs to be called at least **four** times per rotation -to get a reasonably accuracy. +or once per second to get a reasonably precision. -(0.1.3 added mode parameter). - mode == AS5600_MODE_RADIANS (1): radians /second - mode == AS5600_MODE_DEGREES (0): degrees /second (default) - mode other => degrees /second @@ -185,17 +189,23 @@ Negative values indicate reverse rotation. What that means depends on the setup of your project. Note: the first call will return an erroneous value as it has no -reference angle or time. Also if one stops calling this function +reference angle or time. +Also if one stops calling this function for some time the first call after such delays will be incorrect. +Note: the frequency of calling this function of the sensor depends on the application. +The faster the magnet rotates, the faster it may be called. +Also if one wants to detect minute movements, calling it more often is the way to go. + ### Status registers -- **uint8_t readStatus()** see below. +- **uint8_t readStatus()** see Status bits below. - **uint8_t readAGC()** returns the Automatic Gain Control. 0..255 in 5V mode, 0..128 in 3V3 mode. - **uint16_t readMagnitude()** reads the current internal magnitude. -Meaning or scale is unclear. +(page 9 datasheet) +Scale is unclear, can be used as relative scale. - **bool detectMagnet()** returns true if device sees a magnet. @@ -235,6 +245,25 @@ You can only burn a new Angle maximum **THREE** times to the AS5600. You can write this only **ONE** time to the AS5600. +## Software Direction Control + +Experimental 0.2.0 + +Normally one controls the direction of the sensor by connecting the DIR pin to one of the available IO pins of the processor. This IO pin is set in the library as parameter of the **begin(directionPin)** function. + +The directionPin is default set to 255, which defines a software direction control. +To have this working one has to connect the DIR pin of the sensor to GND. +This puts the sensor in a hardware clock wise mode, so it is up to the library to do the additional math so the **readAngle()** and **rawAngle()** behave as if the DIR pin was connected to the processor IO pin. + +The gain is that the user does not need an IO pin for this, which makes connecting the sensor a bit easier. + +In terms of the interface, the user call **setDirection()** as before to change the direction. + +TODO: measure performance impact. + +TODO: investigate impact on functionality of other registers. + + ## Multiplexing The I2C address of the **AS5600** is always 0x36. @@ -245,7 +274,7 @@ Alternative could be the use of a AND port for the I2C clock line to prevent the sensor from listening to signals on the I2C bus. Finally the sensor has an analogue output **OUT**. -This output could be used to connect multiple sensors to different analog ports of the processor. +This output could be used to connect multiple sensors to different analogue ports of the processor. **Warning**: If and how well this analog option works is not verified or tested. (TODO) @@ -281,27 +310,34 @@ See examples. ## Future Some ideas are kept here so they won't get lost. +priority is relative -### high prio +#### high prio - get hardware to test. -- improve documentation -- investigate PGO programming pin. +- improve documentation. - investigate OUT output pin. - PWM, analog_90 and analog_100 -- write examples - - as5600_calibration.ino ? -- add constants for remaining configure functions - - hysteresis, fast / slow filter -- investigate **magnetStrength()** - - combination of AGC and MD, ML and MH flags? +#### med prio -### low prio - -- unit test -- error handling? -- test I2C speeds. +- investigate **readMagnitude()** + - combination of AGC and MD, ML and MH flags? +- investigate performance + - basic performance per function + - I2C improvements + - software direction +- write examples: + - as5600_calibration.ino (needs HW and lots of time) + - different configuration options +- create **changeLog.md** + +#### low prio + +- add error handling +- investigate PGO programming pin. +- add mode parameter to offset functions. + - see getAngularSpeed() diff --git a/examples/AS5600_demo_offset/AS5600_demo_offset.ino b/examples/AS5600_demo_offset/AS5600_demo_offset.ino new file mode 100644 index 0000000..158d646 --- /dev/null +++ b/examples/AS5600_demo_offset/AS5600_demo_offset.ino @@ -0,0 +1,48 @@ +// +// FILE: AS5600_demo_offset.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo + + +#include "AS5600.h" +#include "Wire.h" + +AS5600 as5600; // use default Wire + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.print("AS5600_LIB_VERSION: "); + Serial.println(AS5600_LIB_VERSION); + + Wire.begin(); + + as5600.begin(4); // set direction pin. + as5600.setDirection(AS5600_CLOCK_WISE); // default, just be explicit. +} + + +void loop() +{ + float offset = 0; + while (offset < 360) + { + as5600.setOffset(offset); + Serial.print(millis()); + Serial.print("\t"); + Serial.print(as5600.getOffset(), 2); + Serial.print("\t"); + Serial.print(as5600.readAngle()); + Serial.print("\t"); + Serial.println(as5600.rawAngle() * AS5600_RAW_TO_DEGREES); + delay(100); + offset += 12.34; + } + Serial.println(); + delay(1000); +} + + +// -- END OF FILE -- diff --git a/examples/AS5600_demo_software_direction/AS5600_demo_software_direction.ino b/examples/AS5600_demo_software_direction/AS5600_demo_software_direction.ino new file mode 100644 index 0000000..25bab2b --- /dev/null +++ b/examples/AS5600_demo_software_direction/AS5600_demo_software_direction.ino @@ -0,0 +1,51 @@ +// +// FILE: AS5600_demo_software_direction.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo software direction control + + +// connect the DIR pin of teh AS5600 to GND + + +#include "AS5600.h" +#include "Wire.h" + +AS5600 as5600; // use default Wire + +uint8_t counter = 0; + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.print("AS5600_LIB_VERSION: "); + Serial.println(AS5600_LIB_VERSION); + + Wire.begin(); + + as5600.begin(); // set software direction control. default param = 255 + as5600.setDirection(AS5600_CLOCK_WISE); // default, just be explicit. +} + + +void loop() +{ + // toggle direction every 10 reads. + counter++; + if (counter < 10) as5600.setDirection(AS5600_CLOCK_WISE); + else as5600.setDirection(AS5600_COUNTERCLOCK_WISE); + if (counter >= 20) counter = 0; + + Serial.print(millis()); + Serial.print("\t"); + Serial.print(as5600.getDirection()); + Serial.print("\t"); + Serial.print(as5600.readAngle()); + Serial.print("\t"); + Serial.println(as5600.rawAngle() * AS5600_RAW_TO_DEGREES); + + delay(1000); +} + + +// -- END OF FILE -- diff --git a/examples/AS5600_outmode_pwm_interrupt/AS5600_outmode_pwm_interrupt.ino b/examples/AS5600_outmode_pwm_interrupt/AS5600_outmode_pwm_interrupt.ino new file mode 100644 index 0000000..34cd132 --- /dev/null +++ b/examples/AS5600_outmode_pwm_interrupt/AS5600_outmode_pwm_interrupt.ino @@ -0,0 +1,60 @@ +// +// FILE: AS5600_outmode_pwm_interrupt.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo +// DATE: 2022-05-28 + + +#include "AS5600.h" +#include "Wire.h" + +AS5600 as5600; // use default Wire + +const uint8_t irqPin = 2; + +volatile uint32_t duration = 0; + +void capturePWM() +{ + static uint32_t lastTime = 0; + uint32_t now = micros(); + if (digitalRead(2) == HIGH) + { + duration = now - lastTime; + } +} + + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.print("AS5600_LIB_VERSION: "); + Serial.println(AS5600_LIB_VERSION); + + Wire.begin(); + + attachInterrupt(digitalPinToInterrupt(2), capturePWM, CHANGE); + + as5600.begin(4); + as5600.setOutputMode(AS5600_OUTMODE_PWM); + as5600.setPWMFrequency(AS5600_PWM_115); +} + + +void loop() +{ + Serial.print(millis()); + Serial.print("\t"); + Serial.print(as5600.readAngle()); + Serial.print("\t"); + Serial.print(as5600.rawAngle() * AS5600_RAW_TO_DEGREES); + Serial.print("\t"); + Serial.println(duration); + + delay(1000); +} + + +// -- END OF FILE -- diff --git a/keywords.txt b/keywords.txt index 05de8e7..165bda3 100644 --- a/keywords.txt +++ b/keywords.txt @@ -83,6 +83,25 @@ AS5600_PWM_230 LITERAL1 AS5600_PWM_460 LITERAL1 AS5600_PWM_920 LITERAL1 +AS5600_HYST_OFF LITERAL1 +AS5600_HYST_LSB1 LITERAL1 +AS5600_HYST_LSB2 LITERAL1 +AS5600_HYST_LSB3 LITERAL1 + +AS5600_SLOW_FILT_16X LITERAL1 +AS5600_SLOW_FILT_8X LITERAL1 +AS5600_SLOW_FILT_4X LITERAL1 +AS5600_SLOW_FILT_2X LITERAL1 + +AS5600_FAST_FILT_NONE LITERAL1 +AS5600_FAST_FILT_LSB6 LITERAL1 +AS5600_FAST_FILT_LSB7 LITERAL1 +AS5600_FAST_FILT_LSB9 LITERAL1 +AS5600_FAST_FILT_LSB18 LITERAL1 +AS5600_FAST_FILT_LSB21 LITERAL1 +AS5600_FAST_FILT_LSB24 LITERAL1 +AS5600_FAST_FILT_LSB10 LITERAL1 + AS5600_WATCHDOG_OFF LITERAL1 AS5600_WATCHDOG_ON LITERAL1 diff --git a/library.json b/library.json index 35e6698..6265a01 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/AS5600.git" }, - "version": "0.1.4", + "version": "0.2.0", "license": "MIT", "frameworks": "arduino", "platforms": "*", diff --git a/library.properties b/library.properties index dca73de..c9e2ceb 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AS5600 -version=0.1.4 +version=0.2.0 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for AS5600 magnetic rotation meter diff --git a/test/unit_test_001.cpp b/test/unit_test_001.cpp index cf3f203..e36e103 100644 --- a/test/unit_test_001.cpp +++ b/test/unit_test_001.cpp @@ -50,11 +50,12 @@ unittest(test_constants) { assertEqual(0, AS5600_CLOCK_WISE); assertEqual(1, AS5600_COUNTERCLOCK_WISE); + assertEqual(0, AS5600_MODE_DEGREES); assertEqual(1, AS5600_MODE_RADIANS); - assertEqualFloat(360.0/4095, AS5600_RAW_TO_DEGREES, 0.0001); - assertEqualFloat((PI*2.0)/4095, AS5600_RAW_TO_RADIANS, 0.0001); + assertEqualFloat(360.0/4096, AS5600_RAW_TO_DEGREES, 0.0001); + assertEqualFloat((PI*2.0)/4096, AS5600_RAW_TO_RADIANS, 0.0001); assertEqual(0, AS5600_OUTMODE_ANALOG_100); assertEqual(1, AS5600_OUTMODE_ANALOG_90); @@ -70,6 +71,25 @@ unittest(test_constants) assertEqual(2, AS5600_PWM_460); assertEqual(3, AS5600_PWM_920); + assertEqual(0, AS5600_HYST_OFF); + assertEqual(1, AS5600_HYST_LSB1); + assertEqual(2, AS5600_HYST_LSB2); + assertEqual(3, AS5600_HYST_LSB3); + + assertEqual(0, AS5600_SLOW_FILT_16X); + assertEqual(1, AS5600_SLOW_FILT_8X); + assertEqual(2, AS5600_SLOW_FILT_4X); + assertEqual(3, AS5600_SLOW_FILT_2X); + + assertEqual(0, AS5600_FAST_FILT_NONE); + assertEqual(1, AS5600_FAST_FILT_LSB6); + assertEqual(2, AS5600_FAST_FILT_LSB7); + assertEqual(3, AS5600_FAST_FILT_LSB9); + assertEqual(4, AS5600_FAST_FILT_LSB18); + assertEqual(5, AS5600_FAST_FILT_LSB21); + assertEqual(6, AS5600_FAST_FILT_LSB24); + assertEqual(7, AS5600_FAST_FILT_LSB10); + assertEqual(0, AS5600_WATCHDOG_OFF); assertEqual(1, AS5600_WATCHDOG_ON); } @@ -93,11 +113,30 @@ unittest(test_address) } -unittest(test_direction) +unittest(test_hardware_direction) { AS5600 as5600; as5600.begin(4); + assertEqual(AS5600_CLOCK_WISE, as5600.getDirection()); + + as5600.setDirection(); + assertEqual(AS5600_CLOCK_WISE, as5600.getDirection()); + + as5600.setDirection(AS5600_COUNTERCLOCK_WISE); + assertEqual(AS5600_COUNTERCLOCK_WISE, as5600.getDirection()); + + as5600.setDirection(AS5600_CLOCK_WISE); + assertEqual(AS5600_CLOCK_WISE, as5600.getDirection()); +} + + +unittest(test_software_direction) +{ + AS5600 as5600; + + as5600.begin(255); + assertEqual(AS5600_CLOCK_WISE, as5600.getDirection()); as5600.setDirection(); assertEqual(AS5600_CLOCK_WISE, as5600.getDirection()); @@ -109,6 +148,31 @@ unittest(test_direction) assertEqual(AS5600_CLOCK_WISE, as5600.getDirection()); } + +unittest(test_offset) +{ + AS5600 as5600; + + as5600.begin(); + + for (int of = 0; of < 360; of += 40) + { + as5600.setOffset(of); + assertEqualFloat(of, as5600.getOffset(), 0.05); + } + + as5600.setOffset(-40.25); + assertEqualFloat(319.75, as5600.getOffset(), 0.05); + + as5600.setOffset(-400.25); + assertEqualFloat(319.75, as5600.getOffset(), 0.05); + + as5600.setOffset(753.15); + assertEqualFloat(33.15, as5600.getOffset(), 0.05); +} + + + // FOR REMAINING ONE NEED A STUB unittest_main()