Kode Dot
Buttons
The six buttons on a Kode Dot: a four-way pad and two singles, how five of them reach the P4 through an expander, and the code to read them.
What it is
Six push-buttons: a four-way pad on the front, and one single button above it and one below. Each is a switch to ground with a pull-up, so a line reads high at rest and low while pressed. That is all a button is: one bit, pressed or not, no pressure and no analogue level.
They do not all reach the P4 the same way. Five of them, the pad and the bottom single, hang off a TCA6408 I2C port expander and come back as five bits of one byte. The sixth, the top single, is wired straight to a P4 pin. Reading the buttons is one I2C read plus one pin read, which the Kode driver combines for you.
How it is connected
flowchart LR p4["ESP32-P4"] -- "I2C, 0x20" --> exp["TCA6408"] exp -- "P0" --> bot["bottom"] exp -- "P1..P4" --> pad["pad: up, left, down, right"] top["top"] -- "GPIO35" --> p4
The expander answers at 0x20 on the shared I2C bus and has 10 kΩ pull-ups
on the board for its five button lines. The top button is on GPIO35 with
the P4's internal pull-up. The expander's interrupt line reaches GPIO6, but
Kode's examples poll on a timer instead.
Specifications
| Thing | Value |
|---|---|
| Buttons | Six, all active low: pressed reads 0 |
| Expander | TCA6408, U24, at 0x20 on the shared I2C bus |
| Bottom single | Expander P0 |
| Pad up, left, down, right | Expander P1, P2, P3, P4 |
| Top single | GPIO35 on the P4 |
| Pull-ups | 10 kΩ on the board for the five; the P4's internal one for the top |
| Interrupt | Expander interrupt on GPIO6, unused by any Kode example |
| Kode driver | kode_buttons_init, then kode_buttons_pressed(btn) for one or kode_buttons_mask() for all six in one read |
| Validated | Kode-Dot-Val/11-INPUT: all six on a board |
Gotchas
Apps that use it
On the marketplace, apps that put this part to work. Install one from
start/first-app and see it before you write a line.
Example code
Log every button as it goes down. Press the pad and the two singles and each one prints its name once per press.
/*
* buttons_log.c - 2026-09-18 - from Kode with love
*
* Watches the Kode Dot's six buttons twenty times a second and logs each one
* the moment it goes down. Brings the board up, configures the buttons through
* the Kode driver, then polls the six-bit mask and reports the edges.
*/
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "kode.h"
static const char *NAMES[] = { "bottom", "pad up", "pad left", "pad down", "pad right", "top" };
/* Board, buttons, then compare each poll with the last one. */
void app_main(void)
{
ESP_ERROR_CHECK(kode_bsp_init());
ESP_ERROR_CHECK(kode_buttons_init());
uint8_t last = 0;
while (1) {
uint8_t now = kode_buttons_mask(); /* bit N set while button N is down */
uint8_t went_down = now & ~last;
for (int i = 0; i < 6; i++) {
if (went_down & (1 << i)) ESP_LOGI("buttons", "%s", NAMES[i]);
}
last = now;
vTaskDelay(pdMS_TO_TICKS(50));
}
}Compiled on the date in the header against the kode component with
ESP-IDF v6.1. TBD: a run on a V1 board.
In the SDK
kdrv_buttons.c: the buttons inkode-sdk.kdrv_tca6408a.c: the expander they share with the display.