Skip to content

Commit 07500e8

Browse files
Rewrite I2S from scratch, add I2S input support (#569)
Rewrite the I2S code from scratch to eliminate the dependence on the pico-extras implementation and to support I2S input as well. 8-bit, 16-bit, 24-bit, and 32-bit words are supported. Multiple I2S ports are allowed (theoretically up to 6 because 2 DMA channels are required per port). I2S input and I2S output are supported. Add input example Fixes #535 Fixes #99 Fixes #562
1 parent 3adc1c5 commit 07500e8

File tree

15 files changed

+1120
-284
lines changed

15 files changed

+1120
-284
lines changed

.github/workflows/pull-request.yml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ jobs:
2020
- name: Run codespell
2121
uses: codespell-project/actions-codespell@master
2222
with:
23-
skip: ./pico-extras,./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS
24-
ignore_words_list: ser,DOUT
23+
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS
24+
ignore_words_list: ser,dout
2525

2626
# Consistent style
2727
astyle:
@@ -81,8 +81,6 @@ jobs:
8181
run: |
8282
cd pico-sdk
8383
git submodule update --init
84-
cd ../pico-extras
85-
git submodule update --init
8684
cd ..
8785
bash ./tests/build.sh
8886
@@ -111,8 +109,6 @@ jobs:
111109
run: |
112110
cd pico-sdk
113111
git submodule update --init
114-
cd ../pico-extras
115-
git submodule update --init
116112
cd ..
117113
bash ./tests/build-tinyusb.sh
118114
@@ -147,8 +143,6 @@ jobs:
147143
try { Get-Command python3 } catch { copy (get-command python).source (get-command python).source.Replace("python.exe", "python3.exe") }
148144
cd pico-sdk
149145
git submodule update --init
150-
cd ../pico-extras
151-
git submodule update --init
152146
cd ..
153147
bash ./tests/build.sh
154148
@@ -181,8 +175,6 @@ jobs:
181175
run: |
182176
cd pico-sdk
183177
git submodule update --init
184-
cd ../pico-extras
185-
git submodule update --init
186178
cd ..
187179
bash ./tests/build.sh
188180

.gitmodules

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
[submodule "libraries/SdFat"]
1414
path = libraries/ESP8266SdFat
1515
url = https://github.com/earlephilhower/ESP8266SdFat.git
16-
[submodule "pico-extras"]
17-
path = pico-extras
18-
url = https://github.com/raspberrypi/pico-extras.git
1916
[submodule "libraries/Keyboard"]
2017
path = libraries/Keyboard
2118
url = https://github.com/earlephilhower/Keyboard

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ cd ~/Arduino/hardware/pico/rp2040
7070
git submodule update --init
7171
cd pico-sdk
7272
git submodule update --init
73-
cd ../pico-extras
74-
git submodule update --init
7573
cd ../tools
7674
python3 ./get.py
7775
`````
@@ -145,12 +143,13 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
145143
* Multicore support (setup1() and loop1())
146144
* Overclocking and underclocking from the menus
147145
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
148-
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio output, Servo
146+
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input, I2S audio output, Servo
149147
* printf (i.e. debug) output over USB serial
150148
151149
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
152150
* Servos
153151
* Tones
152+
* I2S Input
154153
* I2S Output
155154
* Software UARTs (Serial ports)
156155
@@ -168,7 +167,7 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
168167
# Licensing and Credits
169168
* The [Arduino IDE and ArduinoCore-API](https://arduino.cc) are developed and maintained by the Arduino team. The IDE is licensed under GPL.
170169
* The [RP2040 GCC-based toolchain](https://github.com/earlephilhower/pico-quick-toolchain) is licensed under under the GPL.
171-
* The [Pico-SDK](https://github.com/raspberrypi/pico-sdk) and [Pico-Extras](https://github.com/raspberrypi/pico-extras) are by Raspberry Pi (Trading) Ltd and licensed under the BSD 3-Clause license.
170+
* The [Pico-SDK](https://github.com/raspberrypi/pico-sdk) is by Raspberry Pi (Trading) Ltd and licensed under the BSD 3-Clause license.
172171
* [Arduino-Pico](https://github.com/earlephilhower/arduino-pico) core files are licensed under the LGPL.
173172
* [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md).
174173
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.

docs/i2s.rst

Lines changed: 150 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,181 @@
1-
I2S (Digital Audio) Output Library
2-
==================================
1+
I2S (Digital Audio) Audio Library
2+
=================================
33

44
While the RP2040 chip on the Raspberry Pi Pico does not include a hardware
55
I2S device, it is possible to use the PIO (Programmable I/O) state machines
66
to implement one dynamically.
77

8-
This I2S library uses the ``pico-extras`` I2S audio library and wraps it in
9-
an Arduino I2S library. It supports 16 bits/sample and frequencies of up
10-
to 48kHZ, with configurable BCLK, LRCLK(always pin "BCLK + 1"), and DOUT pins.
8+
Digital audio input and output are supported at 8, 16, 24, and 32 bits per
9+
sample.
10+
11+
Theoretically up to 6 I2S ports may be created, but in practice there
12+
may not be enough resources (DMA, PIO SM) to actually create and use so
13+
many.
14+
15+
Create an I2S port by instantiating a variable of the I2S class
16+
specifying the direction. Configure it using API calls below before
17+
using it.
1118

12-
**Note:** This I2S device takes over the entire PIO1 (second) unit and adjusts
13-
its clock frequency to meet the I2S needs. That means when only 4 Tones
14-
or only 4 Servos may be used when the I2S device is used.
1519

1620
I2S Class API
1721
-------------
1822

23+
I2S(OUTPUT)
24+
~~~~~~~~~~~
25+
Creates an I2S output port. Needs to be connected up to the
26+
desired pins (see below) and started before any output can happen.
27+
28+
I2S(INPUT)
29+
~~~~~~~~~~
30+
Creates an I2S input port. Needs to be connected up to the
31+
desired pins (see below) and started before any input can happen.
32+
1933
bool setBCLK(pin_size_t pin)
2034
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2135
Sets the BCLK pin of the I2S device. The LRCLK/word clock will be ``pin + 1``
22-
due to limitations of the PIO state machines. Call this before ``I2S.begin()``
23-
Default BCLK = 26, LRCLK = 27
36+
due to limitations of the PIO state machines. Call this before ``I2S::begin()``
2437

25-
bool setDOUT(pin_size_t pin)
38+
bool setDATA(pin_size_t pin)
2639
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27-
Sets the DOUT pin of the I2S device. Any pin may be used. Default DOUT = 28
28-
Call before ``I2S.begin()``
29-
30-
bool begin(long sampleRate)
31-
~~~~~~~~~~~~~~~~~~~~~~~~~~~
32-
Start the I2S device up with the given sample rate. The pins selected above
33-
will be turned to output and the I2S will begin to drive silence frames (all
34-
zero) out.
40+
Sets the DOUT or DIN pin of the I2S device. Any pin may be used.
41+
Call before ``I2S::begin()``
42+
43+
bool setBitsPerSample(int bits)
44+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45+
Specify how many bits per audio sample to read or write. Note that
46+
for 24-bit samples, audio samples must be left-aligned (i.e. bits 31...8).
47+
Call before ``I2S::begin()``
48+
49+
bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0)
50+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51+
Set the number of DMA buffers and their size in 32-bit words as well as
52+
the word to fill when no data is available to send to the I2S hardware.
53+
Call before ``I2S::begin()``.
54+
55+
bool setFrequency(long sampleRate)
56+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
57+
Sets the word clock frequency, but does not start the I2S device if not
58+
already running. May be called after ``I2S::begin()`` to change the
59+
sample rate on-the-fly.
60+
61+
bool begin()/begin(long sampleRate)
62+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
63+
Start the I2S device up with the given sample rate, or with the value set
64+
using the prior ``setFrequency`` call.
3565

3666
void end()
3767
~~~~~~~~~~
38-
Stops the I2S device. **Note, at present the memory allocated for I2S buffers
39-
is not freed leading to a memory leak when ``end()`` is called. This is due
40-
to the state of the ``pico-extras`` release which this code uses.**
68+
Stops the I2S device.
4169

4270
void flush()
4371
~~~~~~~~~~~~
44-
Sends any partial frames in memory to the I2S output device. They may NOT play
45-
immediately. Potential use case for this call would be when the frequency of
46-
the output will be changing.
47-
48-
size_t write(uint8_t)
49-
~~~~~~~~~~~~~~~~~~~~~
50-
Provided for compatibility, but not very useful. Writes a sample from 0...255
51-
to the I2S buffer. See ``write(int16_t)`` for a better one
72+
Waits until all the I2S buffers have been output.
73+
74+
size_t write(uint8_t/int8_t/int16_t/int32_t)
75+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
76+
Writes a single sample of ``bitsPerSample`` to the buffer. It is up to the
77+
user to keep track of left/right channels. Note this writes data equivalent
78+
to one channel's data, not the size of the passed in variable (i.e. if you have
79+
a 16-bit sample size and ``write((int8_t)-5); write((int8_t)5);`` you will have
80+
written **2 samples** to the I2S buffer of whatever the I2S size, not a single
81+
16-bit sample.
82+
83+
This call will block (wait) until space is available to actually write
84+
the data.
85+
86+
size_t write(int32_t val, bool sync)
87+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88+
Writes 32 bits of data to the I2S buffer (regardless of the configured I2S
89+
bit size). When ``sync`` is true, it will not return until the data has
90+
been writte. When ``sync`` is false, it will return ``0`` immediately if
91+
there is no space present in the I2S buffer.
5292

5393
size_t write(const uint8_t \*buffer, size_t size)
5494
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5595
Transfers number of bytes from an application buffer to the I2S output buffer.
5696
Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple
57-
of **4 bytes** (i.e. one left/right sample). Will not block, so check
58-
the return value to find out how many bytes were actually written.
97+
of **4 bytes**. Will not block, so check the return value to find out how
98+
many bytes were actually written.
5999

60100
int availableForWrite()
61101
~~~~~~~~~~~~~~~~~~~~~~~
62-
Returns the number of **32-bit L/R samples** that can be written without
102+
Returns the number of L/R samples that can be written without
63103
potentially blocking.
64104

65-
bool setFrequency(int newFreq)
66-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67-
Adjusts the I2S output frequency. When changing frequency while I2S output
68-
is underway, be sure to use ``I2S.flush()`` before changing the frequency to
69-
ensure the older data is played at the right frequency.
70-
71-
size_t write(int16_t)
72-
~~~~~~~~~~~~~~~~~~~~~
73-
Writes a single 16-bit left or right sample to the I2S output buffer. The
74-
user is required to ensure that an even number of samples is written (i.e.
75-
left and right) over the application lifetime. The application also needs
76-
to track which sample is next to be written (right/left). For this reason,
77-
the ``write(void *b, size_t lrsamples)`` call may be easier and faster to use.
78-
79-
size_t write(const void \*buffer, size_t lrsamples)
80-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
81-
Writes up to size left+right packed samples to the I2S device. Non-blocking,
82-
will writefrom 0...size samples and return that count. Be sure your app
83-
handles partial writes (i.e. by ``yield()`` ing and then retrying to write the
84-
remaining data.)
85-
86-
The ``onTransmit`` callback is not supported.
87-
88-
See the `ESP8266Audio <https://github.com/earlephilhower/ESP8266Audio>`_ library
89-
for a working example, or look at the included sample tone generator.
105+
int read()
106+
~~~~~~~~~~
107+
Reads a single sample of I2S data, whatever the I2S sample size is configured.
108+
Will not return until data is available.
109+
110+
int peek()
111+
~~~~~~~~~~
112+
Returns the next sample to be read from the I2S buffer (without actually
113+
removing it).
114+
115+
void onTransmit(void (\*fn)(void))
116+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117+
Sets a callback to be called when an I2S DMA buffer is fully transmitted.
118+
Will be in an interrupt context so the specified function must operate
119+
quickly and not use blocking calls like delay() or write to the I2S.
120+
121+
void onReceive(void (\*fn)(void))
122+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123+
Sets a callback to be called when an I2S DMA buffer is fully read in.
124+
Will be in an interrupt context so the specified function must operate
125+
quickly and not use blocking calls like delay() or read from the I2S.
126+
127+
Sample Writing/Reading API
128+
--------------------------
129+
Because I2S streams consist of a natural left and right sample, it is often
130+
convenient to write or read both with a single call. The following calls
131+
allow applications to read or write both samples at the same time, and
132+
explicitly indicate the bit widths required (to avoid potential issues with
133+
type conversion on calls).
134+
135+
size_t write8(int8_t l, int8_t r)
136+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
137+
Writes a left and right 8-bit sample to the I2S buffers. Blocks until space
138+
is available.
139+
140+
size_t write16(int16_t l, int16_t r)
141+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142+
Writes a left and right 16-bit sample to the I2S buffers. Blocks until space
143+
is available.
144+
145+
size_t write24(int32_t l, int32_t r)
146+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147+
Writes a left and right 24-bit sample to the I2S buffers. See note below
148+
about 24-bit mode. Blocks until space is available.
149+
150+
size_t write32(int32_t l, int32_t r)
151+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
152+
Writes a left and right 32-bit sample to the I2S buffers. Blocks until space
153+
is available.
154+
155+
bool read8(int8_t \*l, int8_t \*r)
156+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157+
Reads a left and right 8-bit sample and returns ``true`` on success. Will block
158+
until data is available.
159+
160+
bool read16(int16_t \*l, int16_t \*r)
161+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
162+
Reads a left and right 16-bit sample and returns ``true`` on success. Will block
163+
until data is available.
164+
165+
bool read24(int32_t \*l, int32_t \*r)
166+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
167+
Reads a left and right 24-bit sample and returns ``true`` on success. See note below
168+
about 24-bit mode. Will block until data is available.
169+
170+
bool read32(int32_t \*l, int32_t \*r)
171+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
172+
Reads a left and right 32-bit sample and returns ``true`` on success. Will block
173+
until data is available.
174+
175+
176+
Note About 24-bit Samples
177+
-------------------------
178+
24-bit samples are stored as left-aligned 32-bit values with bits 7..0
179+
ignored. Only the upper 24 bits 31...8 will be transmitted or
180+
received. The actual I2S protocol will only transmit or receive 24 bits
181+
in this mode, even though the data is 32-bit packed.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
I2S stereo microphone (input) example
3+
Run using the Arduino Serial Plotter to see waveform.
4+
Released to the Public Domain by Earle F. Philhower, III
5+
6+
For the Google AIY Voice Hat Microphone daughterboard, part
7+
of the Raspberry Pi AIY cardboard box, the I2S stereo pinout
8+
looking at the board top with the RPI logo on the left hand
9+
side:
10+
+-- ------------------------------------ --+
11+
left RPI | (1) GND (2) DIN (3) BCLK (4) LRCLK (5) 3.3V | AIY right
12+
logo +---------------------------------------------+ logo
13+
*/
14+
15+
#include <I2S.h>
16+
17+
I2S i2s(INPUT);
18+
19+
void setup() {
20+
Serial.begin(115200);
21+
22+
i2s.setDATA(0);
23+
i2s.setBCLK(1); // LRCLK = GP2
24+
i2s.setBitsPerSample(16);
25+
i2s.setFrequency(22050);
26+
i2s.begin();
27+
28+
while (1) {
29+
int16_t l, r;
30+
i2s.read16(&l, &r);
31+
Serial.printf("%d %d\n", l, r);
32+
}
33+
}
34+
35+
void loop() {
36+
/* Nothing here */
37+
}

0 commit comments

Comments
 (0)