/m5core_ink

Moddable SDK support for M5Core Ink (experimental)

Primary LanguageJavaScript

Moddable SDK support for M5Core Ink

Updated October 11, 2021

This is experimental. The display fundamentals are working. Feel free to help.

The Moddable SDK Piu that do not depend on touch generally seem to work as-is.

This porting effort depends on the new APIs standardized by Ecma-419. Be sure to grab the latest Moddable SDK to get some fixes that this code depends on. Instructions for updating the Moddable SDK are in [https://github.com/Moddable-OpenSource/moddable/blob/public/documentation/Moddable%20SDK%20-%20Getting%20Started.md#table-of-contents).

This work is similar to the M5Paper port, though the display driver is entirely different as the devices use dramatically different display controllers.

Setup, build, run

Copy the directory at targets/m5core_ink to $MODDABLE/build/devices/esp32/targets

Then cd to $MODDABLE/examples/piu/balls directory and build as usual:

mcconfig -d -m -p esp32/m5core_ink

The display refresh rate is about 3 FPS. The balls bounce slowly.

Porting Status

The following are implemented and working:

  • EPD display driver (GDEW0154M09)
  • RTC (PCF8563 / BM8563)
  • Up / Down / Middle / Power / External buttons
  • LED
  • Buzzer
  • Battery voltage

To be done:

(none)

Known issues:

  • The setup code sets GPIO 12 high to try to keep the power on when running on battery power. But that doesn't seem to work.

Display Driver

The display driver is a Poco PixelsOut implementation. This allows it to use both the Poco graphics APIs and Piu user interface framework from the Moddable SDK.

The display driver is written entirely in JavaScript. It uses Ecma-419 IO APIs for all hardware access. Performance is excellent, often faster than the EPD class built into the native M5Core Ink library.

The display driver implements dithering, which allows many levels of gray to be displayed using only black and white pixels. The default dithering algorithm is the venerable Atkinson dither. To change to Burkes or to disable dithering:

screen.dither = "burkes";
screen.dither = "none"

Dithering is performed using the new commodetto/Dither module.

To support dithering the driver requires that Poco render at 8-bit gray (256 Gray). The driver also only supports full screen updates as partial updates with dithering show seams. Partial updates could, and probably should, be supported as they could be useful when not using dithering.

The driver maintains a back buffer, which is more-or-less necessary because of the way the display controller works. Fortunately the buffer is just 5000 bytes, since it can use 1-bit pixels.

The display driver does a full screen refresh on the first draw after instantiation. To disable this, set refresh to false.

screen.configure({refresh: false});

The display driver uses partial updates after the first frame. To force a full screen update:

screen.configure({refresh: true});

A partial update may be performed on power-up to avoid an initial full screen flash. To do this, the previous frame must first be redrawn to put it back into the controller's memory. To do that, first draw the previous frame with previous set to true, then draw the next frame as usual. The driver resets the value of previous to false after one frame is drawn.

screen.configure({previous: true, refresh: false});
// draw previous
// draw next

Hardware rotation is not supported. It could be, but given that the display is square it isn't obviously useful. Both Poco and Piu support software rotation at build time, so rotation is available if needed, just not at runtime.

Buttons

All of the buttons are available with callbacks when changed. Here's a basic test that installs callbacks on each.

for (let name in device.peripheral.button) {
	new device.peripheral.button[name]({
		onPush() {
			trace(`Button ${name}: ${this.pressed}\n`);
		}
	})
}

LED

The green LED at the top of the unit is available:

const led = new device.peripheral.led.Default;
led.on = 1;		// full strength
led.on = 0;		// off
led.on = 0.5;		// half strength

Buzzer

The buzzer is implemented to play tones. As with the M5 Speaker API, sounds are played immediately.

Instantiate the buzzer:

const buzzer = new device.peripheral.tone.Default;

Play a note by name and octave:

buzzer.note("C", 4);

Play a note by name and octave for a fixed duration in milliseconds:

buzzer.note("Bb", 4, 500);

Play a tone by frequency:

buzzer.tone(262);

Play a tone by frequency for a fixed duration in milliseconds:

buzzer.tone(262, 500);

Mute the buzzer (it automatically unmutes on the next note or tone played):

buzzer.mute();

Close the buzzer:

buzzer.close();

Battery Voltage

To get the battery voltage:

const battery = new device.peripheral.battery.Default;
const voltage = battery.read();

Battery Powered Operation

To operate M5Core Ink on battery power, the power hold line must be set to 1. This is donee by default in the setup/target module.

power.main.write(1);

To turn the device off when running on battery power, set the power hold line to 0.

power.main.write(0);