Playback

This example demonstrates how to encode a 1KHz sine wave signal via CODEC and output audio.

It uses GDMA to transfer I2S data from memory to the I2S transmit FIFO, then encodes it into PDM signals using CODEC.

External PDM players can play fixed-frequency sine wave audio.

Requirements

For requirements, please refer to the Requirements.

In addition, you need to install PuTTY or UartAssist serial assistant tools and audio parsing tools like Audacity on the PC terminal.

Wiring

Connect the external PDM player to the EVB, connecting P4_3 to CLK and P4_2 to DATA.

Building and Downloading

For building and downloading, please refer to the Building and Downloading.

Experimental Verification

Listen to the 1KHz sine wave sound through the PDM player.

Code Overview

This section introduces the code and process description for initialization and corresponding function implementation in the sample.

Source Code Directory

The directory for project file and source code are as follows:

  • Project directory: sdk\samples\peripheral\codec\playback\proj

  • Source code directory: sdk\samples\peripheral\codec\playback\src

Initialization

The initialization flow for peripherals can refer to Initialization Flow in General Introduction.

The initialization process includes initializing the codec, uart, i2s, and gdma modules as follows.

  1. Call Pad_Config() and Pinmux_Config() to configure the PAD and PINMUX for PDM-related pins.

    void board_codec_init(void)
    {
        Pad_Config(PDM_CLK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
        Pad_Config(PDM_DAT_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
    
        Pinmux_Config(PDM_CLK_PIN, PDM_CLK);
        Pinmux_Config(PDM_DAT_PIN, PDM_DATA);
    }
    
  2. Call Pad_Config() and Pinmux_Config() to configure the PAD and PINMUX for I2S-related pins.

    void board_i2s_init(void)
    {
        Pad_Config(CODEC_BCLK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
        Pad_Config(CODEC_LRCLK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE,PAD_OUT_LOW);
        Pad_Config(CODEC_TX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
        Pad_Config(CODEC_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
    
        Pinmux_Config(CODEC_BCLK_PIN, BCLK_SPORT0);
        Pinmux_Config(CODEC_LRCLK_PIN, LRC_SPORT0);
        Pinmux_Config(CODEC_TX_PIN,  DACDAT_SPORT0);
    }
    
  3. Execute I2S_StructInit() and I2S_Init() to initialize the I2S peripheral. Configuration parameters for the I2S0 initialization are as follows:

I2S master RX initialization parameters

I2S Hardware Parameters

Setting in the I2S_InitStruct

I2S master RX

Sample Rate (Mi)

I2S_InitTypeDef::I2S_RxBClockMi

0x271

Sample Rate (Ni)

I2S_InitTypeDef::I2S_RxBClockNi

0x10

Device Mode

I2S_InitTypeDef::I2S_DeviceMode

I2S_DeviceMode_Master

Channel Type

I2S_InitTypeDef::I2S_RxChannelType

I2S_Channel_stereo

Data Format

I2S_InitTypeDef::I2S_RxDataFormat

I2S_Mode

Data Width

I2S_InitTypeDef::I2S_RxDataWidth

I2S_Width_24Bits

  1. Execute GDMA_StructInit() and GDMA_Init() to initialize the GDMA peripheral. Configuration parameters for the GDMA initialization are as follows:

GDMA initialization parameters

GDMA Hardware Parameters

Setting in the GDMA_InitStruct

GDMA Channel

Channel Num

GDMA_InitTypeDef::GDMA_ChannelNum

0

Transfer Direction

GDMA_InitTypeDef::GDMA_DIR

GDMA_DIR_MemoryToPeripheral

Source Address Increment or Decrement

GDMA_InitTypeDef::GDMA_SourceInc

DMA_SourceInc_Inc

Destination Address Increment or Decrement

GDMA_InitTypeDef::GDMA_DestinationInc

DMA_DestinationInc_Fix

Source Data Size

GDMA_InitTypeDef::GDMA_SourceDataSize

GDMA_DataSize_Word

Destination Data Size

GDMA_InitTypeDef::GDMA_DestinationDataSize

GDMA_DataSize_Word

Source Burst Transaction Length

GDMA_InitTypeDef::GDMA_SourceMsize

GDMA_Msize_4

Destination Burst Transaction Length

GDMA_InitTypeDef::GDMA_DestinationMsize

GDMA_Msize_4

Source Address

GDMA_InitTypeDef::GDMA_SourceAddr

codec_drv_cos_table

Destination Address

GDMA_InitTypeDef::GDMA_DestinationAddr

&(I2S0->I2S_TX_FIFO_WR_ADDR)

Destination Handshake

GDMA_InitTypeDef::GDMA_DestHandshake

GDMA_Handshake_I2S0_TDM0_TX

  1. Configure the GDMA transfer complete interrupt GDMA_INT_Transfer and NVIC. Related NVIC configuration can be referred to in 中断配置.

  2. Initialize the CODEC peripheral.

    1. Call CODEC_AnalogCircuitInit() to initialize the analog circuit.

    2. Call RCC_PeriphClockCmd() to enable the CODEC clock.

    3. Execute CODEC_StructInit() and CODEC_Init() to initialize the CODEC peripheral. Configuration parameters for the CODEC initialization are as follows:

CODEC initialization parameters

CODEC Hardware Parameters

Setting in the CODEC_InitStruct

CODEC

Da Mute

CODEC_InitTypeDef::CODEC_DaMute

CODEC_UNMUTE

Da Gain Mode

CODEC_InitTypeDef::CODEC_DaGain

0xAF

DaC Dither

CODEC_InitTypeDef::CODEC_DaC_Dither

DAC_DA_DITHER_DISABLE

I2S Data Format

CODEC_InitTypeDef::CODEC_I2SFormat

CODEC_I2S_DataFormat_I2S

I2S Channel Len

CODEC_InitTypeDef::CODEC_I2SChannelLen

I2S_CHANNELLEN_32

I2S Data Width

CODEC_InitTypeDef::CODEC_I2SRxDataWidth

CODEC_I2S_Tx_DataWidth_24Bits

I2S Channel Sequence

CODEC_InitTypeDef::CODEC_I2SChSequence

CODEC_I2S_CH_L_R

  1. Execute preload_cos_table to prepare the sine wave data to be sent.

  2. Call I2S_Cmd() to enable the I2S receive mode. Call GDMA_Cmd() to enable GDMA transfer.

Functional Implementation

The sine wave data is transferred by GDMA from memory to the I2S TX FIFO. After being converted by DA (Digital-to-Analog) module in CODEC, the audio can be heard through an external PDM amplifier. The data transmission order across each module is illustrated in the diagram below.

this should be PLAYBACK waveform

data transfer module

  1. When the GDMA transfer amount reaches the set BlockSize, it triggers the GDMA_INT_Transfer interrupt. In the interrupt handler, the source address, destination address, and BlockSize are reset, and GDMA transfer is re-enabled to ensure continuous data transmission.

    GDMA_SetSourceAddress(CODEC_GDMA_Channel, (uint32_t)codec_drv_cos_table);
    GDMA_SetDestinationAddress(CODEC_GDMA_Channel, (uint32_t)(&(I2S0->I2S_TX_FIFO_WR_ADDR)));
    GDMA_SetBufferSize(CODEC_GDMA_Channel, CODEC_DRV_COS_TABLE_SAMPLE);
    GDMA_ClearINTPendingBit(CODEC_GDMA_Channel_NUM, GDMA_INT_Transfer);
    GDMA_Cmd(CODEC_GDMA_Channel_NUM, ENABLE);