Microchip® Advanced Software Framework

Quick Start Guide for I2S - Callback

In this use case, the I2S will be used to generate Master Clock (MCK), Serial Clock (SCK), Frame Sync (FS), and Serial Data (SD) signals.

Here MCK is set to the half of processor clock. SCK is set to a quarter of the frequency of processor. FS generates half-half square wave for left and right audio channel data. The output serial data of channels toggle from two values to generate square wave, if codec or DAC is connected.

The I2S module will be set up as follows:

  • GCLK generator 0 (GCLK main) clock source
  • MCK, SCK, and FS clocks outputs are enabled
  • MCK output divider set to 2
  • SCK generation divider set to 4
  • Each frame will contain two 32-bit slots
  • Data will be left adjusted and start transmit without delay

Quick Start

Prerequisites

There are no prerequisites for this use case.

Code

Add to the main application source file, before any functions:

#define CONF_I2S_MODULE I2S
#define CONF_I2S_MCK_PIN PIN_PA09G_I2S_MCK0
#define CONF_I2S_MCK_MUX MUX_PA09G_I2S_MCK0
#define CONF_I2S_SCK_PIN PIN_PA10G_I2S_SCK0
#define CONF_I2S_SCK_MUX MUX_PA10G_I2S_SCK0
#define CONF_I2S_FS_PIN PIN_PA11G_I2S_FS0
#define CONF_I2S_FS_MUX MUX_PA11G_I2S_FS0
#define CONF_I2S_SD_PIN PIN_PA07G_I2S_SD0
#define CONF_I2S_SD_MUX MUX_PA07G_I2S_SD0

Add to the main application source file, outside of any functions:

Copy-paste the following data buffer code to your user application:

uint16_t data_buffer[4] = {0xF87F, 0x901F, 0, 0};

Copy-paste the following callback function code to your user application:

struct i2s_module *const module_inst)
{
I2S_SERIALIZER_0, data_buffer, 4);
}

Copy-paste the following setup code to your user application:

static void _configure_i2s(void)
{
i2s_init(&i2s_instance, CONF_I2S_MODULE);
struct i2s_clock_unit_config config_clock_unit;
config_clock_unit.clock.gclk_src = GCLK_GENERATOR_0;
config_clock_unit.clock.mck_src = I2S_MASTER_CLOCK_SOURCE_GCLK;
config_clock_unit.clock.mck_out_enable = true;
config_clock_unit.clock.mck_out_div = 2;
config_clock_unit.clock.sck_src = I2S_SERIAL_CLOCK_SOURCE_MCKDIV;
config_clock_unit.clock.sck_div = 4;
config_clock_unit.frame.number_slots = 2;
config_clock_unit.frame.slot_size = I2S_SLOT_SIZE_32_BIT;
config_clock_unit.frame.data_delay = I2S_DATA_DELAY_0;
config_clock_unit.frame.frame_sync.source = I2S_FRAME_SYNC_SOURCE_SCKDIV;
config_clock_unit.frame.frame_sync.width = I2S_FRAME_SYNC_WIDTH_HALF_FRAME;
config_clock_unit.mck_pin.enable = true;
config_clock_unit.mck_pin.gpio = CONF_I2S_MCK_PIN;
config_clock_unit.mck_pin.mux = CONF_I2S_MCK_MUX;
config_clock_unit.sck_pin.enable = true;
config_clock_unit.sck_pin.gpio = CONF_I2S_SCK_PIN;
config_clock_unit.sck_pin.mux = CONF_I2S_SCK_MUX;
config_clock_unit.fs_pin.enable = true;
config_clock_unit.fs_pin.gpio = CONF_I2S_FS_PIN;
config_clock_unit.fs_pin.mux = CONF_I2S_FS_MUX;
&config_clock_unit);
struct i2s_serializer_config config_serializer;
config_serializer.clock_unit = I2S_CLOCK_UNIT_0;
config_serializer.mode = I2S_SERIALIZER_TRANSMIT;
config_serializer.data_size = I2S_DATA_SIZE_16BIT;
config_serializer.data_pin.enable = true;
config_serializer.data_pin.gpio = CONF_I2S_SD_PIN;
config_serializer.data_pin.mux = CONF_I2S_SD_MUX;
&config_serializer);
}
static void _configure_i2s_callbacks(void)
{
}

