# Two chips

Why a Kode Dot has an ESP32-P4 and an ESP32-C5, what each one does, and which parts of the board answer to the second one.

## What it is

Two chips share the board, and not evenly. The **ESP32-P4** is the computer:
two RISC-V cores at 400 MHz, 32 MB of RAM and 32 MB of flash, and every
interface the parts need, display, audio, I2C, SDIO, USB. Your app runs on
it, and it is the chip everything else on this section answers to. It has no
radio.

The radio is the **ESP32-C5** next to it. It runs Espressif's `esp-hosted`
firmware and hands the P4 Wi-Fi on 2.4 and 5 GHz and Bluetooth over a link
between the two, so your app asks for a network the way it asks for any
peripheral, and the radio stack runs on the other chip.

The C5 also does three things that have nothing to do with wireless, because
its pins were the ones free: it switches power to the microSD card, it reads
whether a card is present, and it enables the speaker's amplifier. Those parts
of the board come up through the C5, so a C5 running the wrong firmware makes
the card and the speaker disappear together.

## How it is connected

```mermaid
flowchart LR
  p4["ESP32-P4"] -- "SDIO 4-bit, 40 MHz" --> c5["ESP32-C5"]
  p4 -- "UART" --> c5
  p4 -- "EN, BOOT, wake" --> c5
  c5 -. "IO26 SD_PWR" .-> sd["microSD power"]
  c5 -. "IO25 SD_CD" .-> cd["card detect"]
  c5 -. "IO4 PA_CTRL" .-> amp["speaker amplifier"]
```

*The P4 runs the board; the C5 is a peripheral of it that happens to own three enables*

The data link is 4-bit SDIO on the P4's second SD controller, `GPIO48` to
`GPIO53`, at 40 MHz, plus a UART for Bluetooth's HCI. The P4 can hold the C5
in reset and put it in bootloader mode, which is how the C5's firmware is
written: from the P4 over the UART, or through three pins of the expansion
header, `GPIO8` to `GPIO10`. Kode's C5 firmware raises the three enables at
boot.

## Specifications

| Thing | Value |
| --- | --- |
| Main chip | ESP32-P4NRW32X: two RISC-V cores at 400 MHz, 32 MB PSRAM in the package, 32 MB NOR flash beside it |
| The P4 drives | The display over MIPI-DSI, audio over I2S, every I2C part, the microSD over SDIO, the NFC reader over SPI, USB-C |
| Radio chip | ESP32-C5-MINI-1: Wi-Fi 2.4 and 5 GHz, Bluetooth |
| Link | SDIO 4-bit at 40 MHz for data, a UART for Bluetooth, and enable, boot and wake lines |
| C5 firmware | Espressif `esp-hosted-mcu` 2.12.9, with Kode's change that raises the three enables at boot |
| The C5 owns | `SD_PWR` on `IO26`, active low; `SD_CD` on `IO25`; `PA_CTRL` on `IO4` |
| Validated | Wi-Fi scan on both bands, BLE scan and advertising, and the microSD and speaker enables, on a board |

## Gotchas

> **WARNING**
>
> **The card and the speaker vanished together.** Both are switched on by the
> C5, so both go quiet when it runs anything but Kode's firmware. A Wi-Fi scan
> that returns networks is the one test that proves the C5, the link and its
> firmware at once; run it before you debug storage or audio.

> **NOTE**
>
> **Wireless can fail in a way a local peripheral cannot.** Everything Wi-Fi or
> Bluetooth crosses the link to the C5 and comes back. When a network call
> fails, the link itself is a candidate, not only the network.

> **NOTE**
>
> **The C5 could do more than Wi-Fi and Bluetooth.** The silicon speaks other
> protocols; the Kode Dot has run these two, with Espressif's firmware
> unmodified. Do not promise a protocol this page does not name.

## 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.

- https://apps.kode.diy/app/671af895-5ce0-43da-a7d7-769677426cdf
- https://apps.kode.diy/app/88fb0631-d94c-4b92-8aa5-141dbdd22534
- https://apps.kode.diy/app/282397ff-1f75-4c51-803a-873d53268717
- https://apps.kode.diy/app/f2f10f07-aa43-4f5b-86ce-34bbb6f11925
- https://apps.kode.diy/app/0a8a1179-088e-4fae-a2e5-b97a0a0923e1
- https://apps.kode.diy/app/e22664f5-9a5a-4c6f-8fd6-89ef68ab20a3
- https://apps.kode.diy/app/e3e0f8b8-6043-45a3-9fde-69add83d4b5d
- https://apps.kode.diy/app/358599b5-9ee1-4d91-b1c5-47c93da98e0a

## Example code

Scan for Wi-Fi networks through the C5 and log what it finds. The list comes
back within a few seconds; an empty list with no error means the link is up
and there is no network in reach.

```c
/*
 * wifi_scan.c - 2026-09-18 - from Kode with love
 *
 * Asks the Kode Dot's C5 for the Wi-Fi networks around it and logs each name
 * with its channel and signal. Brings the esp-hosted link up first; the C5
 * has to be running Kode's firmware. Expect a list within a few seconds.
 */
#include "esp_hosted.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"

/* Link to the C5, then the ordinary ESP-IDF Wi-Fi calls, which now run over it. */
void app_main(void)
{
    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_hosted_init());

    wifi_init_config_t init = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&init));
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_start());
    ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, true));

    uint16_t count = 20;
    wifi_ap_record_t found[20];
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&count, found));
    for (int i = 0; i < count; i++) {
        ESP_LOGI("wifi", "%-32s ch %2d  %4d dBm", found[i].ssid, found[i].primary, found[i].rssi);
    }
}
```

The calls are the ones Kode's validation ran on a board, `host_wifi_scan` in
`02-ESP-HOSTED-MCU`, which found 46 to 65 networks on both bands. **TBD**: a
compile of this box against the `esp_hosted` component, which is not in the
`kode` component yet.

## In the SDK

- [`kdrv_radio`](https://github.com/kodediy/kode-sdk/tree/main/components/kdrv/kdrv_radio): the C5 link in `kode-sdk`.
- [`kode_slave_c5`](https://github.com/kodediy/kode_slave_c5): the firmware the C5 runs.
