0.2.0 M5ROTATE8

This commit is contained in:
Rob Tillaart 2023-08-09 12:25:58 +02:00
parent a08f62ab34
commit e9836edb6f
12 changed files with 294 additions and 86 deletions

View File

@ -6,5 +6,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.0] 2023-08-08
- testing with hardware led to a major upgrade
- fix keyPressed
- fix read32
- add setAbsCounter example.
- update examples
- fix **writeRGB(8...)**
- add **setAll(R,G,B)**
- update readme.md
- minor edits
## [0.1.0] - 2023-08-03
- initial version

View File

@ -19,56 +19,78 @@ M5ROTATE8 is an Arduino class to read the 8 rotary encoders of the
M5 8ENCODER module.
It also provides means to write RGB values to the 8 LED's in the same module.
The rotary encoders can be read as an absolute counter (since start) or as an relative counter (since last time read).
The value can be both positive and negative.
The absolute counter can be given an initial value.
The rotary encoders can be read as an absolute counter (since start or reset) or as an relative counter (since last time read).
The value can be both positive and negative depending on the direction of turns.
The absolute counters can be given an initial value.
The counters can be reset per channel.
The library can also read the key pressed status of every rotary encoder.
Finally the library can set the RGB value of the 8 LEDS.
The library can read the state of the mini switch.
No tests with hardware have been done yet, so use with care.
Feedback welcome!
The library can set the RGB value of the 9 LEDS.
The RotaryEncoder module has no brightness, like the 8ANGLe unit does.
First tests with hardware have been done.
**Warning:** One strange observation, the RE makes steps of size 2 and occasionally step size 1.
This needs further investigation, so use with care.
Missing in the device is an interrupt signal e.g. on change.
One has to poll all channels for changes which is not efficient.
A single byte register that showed change since last read would allow to monitor
all 8 rotary encoders in one call.
Feedback is welcome!
#### I2C
The address range is in theory from 0..127, however the I2C specification
states it should be between 8 and 119 as some addresses are reserved.
The default address is 0x41.
The default address is **0x41** or **65**.
TODO to what clock does it work?
| clock | works |
|:-------:|:-------:|
| 100 KHz | |
| 200 KHz | |
| 400 KHz | |
| 600 KHz | |
| 800 KHz | |
| clock | works | notes |
|:-------:|:-------:|:-------:|
| 100 KHz | yes |
| 200 KHz | yes |
| 400 KHz | yes | max speed advised.
| 600 KHz | no |
See log file performance sketch.
#### Accuracy
The overall behaviour looks not too bad, there are 30 steps per rotation.
The rotary encoders show a step size of 2 and sometimes a step size of 1.
So normally one rotation gives +60 or -60.
The step size needs investigation as I would expect step size 1, always.
#### Related
- https://github.com/RobTillaart/M5ANGLE8
- https://github.com/RobTillaart/M5ROTATE8
## Interface
```cpp
#include "m5rotate8.h"
#include "M5ROTATE8.h"
```
#### Constructor part
- **M5ROTATE8(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS, TwoWire \*wire = &Wire)** constructor.
Default address = 0x41, default Wire.
- **bool begin(int sda, int scl)** ESP32 et al.
- **bool begin()** initialize I2C, check if connected.
- **bool begin()** initialize I2C, checks if connected.
- **bool isConnected()** checks if address is on the I2C bus.
- **bool setAddress(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS)** set a new address for the device.
Default address = 0x41.
- **uint8_t getAddress()** convenience function.
- **uint8_t getVersion()** get firmware version from device.
#### IO part
#### Rotary encoder part
- **int32_t getAbsCounter(uint8_t channel)**
Read a absolute position of the rotary encoder since reset or start.
@ -80,8 +102,18 @@ Note: this counter will reset after each read.
True is pressed.
- **bool resetCounter(uint8_t channel)** reset a rotary encoder.
- **void resetAll()** reset all counters to 0.
#### Input switch part
- **uint8_t inputSwitch()** read status of the switch.
- **bool writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)** Set the RGB value of a LED.
#### LED part
- **bool writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)** Set the RGB value of a specific LED.
channel = 0..8
- **bool setAll(uint8_t R, uint8_t G, uint8_t B)** set all LEDs.
- **bool allOff()** switches all LEDs off.
@ -90,8 +122,9 @@ True is pressed.
#### Must
- improve documentation
- test with hardware
- keep in sync with M5ANGLE8 where possible.
- keep in sync with **M5ANGLE8** where possible.
- investigate step size 2 / 1.
- An easy patch: divide by 2 resulting in step size 1 or 0
#### Should
@ -99,16 +132,20 @@ True is pressed.
- optimize low level calls
- merge into two functions => read/write array + length.
- resetAll() could be "one call"
- **bool readRGB(channel, &R, &G, &B)**
- or **uint32_t readRGB(uint8_t channel)**
- improve on return values of functions.
- improve performance
- investigate address changes
#### Could
- add examples
- digital lock
- add unit tests
- check performance
- **uint32_t readRGB(uint8_t channel)**
- write/readAllRGB() ? less overhead?
#### Wont (unless)

