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.

Create a new project

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 .elf file in the Binaries folder of the new project.

  • rename the .ioc file with the name of the project

Now we are ready to update the initialization code. From the project explorer, click on the IOC file of the new project and open the CubeMX configurator.

Enable and configure the I2S buses

When the IOC file 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.

I2S1 (DAC)

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).

I2S2 (microphone)

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.

Configure the GPIO pins

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).

Update initialization code

If you now save the IOC file (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 BEGIN and USER CODE END comments; outside of these tags, all code will usually replaced by a change in configuration.

With the peripherals and initialization code updated, we can proceed to wiring the breakout boards!

Tasks solutions

Are you sure you are ready to see the solution? ;)

Last updated