Skip to content

Commit 21157f0

Browse files
committed
add modified Adafruit tone generator example
1 parent 0305051 commit 21157f0

File tree

3 files changed

+193
-16
lines changed

3 files changed

+193
-16
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// Arduino Zero / Feather M0 I2S audio tone generation example.
2+
// Author: Tony DiCola
3+
//
4+
// Connect an I2S DAC or amp (like the MAX98357) to the Arduino Zero
5+
// and play back simple sine, sawtooth, triangle, and square waves.
6+
// Makes your Zero sound like a NES!
7+
//
8+
// NOTE: The I2S signal generated by the Zero does NOT have a MCLK /
9+
// master clock signal. You must use an I2S receiver that can operate
10+
// without a MCLK signal (like the MAX98357).
11+
//
12+
// For an Arduino Zero / Feather M0 connect it to you I2S hardware as follows:
13+
// - Digital 0 -> I2S LRCLK / FS (left/right / frame select clock)
14+
// - Digital 1 -> I2S BCLK / SCLK (bit / serial clock)
15+
// - Digital 9 -> I2S DIN / SD (data output)
16+
// - Ground
17+
//
18+
// Depends on the Adafruit_ASFcore library from:
19+
// https://github.com/adafruit/adafruit_asfcore
20+
//
21+
// Released under a MIT license: https://opensource.org/licenses/MIT
22+
#include <I2S.h>
23+
24+
#define SAMPLERATE_HZ 44100 // The sample rate of the audio. Higher sample rates have better fidelity,
25+
// but these tones are so simple it won't make a difference. 44.1khz is
26+
// standard CD quality sound.
27+
28+
#define AMPLITUDE 5000 // Set the amplitude of generated waveforms. This controls how loud
29+
// the signals are, and can be any value from 0 to 65535. Start with
30+
// a low value like 5000 or less to prevent damaging speakers!
31+
32+
#define WAV_SIZE 256 // The size of each generated waveform. The larger the size the higher
33+
// quality the signal. A size of 256 is more than enough for these simple
34+
// waveforms.
35+
36+
37+
// Define the frequency of music notes (from http://www.phy.mtu.edu/~suits/notefreqs.html):
38+
#define C4_HZ 261.63
39+
#define D4_HZ 293.66
40+
#define E4_HZ 329.63
41+
#define F4_HZ 349.23
42+
#define G4_HZ 392.00
43+
#define A4_HZ 440.00
44+
#define B4_HZ 493.88
45+
46+
// Define a C-major scale to play all the notes up and down.
47+
float scale[] = { C4_HZ, D4_HZ, E4_HZ, F4_HZ, G4_HZ, A4_HZ, B4_HZ, A4_HZ, G4_HZ, F4_HZ, E4_HZ, D4_HZ, C4_HZ };
48+
49+
// Store basic waveforms in memory.
50+
int16_t sine[WAV_SIZE] = {0};
51+
int16_t sawtooth[WAV_SIZE] = {0};
52+
int16_t triangle[WAV_SIZE] = {0};
53+
int16_t square[WAV_SIZE] = {0};
54+
55+
void generateSine(uint16_t amplitude, int16_t* buffer, uint16_t length) {
56+
// Generate a sine wave signal with the provided amplitude and store it in
57+
// the provided buffer of size length.
58+
for (int i=0; i<length; ++i) {
59+
buffer[i] = uint16_t(float(amplitude)*sin(2.0*PI*(1.0/length)*i));
60+
}
61+
}
62+
void generateSawtooth(uint16_t amplitude, int16_t* buffer, uint16_t length) {
63+
// Generate a sawtooth signal that goes from -amplitude/2 to amplitude/2
64+
// and store it in the provided buffer of size length.
65+
float delta = float(amplitude)/float(length);
66+
for (int i=0; i<length; ++i) {
67+
buffer[i] = -(amplitude/2)+delta*i;
68+
}
69+
}
70+
71+
void generateTriangle(uint16_t amplitude, int16_t* buffer, uint16_t length) {
72+
// Generate a triangle wave signal with the provided amplitude and store it in
73+
// the provided buffer of size length.
74+
float delta = float(amplitude)/float(length);
75+
for (int i=0; i<length/2; ++i) {
76+
buffer[i] = -(amplitude/2)+delta*i;
77+
}
78+
for (int i=length/2; i<length; ++i) {
79+
buffer[i] = (amplitude/2)-delta*(i-length/2);
80+
}
81+
}
82+
83+
void generateSquare(uint16_t amplitude, int16_t* buffer, uint16_t length) {
84+
// Generate a square wave signal with the provided amplitude and store it in
85+
// the provided buffer of size length.
86+
for (int i=0; i<length/2; ++i) {
87+
buffer[i] = -(amplitude/2);
88+
}
89+
for (int i=length/2; i<length; ++i) {
90+
buffer[i] = (amplitude/2);
91+
}
92+
}
93+
94+
void playWave(int16_t* buffer, uint16_t length, float frequency, float seconds) {
95+
// Play back the provided waveform buffer for the specified
96+
// amount of seconds.
97+
// First calculate how many samples need to play back to run
98+
// for the desired amount of seconds.
99+
uint32_t iterations = seconds*SAMPLERATE_HZ;
100+
// Then calculate the 'speed' at which we move through the wave
101+
// buffer based on the frequency of the tone being played.
102+
float delta = (frequency*length)/float(SAMPLERATE_HZ);
103+
// Now loop through all the samples and play them, calculating the
104+
// position within the wave buffer for each moment in time.
105+
for (uint32_t i=0; i<iterations; ++i) {
106+
uint16_t pos = uint32_t(i*delta) % length;
107+
int16_t sample = buffer[pos];
108+
// Duplicate the sample so it's sent to both the left and right channel.
109+
// It appears the order is right channel, left channel if you want to write
110+
// stereo sound.
111+
I2S.write(sample);
112+
I2S.write(sample);
113+
}
114+
}
115+
116+
void setup() {
117+
// Configure serial port.
118+
Serial.begin(9600);
119+
Serial.println("I2S Audio Tone Generator");
120+
121+
// Initialize the I2S transmitter.
122+
if (I2S.begin(I2S_PHILIPS_MODE, SAMPLERATE_HZ, 16)) {
123+
Serial.println("Failed to initialize I2S!");
124+
while (1);
125+
}
126+
127+
// Generate waveforms.
128+
generateSine(AMPLITUDE, sine, WAV_SIZE);
129+
generateSawtooth(AMPLITUDE, sawtooth, WAV_SIZE);
130+
generateTriangle(AMPLITUDE, triangle, WAV_SIZE);
131+
generateSquare(AMPLITUDE, square, WAV_SIZE);
132+
}
133+
134+
void loop() {
135+
Serial.println("Sine wave");
136+
for (int i=0; i<sizeof(scale)/sizeof(float); ++i) {
137+
// Play the note for a quarter of a second.
138+
playWave(sine, WAV_SIZE, scale[i], 0.25);
139+
// Pause for a tenth of a second between notes.
140+
delay(100);
141+
}
142+
Serial.println("Sawtooth wave");
143+
for (int i=0; i<sizeof(scale)/sizeof(float); ++i) {
144+
// Play the note for a quarter of a second.
145+
playWave(sawtooth, WAV_SIZE, scale[i], 0.25);
146+
// Pause for a tenth of a second between notes.
147+
delay(100);
148+
}
149+
Serial.println("Triangle wave");
150+
for (int i=0; i<sizeof(scale)/sizeof(float); ++i) {
151+
// Play the note for a quarter of a second.
152+
playWave(triangle, WAV_SIZE, scale[i], 0.25);
153+
// Pause for a tenth of a second between notes.
154+
delay(100);
155+
}
156+
Serial.println("Square wave");
157+
for (int i=0; i<sizeof(scale)/sizeof(float); ++i) {
158+
// Play the note for a quarter of a second.
159+
playWave(square, WAV_SIZE, scale[i], 0.25);
160+
// Pause for a tenth of a second between notes.
161+
delay(100);
162+
}
163+
}

