I2S amplifier/Using it/07. First sound
Using it · 07 of 9

First sound

The first build is a scale of seven notes, Do to Si, on the kit's speaker. The sketch drives CTRL HIGH, starts I2S at 16 kHz on GPIO 15, 16 and 17, and works out every sample of every note with a sine, writing each one twice, left and right. Nothing to install: ESP_I2S comes with the ESP32 core.

What you need

  • An ESP32-S3 dev board on a USB cable.
  • The TK100 and the kit's speaker, plugged into the white socket.
  • Six jumper wires.

Wire it

TK100ESP32-S3
GNDGND
3V33V3
LRCLKGPIO 16
BCLKGPIO 15
DINGPIO 17
CTRLGPIO 18

CTRL is the wire that gets left off. Without it the sketch runs, prints every note, and the speaker stays silent.

What the sketch sends

What the sketch sends for one note
La, 440 Hz
Note
Samples a cycle
36.4
In a 400 ms note
6400 samples
Level
18 % of full
La, 440 Hz: a cycle every 36.4 samples. The sketch works out every one with sinf() and writes it twice, left and right, 16000 times a second: a bit clock of 512 kHz. A higher note gets fewer samples a cycle; the rate stays the same. The level, 6000, is about a fifth of the most a 16-bit sample can hold, to keep the first sound gentle.

playNote() works out each sample as level * sinf(phase) and moves the phase on by one step per sample, so a higher note takes bigger steps and completes a cycle in fewer samples. At 440 Hz that is 16000 / 440, about 36 samples a cycle.

Each sample goes into both halves of the frame, frame[0] = frame[1], so the chip plays it whichever channel its jumper picks. A 400 ms note is 6400 frames.

playNote(0, 100) is the gap: a sine of 0 Hz stays at 0, which is silence.

Three lines that matter

pinMode(PIN_AMP_ON, OUTPUT);
digitalWrite(PIN_AMP_ON, HIGH);       // wake the amplifier

CTRL, driven HIGH before anything is played. The name is PIN_AMP_ON, not PIN_CTRL, because the ESP32-S3 core already uses PIN_CTRL for something of its own, and a sketch that declares it does not compile.

i2s.begin(I2S_MODE_STD, RATE, I2S_DATA_BIT_WIDTH_16BIT,
          I2S_SLOT_MODE_STEREO)

Standard I2S, 16 kHz, 16-bit, stereo: a bit clock of 512 kHz, 32 ticks per frame, which the NS4168 accepts.

What it prints

Playing
261.63
293.66
329.63

and so on to 493.88, a second's pause, and round again, one printed number per note you hear.

The code

tk100_tone.ino

Six wires and the speaker. The sketch plays Do, Re, Mi, Fa, Sol, La, Si, 400 ms each with a short gap, then waits a second and starts again, printing each frequency to the Serial Monitor.

// TK100 I2S Amplifier: first sound. A scale of seven notes on the speaker.
//
// Wiring, TK100 to ESP32-S3:
//   GND   -> GND
//   3V3   -> 3V3
//   LRCLK -> GPIO 16
//   BCLK  -> GPIO 15
//   DIN   -> GPIO 17
//   CTRL  -> GPIO 18   (HIGH plays, LOW or unconnected is off)
//   Speaker, 4 or 8 ohm, in the white two-pin socket.
//
// Arduino IDE: Tools > Board > "ESP32S3 Dev Module" (esp32 core 3.x),
// USB CDC On Boot: Enabled. Serial Monitor at 115200.

#include <ESP_I2S.h>

const int PIN_BCLK   = 15;
const int PIN_LRCLK  = 16;
const int PIN_DIN    = 17;
const int PIN_AMP_ON = 18;

const int RATE = 16000;                 // samples per second
I2SClass i2s;

// One frame is a left sample then a right sample. The amplifier plays
// only one of them, so the same value goes in both.
void playNote(float hz, int ms) {
  const int16_t level = 6000;           // about a fifth of full scale
  int16_t frame[2];
  float phase = 0;
  float step = 2 * PI * hz / RATE;
  for (int i = 0; i < RATE * ms / 1000; i++) {
    frame[0] = frame[1] = (int16_t)(level * sinf(phase));
    i2s.write((uint8_t *)frame, sizeof(frame));
    phase += step;
    if (phase > 2 * PI) phase -= 2 * PI;
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(PIN_AMP_ON, OUTPUT);
  digitalWrite(PIN_AMP_ON, HIGH);       // wake the amplifier

  i2s.setPins(PIN_BCLK, PIN_LRCLK, PIN_DIN);
  if (!i2s.begin(I2S_MODE_STD, RATE, I2S_DATA_BIT_WIDTH_16BIT,
                 I2S_SLOT_MODE_STEREO)) {
    Serial.println("I2S did not start");
    while (true) delay(1000);
  }
  Serial.println("Playing");
}

void loop() {
  const float notes[] = {261.63, 293.66, 329.63, 349.23,
                         392.00, 440.00, 493.88};
  for (float hz : notes) {
    Serial.println(hz);
    playNote(hz, 400);
    playNote(0, 100);                   // a short gap
  }
  delay(1000);
}

Compiled, not run, for an ESP32S3 Dev Module on esp32 core 3.3.10; ESP_I2S is part of that core. The board itself was tested by its maker playing this same scale from his own code on other pins; this sketch puts the amplifier on 15 to 18 so it never meets the microphone's 5 and 6.

When it does not work

It prints the notes but the speaker is silent.

The sketch is running and I2S started, so look at CTRL: it must reach GPIO 18, and the sketch drives it HIGH in setup(). Then check DIN is on GPIO 17 and the speaker plug is fully in the white socket.

It prints I2S did not start.

ESP_I2S refused the pins or the settings. Check the board is set to ESP32S3 Dev Module on esp32 core 3.x, which is the version with ESP_I2S.h, and that nothing else in the sketch uses GPIO 15, 16 or 17.

The Serial Monitor shows nothing at all.

Tools > USB CDC On Boot must be Enabled for Serial to reach the USB port on most ESP32-S3 boards. Set it, upload again, and open the Serial Monitor at 115200.

The notes sound rough or buzzy.

Check the level: 6000 is about a fifth of full scale on purpose, and raised much higher a loud note asks more of the 3.3 V supply. Then check that neither speaker lead touches GND or the other lead's bare end.

ESP_I2S.h: No such file or directory.

The ESP32 core is older than 3.0. Open Tools > Board > Boards Manager, update esp32 by Espressif Systems to a 3.x version, and compile again.

Where this goes next

Three seconds from the TK101 microphone, played back on the TK100.

Record and play back

Edit this page — content/books/i2s-amplifier/first-sound.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

I2S Amplifier

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum