# Camera

A 5 megapixel camera with autofocus for the Kode Dot, for taking photos, watching video on the screen or handing the image to an AI.

![The Camera module: the camera, on its short ribbon, looks up from the component side, and the pins that enter the Kode Dot's expansion header leave from one edge of the board](/modules/camera.jpg)

*Camera module, revision 1.0*

## What it is

The Camera module gives the Kode Dot eyes: a 5 megapixel camera with autofocus. It takes photos, shows on the screen what is in front of it, or hands the image to an **AI** that recognises what it sees, a face or an object. It plugs into the Kode Dot's expansion header.

## How it is connected

The module plugs straight into the expansion header and stands upright above the Kode Dot. **It goes in two ways and both work.** With the lens on the screen side, the camera looks at you. Turned round, it looks away. Each way puts the I2C and the video on different GPIOs.

![Two Kode Dots standing with the Camera module plugged in on top, both marked as correct. On the left, seen from the front, the lens is on the screen side. On the right, seen from the back, the module is turned round and the lens looks the same way as the Kode Dot's back](/modules/camera/dos-maneras.jpg)

*Both work. Left, the lens towards you, on the screen side. Right, seen from the back, the lens looking away*

1. Push the module's pins into the expansion header, with the lens the way you want it to look: towards you, on the screen side, or away.
2. Flash your program with the pins from the matching column of the table below, for example the one at the end of this page.

The 14 GPIOs, for each way of plugging the module in. `D2` to `D9` are the sensor's data lines, your bits 0 to 7. Everything is an input of the P4 except `PWDN`, an output, and the I2C pair:

| GPIO | Lens towards you | Lens looking away |
| --- | --- | --- |
| `GPIO8` | `SCL` | `D4` |
| `GPIO9` | `SDA` | `D3` |
| `GPIO10` | `VSYNC` | `D5` |
| `GPIO11` | `PWDN` | `D2` |
| `GPIO12` | `HSYNC` | `D6` |
| `GPIO13` | `D9` | `PCLK` |
| `GPIO14` | `D8` | `D7` |
| `GPIO15` | `D3` | `SDA` |
| `GPIO16` | `D4` | `SCL` |
| `GPIO17` | `D2` | `PWDN` |
| `GPIO18` | `D5` | `VSYNC` |
| `GPIO19` | `PCLK` | `D9` |
| `GPIO20` | `D6` | `HSYNC` |
| `GPIO21` | `D7` | `D8` |

Both columns come from the netlist of the 2026-10-07 issue, which the 2026-10-26 issue keeps. The same turn rule reproduced the map measured on the earlier camera board.

## Specifications

The module:

| Thing | Value |
| --- | --- |
| Part | KDCMR001, revision 1.0, issue of 2026-10-26. It adds a 220 Ω resistor in series with the sensor's clock, for emissions; the rest of the circuit is the 2026-10-07 issue's |
| Mounts on | The Kode Dot's expansion header, straight |
| Connector | `J401`, 2 × 10, right-angle male, 2.54 mm. Its numbering is mirrored against the expansion header's: pin 1 of `J401`, 3.3 V, lands on the header's pin 19 |
| Board | 46.7 × 45.6 mm, two layers, 1.6 mm, four 3.2 mm mounting holes |
| Supplies | 3.3 V from the expansion header. The module makes 1.5 V for the sensor's core (`U501`) and 2.8 V for its analog side (`U502`). The focus motor takes the 3.3 V straight. Everything starts when the header's 3.3 V comes up |
| I/O supply | The sensor's `DOVDD` pin goes to 3.3 V, above the 3.0 V the OV5640 datasheet recommends (absolute maximum 4.5 V). **TBD**: the limit in the FD5640-500W-V11 datasheet |
| 5 V | Not used |
| Consumption | From the 3.3 V only. About 0.1 A streaming at 800 × 600 and 0.34 A worst case, adding the datasheets. **TBD**: the current measured on a board |
| Validated | Photos and autofocus from a Kode Dot with Kode's camera app, on a module with this pin map, 2026-10-25. Before that, an earlier camera board with another camera and another pin order answered at `0x3C` and sent images both ways round, September 2026 (`Kode-Dot-Val/1-EVT/demo/camera_viewer`). **TBD**: an image captured with the 2026-10-26 issue, both ways round |

The camera:

| Thing | Value |
| --- | --- |
| Sensor | OV5640, 5 MP, autofocus, in an FD5640-500W-V11 camera module on a 24-pin 0.5 mm ribbon, `J501`. The lens is on the component side |
| Image | Espressif's `esp_cam_sensor` component offers the OV5640 over DVP one size with the module's 24 MHz clock: 800 × 600 at 10 frames per second. RGB565 at that size is the mode Kode's apps run on a Kode Dot. **TBD**: a larger size |
| Bus | DVP: eight data lines, `D2` to `D9`, plus `PCLK`, `HSYNC` and `VSYNC`. The sensor has ten data lines and the module wires the top eight |
| Control | SCCB, the sensor's I2C, with 2.2 kΩ pull-ups to 3.3 V on the module. The OV5640 answers at `0x3C`, and its registers `0x300A` and `0x300B` hold its identifier, `0x5640` |
| Clock | A 24 MHz oscillator on the module, through a 220 Ω series resistor (`R503`) since the 2026-10-26 issue, only for the sensor. No pin of the expansion header carries a clock |
| Reset | A 10 kΩ pull-up and a 100 nF capacitor reset the sensor at power-up. It goes to no GPIO. In software, write `0x82` to register `0x3008` |
| Power-down | `PWDN`, active high, with a 10 kΩ pull-down: the sensor runs unless you drive it high |
| Autofocus | A voice-coil motor, driven by a processor inside the sensor that starts empty. It needs about 4 KB of firmware over I2C after every power-up; Kode's camera app loads it. **TBD**: where that firmware ships for your own code |
| Autofocus jumper | `JP501`, marked `autofocus`, is closed and carries 3.3 V to pin 23 of the ribbon. Open it if you fit another camera module that uses that pin for something else |
| Image orientation | Registers `0x3820` and `0x3821`, bits 2 and 1, flip and mirror the image. **TBD**: the setting that leaves the image upright for each way of plugging the module in |
| AI | ESP-DL, Espressif's neural network library, runs on the ESP32-P4 and ships models that detect faces and people in the image. **TBD**: an AI example with this camera run on a Kode Dot |

## Gotchas

> **WARNING**
>
> **Nothing answers at `0x3C`, or the images come out as noise.** Your code uses the column for the other way of plugging the module in. Take the pins from the column that matches how it sits. The camera programs in `Kode-Dot-Val` are for the earlier board, with another order: do not run them on this module.

> **WARNING**
>
> **Do not configure an `XCLK` output.** Almost every camera example drives the sensor's clock out of a GPIO. Here the module generates it, and that GPIO is a video line. Set `xclk_io` to `GPIO_NUM_NC` and `external_xtal` to 1 in the DVP controller.

> **NOTE**
>
> **The lens does not focus.** The sensor's focus processor starts empty. Without its firmware the lens stays at its resting focus. Send it over I2C every time the module powers up.

## Example code

For the image, the pieces are ESP-IDF's DVP controller, `esp_cam_ctlr_dvp`, and Espressif's `esp_cam_sensor` component, which brings the OV5640 driver. The `esp32-camera` component has no target for the ESP32-P4.

This example asks the sensor who it is, with the module plugged in with the lens towards you. In the log of `idf.py monitor` you will see `sensor id = 0x5640`. If it does not answer, the module is turned round: change the I2C pins to the ones in the comment.

```c
/*
 * camera_id.c - 2026-10-14 - from Kode with love
 *
 * Asks the sensor of the Camera module who it is, with the module plugged
 * in with the lens towards you. Opens its I2C on GPIO8 and GPIO9 and reads
 * registers 0x300A and 0x300B of the OV5640. In the monitor you will see
 * "sensor id = 0x5640". The sensor's clock and reset come from the module
 * itself, so nothing else is needed.
 */
#include <stdio.h>
#include "driver/i2c_master.h"

/* Reads one byte from a sensor register; the sensor has 16-bit addresses. */
static uint8_t sensor_read(i2c_master_dev_handle_t sensor, uint16_t reg)
{
    uint8_t address[2] = { reg >> 8, reg & 0xFF };
    uint8_t value = 0;
    i2c_master_transmit_receive(sensor, address, 2, &value, 1, 100);
    return value;
}

/* Opens the camera's I2C and prints the sensor's identifier. */
void app_main(void)
{
    i2c_master_bus_config_t bus_config = {
        .i2c_port = -1,
        .scl_io_num = 8,   /* with the lens looking away: 16 */
        .sda_io_num = 9,   /* with the lens looking away: 15 */
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .glitch_ignore_cnt = 7,
    };
    i2c_device_config_t sensor_config = { .device_address = 0x3C, .scl_speed_hz = 100000 };
    i2c_master_bus_handle_t bus;
    i2c_master_dev_handle_t sensor;
    i2c_new_master_bus(&bus_config, &bus);
    i2c_master_bus_add_device(bus, &sensor_config, &sensor);

    printf("sensor id = 0x%02X%02X\n", sensor_read(sensor, 0x300A), sensor_read(sensor, 0x300B));
}
```

Compiled on the date in the header with ESP-IDF v6.1. **TBD**: a run on a module of the 2026-10-26 issue.

## In the SDK

- [`kode.h`](https://github.com/kodediy/kode-sdk/blob/main/components/kode/include/kode.h): in a kodeOS app, `kode_exp_power(true)` switches the header's 3.3 V on, `kode_exp_lend()` takes the 14 positions the camera occupies under a name and gives you their GPIO numbers, and `kode_exp_ctrl()` hands you a free I2C controller for the sensor.
- **TBD**: a camera driver in `kode-sdk`. Today, `esp_cam_ctlr_dvp` and `esp_cam_sensor`.
- `hardware/camera`: the schematic, to view and download.
