Using SPI Module for I2S

Using SPI Module for I2S

Renesas offers MCUs with the Serial Sound Interface (SSI) peripheral which is used specifically for audio data transfer; however, not all MCUs (particularly lower-end devices) have the SSI.  Still, even without a dedicated module, it is possible to emulate I2S communication by using the SPI and additional timer peripherals.

The following example uses the RA2L1 device and the FSP to configure the necessary modules for communication as an I2S controller.  The required modules are as follows:

  • GPT for bit clock (BCK)

  • GPT for left/right clock (LRCK)

  • SCI SPI for data transmission

  • ELC for event linking

The image below shows these modules added to the FSP configuration view:

The first elements to configure are the I2S clock signals BCK and LRCK.  Both signals are generated by GPT pin outputs.  This example uses 16-bit data for each channel, so the LRCK will need to toggle after 16 periods of the BCK output waveform.

Configure the BCK

Set Pin Output Support to Enabled to allow generation of the output waveform.

Set the Mode to Periodic and the Period Unit to Hertz.  The Period setting will depend on the target audio sample rate.  Setting the Period to 1024000 will get us the desired sample rate of 16kHz for this example.

Here, the GTIOCA pin is used, so the relevant settings are for GTIOA.  Set GTIOCA Output Enabled to True.  Within the Custom Waveform dropdown, set Custom Waveform Enable to Enabled.  In the dropdown for GTIOA, set Initial Output Level to High, Cycle End Output to Toggle, and Compare Match Out Pin Level to Retain

Since the pin output will toggle once with every period of the timer, the actual period of the BCK signal will be the length of two timer periods.  This means that the 1024000Hz timer period will equal 512000 BCK periods.  Dividing 512kHz by 32 (the number of BCK ticks in one audio sample) results in 16kHz, which is our target audio sample rate.

Configure the LRCK

As with the BCK, set Pin Output Support to Enabled to allow generation of the output waveform.

Set the Mode to Periodic and the Period Unit to Raw Counts.  The LRCK will need to be toggled with every 16 BCK periods, so the intended period will need to be doubled as before; therefore, set Period to 32

Again, the GTIOCA pin is used, so set GTIOCA Output Enabled to True.  Within the Custom Waveform dropdown, set Custom Waveform Enable to Enabled.  In the dropdown for GTIOA, set Initial Output Level to Low, Cycle End Output to Retain, and Compare Match Out Pin Level to Toggle

To get the proper timing of the LRCK GPT, it needs to use the BCK GPT overflow as a counting source.  In the dropdown Input -> Count Up Source, check the GPTx COUNTER OVERFLOW box where x is the GPT channel used for the BCK signal.  With this set, each overflow of the BCK GPT increments the timer counter for the LRCK GPT.

Add the ELC module to the Stacks view to complete the link between the GPT channels.

Configure the SPI

For audio data transmission, we will use a channel of the SCI module configured for Simple SPI.  This allows more flexibility and simplicity than using the dedicated SPI module.  Because I2S requires a continuously pulsing BCK, we will not have to worry about underrun errors that would otherwise be detected if using the dedicated SPI.

Notice that the Operating Mode is selected as Slave even though the device will be operating as Master.  This is because we are generating the BCK signal from the GTP module and do not want the SPI to generate its own clock signal.  Set the Clock Phase to Data sampling on even edge, data variation on odd edge, and the Clock Polarity to High when idle.  These settings, along with the GPT settings for BCK will ensure that data will transition on the falling edge of BCK and be sampled on the rising edge.

Since the module is configured as a slave device in the FSP, when writing data from the device, it will be sent from the RXDn pin of SCI channel n since it acts as the MISO line for SPI.  Select a pin to be used for CTSn and physically tie this pin to GND.  This ensures that our “slave” device will always be able to transmit.

I2S Operation

With the FSP configured as shown, the output pins will output the necessary waveforms for data clocking after both the BCK and LRCK timers have been started.

Having the BCK timer output toggle with every period gives us the necessary bit clock for I2S.  Likewise, having the LRCK timer output toggle every 32 BCK periods will result in a clock signal that will allow for 16 bits of data on both left and right audio channels.

At the start of the application, the ELC, GPT channels, and SCI SPI channel need to be initialized as shown below:

The function R_GPT_CounterSet() is called to reduce the initial LRCK timer period by one BCK period.  This is to ensure that the LRCK transitions are on the appropriate edge of the BCK signal; otherwise, the LRCK transitions would be offset by one BCK timer period when using the previously defined timer configuration.

With the BCK timer output serving as the clock signal to the SPI, the SPI can send data at any time; however, it is necessary to synchronize the write function to the LRCK to avoid data corruption.  To do this, the SPI must start to write data based on the falling edge of the LRCK.

In the above image, the program waits until the LRCK pin is high before calling the function R_SCI_SPI_Write().  This ensures that the write doesn’t start while the LRCK signal is already low.  In the file r_sci_spi.c, another wait is added to the function r_sci_spi_start_transfer() to catch the falling edge of the LRCK before transmission begins.

When analyzing the clock and data signals, you can see data being sent out for both audio channels.

In the above image, you can see that the LRCK signal toggles with every 16 cycles of BCK, or every 32 periods of BCK’s GPT channel.  Each channel's data is clocked starting with the second rising edge of BCK after LRCK transitions, in accordance with I2S timing specifications.

Example Project

An example project for e2 studio is included in this page, and it is configured as described in the sections above for use on the EK-RA2L1 evaluation board.  In order to use this example project, certain pin connections must be made with jumper wires.  Each row in the following table indicates an Output pin that should be connected to a corresponding Input pin:

Output

Input

Output

Input

Pin Function

Pin

Pin Function

Pin

GTIOC0A (BCK)

P213

SCK0

P102

GTIOC1A (LRCK)

P405

GPIO (LRCK)

P103

CTS0

P413

GND

GND

As mentioned previously, because the MCU is technically configured as a SPI slave device in the FSP, the outgoing I2S data will be sent on the MISO line for SCI0 (P410).

In this project, a brief audio clip is played once every 3 seconds.  The audio file is stored as a byte array that contains uncompressed PCM data for both left and right channels.