View File

@ -22,66 +22,103 @@ void setup()
Wire.begin();
MM.begin();
start = micros();
for (int ch = 0; ch < 8; ch++)
for (uint32_t speed = 100000; speed <= 400000; speed += 100000)
{
MM.writeRGB(ch, 128, 128, 128);
Wire.setClock(speed);
Serial.println();
Serial.print("I2C:\t");
Serial.println(speed);
performance();
}
}
void performance()
{
start = micros();
for (int i = 0; i < 100; i++)
{
for (int ch = 0; ch < 8; ch++)
{
MM.writeRGB(ch, 128, 128, 128);
}
}
stop = micros();
Serial.print("writeRGB:\t");
Serial.println((stop - start) / 8.0);
delay(100);
start = micros();
Serial.println((stop - start) / 800.0);
MM.allOff();
stop = micros();
Serial.print("allOff:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = MM.inputSwitch();
for (int i = 0; i < 100; i++)
{
MM.allOff();
}
stop = micros();
Serial.print("allOff:\t\t");
Serial.println((stop - start) / 100.0);
delay(100);
start = micros();
for (int i = 0; i < 100; i++)
{
x = MM.inputSwitch();
}
stop = micros();
Serial.print("inputSwitch:\t");
Serial.println(stop - start);
Serial.println((stop - start) / 100.0);
delay(100);
start = micros();
x = MM.getAbsCounter(3);
for (int i = 0; i < 100; i++)
{
x = MM.getAbsCounter(3);
}
stop = micros();
Serial.print("getAbsCounter:\t");
Serial.println(stop - start);
Serial.println((stop - start) / 100.0);
delay(100);
start = micros();
x = MM.getRelCounter(5);
for (int i = 0; i < 100; i++)
{
x = MM.getRelCounter(5);
}
stop = micros();
Serial.print("getRelCounter:\t");
Serial.println(stop - start);
Serial.println((stop - start) / 100.0);
delay(100);
start = micros();
x = MM.getKeyPressed(7);
for (int i = 0; i < 100; i++)
{
x = MM.getKeyPressed(7);
}
stop = micros();
Serial.print("getKeyPressed:\t");
Serial.println(stop - start);
Serial.println((stop - start) / 100.0);
delay(100);
start = micros();
MM.setAbsCounter(1, 1000);
for (int i = 0; i < 100; i++)
{
x = MM.setAbsCounter(1, 1000);
}
stop = micros();
Serial.print("setAbsCounter:\t");
Serial.println(stop - start);
Serial.println((stop - start) / 100.0);
delay(100);
start = micros();
x = MM.resetCounter(1);
for (int i = 0; i < 100; i++)
{
x = MM.resetCounter(1);
}
stop = micros();
Serial.print("resetCounter:\t");
Serial.println(stop - start);
Serial.println((stop - start) / 100.0);
delay(100);
Serial.println("\ndone...");
}

View File

@ -0,0 +1,54 @@
Board: Arduino UNO
IDE: 1.8.19
Numbers are averages and are indicative.
M5ROTATE8_LIB_VERSION: 0.2.0
I2C: 100000
writeRGB: 538.63
allOff: 4847.52
inputSwitch: 840.28
getAbsCounter: 776.00
getRelCounter: 775.52
getKeyPressed: 829.76
setAbsCounter: 637.88
resetCounter: 339.52
done...
I2C: 200000
writeRGB: 320.01
allOff: 2879.64
inputSwitch: 693.48
getAbsCounter: 451.04
getRelCounter: 452.60
getKeyPressed: 682.92
setAbsCounter: 366.64
resetCounter: 199.08
done...
I2C: 300000
writeRGB: 267.05
allOff: 2401.32
inputSwitch: 653.24
getAbsCounter: 363.68
getRelCounter: 365.72
getKeyPressed: 641.72
setAbsCounter: 292.84
resetCounter: 161.84
done...
I2C: 400000
writeRGB: 245.62
allOff: 2210.12
inputSwitch: 635.68
getAbsCounter: 324.20
getRelCounter: 327.12
getKeyPressed: 624.44
setAbsCounter: 260.64
resetCounter: 145.28
done...

View File

@ -19,19 +19,23 @@ void setup()
Wire.begin();
MM.begin();
MM.resetAll();
}
void loop()
{
{
for (int ch = 0; ch < 8; ch++)
{
Serial.print(MM.getAbsCounter(ch));
Serial.print("\t");
Serial.print(MM.getKeyPressed(ch));
Serial.print("\n");
Serial.print("\t");
delay(125);
}
Serial.print(MM.inputSwitch());
Serial.print("\n");
delay(1000);
}

View File

@ -24,13 +24,14 @@ void setup()
void loop()
{
for (int ch = 0; ch < 8; ch++)
for (int ch = 0; ch < 9; ch++)
{
Serial.println(ch);
Serial.print(ch);
MM.writeRGB(ch, 0, 0, 255);
delay(125);
delay(MM.getAbsCounter(0));
MM.writeRGB(ch, 0, 0, 0);
delay(125);
delay(MM.getAbsCounter(0));
Serial.println(MM.getAbsCounter(0));
}
}

View File

@ -1,5 +1,5 @@
//
// FILE: M5ROTATE8_demo_rel_counter.ino
// FILE: M5ROTATE8_rel_counter.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/M5ROTATE8
@ -30,9 +30,10 @@ void loop()
Serial.print(MM.getRelCounter(ch));
Serial.print("\t");
Serial.print(MM.getKeyPressed(ch));
Serial.print("\n");
Serial.print("\t");
delay(125);
}
Serial.println();
}

