The classic ATmega328P-based Arduino's like the UNO and Metro 328 don't have I2S interfaces, so you can't use this breakout with them
But the newer ATSAMD21-based boards like the Zero, Metro M0, Feather M0 can! (Note, Gemma M0 & Trinket M0 do not have I2S pins available). And so can the even newer ATSAMD51-based boards like the Metro M4 and Feather M4.
To use I2S with M0 or M4 boards, you'll need to install the Adafruit Zero I2S library. It is available through the Library Manager. You can search for (see below) and then just click the install button.
Wiring
Wiring connections are the same as those used for CircuitPython. So go to the CircuitPython Wiring & Test page to see how to wire the breakout for your specific board.
Basic Test
To test things out, try running the demo below. It comes with the library installation, so you can find it by going to:
File -> Examples -> Adafruit Zero I2S Library -> basic
Be sure to change this line:
Adafruit_ZeroI2S i2s(0, 1, 9, 2);
to match the pins used for your setup. If you've wired as shown in this guide, then you can try using the default pins by changing that line to this:
Adafruit_ZeroI2S i2s;
#include <Arduino.h> #include <Adafruit_ZeroI2S.h> #include <math.h> /* max volume for 32 bit data */ #define VOLUME ( (1UL << 31) - 1) /* create a buffer for both the left and right channel data */ #define BUFSIZE 128 int left[BUFSIZE]; int right[BUFSIZE]; // Use default pins in board variant Adafruit_ZeroI2S i2s = Adafruit_ZeroI2S(); void setup() { while (!Serial) delay(10); Serial.println("I2S demo"); for(int i=0; i<BUFSIZE; i++){ /* create a sine wave on the left channel */ left[i] = sin( (2*PI / (BUFSIZE) ) * i) * VOLUME; /* create a cosine wave on the right channel */ right[i] = cos( (2*PI / (BUFSIZE) ) * i) * VOLUME; } /* begin I2S on the default pins. 24 bit depth at * 44100 samples per second */ i2s.begin(I2S_32_BIT, 44100); i2s.enableTx(); } void loop() { /* write the output buffers * note that i2s.write() will block until both channels are written. */ for(int i=0; i<BUFSIZE; i++){ i2s.write(left[i], right[i]); } }
DMA Test
The basic test above created the output directly by using the i2s.write()
function in a loop. Another approach is to use DMA to generate the output. With this approach, you do some initial setup to configure the DMA engine for playback. It can then take care of generating the output in the background allowing you to do other things in your code.
To take this approach, you will need to install the Zero DMA library. You can do that through the Library Manager:
And then you can use the DMA example found in the Zero I2S library:
File -> Examples -> Adafruit Zero I2S Library -> dma
#include <Adafruit_ZeroI2S.h> #include <Adafruit_ZeroDMA.h> #include "utility/dma.h" #include <math.h> /* max volume for 32 bit data */ #define VOLUME ( (1UL << 31) - 1) /* create a buffer for both the left and right channel data */ #define BUFSIZE 256 int data[BUFSIZE]; Adafruit_ZeroDMA myDMA; ZeroDMAstatus stat; // DMA status codes returned by some functions Adafruit_ZeroI2S i2s; void dma_callback(Adafruit_ZeroDMA *dma) { /* we don't need to do anything here */ } void setup() { Serial.begin(115200); //while(!Serial); // Wait for Serial monitor before continuing Serial.println("I2S output via DMA"); int *ptr = data; /*the I2S module will be expecting data interleaved LRLR*/ for(int i=0; i<BUFSIZE/2; i++){ /* create a sine wave on the left channel */ *ptr++ = sin( (2*PI / (BUFSIZE/2) ) * i) * VOLUME; /* create a cosine wave on the right channel */ *ptr++ = cos( (2*PI / (BUFSIZE/2) ) * i) * VOLUME; } Serial.println("Configuring DMA trigger"); myDMA.setTrigger(I2S_DMAC_ID_TX_0); myDMA.setAction(DMA_TRIGGER_ACTON_BEAT); Serial.print("Allocating DMA channel..."); stat = myDMA.allocate(); myDMA.printStatus(stat); Serial.println("Setting up transfer"); myDMA.addDescriptor( data, // move data from here #if defined(__SAMD51__) (void *)(&I2S->TXDATA.reg), // to here (M4) #else (void *)(&I2S->DATA[0].reg), // to here (M0+) #endif BUFSIZE, // this many... DMA_BEAT_SIZE_WORD, // bytes/hword/words true, // increment source addr? false); myDMA.loop(true); Serial.println("Adding callback"); myDMA.setCallback(dma_callback); /* begin I2S on the default pins. 24 bit depth at * 44100 samples per second */ i2s.begin(I2S_32_BIT, 44100); i2s.enableTx(); stat = myDMA.startJob(); } void loop() { Serial.println("do other things here while your DMA runs in the background."); delay(2000); }
Text editor powered by tinymce.