libraries/I2S/src/I2S.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,31 @@ void I2SClass::flush()
186186
}
187187

188188
size_t I2SClass::write(uint8_t data)
189+
{
190+
return write((int)data);
191+
}
192+
193+
size_t I2SClass::write(const uint8_t *buffer, size_t size)
194+
{
195+
return 0;
196+
}
197+
198+
size_t I2SClass::availableForWrite()
199+
{
200+
return 0;
201+
}
202+
203+
int I2SClass::read(int8_t data[], int size)
204+
{
205+
return 0;
206+
}
207+
208+
int I2SClass::write(short data)
209+
{
210+
return write((int)data);
211+
}
212+
213+
int I2SClass::write(int data)
189214
{
190215
if (_uc_index == 0) {
191216
while (!_i2s->INTFLAG.bit.TXRDY0);
@@ -203,22 +228,7 @@ size_t I2SClass::write(uint8_t data)
203228
_i2s->INTFLAG.bit.TXRDY1 = 1;
204229
}
205230

206-
return 0;
207-
}
208-
209-
size_t I2SClass::write(const uint8_t *buffer, size_t size)
210-
{
211-
return 0;
212-
}
213-
214-
size_t I2SClass::availableForWrite()
215-
{
216-
return 0;
217-
}
218-
219-
int I2SClass::read(int8_t data[], int size)
220-
{
221-
return 0;
231+
return 1;
222232
}
223233

224234
/*

libraries/I2S/src/I2S.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class I2SClass : public Stream
2929

3030
virtual size_t availableForWrite();
3131

32+
33+
int write(short);
34+
int write(int);
35+
3236
int read(int8_t data[], int size);
3337
int read(int16_t data[], int size);
3438
int read(int32_t data[], int size);

0 commit comments

Comments
 (0)