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/). 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 ## [0.1.0] - 2023-08-03
- initial version - initial version

View File

@ -19,56 +19,78 @@ M5ROTATE8 is an Arduino class to read the 8 rotary encoders of the
M5 8ENCODER module. M5 8ENCODER module.
It also provides means to write RGB values to the 8 LED's in the same 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 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. The value can be both positive and negative depending on the direction of turns.
The absolute counter can be given an initial value. The absolute counters can be given an initial value.
The counters can be reset per channel. The counters can be reset per channel.
The library can also read the key pressed status of every rotary encoder. 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. The library can set the RGB value of the 9 LEDS.
Feedback welcome! 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 #### I2C
The address range is in theory from 0..127, however the I2C specification 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. 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 | notes |
| clock | works | |:-------:|:-------:|:-------:|
|:-------:|:-------:| | 100 KHz | yes |
| 100 KHz | | | 200 KHz | yes |
| 200 KHz | | | 400 KHz | yes | max speed advised.
| 400 KHz | | | 600 KHz | no |
| 600 KHz | |
| 800 KHz | | 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 #### Related
- https://github.com/RobTillaart/M5ANGLE8 - https://github.com/RobTillaart/M5ANGLE8
- https://github.com/RobTillaart/M5ROTATE8
## Interface ## Interface
```cpp ```cpp
#include "m5rotate8.h" #include "M5ROTATE8.h"
``` ```
#### Constructor part
- **M5ROTATE8(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS, TwoWire \*wire = &Wire)** constructor. - **M5ROTATE8(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS, TwoWire \*wire = &Wire)** constructor.
Default address = 0x41, default Wire. Default address = 0x41, default Wire.
- **bool begin(int sda, int scl)** ESP32 et al. - **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 isConnected()** checks if address is on the I2C bus.
- **bool setAddress(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS)** set a new address for the device. - **bool setAddress(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS)** set a new address for the device.
Default address = 0x41. Default address = 0x41.
- **uint8_t getAddress()** convenience function. - **uint8_t getAddress()** convenience function.
- **uint8_t getVersion()** get firmware version from device. - **uint8_t getVersion()** get firmware version from device.
#### IO part
#### Rotary encoder part
- **int32_t getAbsCounter(uint8_t channel)** - **int32_t getAbsCounter(uint8_t channel)**
Read a absolute position of the rotary encoder since reset or start. 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. True is pressed.
- **bool resetCounter(uint8_t channel)** reset a rotary encoder. - **bool resetCounter(uint8_t channel)** reset a rotary encoder.
- **void resetAll()** reset all counters to 0. - **void resetAll()** reset all counters to 0.
#### Input switch part
- **uint8_t inputSwitch()** read status of the switch. - **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. - **bool allOff()** switches all LEDs off.
@ -90,8 +122,9 @@ True is pressed.
#### Must #### Must
- improve documentation - 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 #### Should
@ -99,16 +132,20 @@ True is pressed.
- optimize low level calls - optimize low level calls
- merge into two functions => read/write array + length. - merge into two functions => read/write array + length.
- resetAll() could be "one call" - 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 #### Could
- add examples - add examples
- digital lock
- add unit tests - add unit tests
- check performance
- **uint32_t readRGB(uint8_t channel)**
- write/readAllRGB() ? less overhead?
#### Wont (unless) #### Wont (unless)

View File

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

View File

@ -24,13 +24,14 @@ void setup()
void loop() 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); MM.writeRGB(ch, 0, 0, 255);
delay(125); delay(MM.getAbsCounter(0));
MM.writeRGB(ch, 0, 0, 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 // AUTHOR: Rob Tillaart
// PURPOSE: demo // PURPOSE: demo
// URL: https://github.com/RobTillaart/M5ROTATE8 // URL: https://github.com/RobTillaart/M5ROTATE8
@ -30,9 +30,10 @@ void loop()
Serial.print(MM.getRelCounter(ch)); Serial.print(MM.getRelCounter(ch));
Serial.print("\t"); Serial.print("\t");
Serial.print(MM.getKeyPressed(ch)); Serial.print(MM.getKeyPressed(ch));
Serial.print("\n"); Serial.print("\t");
delay(125); 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", "type": "git",
"url": "https://github.com/RobTillaart/M5ROTATE8" "url": "https://github.com/RobTillaart/M5ROTATE8"
}, },
"version": "0.1.0", "version": "0.2.0",
"license": "MIT", "license": "MIT",
"frameworks": "*", "frameworks": "*",
"platforms": "*", "platforms": "*",

View File

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

View File

@ -1,7 +1,7 @@
// //
// FILE: m5rotate8.cpp // FILE: m5rotate8.cpp
// AUTHOR: Rob Tillaart // AUTHOR: Rob Tillaart
// VERSION: 0.1.0 // VERSION: 0.2.0
// PURPOSE: Arduino library for M5 8ROTATE 8x rotary encoders // PURPOSE: Arduino library for M5 8ROTATE 8x rotary encoders
// URL: https://github.com/RobTillaart/M5ROTATE8 // 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); 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) int32_t M5ROTATE8::getAbsCounter(uint8_t channel)
{ {
// if (channel > 7)
// {
// return M5ROTATE8_ERR_CHANNEL;
// }
return read32(M5ROTATE8_REG_BASE_ABS + (channel << 2)); return read32(M5ROTATE8_REG_BASE_ABS + (channel << 2));
} }
bool M5ROTATE8::setAbsCounter(uint8_t channel, int32_t value) 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); return write32(M5ROTATE8_REG_BASE_ABS + (channel << 2), value);
} }
int32_t M5ROTATE8::getRelCounter(uint8_t channel) int32_t M5ROTATE8::getRelCounter(uint8_t channel)
{ {
// if (channel > 7)
// {
// return M5ROTATE8_ERR_CHANNEL;
// }
return read32(M5ROTATE8_REG_BASE_REL + (channel << 2)); return read32(M5ROTATE8_REG_BASE_REL + (channel << 2));
} }
@ -117,7 +105,7 @@ bool M5ROTATE8::getKeyPressed(uint8_t channel)
{ {
return false; 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() uint8_t M5ROTATE8::inputSwitch()
{ {
return read8(M5ROTATE8_REG_SWITCH); return read8(M5ROTATE8_REG_SWITCH);
} }
////////////////////////////////////////////////
//
// LED PART
//
bool M5ROTATE8::writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B) bool M5ROTATE8::writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)
{ {
if (channel > 7) if (channel > 8)
{ {
return false; 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; return true;
} }
bool M5ROTATE8::allOff()
{
return setAll(0, 0, 0);
}
//////////////////////////////////////////////// ////////////////////////////////////////////////
// //
// PRIVATE // PRIVATE
@ -239,7 +241,7 @@ uint32_t M5ROTATE8::read32(uint8_t reg)
// error handling // error handling
return 0; return 0;
} }
if (_wire->requestFrom(_address, (uint8_t)1) != 1) if (_wire->requestFrom(_address, (uint8_t)4) != 4)
{ {
// error handling // error handling
return 0; return 0;

View File

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