M5Stack Cardputer

M5Stack-Cardputer

The M5Stack Cardputer (K132) and Cardputer ADV are card-sized computers based on the ESP32-S3 StampS3 module. They feature a 56-key QWERTY keyboard, a 1.14” 240x135 IPS display, a mono speaker, a microphone, a micro-SD card slot, an IR transmitter, a Grove port, and a WS2812 RGB LED.

The espp::M5StackCardputer component supports both variants with the same API - the board is detected at runtime - and provides a singleton hardware abstraction for initializing the display, keyboard (74HC138 GPIO matrix on the original, TCA8418 I2C controller on the ADV), audio (NS4168 amplifier on the original, ES8311 codec on the ADV), microphone, uSD card, RGB LED, battery measurement, and button subsystems.

Note

The speaker and the microphone share I2S pins, so they cannot be used at the same time; initializing one while the other is active will fail.

API Reference

Header File

Classes

class M5StackCardputer : public espp::BaseComponent

The M5StackCardputer class provides an interface to the M5Stack Cardputer (K132) and Cardputer ADV, ESP32-S3 (StampS3) based card-sized computers with a 56-key QWERTY keyboard. The variant is detected automatically at runtime (see variant()); both share the same 56-key layout and the same API.

The class provides access to the following features:

  • Display (1.14” 240x135 IPS TFT, ST7789V2)

  • Keyboard (original: 56-key matrix scanned through a 74HC138 demultiplexer; ADV: TCA8418 I2C keyboard controller)

  • Audio output (mono speaker; original: NS4168 I2S amplifier; ADV: ES8311 codec + NS4150B amplifier, initialized automatically)

  • Microphone (original: SPM1423 PDM; ADV: analog MEMS mic via the ES8311 codec)

  • micro-SD (uSD) card (SPI mode)

  • RGB LED (WS2812, on the StampS3 module)

  • Battery voltage measurement

  • G0 (BOOT) button

  • IR transmitter and Grove port pin definitions

  • Internal I2C bus accessor (ADV only; also hosts a BMI270 IMU at 0x68 which can be used with the espp bmi270 component)

The class is a singleton and can be accessed using the get() method.

