SK-S7G2 How to receive and transmit data using I2S

I am using the SK-S7G2 board. I am attempting to receive and transmit data using I2S. I followed the instructions in ssp-user-manual-html-v1.10-sspv1.3.0/html/_h_a_l_i2_s_interface.html#configuring-the-i2s-hal-module. The I2S callback is getting the I2S_EVENT_TX_EMPTY event, so it looks like the S7 is attempting to transmit, but I am not seeing I2S signals on the pins.

See details and project files below.

Does anybody have a simple working example of I2S on the SK-S7G2 board?

Is there something I mixed in my Synergy Configuration?

Thanks,

Bruce Graham

Senior Software Engineer

 

Synergy Configuration:

Peripherals | Connectivity:SSI | SSI0

Pin Group Selection: Mixed

Operation Mode: Custom

Input/Output

SSISCK: P403

SSIWS: P404

SSITXD: P405

SSIRXD: P406

HAL/Common Stacks

g_i2s0 I2S Driver on r_ssi

 

bool b_txIsEmpty = false;
ssp_err_t rtn_main = SSP_SUCCESS;


/*******************************************************************************************************************//**
* @brief Blinky example application
**********************************************************************************************************************/
void hal_entry(void) {
          uint8_t buffer[4] = {0x55,0x55,0x55,0x55};

          rtn_main = g_i2s0.p_api->open(g_i2s0.p_ctrl,g_i2s0.p_cfg);
          if (SSP_SUCCESS == rtn_main)
          {
                    rtn_main = g_i2s0.p_api->write(g_i2s0.p_ctrl, buffer, sizeof(buffer));
                    if (SSP_SUCCESS == rtn_main)
                    {
                              rtn_main = g_i2s0.p_api->read(g_i2s0.p_ctrl, buffer, sizeof(buffer));
                    }
          }

...

 

typedef struct {
          union
          {
                    uint8_t bytes[4];
                    struct {
                              int32_t zeros : 32-18; // 14 bits of zeros in lower data.
                              int32_t signed18bits : 18; // 18 signed bits in upper 32 bit of data.
                    };
          };
} T_DATA_BUFFER;

#define MAX_SAMPLES 64

T_DATA_BUFFER rx_buffer[MAX_SAMPLES];

uint8_t tx_buffer[4] = {0x55, 0x55, 0x55, 0x55};

ssp_err_t rnt_cb_tx = SSP_SUCCESS;
ssp_err_t rnt_cb_rx = SSP_SUCCESS;


void i2s_cb(i2s_callback_args_t * p_args)
{
          static int index = 0;

          switch(p_args->event)
          {
          case I2S_EVENT_IDLE: ///< Communication is idle
                    rnt_cb_tx = g_i2s0.p_api->write(g_i2s0.p_ctrl, tx_buffer, sizeof(tx_buffer));
                    break;
          case I2S_EVENT_TX_EMPTY: ///< Transmit buffer is below FIFO trigger level
                    rnt_cb_tx = g_i2s0.p_api->write(g_i2s0.p_ctrl, tx_buffer, sizeof(tx_buffer));
                    b_txIsEmpty = true;
                    break;
          case I2S_EVENT_RX_FULL: ///< Receive buffer is above FIFO trigger level
                    rnt_cb_rx = g_i2s0.p_api->read(g_i2s0.p_ctrl, rx_buffer[index].bytes, sizeof(rx_buffer[index].bytes));
                    index++;
                    if (MAX_SAMPLES == index)
                    {
                              index = 0;
                    }
                    break;
           default:
                    break;
          }
}

  • I have the r_ssi "Sampling Frequency (Hertz)" set to 4000. I have some obvious questions about how to handle sampling.

    I want to read from the attached I2S device at 4KHz. Why am I not seeing the I2S_EVENT_RX_FULL event occuring at 4KHz?

    Do I have to initiate the receive by first starting a transmit?

    Thanks,
    Bruce
  • In reply to bgraham:

    Hi Bruce,

    You should connect the timer output to AUIDO_CLK pin. Please find this information in the following thread
    renesasrulz.com/.../ssi-output-not-happening

    More interesting tips regarding I2S can be found in these threads: renesasrulz.com/search

    Regards,
    adboc
  • In reply to adboc:

    Your references were no help. I have a S7, not a S5, nor a S3. Perhaps there is a bug in the S7 hardware or 1.3.0 software?

    r_gpt GTIOOCA and GTIOCB is set up to provide a 2.8 MHz I2S CLK on P512 and P513.
    SSI0 is set up: SSISCK: None, SSIWS: P404, SSITXD: P405, SSIRXD: P406

    PROBLEMS:
    The S7 is NOT toggling the SSIWS. The pin is stuck high. The RX Full event does not occur.
    The S7 is NOT transmitting on SSITXD. The TX empty event in the I2S callback occurs 3 times, then stops.

    Since your documentation and references are messed up, can you provide a SK-S7G2 configuration file that actually has receiving and transmitting with a real I2S device?

    Thanks,
    Bruce Graham
    Senior Software Engineer
  • In reply to bgraham:

    Hi Bruce,

    The same apply for S7: timer output should be supplied to AUDIO_CLK pin. I configured the SSI channel 0 (P112-P115), but also AUDIO_CLK pin in Pins tab > Peripherals > Connectivity:SSI > SSI:

     

    The timer instance supplied to the SSI driver is a GPT instance on channel 0 with the GTIOCA output enabled, configured on P512. Then I made a hardware connection from P512 to P400. Finally I observed the callback (I2S_EVENT_TX_EMPTY) being periodically called, which means the SSI periodically sent out the data.

    I used a modified version of your above code. Please find the project here:

    S7_SK_I2S_1_2_1.zip

    Regards,
    adboc

  • In reply to adboc:

    Your example does not work properly for me.
    Have you connected a real I2S device and verified that it is working?

    I modified the code for readability. See info below.

    Thanks,
    Bruce Graham
    Senior Software Engineer.


    I2S DEVICE: Adafruit I2S MEMS Microphone - SPH0645

    =================================
    Wiring between S7 and SPH0645
    =================================
    S7.VCC -> SPH0645.3V
    S7.GND -> SPH0645.GND
    S7.GND -> SPH0645.SEL (left channel mono)
    S7.GPT0.GTIOCA (P512) -> S7.SSI.AUDIO_CLK (P400)
    S7.SSI0.SSISCK (P112) -> not connected
    S7.GPT0.GTIOCA (P512) -> SPH0645.BCLK (bit clock)
    S7.SSI0.SSIWS (P113) -> SPH0645.LRCLK (word select)
    S7.SSI0.SSITXD (P115) -> O-scope
    S7.SSI0.SSIRXD (P114) <- SPH0645.DOUT (data output)

    =================================
    Verified signals using o-scope
    =================================
    The S7 is generating a fixed 2.8 MHz clock.
    GOOD: S7 I2S bit clock is working.
    The S7 is toggling the S7.SSI0.SSIWS
    GOOD: S7 I2S word select is working.
    The S7 never phsyically transmits on the I2S BUS.
    BAD: S7 I2S transmit is not working.
    The S7 never receives data on the I2S BUS.
    GOOD: The SPH0645 is clocking out audio data. The o-scope shows audio data in the bit stream.
    BAD: When the RX_FULL event occurs, the receive buffer does not contain audio data.
    After a few transmits, and 1 receive, the S7 stops generating I2S signals.
    BAD: The S7's Thread #1 has been suspended.
    See Console output below.


    =================================
    Console output
    =================================
    write TX_EMPTY (96 in total)
    read RX_FULL (left word contain junk, not audio data, right word is all zeros)
    write IDLE
    write TX_EMPTY (8 in total)

    Temporary breakpoint 6, main () at ../src/synergy_gen/main.c:52
    52 {
    write in main
    read in main (left word contain junk, not audio data, right word is all zeros)

    write IDLE and then a write TX_EMPTY (30 times)

    RX_FULL (left word contain junk, not audio data, right word is all zeros)

    write IDLE and then a write TX_EMPTY (5 times)

    [Thread 1.1] #1 stopped.
    _skip_vfp_restore () at ssp\src\framework\el\tx\tx_src\synergy\tx_thread_schedule.c:338
    338 ssp\src\framework\el\tx\tx_src\synergy\tx_thread_schedule.c: No such file or directory.
    [New Thread 1.1001]

    Program received signal SIGINT, Interrupt.
    _tx_thread_system_return_inline () at inc\el/./cm4_gcc/tx_port.h:352
    352 inc\el/./cm4_gcc/tx_port.h: No such file or directory.


    =================================
    i2s_thread_entry.c
    =================================
    #include "i2s_thread.h"

    #define MAX_RX_SAMPLES 64
    #define MAX_TX_SAMPLES 2

    typedef struct {
    int32_t signed18bits : 18; // 18 signed bits
    int32_t not_used : 14; // 14 bits of ones
    } T_I2S_SAMPLE;


    typedef struct {
    union
    {
    struct {
    uint32_t left;
    uint32_t right;
    } words;
    uint8_t bytes[8];
    struct {
    T_I2S_SAMPLE left;
    T_I2S_SAMPLE right;
    } samples;
    };
    } T_DATA_BUFFER;


    int rx_index = 0;
    T_DATA_BUFFER rx_buffer[MAX_RX_SAMPLES];

    int tx_index = 0;
    T_DATA_BUFFER tx_buffer[MAX_TX_SAMPLES] = {
    { .words = {0x55555555, 0x66666666}},
    { .words = {0x55555555, 0x66666666}}
    };


    /* I2S Thread entry function */
    void i2s_thread_entry(void)
    {
    ssp_err_t err;

    memset(rx_buffer, 0, sizeof(rx_buffer));

    err = g_i2s0.p_api->open(g_i2s0.p_ctrl, g_i2s0.p_cfg);
    if (err != SSP_SUCCESS)
    {
    __BKPT(0);
    }

    err = g_i2s0.p_api->write(g_i2s0.p_ctrl, &tx_buffer[tx_index].bytes[0], sizeof(T_DATA_BUFFER));
    if (err != SSP_SUCCESS)
    {
    __BKPT(0);
    }

    err = g_i2s0.p_api->read(g_i2s0.p_ctrl, &rx_buffer[rx_index].bytes[0], sizeof(T_DATA_BUFFER));
    if (err != SSP_SUCCESS)
    {
    __BKPT(0);
    }

    while (1)
    {
    tx_thread_sleep (100);
    }
    }

    void i2s_callback(i2s_callback_args_t * p_args)
    {
    ssp_err_t err;

    switch(p_args->event)
    {
    case I2S_EVENT_IDLE:
    err = g_i2s0.p_api->write(g_i2s0.p_ctrl, &tx_buffer[tx_index].bytes[0], sizeof(T_DATA_BUFFER));
    if (err != SSP_SUCCESS)
    {
    __BKPT(0);
    }
    break;
    case I2S_EVENT_TX_EMPTY:
    err = g_i2s0.p_api->write(g_i2s0.p_ctrl, &tx_buffer[tx_index].bytes[0], sizeof(T_DATA_BUFFER));
    if (err != SSP_SUCCESS)
    {
    __BKPT(0);
    }
    // else
    // {
    // ++tx_index;
    // if (MAX_TX_SAMPLES <= tx_index)
    // {
    // tx_index = 0;
    // }
    // }
    break;
    case I2S_EVENT_RX_FULL:
    err = g_i2s0.p_api->read(g_i2s0.p_ctrl, &rx_buffer[rx_index].bytes[0], sizeof(T_DATA_BUFFER));
    if (err != SSP_SUCCESS)
    {
    __BKPT(0);
    }
    else
    {
    ++rx_index;
    if (MAX_RX_SAMPLES <= rx_index)
    {
    rx_index = 0;
    }
    }
    break;
    default:
    break;
    }
    }
  • In reply to bgraham:

    Hi Bruce,

    As far as I see, SPH0645 uses 24-bit format. Did you set it in the configurator? Moreover I suggest connecting S7.SSI0.SSISCK (P112) to SPH0645.BCLK (bit clock), instead of S7.GPT0.GTIOCA (P512).

    Regards,
    adboc
  • In reply to adboc:

    The SPH0645 uses Data Bits: 18, Word Length: 32 bits. I made these changes to r_ssi, Threads, Properties.

    Your pin change has helped, but the I2S is still not working correctly. The RX only happens 1 time, the TX only occurs 25 times.

    Why does the S7 stop sending and receiving?

    Thanks,
    Bruce Graham
    Senior Software Engineer



    =================================
    Verified signals using o-scope
    =================================
    The S7 is generating a fixed 2.8 MHz clock.
    GOOD: S7 I2S bit clock is working.
    The S7 is toggling the S7.SSI0.SSIWS
    GOOD: S7 I2S word select is working.
    S7 I2S TX data
    GOOD: TX data is appearing on pin S7.SSI0.SSITXD.
    S7 I2S RX (audio data from SPH0645).
    GOOD: RX audio data is received during RX FULL event.
    Continuous RX and TX
    BAD: The S7 stops transmitting and receiving after a few transfers.

    =================================
    I2S Thread
    =================================
    Channel: 0
    Data Bits: 18
    Word Length: 32 bits


    =================================
    Wiring between S7 and SPH0645
    =================================
    S7.VCC -> SPH0645.3V
    S7.GND -> SPH0645.GND
    S7.GND -> SPH0645.SEL (left channel mono)
    S7.GPT0.GTIOCA (P512) -> S7.SSI.AUDIO_CLK (P400)
    S7.SSI0.SSISCK (P112) -> SPH0645.BCLK (bit clock)
    S7.SSI0.SSIWS (P113) -> SPH0645.LRCLK (word select)
    S7.SSI0.SSIRXD (P114) <- SPH0645.DOUT (data output)
    S7.SSI0.SSITXD (P115) -> O-scope


    =================================
    Console output
    =================================
    Temporary breakpoint 6, main () at ../src/synergy_gen/main.c:52
    52 {
    write in main
    read in main
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    RX_FULL Left data: 0x00000000 Right data: 0x00003abb
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
    write TX_EMPTY
    write IDLE
  • In reply to bgraham:

    Hi Bruce,

    Here's the extract from the datasheet (section "Interface Description"):
    "The Data Format is I2S, 24 bit, 2’s compliment, MSB first. The Data Precision is 18 bits, unused bits are zeros."

    I think you should set the Word length to 24 bits and leave the Data bits to 18 bits.

    Regards,
    adboc
  • In reply to adboc:

    Nope, those changes did not correct any of the problems. The example code is still not sending and receiving, and it craps out after a few seconds.

    Did you verify this code and the connections with real hardware connected to the S7?

    Thanks,
    Bruce Graham
    AKA - A VERY UPSET CUSTOMER!!!!!!!!!!!!!!!!!!
  • In reply to bgraham:

    Hello Bruce,

    Did you get a change to investigate code in sf_audio_playback_hw_i2s framework? It implements code responsible for initializing and operating lower level I2S/SSI driver. To my knowledge, SSI and audio framework modules were all tested with I2S DAC connected on PMOD.

    For continuous playback on sf_audio_playback_hw_i2s or r_ssi, you should call play or write (respectively) in the ISR handler for TX_EMPTY callback.

    Regards