View File

@ -0,0 +1,56 @@
//
// FILE: M5ROTATE8_set_abs_counter.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/M5ROTATE8
#include "m5rotate8.h"
M5ROTATE8 MM;
void setup()
{
Serial.begin(115200);
Serial.print("M5ROTATE8_LIB_VERSION: ");
Serial.println(M5ROTATE8_LIB_VERSION);
delay(100);
Wire.begin();
MM.begin();
MM.resetAll();
}
void loop()
{
for (int ch = 0; ch < 8; ch++)
{
Serial.print(MM.getAbsCounter(ch));
Serial.print("\t");
uint8_t x = MM.getKeyPressed(ch);
Serial.print(x);
Serial.print("\t");
if (x == 1) // if key pressed randomize
{
MM.setAbsCounter(ch, random(1000) - 500);
}
delay(10);
}
uint8_t clr = MM.inputSwitch(); // use as clear flag
Serial.print(clr);
Serial.print("\n");
if (clr == 1)
{
for (int ch = 0; ch < 8; ch++)
{
MM.setAbsCounter(ch, 0);
}
}
delay(20);
}
// -- END OF FILE --

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/M5ROTATE8"
},
"version": "0.1.0",
"version": "0.2.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=M5ROTATE8
version=0.1.0
version=0.2.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for M5 8ROTATE 8x rotary encoders

View File

