M5Unit-8Encoder only for ESP32?
-
Hi, I got a M5Unit-8Encoder and I am trying to get it to work with a Arduino Nano Every and a RB Pi Pico. I installed the library on https://github.com/m5stack/M5Unit-8Encoder and have tried the example. However it throws many compiler errors. Digging deeper, I found that the library calls _wire->begin(_sda, _scl, _speed). So it passes three arguments, where the standard TwoWire class only has begin() functions with zero or one argument. However I am quite a beginner so am pretty much stuck.
What am I missing here? Is the library only supposed to work for ESP32? There is little to no further documentation to be found.
-
@jmcdeg
Did you ever progress with this issue. I am trying to pair the 8Ch Encoder unit with an M5Dial and am getting no-where. Fairly sure like you its an I2C issue.Strangely I had no problem getting it to work on a bare bones ESP32 Dev Module on the default I2C pins. https://www.az-delivery.de/en/products/esp32-developmentboard
See Code Below for that working example.
Somewhat Ironic that when trying to pair it with one of their own Boards (M5Dial) it doesn't work out of the box. UIFlow2 works fine. I just cant for the life of me get the Arduino framework example they provide to work.// ========== SETUP & LOOP ========== // void setup() { Serial.begin(115200); sensor.begin(&Wire, ENCODER_ADDR, 21, 22, 100000UL); while (!Serial); // Wait for serial Serial.println("System Ready - Send 'enc all set zero' to reset encoders"); // Initialize to first state sensor.setAllLEDColor(0xff0000); // Start main LEDs RED }
/* * Sequential Non-Blocking LED Control for UNIT_8ENCODER * - Main LEDs complete full cycle first * - Then Channel 0 LED runs its cycle * - Continues in this sequential pattern */ #include "UNIT_8ENCODER.h" UNIT_8ENCODER sensor; // ========== TIMING CONTROL ========== // unsigned long prevLedUpdate = 0; unsigned long prevEncoderReport = 0; const long LED_UPDATE_INTERVAL = 1000; // 1 second per color for main LEDs const long CH0_LED_INTERVAL = 250; // 250ms per color for channel 0 const long ENCODER_REPORT_INTERVAL = 2000; // Report every 2 seconds // ========== SYSTEM STATE ========== // enum SystemMode { RUNNING_MAIN_LEDS, RUNNING_CH0_LED }; SystemMode currentMode = RUNNING_MAIN_LEDS; // ========== LED STATE MACHINES ========== // enum MainLedState { MAIN_RED, MAIN_GREEN, MAIN_BLUE, MAIN_OFF, MAIN_COMPLETE }; MainLedState mainLedState = MAIN_RED; enum Ch0LedState { CH0_RED, CH0_GREEN, CH0_BLUE, CH0_OFF, CH0_COMPLETE }; Ch0LedState ch0LedState = CH0_RED; // ========== ENCODER FUNCTIONS ========== // void show_encoder_values() { Serial.println("\n----- Encoder Report -----"); for (int i = 0; i < 8; i++) { Serial.printf("Encoder CH-%d: %ld\n", i, sensor.getEncoderValue(i)); Serial.printf("Button CH-%d: %d\n", i, sensor.getButtonStatus(i)); } Serial.printf("Switch: %s\n", sensor.getSwitchStatus() ? "ON" : "OFF"); } void Zero_All_Encoders() { for (int i = 0; i < 8; i++) { sensor.resetCounter(i); } Serial.println("All encoders zeroed!"); } // ========== SEQUENTIAL LED CONTROL ========== // void update_leds_sequentially() { unsigned long currentMillis = millis(); switch(currentMode) { case RUNNING_MAIN_LEDS: if (currentMillis - prevLedUpdate >= LED_UPDATE_INTERVAL) { prevLedUpdate = currentMillis; switch(mainLedState) { case MAIN_RED: sensor.setAllLEDColor(0xff0000); // RED mainLedState = MAIN_GREEN; break; case MAIN_GREEN: sensor.setAllLEDColor(0x00ff00); // GREEN mainLedState = MAIN_BLUE; break; case MAIN_BLUE: sensor.setAllLEDColor(0x0000ff); // BLUE mainLedState = MAIN_OFF; break; case MAIN_OFF: sensor.setAllLEDColor(0x000000); // OFF mainLedState = MAIN_COMPLETE; break; case MAIN_COMPLETE: // Main cycle complete, switch to channel 0 currentMode = RUNNING_CH0_LED; ch0LedState = CH0_RED; // Reset channel 0 state prevLedUpdate = currentMillis; // Reset timer for channel 0 break; } } break; case RUNNING_CH0_LED: if (currentMillis - prevLedUpdate >= CH0_LED_INTERVAL) { prevLedUpdate = currentMillis; switch(ch0LedState) { case CH0_RED: sensor.setLEDColor(0, 0xff0000); // RED ch0LedState = CH0_GREEN; break; case CH0_GREEN: sensor.setLEDColor(0, 0x00ff00); // GREEN ch0LedState = CH0_BLUE; break; case CH0_BLUE: sensor.setLEDColor(0, 0x0000ff); // BLUE ch0LedState = CH0_OFF; break; case CH0_OFF: sensor.setLEDColor(0, 0x000000); // OFF ch0LedState = CH0_COMPLETE; break; case CH0_COMPLETE: // Channel 0 cycle complete, switch back to main LEDs currentMode = RUNNING_MAIN_LEDS; mainLedState = MAIN_RED; // Reset main LED state prevLedUpdate = currentMillis; // Reset timer for main LEDs break; } } break; } } // ========== SETUP & LOOP ========== // void setup() { Serial.begin(115200); sensor.begin(&Wire, ENCODER_ADDR, 21, 22, 100000UL); while (!Serial); // Wait for serial Serial.println("System Ready - Send 'enc all set zero' to reset encoders"); // Initialize to first state sensor.setAllLEDColor(0xff0000); // Start main LEDs RED } void loop() { // Handle serial commands if (Serial.available() > 0) { String input = Serial.readStringUntil('\n'); input.trim(); input.toLowerCase(); if (input == "enc all set zero") { Zero_All_Encoders(); } else { Serial.println("Unknown command. Try: 'enc all set zero'"); } } // Update LEDs sequentially update_leds_sequentially(); // Periodic encoder reports if (millis() - prevEncoderReport >= ENCODER_REPORT_INTERVAL) { prevEncoderReport = millis(); show_encoder_values(); } }
-
-
Hi @felmue, thanks for responding.
The M5Stack Supplied github example is below./* Description: Provide three LEGO motor drive modes。Press button B to switch the mode, button A and C control parameter value increase and decrease */ #include <M5Stack.h> #include "UNIT_8ENCODER.h" #include <M5GFX.h> M5GFX display; M5Canvas canvas(&display); UNIT_8ENCODER sensor; long delay_time = 0; void show_rgb_led(void) { sensor.setAllLEDColor(0xff0000); delay(1000); sensor.setAllLEDColor(0x00ff00); delay(1000); sensor.setAllLEDColor(0x0000ff); delay(1000); sensor.setAllLEDColor(0x000000); } void show_encoder_value(void) { int32_t encoder[8] = {0}; uint8_t btn_stauts[8] = {0}; bool switch_status = false; canvas.clear(BLACK); canvas.setCursor(80, 0); canvas.setTextSize(2); canvas.setTextColor(YELLOW); canvas.printf("8Encoder Demo"); canvas.setColor(ORANGE); canvas.drawLine(0, 25, 320, 25); canvas.drawLine(0, 25 + 30, 320, 25 + 30); canvas.setCursor(0, 30); canvas.setTextSize(2); canvas.setTextColor(WHITE); canvas.printf("1-4"); canvas.setColor(ORANGE); canvas.drawLine(60, 30, 60, 25 + 30); canvas.drawLine(125, 30, 125, 25 + 30); canvas.drawLine(190, 30, 190, 25 + 30); canvas.drawLine(255, 30, 255, 25 + 30); canvas.setColor(ORANGE); canvas.drawLine(0, 55 + 30, 320, 55 + 30); canvas.setCursor(0, 30 + 30); canvas.setTextSize(2); canvas.setTextColor(WHITE); canvas.printf("5-8"); canvas.setColor(ORANGE); canvas.drawLine(60, 25 + 30, 60, 55 + 30); canvas.drawLine(125, 25 + 30, 125, 55 + 30); canvas.drawLine(190, 25 + 30, 190, 55 + 30); canvas.drawLine(255, 25 + 30, 255, 55 + 30); canvas.setTextColor(GREEN); for (int i = 0; i < 8; i++) { encoder[i] = sensor.getEncoderValue(i); btn_stauts[i] = sensor.getButtonStatus(i); } for (int i = 0; i < 8; i++) { if (!btn_stauts[i]) { if (i < 4) canvas.fillRect(60 + 65 * i, 30, 65, 25, GREEN); else canvas.fillRect(60 + 65 * (i - 4), 60, 65, 25, GREEN); } } canvas.drawString(String(encoder[0]), 60, 30); canvas.drawString(String(encoder[1]), 125, 30); canvas.drawString(String(encoder[2]), 190, 30); canvas.drawString(String(encoder[3]), 255, 30); canvas.drawString(String(encoder[4]), 60, 60); canvas.drawString(String(encoder[5]), 125, 60); canvas.drawString(String(encoder[6]), 190, 60); canvas.drawString(String(encoder[7]), 255, 60); switch_status = sensor.getSwitchStatus(); canvas.setCursor(10, 120); canvas.setTextColor(WHITE); canvas.printf("switch:"); if (switch_status) { canvas.fillRect(100, 110, 50, 30, GREEN); } else { canvas.fillRect(100, 110, 50, 30, RED); } canvas.setColor(ORANGE); canvas.drawLine(0, 185, 320, 185); canvas.drawLine(120, 185, 120, 320); canvas.drawLine(210, 185, 210, 320); canvas.setTextColor(YELLOW); canvas.drawString("RGB", 30, 190); canvas.drawString("Show", 30, 220); canvas.drawString("Encoder", 130, 190); canvas.drawString("Reset", 130, 220); canvas.pushSprite(0, 0); } void setup() { M5.begin(true, false, true); M5.Power.begin(); display.begin(); sensor.begin(&Wire, ENCODER_ADDR, 21, 22, 100000UL); canvas.setColorDepth(8); // mono color // canvas.setFont(&fonts::efontCN_12); canvas.createSprite(display.width(), display.height()); delay_time = millis() + 10; } void loop() { show_encoder_value(); M5.update(); if (M5.BtnA.wasPressed()) { show_rgb_led(); } else if (M5.BtnB.wasPressed()) { for (int i = 0; i < 8; i++) { sensor.resetCounter(i); } } }
My assumption was just to change line 110 from (their default esp32 pin definition) for SDA / SCL
sensor.begin(&Wire, ENCODER_ADDR, 21, 22, 100000UL);
To my pin definition for M5Dial Port A
sensor.begin(&Wire, ENCODER_ADDR, 13, 15, 100000UL);
However that didn't work, After hours and hours of mucking about I found what works for me.
ADD
#define WIRE Wire
In Setup ADD
WIRE.begin(13,15); sensor.begin(&Wire, ENCODER_ADDR, 13, 15, 100000UL);
Full Working Code Below
#include "M5Dial.h" #include <Arduino.h> #include <lvgl.h> //#include <Wire.h> #include <SPI.h> #include "ui.h" #include "ui_helpers.h" #include "UNIT_8ENCODER.h" UNIT_8ENCODER sensor; // init the tft espi static lv_disp_draw_buf_t draw_buf; static lv_disp_drv_t disp_drv; // Descriptor of a display driver static lv_indev_drv_t indev_drv; // Descriptor of a touch driver #define EXAMPLE_LCD_H_RES 240 #define EXAMPLE_LCD_V_RES 240 #define LV_VER_RES_MAX 240 #define LV_HOR_RES_MAX 240 M5GFX *tft; #define WIRE Wire void tft_lv_initialization() { lv_init(); static lv_color_t buf1[(LV_HOR_RES_MAX * LV_VER_RES_MAX) / 10]; // Declare a buffer for 1/10 screen size static lv_color_t buf2[(LV_HOR_RES_MAX * LV_VER_RES_MAX) / 10]; // second buffer is optionnal // Initialize `disp_buf` display buffer with the buffer(s). lv_disp_draw_buf_init(&draw_buf, buf1, buf2, (LV_HOR_RES_MAX * LV_VER_RES_MAX) / 10); tft=&M5Dial.Lcd; } // Display flushing void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { uint32_t w = (area->x2 - area->x1 + 1); uint32_t h = (area->y2 - area->y1 + 1); tft->startWrite(); tft->setAddrWindow(area->x1, area->y1, w, h); tft->pushColors((uint16_t *)&color_p->full, w * h, true); tft->endWrite(); lv_disp_flush_ready(disp); } void init_disp_driver() { lv_disp_drv_init(&disp_drv); // Basic initialization disp_drv.flush_cb = my_disp_flush; // Set your driver function disp_drv.draw_buf = &draw_buf; // Assign the buffer to the display disp_drv.hor_res = LV_HOR_RES_MAX; // Set the horizontal resolution of the display disp_drv.ver_res = LV_VER_RES_MAX; // Set the vertical resolution of the display lv_disp_drv_register(&disp_drv); // Finally register the driver lv_disp_set_bg_color(NULL, lv_color_hex3(0x000)); // Set default background color to black } void my_touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t * data) { uint32_t currentTime = millis(); M5.Touch.update(currentTime); if(M5.Touch.getCount() > 0) { auto pos = M5.Touch.getDetail(); data->state = LV_INDEV_STATE_PRESSED; data->point.x = pos.x; data->point.y = pos.y; } else { data->state = LV_INDEV_STATE_RELEASED; } } void init_touch_driver() { lv_disp_drv_register(&disp_drv); lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = my_touchpad_read; lv_indev_t * my_indev = lv_indev_drv_register(&indev_drv); // register } void setup() { auto cfg = M5.config(); M5Dial.begin(cfg, true, false); M5Dial.Display.setBrightness(80); Serial.begin(115200); tft_lv_initialization(); init_disp_driver(); init_touch_driver(); ui_init(); WIRE.begin(13,15); sensor.begin(&Wire, ENCODER_ADDR, 13, 15, 100000UL); } void loop() { uint32_t wait_ms = lv_timer_handler(); M5.delay(wait_ms); M5Dial.update(); } void SLS_Function_1(lv_event_t *e) { // Squareline Studio Function 1 Code Runs Here bool switch_status = false; sensor.setAllLEDColor(0x00ff00); // GREEN switch_status = sensor.getSwitchStatus(); Serial.println("function-1 Set All Leds Green - Switch Status is: " + String(switch_status)); } void SLS_Function_2(lv_event_t *e) { // Squareline Studio Function 2 Code Runs Here bool switch_status = false; sensor.setAllLEDColor(0x0000ff); // BLUE switch_status = sensor.getSwitchStatus(); Serial.println("function-2 Set All Leds Blue - Switch Status is: " + String(switch_status)); }
So, I got there in the end, and a pretty easy fix, once you know. Isn't that half the fun??
I just think that their documentation is a little lacking unless you want to use the "Exact same HW setup" as provided in the limited examples. For example you have to dig into the github repo for this module to find all the functions available for this unit, especially if they are targeting a potentially large STEM customer base? Unless of course you just want to use UIFlow.
Anyway, once again thanks for responding and hopefully the above may help anyone else using the Encoder.