Skip to content

Commit e99df4f

Browse files
Add I2S class support (esp8266#7874)
Fixes esp8266#427 Adds a basic I2S class based off of the Arduino-SAMD core. The raw i2s_xxx functions are still a better way to use I2S due to their flexibility, but this will allow basic Arduino sketches to work.
1 parent 9fc5afd commit e99df4f

File tree

9 files changed

+521
-89
lines changed

9 files changed

+521
-89
lines changed

cores/esp8266/core_esp8266_i2s.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include "osapi.h"
2525
#include "ets_sys.h"
2626
#include "i2s_reg.h"
27-
#include "i2s.h"
27+
#include "core_esp8266_i2s.h"
2828

2929
extern "C" {
3030

@@ -194,11 +194,11 @@ static void ICACHE_RAM_ATTR i2s_slc_isr(void) {
194194
}
195195

196196
void i2s_set_callback(void (*callback) (void)) {
197-
tx->callback = callback;
197+
if (tx) tx->callback = callback;
198198
}
199199

200200
void i2s_rx_set_callback(void (*callback) (void)) {
201-
rx->callback = callback;
201+
if (rx) rx->callback = callback;
202202
}
203203

204204
static bool _alloc_channel(i2s_state_t *ch) {
@@ -343,7 +343,7 @@ bool i2s_write_lr(int16_t left, int16_t right){
343343

344344
// writes a buffer of frames into the DMA memory, returns the amount of frames written
345345
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
346-
static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mono, bool nb) {
346+
static uint16_t _i2s_write_buffer(const int16_t *frames, uint16_t frame_count, bool mono, bool nb) {
347347
uint16_t frames_written=0;
348348

349349
while(frame_count>0) {
@@ -401,13 +401,13 @@ static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mo
401401
return frames_written;
402402
}
403403

404-
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, true); }
404+
uint16_t i2s_write_buffer_mono_nb(const int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, true); }
405405

406-
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, false); }
406+
uint16_t i2s_write_buffer_mono(const int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, false); }
407407

408-
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, true); }
408+
uint16_t i2s_write_buffer_nb(const int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, true); }
409409

410-
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, false); }
410+
uint16_t i2s_write_buffer(const int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, false); }
411411