@ -1,7 +1,7 @@
//
// FILE: m5rotate8.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.2.0
// PURPOSE: Arduino library for M5 8ROTATE 8x rotary encoders
// URL: https://github.com/RobTillaart/M5ROTATE8
@ -71,7 +71,7 @@ uint8_t M5ROTATE8::getAddress()
}
uint8_t M5ROTATE8::getVersion()
uint8_t M5ROTATE8::getVersion()
{
return read8(M5ROTATE8_REG_VERSION);
}
@ -79,34 +79,22 @@ uint8_t M5ROTATE8::getVersion()
////////////////////////////////////////////////
//
// INPUT PART
// ROTARY ENCODER PART
//
int32_t M5ROTATE8::getAbsCounter(uint8_t channel)
{
// if (channel > 7)
// {
// return M5ROTATE8_ERR_CHANNEL;
// }
return read32(M5ROTATE8_REG_BASE_ABS + (channel << 2));
}
bool M5ROTATE8::setAbsCounter(uint8_t channel, int32_t value)
{
// if (channel > 7)
// {
// return M5ROTATE8_ERR_CHANNEL;
// }
return write32(M5ROTATE8_REG_BASE_ABS + (channel << 2), value);
}
int32_t M5ROTATE8::getRelCounter(uint8_t channel)
{
// if (channel > 7)
// {
// return M5ROTATE8_ERR_CHANNEL;
// }
return read32(M5ROTATE8_REG_BASE_REL + (channel << 2));
}
@ -117,7 +105,7 @@ bool M5ROTATE8::getKeyPressed(uint8_t channel)
{
return false;
}
return read8(M5ROTATE8_REG_BASE_BUTTON + channel);
return (0 == read8(M5ROTATE8_REG_BASE_BUTTON + channel));
}
@ -141,15 +129,23 @@ void M5ROTATE8::resetAll()
}
////////////////////////////////////////////////
//
// INPUT SWITCH PART
//
uint8_t M5ROTATE8::inputSwitch()
{
return read8(M5ROTATE8_REG_SWITCH);
}
////////////////////////////////////////////////
//
// LED PART
//
bool M5ROTATE8::writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)
{
if (channel > 7)
if (channel > 8)
{
return false;
}
@ -158,16 +154,22 @@ bool M5ROTATE8::writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)
}
bool M5ROTATE8::allOff()
bool M5ROTATE8::setAll(uint8_t R, uint8_t G, uint8_t B)
{
for (uint8_t ch = 0; ch < 8; ch++)
for (uint8_t ch = 0; ch < 9; ch++)
{
write24(M5ROTATE8_REG_RGB + (ch * 3), 0, 0, 0);
write24(M5ROTATE8_REG_RGB + (ch * 3), R, G, B);
}
return true;
}
bool M5ROTATE8::allOff()
{
return setAll(0, 0, 0);
}
////////////////////////////////////////////////
//
// PRIVATE
@ -239,7 +241,7 @@ uint32_t M5ROTATE8::read32(uint8_t reg)
// error handling
return 0;
}
if (_wire->requestFrom(_address, (uint8_t)1) != 1)
if (_wire->requestFrom(_address, (uint8_t)4) != 4)
{
// error handling
return 0;

View File

@ -2,7 +2,7 @@
//
// FILE: m5rotate8.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.2.0
// PURPOSE: Arduino library for M5 8ROTATE 8x rotary encoders
// URL: https://github.com/RobTillaart/M5ROTATE8
@ -10,7 +10,7 @@
#include "Arduino.h"
#include "Wire.h"
#define M5ROTATE8_LIB_VERSION (F("0.1.0"))
#define M5ROTATE8_LIB_VERSION (F("0.2.0"))
#define M5ROTATE8_DEFAULT_ADDRESS 0x41
@ -35,7 +35,7 @@ public:
uint8_t getAddress();
uint8_t getVersion();
// IO PART
// ROTARY ENCODER PART
// channel = 0..7
int32_t getAbsCounter(uint8_t channel);
bool setAbsCounter(uint8_t channel, int32_t value);
@ -44,10 +44,14 @@ public:
bool resetCounter(uint8_t channel);
void resetAll();
// INPUT SWITCH PART
uint8_t inputSwitch();
// LED PART
// channel = 0..7
// R,G,B = 0..255
bool writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B);
bool setAll(uint8_t R, uint8_t G, uint8_t B);
bool allOff();