Add to user application initialization (typically the start of main()):

Add to user application start transmitting job (typically in main(), after initialization):

Workflow

  1. Create a module software instance structure for the I2S module to store the I2S driver state while it is in use.
    Note
    This should never go out of scope as long as the module is in use. In most cases, this should be global.
  2. Configure the I2S module.
    1. Initialize the I2S module.
      i2s_init(&i2s_instance, CONF_I2S_MODULE);
    2. Initialize the I2S Clock Unit.
      1. Create a I2S module configuration struct, which can be filled out to adjust the configuration of a physical I2S Clock Unit.
        struct i2s_clock_unit_config config_clock_unit;
      2. Initialize the I2S Clock Unit configuration struct with the module's default values.
        Note
        This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
      3. Alter the I2S Clock Unit settings to configure the general clock source, MCK, SCK, and FS generation.
        config_clock_unit.clock.gclk_src = GCLK_GENERATOR_0;
        config_clock_unit.clock.mck_src = I2S_MASTER_CLOCK_SOURCE_GCLK;
        config_clock_unit.clock.mck_out_enable = true;
        config_clock_unit.clock.mck_out_div = 2;
        config_clock_unit.clock.sck_src = I2S_SERIAL_CLOCK_SOURCE_MCKDIV;
        config_clock_unit.clock.sck_div = 4;
        config_clock_unit.frame.number_slots = 2;
        config_clock_unit.frame.slot_size = I2S_SLOT_SIZE_32_BIT;
        config_clock_unit.frame.data_delay = I2S_DATA_DELAY_0;
        config_clock_unit.frame.frame_sync.source = I2S_FRAME_SYNC_SOURCE_SCKDIV;
        config_clock_unit.frame.frame_sync.width = I2S_FRAME_SYNC_WIDTH_HALF_FRAME;
      4. Alter the I2S Clock Unit settings to configure the MCK, SCK, and FS output on physical device pins.
        config_clock_unit.mck_pin.enable = true;
        config_clock_unit.mck_pin.gpio = CONF_I2S_MCK_PIN;
        config_clock_unit.mck_pin.mux = CONF_I2S_MCK_MUX;
        config_clock_unit.sck_pin.enable = true;
        config_clock_unit.sck_pin.gpio = CONF_I2S_SCK_PIN;
        config_clock_unit.sck_pin.mux = CONF_I2S_SCK_MUX;
        config_clock_unit.fs_pin.enable = true;
        config_clock_unit.fs_pin.gpio = CONF_I2S_FS_PIN;
        config_clock_unit.fs_pin.mux = CONF_I2S_FS_MUX;
      5. Configure the I2S Clock Unit with the desired settings.
    3. Initialize the I2S Serializer.
      1. Create a I2S Serializer configuration struct, which can be filled out to adjust the configuration of a physical I2S Serializer.
        struct i2s_serializer_config config_serializer;
      2. Initialize the I2S Serializer configuration struct with the module's default values.
        Note
        This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
      3. Alter the I2S Serializer settings to configure the serial data generation.
        config_serializer.clock_unit = I2S_CLOCK_UNIT_0;
        config_serializer.mode = I2S_SERIALIZER_TRANSMIT;
        config_serializer.data_size = I2S_DATA_SIZE_16BIT;
      4. Alter the I2S Serializer settings to configure the SD on a physical device pin.
        config_serializer.data_pin.enable = true;
        config_serializer.data_pin.gpio = CONF_I2S_SD_PIN;
        config_serializer.data_pin.mux = CONF_I2S_SD_MUX;
      5. Configure the I2S Serializer with the desired settings.
    4. Enable the I2S module, the Clock Unit, and Serializer to start the clocks and ready to transmit data.
  3. Configure the I2S callbacks.
    1. Register the Serializer 0 TX ready callback function with the driver.
    2. Enable the Serializer 0 TX ready callback so that it will be called by the driver when appropriate.
  4. Start a transmitting job.

Use Case

Code

Copy-paste the following code to your user application:

Workflow

  1. Enter an infinite loop while the output is generated via the I2S module.
    while (true) {
    }