Example

  espp::M5StackCardputer &cardputer = espp::M5StackCardputer::get();
  cardputer.set_log_level(espp::Logger::Verbosity::INFO);

  // initialize the LCD
  if (!cardputer.initialize_lcd()) {
    logger.error("Failed to initialize LCD!");
    return;
  }
  // initialize the display, using a pixel buffer of 50 lines
  static constexpr size_t pixel_buffer_size = cardputer.lcd_width() * 50;
  if (!cardputer.initialize_display(pixel_buffer_size)) {
    logger.error("Failed to initialize display!");
    return;
  }

  // initialize the RGB LED and the sound subsystem (the microphone shares a
  // pin with the speaker, so this example only uses the speaker)
  if (!cardputer.initialize_led()) {
    logger.error("Failed to initialize RGB LED!");
    return;
  }
  if (!cardputer.initialize_sound()) {
    logger.error("Failed to initialize sound!");
    return;
  }
  cardputer.volume(60.0f);

  // try to mount the uSD card (warn and continue if it's not inserted)
  if (!cardputer.initialize_sdcard({})) {
    logger.warn("Could not mount the uSD card; is one inserted?");
  }

  // create the GUI (a small keyboard-driven text editor)
  static Gui gui({});

  // print the controls (also available on-screen via the fn+1 help popup)
  logger.info("Controls:\n{}", Gui::HELP_TEXT);

  // whether the board has a working IMU; set after keyboard / variant
  // detection below, referenced by the keypress callback
  static bool have_imu = false;

  // the keyboard scanner delivers one event per key state change; use it to
  // drive the text editor, play key-click sounds, and show what's happening
  // in the status bar
  auto keypress_callback = [&](const espp::M5StackCardputer::KeyEvent &event) {
    if (!event.pressed) {
      return;
    }
    if (event.special == espp::M5StackCardputer::SpecialKey::F1) {
      // toggle the help popup
      bool shown = gui.toggle_help();
      gui.set_status_text(shown ? "Help (fn+1 to close)" : "Ready");
      play_beep(cardputer, 660.0f);
    } else if (event.special == espp::M5StackCardputer::SpecialKey::F2) {
      // toggle the IMU popup
      if (have_imu) {
        bool visible = gui.toggle_imu_visible();
        gui.set_status_text(visible ? "IMU popup shown" : "IMU popup hidden");
      } else {
        gui.set_status_text("No IMU on this board");
      }
      play_beep(cardputer, 660.0f);
    } else if (event.special != espp::M5StackCardputer::SpecialKey::NONE) {
      gui.handle_special_key(event.special);
      gui.set_status_text(espp::M5StackCardputer::special_key_name(event.special));
      play_beep(cardputer, 660.0f);
    } else if (event.value != 0) {
      gui.add_char(event.value);
      play_beep(cardputer, 880.0f);
    } else {
      // a modifier key by itself
      std::string status;
      if (event.modifiers.fn)
        status += "fn ";
      if (event.modifiers.shift)
        status += "shift ";
      if (event.modifiers.ctrl)
        status += "ctrl ";
      if (event.modifiers.opt)
        status += "opt ";
      if (event.modifiers.alt)
        status += "alt ";
      gui.set_status_text(status.empty() ? "Ready" : status);
    }
  };
  // the keyboard scanner auto-detects the board variant: the original's
  // 74HC138 GPIO matrix or the ADV's TCA8418 I2C keyboard controller
  if (!cardputer.initialize_keyboard(keypress_callback)) {
    logger.error("Failed to initialize keyboard!");
    return;
  }
  logger.info("Board variant: {}", espp::M5StackCardputer::variant_name(cardputer.variant()));

  // the ADV has a BMI270 IMU on the internal I2C bus; initialize it if we're
  // on one (warn and continue otherwise - the original has no IMU)
  if (cardputer.variant() == espp::M5StackCardputer::Variant::ADV) {
    have_imu = cardputer.initialize_imu();
    if (have_imu) {
      // show the IMU popup by default (fn+2 toggles it)
      gui.toggle_imu_visible();
    } else {
      logger.warn("Could not initialize the IMU!");
    }
  }

  // the G0 (BOOT) button cycles the RGB LED color
  static std::atomic<int> led_hue{0};
  auto button_callback = [&](const espp::Interrupt::Event &event) {
    if (event.active) {
      led_hue = (led_hue + 60) % 360;
      cardputer.led(espp::Hsv(static_cast<float>(led_hue), 1.0f, 0.2f));
      play_beep(cardputer, 440.0f);
    }
  };
  if (!cardputer.initialize_button(button_callback)) {
    logger.error("Failed to initialize button!");
    return;
  }

  // set the initial LED color
  cardputer.led(espp::Hsv(static_cast<float>(led_hue), 1.0f, 0.2f));

  // periodically update the status bar with the battery voltage / state of
  // charge, and (on the ADV) the IMU overlay with the latest accelerometer
  // and gyroscope readings
  static constexpr auto imu_period = 100ms;
  int loops_per_battery_update = std::chrono::seconds(5) / imu_period;
  int loop_count = 0;
  while (true) {
    if (have_imu && gui.imu_visible()) {
      auto imu = cardputer.imu();
      std::error_code ec;
      if (imu->update(std::chrono::duration<float>(imu_period).count(), ec)) {
        auto accel = imu->get_accelerometer();
        auto gyro = imu->get_gyroscope();
        gui.set_imu_text(fmt::format("a {:+.1f} {:+.1f} {:+.1f}\ng {:+5.0f} {:+5.0f} {:+5.0f}",
                                     accel.x, accel.y, accel.z, gyro.x, gyro.y, gyro.z));
      }
    }
    if ((loop_count % loops_per_battery_update) == 0) {
      gui.set_status_text(fmt::format("Battery: {:.2f} V ({:.0f}%)", cardputer.battery_voltage(),
                                      cardputer.battery_soc()));
    }
    loop_count++;
    std::this_thread::sleep_for(imu_period);
  }

Note

The speaker and the microphone share I2S pins (GPIO 43 word-select / PDM clock on the original; GPIO 41/43 bit-clock and word-select on the ADV), so they cannot be used at the same time. Initializing one while the other is active will fail.

Public Types

enum class SpecialKey : uint8_t

Special (non-printable) keys, produced by the Fn layer of the keyboard.

Values:

enumerator NONE

Not a special key.

