Adding a Speaker to CV1 & DevKit 1
This page covers adding a small I2S amplifier and dynamic micro-speaker to Omi hardware that does not ship with a usable speaker, so that a phone or host application can play audio through the device.Before you start: which board do you have?
Omi’s audio hardware differs per model, and this determines whether the mod is worth attempting at all.
Only CV1 uses the nRF5340. DevKit 1 and DevKit 2 are both Xiao nRF52840 boards, and the
devkit firmware targets the upstream
xiao_ble_sense board rather than an Omi board file.
These are source-level facts from this repository, not marketing copy: the SoC split is
documented in
docs/doc/hardware/OmiConsumer.mdx and docs/doc/hardware/DevKit2.mdx,
the CV1 main SoC is listed as nRF5340-CLAA in
docs/doc/hardware/consumer/electronics.mdx, and the DevKit 2 audio hardware is listed in
omi/hardware/triangle v2 w memory/README.md.Why an amplifier is required
A passive buzzer or transducer is driven at its resonant frequency and cannot reproduce intelligible speech, so it is useless for voice feedback. A dynamic micro-speaker can, but an nRF GPIO pin cannot drive a speaker coil: GPIOs are low-current digital signals, and their drive strength is bounded by the datasheet. The usual solution is an I2S input Class-D amplifier, which accepts digital audio and delivers the current the coil needs. The amplifier’s audio inputs are high-impedance, so they do not fight the GPIO’s limits.Suggested parts
These are reasonable, widely available choices. They are not a validated combination for Omi hardware, and no part here has been tested with an Omi board.Wiring
Because no I2S pin mapping is published for CV1 or DevKit 1, you must choose and verify the pins yourself. This repository contains no documented table mapping those boards’ pads or test points to I2S signals, and their published pinouts do not cover audio. Do not assume a pad is exposed: on CV1 the documented pogo pins are charging contacts, and on DevKit 2 the audio pads are solder joints between the XIAO and the audio board rather than documented test points. The connection itself is conventional:- VIN — connect to a supply the amplifier accepts. Use the board’s regulated rail, and confirm the MAX98357A breakout’s input range matches it.
- GND — common ground with the board.
- BCLK — I2S bit clock, from a GPIO you have assigned as
I2S_SCK. - LRC — I2S word select / left-right clock, from a GPIO assigned as
I2S_LRCK. - DIN — I2S data out from the SoC, from a GPIO assigned as
I2S_SDOUT. - GAIN — the MAX98357A has several gain settings. Tie it appropriately for your speaker and volume; the breakout’s default is usually a reasonable starting point.
What you would have to build
Concretely, the gaps are:- No I2S output path in firmware. CV1’s board devicetree has no
i2s0node, andomi/firmware/boards/omi/omi-pinctrl.dtsidefines UART, I2C, PDM, QSPI, SPI and PWM pin groups but no I2S group. A dormantspeaker.cexists under the CV1 sources, but it is not in the CV1 build’s source list and the speaker feature is disabled inomi/firmware/omi/omi.confviaCONFIG_OMI_ENABLE_SPEAKER=n. - DevKit 1 has no audio output either. Its standard overlay enables nothing and states that no modules are used.
- The firmware does not synthesise speech. Omi’s device firmware consumes PCM; it does
not do text-to-speech. TTS exists in the mobile app, which calls the backend’s
/v2/tts/synthesizeendpoint and plays the returned audio through the phone. A host-side script in the firmware tree does the same for DevKit 2, generating audio with a cloud TTS provider and streaming it to the device over BLE. - You would need an audio source. Since the device will not generate speech itself,
sound has to come from the phone or a host computer. You would be bridging a new path
(BLE or otherwise) from that source into an
i2s_writecall.
i2s0 node and a pinctrl group for your board
in a custom overlay, enable the I2S driver and the speaker feature, and write or port a
playback path. All of that is currently out-of-tree.
Firmware symbols that actually exist
If you write that overlay, these are the real symbols in this repository, not invented ones:
Board targets, for reference:
Nordic’s
nrf5340dk_nrf5340_cpuapp DK target is not used by Omi firmware and is not a
build target in this repository. If you are flashing a devkit, you are building for
xiao_ble_sense, not for a DK board.
How DevKit 2 does it (verified)
If your goal is simply “hear audio from the device”, DevKit 2 is the supported path and you do not need this mod. Its firmware contains a working I2S transmit path:- The DevKit 2 overlay enables
i2s0and assigns the I2S pins: BCLK/SCK = P0.29 (board pad A3), LRCLK = P0.28 (A2), SDOUT = P0.03 (A1). The speaker driver also uses P0.04 as a speaker-control GPIO. - The speaker driver obtains
I2S_0, configures it for transmit, and sends buffered PCM withi2s_write. - PCM arrives over BLE: a write to the device’s audio characteristic is routed to the speaker path.
- The firmware also plays a boot chime through the same path.
omi/firmware/devkit/overlay/xiao_ble_sense_devkitv2-adafruit.overlay and
omi/firmware/devkit/src/speaker.c. They are source assignments on that specific board,
not a general Omi pinout, and not a set of exposed test pads.
To play arbitrary text through DevKit 2, the firmware tree includes a host-side script that
generates speech with a cloud TTS provider and streams it to the device over BLE:
omi/firmware/scripts/devkit/play_sound_on_friend.py. It needs a TTS API key and a BLE
client, and it targets DevKit 2’s audio characteristic.
Acoustic design tips
These are general speaker-in-a-small-enclosure considerations and apply regardless of the board you are modifying.- Acoustic porting. Give the enclosure a grille or an opening, roughly 1.5–2 mm, aligned with the front of the speaker diaphragm. Without a port, the enclosure walls dominate the low end and the speaker sounds thin.
- Gasket sealing. Use closed-cell foam or a silicone gasket around the speaker perimeter. Sealing the front and back cavities prevents cancellation and gives a noticeably cleaner, louder result.
- Headroom. Keep the amplifier’s gain low enough that normal speech does not clip. Clipped speech is more fatiguing than slightly quiet speech.
- Keep the mic clear. Omi captures audio with PDM microphones. Do not route speaker output into the microphone cavity in a way that causes the device to hear itself.
If you build this
Omi accepts pull requests, and a validated version of this page would be a genuine
contribution. If you work through the gaps above, please open a PR with the details that
were missing here: which board you used, the exact pin or pad mapping, the devicetree
overlay and Kconfig lines you actually flashed, and whether you got audio out. That would
let this page be rewritten from tested instructions instead of a design sketch.