{"id":13893947,"url":"https://github.com/RobTillaart/AS5600","last_synced_at":"2025-07-17T08:31:39.551Z","repository":{"id":38818474,"uuid":"497617158","full_name":"RobTillaart/AS5600","owner":"RobTillaart","description":"Arduino library for AS5600 magnetic rotation meter","archived":false,"fork":false,"pushed_at":"2024-10-31T10:20:18.000Z","size":89,"stargazers_count":111,"open_issues_count":0,"forks_count":22,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-19T06:32:54.489Z","etag":null,"topics":["angle","arduino","rotation","sensor"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobTillaart.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"RobTillaart","custom":"https://www.paypal.me/robtillaart"}},"created_at":"2022-05-29T14:38:08.000Z","updated_at":"2024-11-18T05:44:07.000Z","dependencies_parsed_at":"2023-12-07T14:28:30.771Z","dependency_job_id":"a2fee6de-4d42-4c9f-9182-0ee118fade75","html_url":"https://github.com/RobTillaart/AS5600","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAS5600","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAS5600/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAS5600/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAS5600/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobTillaart","download_url":"https://codeload.github.com/RobTillaart/AS5600/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226243893,"owners_count":17594452,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angle","arduino","rotation","sensor"],"created_at":"2024-08-06T18:01:20.504Z","updated_at":"2025-07-17T08:31:39.538Z","avatar_url":"https://github.com/RobTillaart.png","language":"C++","funding_links":["https://github.com/sponsors/RobTillaart","https://www.paypal.me/robtillaart"],"categories":["C++"],"sub_categories":[],"readme":"\n[![Arduino CI](https://github.com/RobTillaart/AS5600/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)\n[![Arduino-lint](https://github.com/RobTillaart/AS5600/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/AS5600/actions/workflows/arduino-lint.yml)\n[![JSON check](https://github.com/RobTillaart/AS5600/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/AS5600/actions/workflows/jsoncheck.yml)\n[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/AS5600.svg)](https://github.com/RobTillaart/AS5600/issues)\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AS5600/blob/master/LICENSE)\n[![GitHub release](https://img.shields.io/github/release/RobTillaart/AS5600.svg?maxAge=3600)](https://github.com/RobTillaart/AS5600/releases)\n[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/AS5600.svg)](https://registry.platformio.org/libraries/robtillaart/AS5600)\n\n\n# AS5600\n\nArduino library for AS5600 and AS5600L magnetic rotation meter.\n\n\n## Description\n\n**AS5600** is a library for an AS5600 / AS5600L based magnetic **rotation** meter.\nMore exact, it measures the angle (rotation w.r.t. reference) and not RPM.\nMultiple angle measurements allows one to calculate or estimate the RPM.\n\nThe AS5600 and AS5600L sensors are pin compatible (always check your model's datasheet).\n\n**Warning: experimental**\n\nThe sensor can measure a full rotation in 4096 steps.\nThe precision of the position is therefore limited to approx 0.1°.\nNoise levels are unknown, but one might expect that the sensor is affected by electric\nand or magnetic signals in the environment.\nAlso unknown is the influence of metals near the sensor or an unstable\nor fluctuating power supply.\n\nPlease share your experiences.\n\n\n### 0.6.2 bug fixes.\n\nVersion 0.6.2 fixes bugs that might affect your code.\n\n- fix **getCumulativePosition()** to make it direction aware.\n- fix negative values in **getRevolutions()**.\n- fix **setOffset()** to not set offset to 360 degrees.\n- fix #66, make I2C functions virtual.\n\n\n### 0.5.0 Breaking change\n\nVersion 0.5.0 introduced a breaking change.\nYou cannot set the SDA and SCL pins in **begin()** any more.\nThis reduces the dependency of processor dependent Wire implementations.\nThe user has to call **Wire.begin()** and can optionally set the I2C pins\nbefore calling **AS5600.begin()**.\n\n\n### Related libraries\n\n- https://github.com/RobTillaart/Angle\n- https://github.com/RobTillaart/AngleConvertor\n- https://github.com/RobTillaart/AverageAngle\n- https://github.com/RobTillaart/runningAngle\n\n\n## Hardware connection\n\nThe I2C address of the **AS5600** is always 0x36.\n\nThe sensor should connect the I2C lines SDA and SCL and the\nVCC and GND to communicate with the processor.\nDo not forget to add the pull up resistors to improve the I2C signals.\n\nThe AS5600 datasheet states it supports Fast-Mode == 400 KHz\nand Fast-Mode-Plus == 1000 KHz.\n\n\n### Pull ups\n\nI2C performance tests with an AS5600L with an UNO failed at 400 KHz.\nAfter investigation it became clear that pull ups are mandatory.\nThe UNO expects 5 Volt I2C signals from the AS5600.\nHowever the device only provides 3V3 pulses on the bus.\nSo the signal was not stable fast enough (not \"square enough\").\nAfter applying pull ups the AS5600L worked up to 1000 KHz.\n\n\n### DIR pin\n\nFrom datasheet, page 30 - Direction (clockwise vs. counter-clockwise)\n\n_**The AS5600 allows controlling the direction of the magnet\nrotation with the DIR pin. If DIR is connected to GND (DIR = 0)\na clockwise rotation viewed from the top will generate an\nincrement of the calculated angle. If the DIR pin is connected\nto VDD (DIR = 1) an increment of the calculated angle will\nhappen with counter-clockwise rotation.**_\n\nThis AS5600 library offers a 3rd option for the DIR (direction) pin of the sensor:\n\n1. Connect to **GND** ==\u003e fixed clockwise(\\*).  This is the default.\n1. Connect to **VCC** ==\u003e fixed counter-clockwise.\n1. Connect to an IO pin of the processor == Hardware Direction Control by library.\n\nIn the 3rd configuration the library controls the direction of counting by initializing\nthis pin in **begin(directionPin)**, followed by **setDirection(direction)**.\nFor the parameter direction the library defines two constants named:\n\n- **AS5600_CLOCK_WISE (0)**\n- **AS5600_COUNTERCLOCK_WISE (1)**\n\n(\\*) if **begin()** is called without **directionPin** or with this\nparameter set to **255**, Software Direction Control is enabled.\n\nSee Software Direction Control below for more information.\n\n\n### OUT pin\n\nThe sensor has an output pin named **OUT**.\nThis pin can be used for an analogue or PWM output signal (AS5600),\nand only for PWM by the AS5600L.\n\nSee **Analogue Pin** and **PWM Pin** below.\n\nExamples are added to show how to use this pin with **setOutputMode()**.\n\nSee more in the sections Analog OUT and PWM OUT below.\n\n\n#### Note: (From Zipdox2 - See issue #36)\n\nSome AS5600 modules seem to have a resistor between **PGO** and **GND**.\nThis causes the AS5600 to disable the output (to use it for programming, see datasheet).\nThis resistor needs to be removed to use the **OUT** pin.\n\n\n### PGO pin\n\nNot tested. ==\u003e Read the datasheet!\n\nPGO stands for ProGramming Option, it is used to calibrate and program the sensor.\nAs the sensor can be programmed only a few times one should\nuse this functionality with extreme care.\nSee datasheet for a detailed list of steps to be done.\n\nSee **Make configuration persistent** below.\n\n\n## I2C\n\nThe I2C address of the **AS5600** is always 0x36.\n\n### Address\n\n|  sensor  |  address  |  changeable  |\n|:--------:|:---------:|:-------------|\n|  AS5600  |    0x36   |  NO          |\n|  AS5600L |    0x40   |  YES, check setAddress()  |\n\nTo use more than one **AS5600** on one I2C bus, see Multiplexing below.\n\nThe **AS5600L** supports the change of I2C address, optionally permanent.\nCheck the **setAddress()** function for non-permanent change.\n\n\n### I2C multiplexing\n\nSometimes you need to control more devices than possible with the default\naddress range the device provides.\nThis is possible with an I2C multiplexer e.g. TCA9548 which creates up\nto eight channels (think of it as I2C subnets) which can use the complete\naddress range of the device.\n\nDrawback of using a multiplexer is that it takes more administration in\nyour code e.g. which device is on which channel.\nThis will slow down the access, which must be taken into account when\ndeciding which devices are on which channel.\nAlso note that switching between channels will slow down other devices\ntoo if they are behind the multiplexer.\n\n- https://github.com/RobTillaart/TCA9548\n\nAlternative could be the use of a AND port for the I2C clock line to prevent\nthe sensor from listening to signals on the I2C bus.\n\nFinally the sensor has an analogue output **OUT**.\nThis output could be used to connect multiple sensors to different analogue ports of the processor.\n\n**Warning**: If and how well this analog option works is not verified or tested.\n\n\n### Performance\n\n|     board     |  sensor   |  results         |  notes  |\n|:-------------:|:---------:|:-----------------|:--------|\n|  Arduino UNO  |  AS5600   |  up to 900 KHz.  |  https://github.com/RobTillaart/AS5600/issues/22\n|  Arduino UNO  |  AS5600L  |  up to 300 KHz.  |\n|  ESP32        |  AS5600   |  no data         |\n|  ESP32        |  AS5600L  |  up to 800 KHz   |\n\nNo other boards tested yet.\n\n\n### ESP32 and I2C\n\nWhen polling the AS5600 with an ESP32 to measure RPM an issue has been reported.\nSee https://github.com/RobTillaart/AS5600/issues/28\n\nThe problem is that the ESP32 can be blocking for up to one second if there is a\nproblem in the connection with the sensor.\nUsing **setWireTimeout()** does not seem to solve the problem (2023-01-31).\nIn the issue the goal was to measure the turns of a rotating device at around 3800 RPM.\n\n3800 RPM == 64 rounds / second.\n\nTo measure speed one need at least 3 angle measurements per rotation.\nThis results in at least 192 measurements per second which is about 1 per 5 milliseconds.\n\nGiven that the ESP32 can block for a second, it can not be guaranteed to be up to date.\nNot for speed, but also not for total number of rotations.\n\n\n## Interface\n\n```cpp\n#include \"AS5600.h\"\n```\n\n### Constants\n\nMost important are:\n\n```cpp\n//  setDirection\nconst uint8_t AS5600_CLOCK_WISE         = 0;  //  LOW\nconst uint8_t AS5600_COUNTERCLOCK_WISE  = 1;  //  HIGH\n\n//  0.087890625;\nconst float   AS5600_RAW_TO_DEGREES     = 360.0 / 4096;\n//  0.00153398078788564122971808758949;\nconst float   AS5600_RAW_TO_RADIANS     = PI * 2.0 / 4096;\n//  4.06901041666666e-6\nconst float   AS5600_RAW_TO_RPM         = 1.0 / 4096 / 60;\n\n//  getAngularSpeed\nconst uint8_t AS5600_MODE_DEGREES       = 0;\nconst uint8_t AS5600_MODE_RADIANS       = 1;\nconst uint8_t AS5600_MODE_RPM           = 2;\n```\n\nSee AS5600.h file (and datasheet) for all constants.\nAlso Configuration bits below for configuration related ones.\n\n\n### Constructor + I2C\n\n- **AS5600(TwoWire \\*wire = \u0026Wire)** Constructor with optional Wire\ninterface as parameter.\n- **bool begin(uint8_t directionPin = AS5600_SW_DIRECTION_PIN)**\n  set the value for the directionPin.\nIf the pin is set to AS5600_SW_DIRECTION_PIN, the default value,\nthere will be software direction control instead of hardware control.\nSee below.\n- **bool isConnected()** checks if the address 0x36 (AS5600) is on the I2C bus.\n- **uint8_t getAddress()** returns the fixed device address 0x36 (AS5600).\n\n\n### Direction\n\nTo define in which way the sensor counts up.\n\n- **void setDirection(uint8_t direction = AS5600_CLOCK_WISE)** idem.\n- **uint8_t getDirection()** returns AS5600_CLOCK_WISE (0) or\nAS5600_COUNTERCLOCK_WISE (1).\n\nSee Software Direction Control below for more information.\n\n\n### Configuration registers\n\nPlease read the datasheet (including. BURN section) for details.\n\n- **bool setZPosition(uint16_t value)** set start position for limited range.\nValue = 0..4095. Returns false if parameter is out of range.\nOne need to wait at least 1 ms after writing ZPOS (see BURN section datasheet).\n- **uint16_t getZPosition()** get current start position.\n- **bool setMPosition(uint16_t value)** set stop position for limited range.\nValue = 0..4095. Returns false if parameter is out of range.\nOne need to wait at least 1 ms after writing MPOS (see BURN section datasheet).\n- **uint16_t getMPosition()** get current stop position.\n- **bool setMaxAngle(uint16_t value)** set limited range.\nValue = 0..4095. Returns false if parameter is out of range.\nSee datasheet **Angle Programming**\n- **uint16_t getMaxAngle()** get limited range.\n\n\n### Configuration bits\n\nPlease read datasheet for details.\n\n- **bool setConfigure(uint16_t value)** value == 0..0x3FFF\nAccess the register as bit mask.\nReturns false if parameter is out of range.\n- **uint16_t getConfigure()** returns the current configuration register a bit mask.\n\n\n|  bit    |  short  |  description    |  values                                                |\n|:-------:|:--------|:----------------|:-------------------------------------------------------|\n|  0-1    |  PM     |  Power mode     |  00 = NOM,  01 = LPM1,   10 = LPM2,   11 = LPM3        |\n|  2-3    |  HYST   |  Hysteresis     |  00 = OFF,  01 = 1 LSB,  10 = 2 LSB,  11 = 3 LSB       |\n|  4-5    |  OUTS   |  Output Stage   |  00 = analog (0-100%), 01 = analog (10-90%), 10 = PWM  |\n|  6-7    |  PWMF   |  PWM frequency  |  00 = 115,  01 = 230,    10 = 460,    11 = 920 (Hz)    |\n|  8-9    |  SF     |  Slow Filter    |  00 = 16x,  01 = 8x,     10 = 4x,     11 = 2x          |\n|  10-12  |  FTH    |  Fast Filter    |  Threshold 000 - 111 check datasheet                   |\n|  13     |  WD     |  Watch Dog      |  0 = OFF,    1 = ON                                    |\n|  15-14  |         |  not used       |\n\n\nThe library has functions to address these fields directly.\n\nThe setters() returns false if parameter is out of range.\n\n- **bool setPowerMode(uint8_t powerMode)**\n- **uint8_t getPowerMode()**\n- **bool setHysteresis(uint8_t hysteresis)**\nSuppresses \"noise\" on the output when the magnet is not moving.\nIn a way one is trading precision for stability.\n- **uint8_t getHysteresis()**\n- **bool setOutputMode(uint8_t outputMode)**\n- **uint8_t getOutputMode()**\n- **bool setPWMFrequency(uint8_t pwmFreq)**\n- **uint8_t getPWMFrequency()**\n- **bool setSlowFilter(uint8_t mask)**\n- **uint8_t getSlowFilter()**\n- **bool setFastFilter(uint8_t mask)**\n- **uint8_t getFastFilter()**\n- **bool setWatchDog(uint8_t mask)**\n- **uint8_t getWatchDog()**\n\n\n### Read Angle\n\n- **uint16_t rawAngle()** returns 0 .. 4095. (12 bits)\nConversion factor AS5600_RAW_TO_DEGREES = 360 / 4096 = 0.087890625\nor use AS5600_RAW_TO_RADIANS if needed.\n- **uint16_t readAngle()** returns 0 .. 4095. (12 bits)\nConversion factor AS5600_RAW_TO_DEGREES = 360 / 4096 = 0.087890625\nor use AS5600_RAW_TO_RADIANS if needed.\nThe value of this register can be affected by the configuration bits above.\nThis is the one most used.\n- **bool setOffset(float degrees)** overwrites the **existing** offset.\nIt sets an offset in degrees, e.g. to calibrate the sensor after mounting.\nTypical values are -359.99 - 359.99 probably smaller.\nLarger values will be mapped back to this interval.\nBe aware that larger values will affect / decrease the precision of the\nmeasurements as floats have only 7 significant digits.\nVerify this for your application.\nReturns false if **degrees** \u003e 360000.\n- **float getOffset()** returns offset in degrees.\n- **bool increaseOffset(float degrees)** adds degrees to the **existing** offset.\nIf **setOffset(20)** is called first and **increaseOffset(-30)** thereafter the\nnew offset is -10 degrees.\nReturns false if **degrees** \u003e 360000.\n\nIn issue #14 there is a discussion about **setOffset()**.\nA possible implementation is to ignore all values outside the\n-359.99 - 359.99 range.\nThis would help to keep the precision high. User responsibility.\n\nIn #51 increaseOffset is discussed.\n\n```cpp\n//  offset == 0;\nas.setOffset(20);\n//  offset == 20;\nas.setOffset(-30);\n//  offset = -30;\n\n//  versus\n\n//  offset == 0;\nas.setOffset(20);\n//  offset == 20;\nas.increaseOffset(-30);\n//  offset = -10;\n```\n\n\n### Angular Speed\n\n- **float getAngularSpeed(uint8_t mode = AS5600_MODE_DEGREES, bool update = true)**\nis an experimental function that returns\nan approximation of the angular speed in rotations per second.\n\nIf update is false, the function will use the last read value of **readAngle()**.\nThis is also used by **getCumulativePosition()** and when used both these\nfunctions a substantial performance gain is made.\nSee example **AS5600_position_speed.ino**.\n\nIn case of a reading failure (when update == true), the function can return NAN.\n\nThe function needs to be called at least **four** times per rotation\nor once per second to get a reasonably precision.\n\n|  mode                 |  value  |  description   |  notes  |\n|:----------------------|:-------:|:---------------|:--------|\n|  AS5600_MODE_RADIANS  |    1    |  radians /sec  |         |\n|  AS5600_MODE_DEGREES  |    0    |  degrees /sec  | default |\n|  other                |    -    |  degrees /sec  |         |\n\nNegative return values indicate reverse rotation.\nWhat that exactly means depends on the setup of your project.\n\nNote: the first call will return an erroneous value as it has no\nreference angle or time.\nAlso if one stops calling this function\nfor some time the first call after such delays will be incorrect.\n\nNote: the frequency of calling this function of the sensor depends on the application.\nThe faster the magnet rotates, the faster it may be called.\nAlso if one wants to detect minute movements, calling it more often is the way to go.\n\nAn alternative implementation is possible in which the angle is measured twice\nwith a short interval. The only limitation then is that both measurements\nshould be within 180° = half a rotation.\n\n\n### Cumulative position (experimental)\n\nSince 0.3.3 an experimental cumulative position can be requested from the library.\nThe sensor does not provide interrupts to indicate a movement or revolution\nTherefore one has to poll the sensor at a frequency at least **three** times\nper revolution with **getCumulativePosition()**\n\nThe cumulative position (32 bits) consists of 3 parts\n\n|  bit    |  meaning      |  notes  |\n|:-------:|:--------------|:--------|\n|    31   |  sign         |  typical + == CW, - == CCW\n|  30-12  |  revolutions  |\n|  11-00  |  raw angle    |  call getCumulativePosition()\n\n\nFunctions are:\n\n- **int32_t getCumulativePosition(bool update = true)** reads sensor and updates cumulative position.\nUpdated in 0.6.2 to follow the setting of the **directionPin**.\nIf update is false, the function will use the last read value of **readAngle()**.\nThis is also used by **getCumulativePosition()** and when used both these\nfunctions a substantial performance gain is made.\nSee example **AS5600_position_speed.ino**.\n- **int32_t getRevolutions()** converts last position to whole revolutions.\nConvenience function.\nUpdated in 0.6.2 to return **zero** for the first negative revolution as this\nis more correct as there is not yet a negative turn made.\nThis might be breaking behaviour.\n- **int32_t resetPosition(int32_t position = 0)** resets the \"revolutions\" to position (default 0).\nIt does not reset the delta (rotation) since last call to **getCumulativePosition()**.\nReturns last position (before reset).\n- **int32_t resetCumulativePosition(int32_t position = 0)** completely resets the cumulative counter.\nThis includes the delta (rotation) since last call to **getCumulativePosition()**.\nReturns last position (before reset).\n\nAs this code is experimental, names might change in the future.\nAs the function are mostly about counting revolutions the current thoughts for new names are:\n\n```cpp\nint32_t updateRevolutions();  //  replaces getCumulativePosition();\nint32_t getRevolutions();\nint32_t resetRevolutions();   //  replaces resetPosition();\n```\n\n### Angular Speed + Cumulative position optimization.\n\nSince 0.6.4 it is possible to optimize the performance of getting both.\n- **getCumulativePosition()**\n- **getAngularSpeed()**\n\nAs both use to read the Angle, one can reuse this by setting the update flag to false.\nOne must call **readAngle()** right before both of them\nIn code:\n\n```cpp\n    ...\n    alpha    = as5600.readAngle();\n    position = as5600.getCumulativePosition(false);\n    speed    = as5600.getAngularSpeed(AS5600_MODE_DEGREES, false);\n\n    //  process the values...\n```\n\nPlease note that the **mode** parameter for getAngularSpeed() becomes mandatory.\n\nThe call to **readAngle()** caches the angle read and uses it in both functions.\nThe savings are substantial, see **AS5600_position_speed.ino**\n\nThe advantage is that both speed and position are based upon the same reading.\nA disadvantage is that the latter of the two calls is not max up to date.\n\nUse with care.\n\n\n### Status registers\n\n- **uint8_t readStatus()** see Status bits below.\n- **uint8_t readAGC()** returns the Automatic Gain Control.\n0..255 in 5V mode, 0..128 in 3V3 mode.\n- **uint16_t readMagnitude()** reads the current internal magnitude.\n(page 9 datasheet)\nScale is unclear, can be used as relative scale.\n- **bool detectMagnet()** returns true if device sees a magnet.\n- **bool magnetTooStrong()** idem.\n- **bool magnetTooWeak()** idem.\n\n\n### Status bits\n\nPlease read datasheet for details.\n\n|  bit  | short |  description    |  values                 |\n|:-----:|:------|:---------------:|:------------------------|\n|  0-2  |       |  not used       |                         |\n|  3    |  MH   |  overflow       |  1 = magnet too strong  |\n|  4    |  ML   |  underflow      |  1 = magnet too weak    |\n|  5    |  MD   |  magnet detect  |  1 = magnet detected    |\n|  6-7  |       |  not used       |                         |\n\n\n### Error handling\n\nSince 0.5.2 the library has added **experimental** error handling.\nFor now only lowest level I2C errors are checked for transmission errors.\nError handling might be improved upon in the future.\n\nNote: The public functions do not act on error conditions.\nThis might change in the future.\nSo the user should check for error conditions.\n\n```cpp\nint e = lastError();\nif (e != AS5600_OK)\n{\n  //  handle error\n}\n```\n\n\n- **int lastError()** returns the last error code.\nAfter reading the error status is cleared to **AS5600_OK**.\n\n\n|  error codes               |  value  |  notes    |\n|:---------------------------|:-------:|:----------|\n|  AS5600_OK                 |     0   |  default  |\n|  AS5600_ERROR_I2C_READ_0   |  -100   |\n|  AS5600_ERROR_I2C_READ_1   |  -101   |\n|  AS5600_ERROR_I2C_READ_2   |  -102   |\n|  AS5600_ERROR_I2C_READ_3   |  -103   |\n|  AS5600_ERROR_I2C_WRITE_0  |  -200   |\n|  AS5600_ERROR_I2C_WRITE_1  |  -201   |\n\n\n## Make configuration persistent. BURN\n\n### Read burn count\n\n- **uint8_t getZMCO()** reads back how many times the ZPOS and MPOS\nregisters are written to permanent memory.\nYou can only burn a new Angle 3 times to the AS5600, and only 2 times for the AS5600L.\nThis function is safe as it is read-only.\n\n\n### BURN function\n\nThe burn functions are used to make ZPOS, MPOS and MANG settings persistent.\nThese burn functions are permanent, therefore they are commented in the library.\nPlease read datasheet twice (page 21-24), before uncomment these functions.\n\nNote you need to add a delay of 1 ms after writing\n**USE AT OWN RISK**\n\nPlease read datasheet **twice** as these changes are not reversible.\n\nThe risk is that you make your AS5600 / AS5600L **USELESS**.\n\n**USE AT OWN RISK**\n\nThese are the two \"unsafe\" functions:\n- **void burnAngle()** writes the **ZPOS** and **MPOS** registers to permanent memory.\nYou can only burn a new Angle maximum **THREE** times to the AS5600\nand **TWO** times for the AS5600L.\n- **void burnSetting()** writes the **MANG** register to permanent memory.\nYou can write this only **ONE** time to the AS5600.\nNote that MANG can be written only if ZPOS and MPOS have **never** been\npermanently written (ZMCO == 00).\n\nSome discussion about burning see issue #38\n(I have no hands on experience with this functions)\n\n**USE AT OWN RISK**\n\n\n## Software Direction Control\n\nExperimental 0.2.0\n\nNormally one controls the direction of the sensor by connecting the DIR pin\nto one of the available IO pins of the processor.\nThis IO pin is set in the library as parameter of the **begin(directionPin)** function.\n\nThe directionPin is default set to 255, which defines a **Software Direction Control**.\n\nTo have this working one has to connect the **DIR pin of the sensor to GND**.\nThis puts the sensor in a hardware clockwise mode. Then it is up to the library\nto do the additional math so the **readAngle()** and **rawAngle()** behave as\nif the DIR pin was connected to a processor IO pin.\n\nThe user still calls **setDirection()** as before to change the direction\nof the increments and decrements.\n\nThe advantage is one does not need that extra IO pin from the processor.\nThis makes connecting the sensor a bit easier.\n\nTODO: measure performance impact.\n\nTODO: investigate impact on functionality of other registers.\n\n\n## Analog OUT\n\n(details datasheet - page 25 = AS5600)\n\nThe OUT pin can be configured with the function:\n\n- **bool setOutputMode(uint8_t outputMode)**\n\n\n### AS5600\n\nWhen the analog OUT mode is set the OUT pin provides a voltage\nwhich is linear with the angle.\n\n|  VDD  |  mode  |  percentage  |  output     |  1° in V     |\n|:-----:|:------:|:------------:|:-----------:|:------------:|\n|  5V0  |   0    |   0 - 100%   |  0.0 - 5.0  |  0.01388889  |\n|  5V0  |   1    |   10 - 90%   |  0.5 - 4.5  |  0.01111111  |\n|  3V3  |   0    |   0 - 100%   |  0.0 - 3.3  |  0.00916667  |\n|  3V3  |   1    |   10 - 90%   |  0.3 - 3.0  |  0.00750000  |\n\nTo measure these angles a 10 bit ADC or higher is needed.\n\nWhen analog OUT is selected **readAngle()** will still return valid values.\n\n\n### AS5600L\n\nThe AS5600L does **NOT** support analog OUT.\nBoth mode 0 and 1 will set the OUT pin to VDD (+5V0 or 3V3).\n\n\n## PWM OUT\n\n(details datasheet - page 27 = AS5600)\n\nThe OUT pin can be configured with the function:\n\n- **bool setOutputMode(uint8_t outputMode)** outputMode = 2 = PWM\n\nWhen the PWM OUT mode is set the OUT pin provides a duty cycle which is linear\nwith the angle. However they PWM has a lead in (HIGH) and a lead out (LOW).\n\nThe pulse width is 4351 units, 128 high, 4095 angle, 128 low.\n\n|  angle  |   HIGH  |  LOW   |  HIGH %  |  LOW %   |  notes  |\n|:-------:|:-------:|:------:|:--------:|:--------:|:--------|\n|     0   |    128  |  4223  |   2,94%  |  97,06%  |\n|    10   |    242  |  4109  |   5,56%  |  94,44%  |\n|    20   |    356  |  3996  |   8,17%  |  91,83%  |\n|    45   |    640  |  3711  |  14,71%  |  85,29%  |\n|    90   |   1152  |  3199  |  26,47%  |  73,53%  |\n|   135   |   1664  |  2687  |  38,24%  |  61,76%  |\n|   180   |   2176  |  2176  |  50,00%  |  50,00%  |\n|   225   |   2687  |  1664  |  61,76%  |  38,24%  |\n|   270   |   3199  |  1152  |  73,53%  |  26,47%  |\n|   315   |   3711  |   640  |  85,29%  |  14,71%  |\n|   360   |   4223  |   128  |  97,06%  |   2,94%  |  in fact 359.9 something as 360 == 0\n\n\n### Formula\n\nBased upon the table above ```angle = map(dutyCycle, 2.94, 97.06, 0.0, 359.9);```\n\nor in code ..\n```cpp\nt0 = micros();  //  rising;\nt1 = micros();  //  falling;\nt2 = micros();  //  rising;  new t0\n\n//  note that t2 - t0 should be a constant depending on frequency set.\n//  however as there might be up to 5% variation it cannot be hard coded.\nfloat dutyCycle = (1.0 * (t1 - t0)) / (t2 - t0);\nfloat angle     = (dutyCycle - 0.0294) * (359.9 / (0.9706 - 0.0294));\n\n```\n\n\n### PWM frequency\n\nThe AS5600 allows one to set the PWM base frequency (~5%)\n- **bool setPWMFrequency(uint8_t pwmFreq)**\n\n|  mode  |  pwmFreq  |  step in us  |  1° in time  |\n|:------:|:---------:|:------------:|:------------:|\n|   0    |  115 Hz   |     2.123    |    24.15     |\n|   1    |  230 Hz   |     1.062    |    12.77     |\n|   2    |  460 Hz   |     0.531    |     6.39     |\n|   3    |  920 Hz   |     0.216    |     3.20     |\n\nNote that at the higher frequencies the step size becomes smaller\nand smaller and it becomes harder to measure.\nYou need a sub-micro second hardware timer to measure the pulse width\nwith enough precision to get the max resolution.\n\nWhen PWM OUT is selected **readAngle()** will still return valid values.\n\n\n----\n\n## AS5600L class\n\n- **AS5600L(uint8_t address = 0x40, TwoWire \\*wire = \u0026Wire)** constructor.\nAs the I2C address can be changed in the AS5600L, the address is a parameter of the constructor.\nThis is a difference with the AS5600 constructor.\n\n\n### Setting I2C address\n\n- **bool setAddress(uint8_t address)** Returns false if the I2C address is not in valid range (8-119).\n\n\n### Setting I2C UPDT\n\nUPDT = update  page 30 - AS5600L\n\n- **bool setI2CUPDT(uint8_t value)**\n- **uint8_t getI2CUPDT()**\n\nThese functions seems to have only a function in relation to **setAddress()**\nso possibly obsolete in the future.\nIf you got other insights on these functions please let me know.\n\n----\n\n## Operational\n\nThe base functions are:\n\n```cpp\nAS5600 as5600;\n\nvoid setup()\n{\n  Serial.begin(115200);\n  ...\n  as5600.begin(4);     //  set the direction pin\n  as5600.setDirection(AS5600_CLOCK_WISE);\n  ...\n}\n\nvoid loop()\n{\n...\n  Serial.println(as5600.readAngle());\n  delay(1000);\n...\n}\n```\n\nSee examples.\n\n\n## Future\n\nSome ideas are kept here so they won't get lost.\npriority is relative.\n\n\n#### Must\n\n- re-organize readme.md\n- rename revolution functions\n  - to what?\n\n#### Should\n\n- Implement extended error handling in public functions.\n  - will increase footprint !! how much?\n  - **call writeReg() only if readReg() is OK** ==\u003e prevent incorrect writes\n    - ```if (_error != 0) return false;```\n    - idem readReg2()\n  - set AS5600_ERROR_PARAMETER  e.g. setZPosition()\n  - a derived class with extended error handling?\n- investigate **readMagnitude()**\n  - combination of AGC and MD, ML and MH flags?\n- investigate **OUT** behaviour in practice\n  - analogue\n  - PWM\n  - need AS5600 on breakout with support\n- check / verify Power-up time\n  - 1 minute (need HW)\n- check Timing Characteristics (datasheet)\n  - is there improvement possible.\n- investigate **GEAR** idea - See PR 79\n  - wrapper class seems be ideal \n  - GEAR myGear(AS5600 as); -\u003e  myGear.setRatio(5); and what more?\n  - embed into main class? footprint / conditional extra math.\n\n#### Could\n\n- investigate **PGO** programming pin.\n- check for compatible devices\n  - AS5200 ?\n- investigate performance\n  - basic performance per function\n  - I2C improvements\n  - software direction\n- write examples:\n  - as5600_calibration.ino (needs HW and lots of time)\n  - different configuration options\n\n#### Wont (unless)\n\n- fix for AS5600L as it does not support analog OUT.\n  - type field?\n  - other class hierarchy?\n    - base class with commonalities?\n  - ==\u003e just ignore for now.\n- add mode parameter to offset functions.\n  - see getAngularSpeed()\n\n\n## Support\n\nIf you appreciate my libraries, you can support the development and maintenance.\nImprove the quality of the libraries by providing issues and Pull Requests, or\ndonate through PayPal or GitHub sponsors.\n\nThank you,\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobTillaart%2FAS5600","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FRobTillaart%2FAS5600","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobTillaart%2FAS5600/lists"}