412412
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking) {
413413
if (!rx) {

cores/esp8266/core_esp8266_i2s.h

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
i2s.h - Software I2S library for esp8266
3+
4+
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
5+
This file is part of the esp8266 core for Arduino environment.
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
#ifndef I2S_h
22+
#define I2S_h
23+
24+
#define I2S_HAS_BEGIN_RXTX_DRIVE_CLOCKS 1
25+
26+
/*
27+
How does this work? Basically, to get sound, you need to:
28+
- Connect an I2S codec to the I2S pins on the ESP.
29+
- Start up a thread that's going to do the sound output
30+
- Call i2s_set_bits() if you want to enable 24-bit mode
31+
- Call i2s_begin()
32+
- Call i2s_set_rate() with the sample rate you want.
33+
- Generate sound and call i2s_write_sample() with 32-bit samples.
34+
The 32bit samples basically are 2 16-bit signed values (the analog values for
35+
the left and right channel) concatenated as (Rout<<16)+Lout
36+
37+
i2s_write_sample will block when you're sending data too quickly, so you can just
38+
generate and push data as fast as you can and i2s_write_sample will regulate the
39+
speed.
40+
*/
41+
42+
#ifdef __cplusplus
43+
extern "C" {
44+
#endif
45+
46+
bool i2s_set_bits(int bits); // Set bits per sample, only 16 or 24 supported. Call before begin.
47+
// Note that in 24 bit mode each sample must be left-aligned (i.e. 0x00000000 .. 0xffffff00) as the
48+
// hardware shifts starting at bit 31, not bit 23.
49+
50+
void i2s_begin(); // Enable TX only, for compatibility
51+
bool i2s_rxtx_begin(bool enableRx, bool enableTx); // Allow TX and/or RX, returns false on OOM error
52+
bool i2s_rxtxdrive_begin(bool enableRx, bool enableTx, bool driveRxClocks, bool driveTxClocks);
53+
void i2s_end();
54+
void i2s_set_rate(uint32_t rate);//Sample Rate in Hz (ex 44100, 48000)
55+
void i2s_set_dividers(uint8_t div1, uint8_t div2);//Direct control over output rate
56+
float i2s_get_real_rate();//The actual Sample Rate on output
57+
bool i2s_write_sample(uint32_t sample);//32bit sample with channels being upper and lower 16 bits (blocking when DMA is full)
58+
bool i2s_write_sample_nb(uint32_t sample);//same as above but does not block when DMA is full and returns false instead
59+
bool i2s_write_lr(int16_t left, int16_t right);//combines both channels and calls i2s_write_sample with the result
60+
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking); // RX data returned in both 16-bit outputs.
61+
bool i2s_is_full();//returns true if DMA is full and can not take more bytes (overflow)
62+
bool i2s_is_empty();//returns true if DMA is empty (underflow)
63+
bool i2s_rx_is_full();
64+
bool i2s_rx_is_empty();
65+
uint16_t i2s_available();// returns the number of samples than can be written before blocking
66+
uint16_t i2s_rx_available();// returns the number of samples than can be written before blocking
67+
void i2s_set_callback(void (*callback) (void));
68+
void i2s_rx_set_callback(void (*callback) (void));
69+
70+
// writes a buffer of frames into the DMA memory, returns the amount of frames written
71+
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
72+
uint16_t i2s_write_buffer_mono(const int16_t *frames, uint16_t frame_count);
73+
uint16_t i2s_write_buffer_mono_nb(const int16_t *frames, uint16_t frame_count);
74+
uint16_t i2s_write_buffer(const int16_t *frames, uint16_t frame_count);
75+
uint16_t i2s_write_buffer_nb(const int16_t *frames, uint16_t frame_count);
76+
77+
#ifdef __cplusplus
78+
}
79+
#endif
80+
81+
#endif

cores/esp8266/i2s.h

+12-81
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,12 @@
1-
/*
2-
i2s.h - Software I2S library for esp8266
3-
4-
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
5-
This file is part of the esp8266 core for Arduino environment.
6-
7-
This library is free software; you can redistribute it and/or
8-
modify it under the terms of the GNU Lesser General Public
9-
License as published by the Free Software Foundation; either
10-
version 2.1 of the License, or (at your option) any later version.
11-
12-
This library is distributed in the hope that it will be useful,
13-
but WITHOUT ANY WARRANTY; without even the implied warranty of
14-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15-
Lesser General Public License for more details.
16-
17-
You should have received a copy of the GNU Lesser General Public
18-
License along with this library; if not, write to the Free Software
19-
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20-
*/
21-
#ifndef I2S_h
22-
#define I2S_h
23-
24-
#define I2S_HAS_BEGIN_RXTX_DRIVE_CLOCKS 1
25-
26-
/*
27-
How does this work? Basically, to get sound, you need to:
28-
- Connect an I2S codec to the I2S pins on the ESP.
29-
- Start up a thread that's going to do the sound output
30-
- Call i2s_set_bits() if you want to enable 24-bit mode
31-
- Call i2s_begin()
32-
- Call i2s_set_rate() with the sample rate you want.
33-
- Generate sound and call i2s_write_sample() with 32-bit samples.
34-
The 32bit samples basically are 2 16-bit signed values (the analog values for
35-
the left and right channel) concatenated as (Rout<<16)+Lout
36-
37-
i2s_write_sample will block when you're sending data too quickly, so you can just
38-
generate and push data as fast as you can and i2s_write_sample will regulate the
39-
speed.
40-
*/
41-
42-
#ifdef __cplusplus
43-
extern "C" {
44-
#endif
45-
46-
bool i2s_set_bits(int bits); // Set bits per sample, only 16 or 24 supported. Call before begin.
47-
// Note that in 24 bit mode each sample must be left-aligned (i.e. 0x00000000 .. 0xffffff00) as the
48-
// hardware shifts starting at bit 31, not bit 23.
49-
50-
void i2s_begin(); // Enable TX only, for compatibility
51-
bool i2s_rxtx_begin(bool enableRx, bool enableTx); // Allow TX and/or RX, returns false on OOM error
52-
bool i2s_rxtxdrive_begin(bool enableRx, bool enableTx, bool driveRxClocks, bool driveTxClocks);
53-
void i2s_end();
54-
void i2s_set_rate(uint32_t rate);//Sample Rate in Hz (ex 44100, 48000)
55-
void i2s_set_dividers(uint8_t div1, uint8_t div2);//Direct control over output rate
56-
float i2s_get_real_rate();//The actual Sample Rate on output
57-
bool i2s_write_sample(uint32_t sample);//32bit sample with channels being upper and lower 16 bits (blocking when DMA is full)
58-
bool i2s_write_sample_nb(uint32_t sample);//same as above but does not block when DMA is full and returns false instead
59-
bool i2s_write_lr(int16_t left, int16_t right);//combines both channels and calls i2s_write_sample with the result
60-
bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking); // RX data returned in both 16-bit outputs.
61-
bool i2s_is_full();//returns true if DMA is full and can not take more bytes (overflow)
62-
bool i2s_is_empty();//returns true if DMA is empty (underflow)
63-
bool i2s_rx_is_full();
64-
bool i2s_rx_is_empty();
65-
uint16_t i2s_available();// returns the number of samples than can be written before blocking
66-
uint16_t i2s_rx_available();// returns the number of samples than can be written before blocking
67-
void i2s_set_callback(void (*callback) (void));
68-
void i2s_rx_set_callback(void (*callback) (void));
69-
70-
// writes a buffer of frames into the DMA memory, returns the amount of frames written
71-
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
72-
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count);
73-
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count);
74-
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count);
75-
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count);
76-
77-
#ifdef __cplusplus
78-
}
79-
#endif
80-
81-
#endif
1+
// This include file is a hack to ensure backward compatibility with
2+
// pre 3.0.0 versions of the core. There was a *lowercase* "i2s.h"
3+
// header which was in this directory, now renamed to "core_esp82i66s.h"
4+
// But, the I2S class has a header, "I2S.h" in uppercase. On Linux
5+
// the two names are different, but on Windows it's case-insensitive
6+
// so the names conflict.
7+
//
8+
// Avoid the issue by preserving the old i2s.h file and have it redirect
9+
// to I2S.h which will give the ESP8266-specific functions as well as
10+
// the generic I2S class.
11+
12+
#include "../../libraries/I2S/src/I2S.h"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
This example reads audio data from an Invensense's ICS43432 I2S microphone
3+
breakout board, and prints out the samples to the Serial console. The
4+
Serial Plotter built into the Arduino IDE can be used to plot the audio
5+
data (Tools -> Serial Plotter)
6+
created 17 November 2016
7+
by Sandeep Mistry
8+
*/
9+
10+
#include <I2S.h>
11+
12+
void setup() {
13+
// Open serial communications and wait for port to open:
14+
// A baud rate of 115200 is used instead of 9600 for a faster data rate
15+
// on non-native USB ports
16+
Serial.begin(115200);
17+
while (!Serial) {
18+
; // wait for serial port to connect. Needed for native USB port only
19+
}
20+
21+
// start I2S at 8 kHz with 24-bits per sample
22+
if (!I2S.begin(I2S_PHILIPS_MODE, 8000, 24)) {
23+
Serial.println("Failed to initialize I2S!");
24+
while (1); // do nothing
25+
}
26+
}
27+
28+
void loop() {
29+
// read a sample
30+
int sample = I2S.read();
31+
32+
if (sample) {
33+
// if it's non-zero print value to serial
34+
Serial.println(sample);
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
This example generates a square wave based tone at a specified frequency
3+
and sample rate. Then outputs the data using the I2S interface to a
4+
MAX08357 I2S Amp Breakout board.
5+
6+
created 17 November 2016
7+
by Sandeep Mistry
8+
modified for ESP8266 by Earle F. Philhower, III <[email protected]>
9+
*/
10+
11+
#include <I2S.h>
12+
13+
const int frequency = 440; // frequency of square wave in Hz
14+
const int amplitude = 500; // amplitude of square wave
15+
const int sampleRate = 8000; // sample rate in Hz
16+
17+
const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave
18+
19+
short sample = amplitude; // current sample value
20+
int count = 0;
21+
22+
void setup() {
23+
Serial.begin(115200);
24+
Serial.println("I2S simple tone");
25+
26+
// start I2S at the sample rate with 16-bits per sample
27+
if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, 16)) {
28+
Serial.println("Failed to initialize I2S!");
29+
while (1); // do nothing
30+
}
31+
}
32+
33+
void loop() {
34+
if (count % halfWavelength == 0) {
35+
// invert the sample every half wavelength count multiple to generate square wave
36+
sample = -1 * sample;
37+
}
38+
39+
// write the same sample twice, once for left and once for the right channel
40+
I2S.write(sample);
41+
I2S.write(sample);
42+
43+
// increment the counter for the next sample
44+
count++;
45+
}
46+

libraries/I2S/keywords.txt

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#######################################
2+
# Syntax Coloring Map I2S
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
I2S KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
begin KEYWORD2
15+
end KEYWORD2
16+
17+
onReceive KEYWORD2
18+
onTransmit KEYWORD2
19+
20+
#######################################
21+
# Constants (LITERAL1)
22+
#######################################
23+
I2S_PHILIPS_MODE LITERAL1

libraries/I2S/library.properties

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=I2S
2+
version=1.0
3+
author=Earle F. Philhower, III <[email protected]>
4+
maintainer=Earle F. Philhower, III <[email protected]>
5+
sentence=Enables the communication with devices that use the Inter-IC Sound (I2S) Bus. Specific implementation for ESP8266, based off of SAMD.
6+
paragraph=
7+
category=Communication
8+
url=http://www.arduino.cc/en/Reference/I2S
9+
architectures=esp8266

0 commit comments

Comments
 (0)