Comment on page
Setting up the I/O
The initialization code we generated in the blinking LED example will need to be updated as it does not perform the setup for the two I2S buses that we will need to communicate with the microphone and the DAC.
First, let's make a copy of our working LED blinking project. We want to keep tracks of old projects in order to be able to go back to a known working configuration if something is not functioning anymore. To copy the project use the "Project Explorer" of the SW4STM32 software. Open the project you want and do a simple copy/paste operation. When you paste the project, a pop-up will ask you to rename the copied project: we recommend choosing a name that includes the current date and the word "passthrough" in it for bookkeeping purposes.
To finish the copying process:
- make sure that the binary file of the original project is removed by deleting the
.elffile in the
Binariesfolder of the new project.
- rename the
.iocfile with the name of the project
Now we are ready to update the initialization code. From the project explorer, click on the
IOCfile of the new project and open the CubeMX configurator.
IOCfile has successfully loaded, you should see something similar to the figure below. On the left-hand column, select "Multimedia" and expose the I2S1 and I2S2 selectors.
Let's begin by setting up the I2S channel that communicates with the DAC. Click on I2S1 and select the "Half-Duplex Master" for the Mode in the top middle panel.
You should see several pins highlighted in green: after enabling an I2S bus, the interface shows in green the electrical pins in the microcontroller that will be devoted to the signals used in the I2S protocol. Recall that an I2S bus uses three pins according to the I2S specification:
- 1.Clock (CK).
- 2.Word select (WS).
- 3.Serial data (SD).
Move your attention now to the "Configuration" panel below; we'll need to set up the structure of the data that transits on the bus (bits per word and per frame) and the data rate.
Select the "Parameter Setting" tab and set the transmission mode to "Mode Master Transmit" and the Communication Standard to "I2S Philips".
Now let's configure the DMA transfers. Select the "DMA Settings" tab and press "Add". Adjust the settings so that DMA Request is set to "SPI1_TX, Data Width is set to "Half Word" and Mode is set to "Circular", as in the screenshot below. Note that the DMA stream can differ if you are using a different microcontroler as it is dependent on the physical implementation of the internal circuitry.
TASK 1: Finish the set up for I2S1 so that it can be used to communicate to the DAC by setting the Data and Frame Format and the Audio Frequency. You will have to check the DAC datasheet in order to find the correct parameters (sampling frequency, data and frame format).
Repeat the previous steps for I2S2 with the following differences:
- set the Transmission Mode to "Mode Master Receive"
- set the DMA request to "SPI2_RX
Finally, complete the configuration:
TASK 2: Finish the set up for I2S2 so that it can be used to communicate with the microphone by setting the Data and Frame Format and the Audio Frequency. You will have to check the microphone datasheet in order to find the correct parameters (sampling frequency, data and frame format).
Hint: make sure that the DAC and the microphone have the same "Selected Audio Frequency" while satisfying the specifications detailed on the datasheets! An audio frequency below the specified limits will most likely result in aliasing.
As a final sanity check, click on "NVIC" under "System" in the left column and ensure that the interrupts are enabled for both selected DMA channels, as below.
The configuration we have done so far would be sufficient in order to create an audio passthrough. However, we will configure two more pins of the microcontroller so that we can programmatically:
- 1.Mute the DAC.
- 2.Assign the microphone to the left or the right channel.
Go back to the "Pinout" tab, as seen below.
By clicking on any of the pins, you should be able to see the different functions that particular pin can assume, see below.
We are interested in using two pins as "GPIO_Output" (GPIO stands for "General-Purpose Input/Output") in order to output a HIGH or LOW value to the Adafruit breakout boards. Set the pins "PCO" and "PC1" to "GPIO_Output" (see below). You can reset a pin to having no function by selecting "Reset_State".
Just as in the case of variables in a program, we should give meaningful names to our GPIO pins. We will rename "PC0" and "PC1" as "MUTE" and "LR_SEL" respectively. You can rename a pin by right-clicking it and selecting "Enter User Label" (see below).
If you now save the
IOCfile (or if you change perspective) the source code will be updated:
If you have any of the source files open on SW4STM32, they should refresh automatically to reflect the settings you have changed in CubeMX. Remember that this is why you should not add or modify any section in the code outside of the
USER CODE BEGINand
USER CODE ENDcomments; outside of these tags, all code will usually replaced by a change in configuration.
Are you sure you are ready to see the solution? ;)
The transmission mode is defined by the fact that the peripheral is a DAC, thus the I2S internal peripheral of the micro-controller will have to transmit data to the DAC. The mode to select is then "Master transmit".
The communication standard can be either "I2S" or "LSB-justified" as shown in section 1.2 of the datasheet, we will then choose "I2S Phillips" as it is the default value selected when SF0 and SF1 of the breakout are not connected.
The second paragraph of section 3 of the datasheet says:
The UDA1334ATS supports the I2S-bus data format with word lengths of up to 24 bits and the LSB-justified serial data format with word lengths of 16, 20 and 24 bits.
In the code, we will be using 16-bit samples, so the word size is 16 bit. It is not so clear what is meant by "frame" in this context, since the term is not part of the original I2S specification. Nevertheless, we assume that, since the word size could be up to 24 bit, we should choose a "frame" of 32 bits. This is confirmed experimentally in the sense that, if we choose a frame of 16 bits, the passthrough does not work. You could also test both parameters and control with a logic analyzer what is the frame length. Such type of missing information is often encountered when reading a datasheet.
Lastly, the Audio frequency has to be defined. It is important to keep in mind that a faster sampling frequency implies less time for the micro-controller to process each sample. On the other hand, a slow sampling frequency impacts the quality of the signal as it reduces its bandwidth.
The pin called "PLL0" is set to 0 by default (according to the schematic), which means that the chip is in audio mode. Section 8.1.1, explains that in this mode the pin "PLL1" selects for audio frequency from 16 to 50 kHz (PLL1 = LOW) or from 50 to 100 kHz (PLL1 = HIGH). In this breakout, PLL1 is set to LOW according to the schematic. In order to make our final choice we will chose 32 kHz, this choice will be confirmed by task 2.
The transmission mode is defined by the fact that the peripheral is a microphone, thus the I2S internal peripheral of the micro-controller will have to receive data form the microphone. The mode to select is then "Master Receive".
This datasheet gives more information about the Data and Frame format. We will chose the same parameter as for I2S1 but figure 7 of the datasheet shows us that the frame is 32bits and that the microphone will send 18 bits with the actual value, then 6 of 0 state and then 8 of tri-state. Nevertheless, we will chose "16 Bits Data on 32 Bits Frame" in order to have a faster processing.
The Audio frequency has to be defined. This device is a bit more restrictive that the DAC. Indeed in page 7 of the datasheet we can read the following: Clock frequencies from 2.048Mhz to 4.096MHz are supported so sampling rates from 32KHz to 64KHz can be had by changing the clock frequency. In this case we clearly see that a frequency slower than 32kHz will not work properly.