I2S for PIC32MX/MZ – Introduction

Skill level: Advanced, with C and 32-bit experience. SMD soldering experience is a must too!

This tutorial requires an oscilloscope to view the output audio signals!

What do all the digital audio players, smart devices and sound cards have in common?

They all have Audio DACs inside. DAC, or Digital to Analog Converter, converts digital signals to analog signals. In this tutorial, we use an audio DAC to convert the digital signals from a microcontroller/processor to audible audio signals.

In case if you are wondering, why are we using an Audio DAC and not a regular DAC for audio playback? You can use an ordinary DAC or a PWM (Pulse Width Modulation) with a microcontroller to generate audio signals, but they are not clear enough and the quality may not be the best one.

Audio DACs are specialized DACs which contain extra hardware to convert the digital signals to the audio signals so that the resulting audio signals are clear and with lesser noise. Audiophiles purchase very expensive external audio DACs for their computers or their Hi-Fi sets just because they want to listen to very crystal clear sound.

These mentioned DACs come in many kinds, from the simple to the advanced. The highest end contains a small DSP (Digital Signal Processor) to process the digital audio and many extra features such as controlling the settings in the DAC. Some of the DACs have ADC (Analog to Digital converter) for capturing the signals from the microphone, converted to digital signals and then these are sent to the microcontroller/processor.

In this tutorial, we are only focusing on the basic Audio DAC, for simplicity purposes. The Audio DAC is connected to the microcontroller by I2S (Inter-IC Sound) bus. Not all DACs are with I2S interface – this will be explained in the other tutorial!

I2S Protocol

The I2S bus is a type of serial connection designed by Philips/NXP. According to the “I2S Specification” from the company, the bus has three major lines:

  • Continuous Serial Clock (SCK)
  • Word Select (WS)
  • Serial Data (SD)

The generation of the clock (SCK) and the word select (WS) are by the Master, which is the microcontroller.

Here is the diagram for the basic I2S transmission, from the Microchip PIC32MX reference manual. Note that the SCK in the microcontroller is called BCLK (bit clock), and the WS is called LRCK (left-right clock). Different microcontrollers have different labels for the SCK, WS and SD but in the end they have the same meanings respectively.

Since audio DAC operates at mainly stereo mode, there is a left and a right channel. When the left audio data is being pushed into the DAC, the WS/LRCK is being low. When the right audio data is being pushed into the DAC, the WS/LRCK is being high.

If the audio data is 16-bit, 16 clock pulses are sent out together with the audio data per channel. And if the audio data is 32-bit, 32 clock pulses are sent out together with the audio data per channel.

You also notice that in this microcontroller, the I2S line is shared with the SPI line. In order to switch to the I2S mode, you need to change the SPI settings first during the initialization. Here’s how to do this with the help of the PIC32 SPI Reference Manual:

SPI1CON2 = 0x00000080; // I2S Mode, AUDEN = 1, AUDMON = 0
SPI1CON2bits.IGNROV = 1; // Ignore Receive Overflow bit (for Audio Data Transmissions)
SPI1CON2bits.IGNTUR = 1; //  Ignore Transmit Underrun bit (for Audio Data Transmissions) 1 = A TUR is not a critical error and zeros are transmitted until thSPIxTXB is not empty 0 = A TUR is a critical error which stop SPI operation
SPI1BRG = 38;
SPI1CON = 0x00000060; // Master mode, SPI ON, CKP = 1, 16-bit audio channel
SPI1CONbits.STXISEL = 0b11;
SPI1CONbits.DISSDI = 1; // 0 = Disable SDI bit
SPI1CONSET = 0x00008000;

In this example, we are using SPI1. This code can be used for PIC32MX/MZ, but for configuring the interrupts, you have to refer to the PIC32MX/MZ datasheet.

How about the SPI1BRG? This register determines the bit rate for the I2S transmission. Say that we want to configure this transmission at 8kHz audio sample rate, at 16-bit data per channel. Assume that we have 20MHz peripheral bus too.

  • FPB = 20MHz
  • Sampling rate: 8kHz
  • Data: 16-bit (signed)

Using the following equation:

The baud rate is calculated as: 8000 * 32 (The 32 is because in this example, combining the left and right data to form one audio frame gives you total of 32 bits) Calculating the SPI1BRG, we get 38.0625 which is rounded to 38.

After all the calculation, we start the I2S module:

SPI1CONSET = 0x00008000;

Sending audio data into the DAC

Of course, you need to put audio data into the SPI transmit buffer, or else there is no output at all! However, you must continuously send the audio data into the buffer every time the transmit is complete or else you would not be hearing the correct sound output. Using interrupts, we allow the program to jump into the interrupt vector when the SPI module is done transferring the data.

void __ISR(_SPI1_VECTOR, ipl7AUTO) _IntHandlerDrvI2SInstance0(void)
if(channel) {
SPI1BUF = data_left;
else {
SPI1BUF = data_right;
channel ^= 0x01;       
IFS1bits.SPI1TXIF = 0; // Clear the SPI1 interrupt.

In the code example, when the interrupt is up, it loads a value into the SPI1BUF. Each successful transmission is for the value of the left channel (remember that the audio DAC has left and right channels) and another for the right. Therefore, the ‘channel’ variable is being toggled every time the interrupt is triggered.

Also, the data for the I2S is a 16-bit and signed for this tutorial, which means the buffer can only take values between -32767 and 32767.

Connecting the PIC32 to the Audio DAC

Here is the general block diagram of how you should connect the PIC32 to the Audio DAC. For some Audio DACs with the ADC inside, the converted ADC data is being fed back into the SDIx. Since we are only focusing on the audio output for now, the SDIx is not used in this example.

We are using an NXP UDA1334ATS Audio DAC in this tutorial. You are free to use other audio DAC, but make sure you need to configure the Audio DAC into I2S mode first. Unfortunately, the DAC does not come in the form of DIP package, therefore you need a SMD breakout board. The information of how to configure the DAC is by reading the datasheet:

In addition, you should:

1.) Ground both SFOR0 and SFOR1 inputs to select this DAC to I2S mode.

2.) DEEM/CLKOUT to ground too.

3.) MUTE to ground.

4.) Connect the digital and analog supply voltage to +3.3V.

5.) SYSCLK/PLL1 to ground.

When all are done (on the breadboard),  do not run or compile the code yet! Reserve this “platform” for some cool sound and music guides in Cytron tutorial!


1.) http://chipkit.net/forum/viewtopic.php?f=6&t=3137&start=10

2.) UDA1334ATS datasheet: www.nxp.com/docs/en/data-sheet/UDA1334ATS.pdf

3.) PIC32 SPI Reference Manual: ww1.microchip.com/downloads/en/DeviceDoc/61106G.pdf



, ,

Related Post

I2S for PIC32MX/MZ – Application: Music Box

I2S for PIC32MX/MZ – Direct Memory Access (DMA)

I2S for PIC32MX/MZ – Sine wave generation using DDS

Driving RainbowBits with Cytron’s sk1632!

Leave a Reply

Your email address will not be published. Required fields are marked *