enumerator ESC

Escape (fn + `)

enumerator F1

F1 (fn + 1)

enumerator F2

F2 (fn + 2)

enumerator F3

F3 (fn + 3)

enumerator F4

F4 (fn + 4)

enumerator F5

F5 (fn + 5)

enumerator F6

F6 (fn + 6)

enumerator F7

F7 (fn + 7)

enumerator F8

F8 (fn + 8)

enumerator F9

F9 (fn + 9)

enumerator F10

F10 (fn + 0)

enumerator F11

F11 (fn + -)

enumerator F12

F12 (fn + =)

enumerator DELETE

Delete (fn + backspace)

enumerator UP

Up arrow (fn + ;)

enumerator DOWN

Down arrow (fn + .)

enumerator LEFT

Left arrow (fn + ,)

enumerator RIGHT

Right arrow (fn + /)

enum class Variant : uint8_t

The hardware variant of the board.

Values:

enumerator ORIGINAL

Original Cardputer (K132): 74HC138 matrix keyboard, NS4168 I2S amplifier, SPM1423 PDM microphone

enumerator ADV

Cardputer ADV: TCA8418 I2C keyboard controller, ES8311 codec (speaker + microphone), BMI270 IMU on the internal I2C bus

using Pixel = lv_color16_t

Alias for the pixel type used by the display.

using DisplayDriver = espp::St7789

Alias for the display driver.

using button_callback_t = std::function<void(const espp::Interrupt::Event&)>

Alias for the button callback function.

using keypress_callback_t = std::function<void(const KeyEvent&)>

Alias for the keypress callback function. Called once for each key that changes state during a keyboard scan.

using microphone_callback_t = std::function<void(const uint8_t *data, size_t num_bytes)>

Alias for the microphone data callback. Called with 16-bit signed mono samples read from the PDM microphone.

using Imu = espp::Bmi270<espp::bmi270::Interface::I2C>

Alias for the IMU (BMI270) on the Cardputer ADV’s internal I2C bus.

Public Functions

espp::Interrupt &interrupts()

Get a reference to the interrupts

Returns:

A reference to the interrupts

Variant variant()

Get the hardware variant of the board.

Note

The first call detects the variant by probing for the ADV’s TCA8418 keyboard controller on the internal I2C bus (GPIO 8/9); on the original those pins are then returned to plain GPIO for the 74HC138 matrix.

Returns:

The hardware variant of the board

I2c *internal_i2c()

Get a pointer to the internal I2C bus (ADV only)

Note

On the ADV the internal bus hosts the TCA8418 keyboard controller (0x34), the ES8311 codec (0x18), and a BMI270 IMU (0x68)

Returns:

A pointer to the internal I2C bus, or nullptr on the original Cardputer (which has no internal I2C bus)

bool initialize_keyboard (const keypress_callback_t &callback=nullptr, std::chrono::milliseconds poll_interval=std::chrono::milliseconds(10), const espp::Task::BaseConfig &task_config={ .name="keyboard",.stack_size_bytes=CONFIG_M5STACK_CARDPUTER_KEYBOARD_TASK_STACK_SIZE,.priority=CONFIG_M5STACK_CARDPUTER_KEYBOARD_TASK_PRIORITY,.core_id=CONFIG_M5STACK_CARDPUTER_KEYBOARD_TASK_CORE_ID})

Initialize the keyboard

Note

The keyboard is a 4x14 matrix (a 74HC138-scanned GPIO matrix on the original, a TCA8418 I2C controller on the ADV); a scanner task owned by this class polls it at the given interval and calls the callback once per key state change.

Note

The callback runs in the scanner task’s context, so the task’s stack must be large enough for whatever the callback calls into (e.g. LVGL).

Parameters:
  • callback – The callback function to call when a key changes state

  • poll_interval – The interval at which to scan the keyboard matrix

  • task_config – The configuration for the keyboard scanner task. The defaults come from the M5STACK_CARDPUTER_KEYBOARD_TASK_* Kconfig options.

Returns:

true if the keyboard was successfully initialized, false otherwise

bool is_key_pressed(uint8_t row, uint8_t col) const

Get whether a key is currently pressed

Parameters:
  • row – The row of the key in the matrix

  • col – The column of the key in the matrix

Returns:

true if the key is currently pressed, false otherwise

Modifiers modifiers() const

Get the current state of the modifier keys

Returns:

The current state of the modifier keys

std::array<uint16_t, KEYBOARD_ROWS> keyboard_state() const

Get the raw state of the keyboard matrix

Returns:

One entry per row; in each entry bit N is set if the key in column N is currently pressed

bool initialize_button(const button_callback_t &callback = nullptr)

Initialize the G0 (BOOT) button

Parameters:

callback – The callback function to call when the button changes state

Returns:

true if the button was successfully initialized, false otherwise

bool button_state() const

Get the state of the G0 (BOOT) button

Returns:

true if the button is pressed, false otherwise

bool initialize_lcd()

Initialize the LCD (low level display driver)

Returns:

true if the LCD was successfully initialized, false otherwise

bool initialize_display(size_t pixel_buffer_size)

Initialize the display (lvgl display driver)

Parameters:

pixel_buffer_size – The size of the pixel buffer

Returns:

true if the display was successfully initialized, false otherwise

std::shared_ptr<Display<Pixel>> display() const

Get a shared pointer to the display

Returns:

A shared pointer to the display

inline const std::shared_ptr<DisplayDriver> &display_driver() const

Get a shared pointer to the low-level display driver

Returns:

A shared pointer to the display driver

void brightness(float brightness)

Set the brightness of the backlight

Note

This function will only work after initialize_lcd() has been called

Parameters:

brightness – The brightness of the backlight as a percentage (0 - 100)

float brightness() const

Get the brightness of the backlight

Note

This function will only work after initialize_lcd() has been called

Returns:

The brightness of the backlight as a percentage (0 - 100)

Pixel *vram0() const

Get the VRAM 0 pointer (DMA memory used by LVGL)

Note

This is the memory used by LVGL for rendering

Note

This is null unless initialize_display() has been called

Returns:

The VRAM 0 pointer

Pixel *vram1() const

Get the VRAM 1 pointer (DMA memory used by LVGL)

Note

This is the memory used by LVGL for rendering

Note

This is null unless initialize_display() has been called

Returns:

The VRAM 1 pointer

void write_lcd_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, uint8_t *data)

Write a frame to the LCD

Note

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

Parameters:
  • x – The x coordinate

  • y – The y coordinate

  • width – The width of the frame, in pixels

  • height – The height of the frame, in pixels

  • data – The data to write

void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)

Write lines to the LCD

Note

This method queues the panel transfer asynchronously and may return before the write has completed.

Parameters:
  • xs – The x start coordinate

  • ys – The y start coordinate

  • xe – The x end coordinate

  • ye – The y end coordinate

  • data – The data to write

  • user_data – User data to pass to the SPI transaction callback

bool initialize_sound (uint32_t default_audio_rate=44100, const espp::Task::BaseConfig &task_config={ .name="audio",.stack_size_bytes=CONFIG_M5STACK_CARDPUTER_AUDIO_TASK_STACK_SIZE,.priority=CONFIG_M5STACK_CARDPUTER_AUDIO_TASK_PRIORITY,.core_id=CONFIG_M5STACK_CARDPUTER_AUDIO_TASK_CORE_ID})

Initialize the sound subsystem (mono speaker; NS4168 I2S amplifier on the original, ES8311 codec + NS4150B amplifier on the ADV)

Note

The speaker shares I2S pins with the microphone, so this will fail if the microphone has been initialized.

Parameters:
  • default_audio_rate – The default sample rate for the audio, in Hz

  • task_config – The configuration for the audio task. The defaults come from the M5STACK_CARDPUTER_AUDIO_TASK_* Kconfig options.

Returns:

true if the sound subsystem was successfully initialized, false otherwise

uint32_t audio_sample_rate() const

Get the audio sample rate

Returns:

The audio sample rate, in Hz

void audio_sample_rate(uint32_t sample_rate)

Set the audio sample rate

Parameters:

sample_rate – The audio sample rate, in Hz

size_t audio_buffer_size() const

Get the audio buffer size

Returns:

The audio buffer size, in bytes

void mute(bool mute)

Mute or unmute the audio

Parameters:

mute – true to mute the audio, false to unmute it

bool is_muted() const

Check if the audio is muted

Returns:

true if the audio is muted, false otherwise

void volume(float volume)

Set the volume of the audio

Note

The NS4168 has no volume control, so the volume is applied in software when the samples are written to the I2S peripheral

Parameters:

volume – The volume as a percentage (0 - 100)

float volume() const

Get the volume of the audio

Returns:

The volume as a percentage (0 - 100)

void play_audio(const std::vector<uint8_t> &data)

Play the audio data

Note

This function is non-blocking and queues the data for the audio task to play

Parameters:

data – The audio data to play (16-bit signed mono samples)

void play_audio(const uint8_t *data, uint32_t num_bytes)

Play the audio data

Note

This function is non-blocking and queues the data for the audio task to play

Parameters:
  • data – The audio data to play (16-bit signed mono samples)

  • num_bytes – The number of bytes to play

bool initialize_microphone (const microphone_callback_t &callback, uint32_t sample_rate=16000, const espp::Task::BaseConfig &task_config={ .name="microphone",.stack_size_bytes=CONFIG_M5STACK_CARDPUTER_MICROPHONE_TASK_STACK_SIZE,.priority=CONFIG_M5STACK_CARDPUTER_MICROPHONE_TASK_PRIORITY,.core_id=CONFIG_M5STACK_CARDPUTER_MICROPHONE_TASK_CORE_ID})

Initialize the microphone (SPM1423 PDM on the original, analog MEMS via the ES8311 codec on the ADV) and start delivering audio data to the provided callback

Note

The callback runs in the microphone task’s context, so the task’s stack must be large enough for whatever the callback does with the audio data.

Note

The microphone shares I2S pins with the speaker, so this will fail if the sound subsystem has been initialized.

Parameters:
  • callback – The callback to call with recorded audio data (16-bit signed mono samples)

  • sample_rate – The sample rate for the microphone, in Hz

  • task_config – The configuration for the microphone task. The defaults come from the M5STACK_CARDPUTER_MICROPHONE_TASK_* Kconfig options.

Returns:

true if the microphone was successfully initialized, false otherwise

uint32_t microphone_sample_rate() const

Get the microphone sample rate

Returns:

The microphone sample rate, in Hz

bool initialize_sdcard(const SdCardConfig &config)

Initialize the uSD card (SPI mode)

Parameters:

config – The configuration for the uSD card

Returns:

True if the uSD card was initialized properly.

inline sdmmc_card_t *sdcard() const

Get the uSD card

Note

The uSD card is only available if it was successfully initialized and the mount point is valid

Returns:

A pointer to the uSD card

bool initialize_led()

Initialize the RGB LED (WS2812 on the StampS3 module)

Returns:

true if the LED was successfully initialized, false otherwise

bool led(const Hsv &hsv)

Set the color of the LED

Parameters:

hsv – The color of the LED in HSV format

Returns:

true if the color was successfully set, false otherwise

bool led(const Rgb &rgb)

Set the color of the LED

Parameters:

rgb – The color of the LED in RGB format

Returns:

true if the color was successfully set, false otherwise

float battery_voltage()

Get the battery voltage

Note

The battery voltage is measured through a 2:1 divider on GPIO 10

Returns:

The battery voltage, in volts

float battery_soc()

Get the battery state of charge

Note

This is estimated from the battery voltage using a typical 1S lithium-ion discharge curve, so it is only an approximation - the voltage sags under load (e.g. with the backlight at full brightness or the speaker playing) which will lower the estimate.

Returns:

The battery state of charge as a percentage (0 - 100)

bool initialize_imu (const Imu::filter_fn &orientation_filter=nullptr, const Imu::ImuConfig &imu_config={ .accelerometer_range=Imu::AccelerometerRange::RANGE_4G,.accelerometer_odr=Imu::AccelerometerODR::ODR_100_HZ,.accelerometer_bandwidth=Imu::AccelerometerBandwidth::NORMAL_AVG4,.gyroscope_range=Imu::GyroscopeRange::RANGE_1000DPS,.gyroscope_odr=Imu::GyroscopeODR::ODR_100_HZ,.gyroscope_bandwidth=Imu::GyroscopeBandwidth::NORMAL_MODE,.gyroscope_performance_mode=Imu::GyroscopePerformanceMode::PERFORMANCE_OPTIMIZED})

Initialize the IMU (BMI270; Cardputer ADV only)

Note

The original Cardputer has no IMU, so this fails (with an error log) unless the board is a Cardputer ADV.

Parameters:
  • orientation_filter – Optional filter function for orientation (e.g. a kalman or madgwick filter); called by Imu::update()

  • imu_config – The IMU configuration

Returns:

true if the IMU was successfully initialized, false otherwise

inline std::shared_ptr<Imu> imu() const

Get a shared pointer to the IMU

Returns:

A shared pointer to the IMU, or nullptr if it has not been (successfully) initialized

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

Public Static Functions

static inline M5StackCardputer &get()

Access the singleton instance of the M5StackCardputer class.

Returns:

Reference to the singleton instance of the M5StackCardputer class

static inline const char *variant_name(Variant variant)

Get the name of a variant

Parameters:

variant – The variant to get the name of

Returns:

The name of the variant

static char key_value(uint8_t row, uint8_t col, const Modifiers &modifiers)

Get the character for a key, given a modifier state

Parameters:
  • row – The row of the key in the matrix

  • col – The column of the key in the matrix

  • modifiers – The modifier state to apply

Returns:

The character for the key (with the shift layer applied), or 0 if the key has no character

static SpecialKey special_key(uint8_t row, uint8_t col)

Get the special key (fn layer) for a key

Parameters:
  • row – The row of the key in the matrix

  • col – The column of the key in the matrix

Returns:

The special key for the key, or SpecialKey::NONE if it has none

static const char *special_key_name(SpecialKey key)

Get the name of a special key

Parameters:

key – The special key to get the name of

Returns:

The name of the special key

static inline constexpr size_t lcd_width()

Get the width of the LCD in pixels

Returns:

The width of the LCD in pixels

static inline constexpr size_t lcd_height()

Get the height of the LCD in pixels

Returns:

The height of the LCD in pixels

static inline constexpr auto get_lcd_dc_gpio()

Get the GPIO pin for the LCD data/command signal

Returns:

The GPIO pin for the LCD data/command signal

static inline constexpr gpio_num_t ir_tx_gpio()

Get the GPIO pin for the IR transmitter

Returns:

The GPIO pin for the IR transmitter

static inline constexpr gpio_num_t grove_scl_gpio()

Get the GPIO pin for the Grove port SCL / G1 signal

Returns:

The GPIO pin for the Grove port SCL / G1 signal

static inline constexpr gpio_num_t grove_sda_gpio()

Get the GPIO pin for the Grove port SDA / G2 signal

Returns:

The GPIO pin for the Grove port SDA / G2 signal

Public Static Attributes

static constexpr size_t KEYBOARD_ROWS = 4

Number of rows in the keyboard matrix.

static constexpr size_t KEYBOARD_COLS = 14

Number of columns in the keyboard matrix.

static constexpr size_t SPI_MAX_TRANSFER_BYTES = SPI_LL_DMA_MAX_BIT_LEN / 8

Maximum number of bytes that can be transferred in a single SPI transaction to the display. 32k on the ESP32-S3.

static constexpr char mount_point[] = "/sdcard"

Mount point for the uSD card.

struct KeyEvent

A single key state change reported by the keyboard scanner.

Public Members

uint8_t row

Row of the key in the matrix (0 = top / esc row)

uint8_t col

Column of the key in the matrix (0 = leftmost)

bool pressed

True if the key is now pressed, false if released.

char value

The character for the key, with the shift layer applied (0 if the key has no character, e.g. a modifier or an fn-layer special key). Backspace, tab, enter, and space are reported as ‘

’, ‘\t’, ‘

’, and ‘ ‘.

SpecialKey special

The special key (fn layer) if fn was held and the key has one, SpecialKey::NONE otherwise

Modifiers modifiers

The modifier state when the event was generated.

struct Modifiers

The state of the keyboard modifier keys.

Public Members

bool fn = {false}

Fn key.

bool shift = {false}

Left shift key.

bool ctrl = {false}

Left ctrl key.

bool opt = {false}

Opt key.

bool alt = {false}

Left alt key.

struct SdCardConfig

Configuration for the uSD card.

Public Members

bool format_if_mount_failed = false

Format the uSD card if mount failed.

int max_files = 5

The maximum number of files to open at once.

size_t allocation_unit_size = 2 * 1024

The allocation unit size in bytes.