I2S

HI

I am using the I2S on the nRF52840DK I have constructed an array and all works well except once I start it , it continues to run, I cant get it to play the sample just once, how can I do this

Start Code

NRF_I2S->ENABLE = 1;

// Configure data pointer
NRF_I2S->TXD.PTR = (uint32_t)&sine_table2[0];
NRF_I2S->RXTXD.MAXCNT = sizeof(sine_table2) / sizeof(uint32_t);

NRF_I2S->TASKS_START = 1;

for (;;)
{

    __WFE();

}

Any assistance would be appreciated.

Kind Regards

David

Parents
  • Hi,

    The TXPTRUPD event will be generated every time RXTXD.MAXCNT number of transmitted data words has been sent. You can stop transmitting when this event is generated. Alternatively, you can use our driver which makes it much more easier to setup and use the I2S peripheral.

    regards

    Jared 

  • Hi Jared

    Thanks for getting back to me, can you please show me how I can intercept and use the TXPTRUPD event in __WFE (Sleep Mode) as I cant seem to find any details on how to do this.

    Kind Regards

    David

  • Here you go:

    #include <nrf.h>
    
    #define PIN_MCK    (13)
    #define PIN_SCK    (14)
    #define PIN_LRCK   (15)
    #define PIN_SDOUT  (16)
    
    int main(void)
    {
      // Sine table (stereo, so every value is duplicated)
      int16_t sine_table[] = { 0, 0, 23170, 23170, 32767, 32767, 23170, 23170, 0, 0, -23170, -23170, -32768, -32768, -23170, -23170};
      
      // Enable transmission
      NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_ENABLE << I2S_CONFIG_TXEN_TXEN_Pos);
      
      // Enable MCK generator
      NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_ENABLE << I2S_CONFIG_MCKEN_MCKEN_Pos);
      
      // MCKFREQ = 4 MHz
      NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV11  << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos;
      
      // Ratio = 64 
      NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_64X << I2S_CONFIG_RATIO_RATIO_Pos;
        
      // Master mode, 16Bit, left aligned
      NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_MASTER << I2S_CONFIG_MODE_MODE_Pos;
      NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16BIT << I2S_CONFIG_SWIDTH_SWIDTH_Pos;
      NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_LEFT << I2S_CONFIG_ALIGN_ALIGN_Pos;
      
      // Format = I2S
      NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos;
      
      // Use stereo 
      NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_STEREO << I2S_CONFIG_CHANNELS_CHANNELS_Pos;
      
      // Configure pins
      NRF_I2S->PSEL.MCK = (PIN_MCK << I2S_PSEL_MCK_PIN_Pos);
      NRF_I2S->PSEL.SCK = (PIN_SCK << I2S_PSEL_SCK_PIN_Pos); 
      NRF_I2S->PSEL.LRCK = (PIN_LRCK << I2S_PSEL_LRCK_PIN_Pos); 
      NRF_I2S->PSEL.SDOUT = (PIN_SDOUT << I2S_PSEL_SDOUT_PIN_Pos);
      
      
      // Configure data pointer
      NRF_I2S->TXD.PTR = (uint32_t)&sine_table[0];
      NRF_I2S->RXTXD.MAXCNT = sizeof(sine_table) / sizeof(uint32_t);
      
      //Enable interrupt and IRQ
      NRF_I2S->INTENSET = I2S_INTENSET_TXPTRUPD_Enabled << I2S_INTENSET_TXPTRUPD_Pos;
    
      
      NVIC_EnableIRQ(I2S_IRQn);
      
      NRF_I2S->ENABLE = 1;
      // Start transmitting I2S data
      NRF_I2S->TASKS_START = 1;
      
      
      // Since we are not updating the TXD pointer, the sine wave will play over and over again.
      // The TXD pointer can be updated after the EVENTS_TXPTRUPD arrives.
      while (1)
      {
        //__WFE();
      }
    }
    
    //IRQ handler
    
    void I2S_IRQHandler(void)
    {
      if (NRF_I2S->EVENTS_TXPTRUPD == 1)
      {
          NRF_I2S->EVENTS_TXPTRUPD = 0;
          NRF_I2S->TASKS_STOP = 1;
    
      }
    }

  • Hi Jared

    Thank for sending this code, the only problem is, when I put in 

    //IRQ handler

    void I2S_IRQHandler(void)
    {
    if (NRF_I2S->EVENTS_TXPTRUPD == 1)
    {
    NRF_I2S->EVENTS_TXPTRUPD = 0;
    NRF_I2S->TASKS_STOP = 1;

    }
    }

    I get these errors please see attached

     

    Thank you for all your help

    David

  • Hi,

    It's because you have included a source file which already contains the definition of the IRQ handler, the error message specifies that this is first defined in nrfx_I2S. I suggest omitting the driver from the project if you're only going to use the peripheral bare metal.

    regards

    Jared 

  • Hi Jared

    Thanks for getting back so promptly, I am trying to use your driver please see code below (first time I have used Nordic), I think I am mixing both, but it does work can you please amend so I am only using your driver and I am able to use the interrupt.

    #include <stdio.h>
    #include "nrf_drv_i2s.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"

    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"

    #include <nrf.h>

    #include "sounds.h"

    #define PIN_MCK (41) //P1.09
    #define PIN_BCLK (40) //P1.08
    #define PIN_LRCK (38) //P1.06
    #define PIN_SDOUT (39) //P1.07

    #define Button 11
    #define LED 13


    static void data_handler(nrf_drv_i2s_buffers_t const * p_released,uint32_t status)
    {

    }


    int main(void)
    {
    uint32_t err_code = NRF_SUCCESS;

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;

    config.sck_pin = PIN_BCLK;
    config.lrck_pin = PIN_LRCK;
    config.sdout_pin = PIN_SDOUT;

    config.mode = I2S_CONFIG_MODE_MODE_Master;
    config.sample_width = I2S_CONFIG_SWIDTH_SWIDTH_16BIT;

    config.mck_setup = NRF_I2S_MCK_32MDIV8;
    config.ratio = NRF_I2S_RATIO_512X;
    config.channels = NRF_I2S_CHANNELS_RIGHT;

    err_code = nrf_drv_i2s_init(&config, data_handler);
    APP_ERROR_CHECK(err_code);



    // // Enable transmission
    NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_ENABLE << I2S_CONFIG_TXEN_TXEN_Pos);

    // // Configure data pointer
    NRF_I2S->TXD.PTR = (uint32_t)&sine_table2[0];
    NRF_I2S->RXTXD.MAXCNT = sizeof(sine_table2) / sizeof(uint32_t);

    nrf_gpio_cfg_output(LED);
    nrf_gpio_cfg_input(Button, NRF_GPIO_PIN_PULLUP);

    NRF_I2S->ENABLE = 1;


    NRF_I2S->TASKS_START = 1;

    for (;;)
    {

    if(nrf_gpio_pin_read(Button) == 0)
    {
    nrf_gpio_pin_clear(LED);
    //printf("Button is Pressed \r\n");
    }
    else
    {
    nrf_gpio_pin_set(LED);
    //printf("Button is Released \r\n");
    }

    // Wait for an event.
    //__WFE();
    // Clear the event register.
    //__SEV();
    // __WFE();

    //NRF_LOG_FLUSH();

    }
    }

    Thank you

    David

Reply
  • Hi Jared

    Thanks for getting back so promptly, I am trying to use your driver please see code below (first time I have used Nordic), I think I am mixing both, but it does work can you please amend so I am only using your driver and I am able to use the interrupt.

    #include <stdio.h>
    #include "nrf_drv_i2s.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"

    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"

    #include <nrf.h>

    #include "sounds.h"

    #define PIN_MCK (41) //P1.09
    #define PIN_BCLK (40) //P1.08
    #define PIN_LRCK (38) //P1.06
    #define PIN_SDOUT (39) //P1.07

    #define Button 11
    #define LED 13


    static void data_handler(nrf_drv_i2s_buffers_t const * p_released,uint32_t status)
    {

    }


    int main(void)
    {
    uint32_t err_code = NRF_SUCCESS;

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;

    config.sck_pin = PIN_BCLK;
    config.lrck_pin = PIN_LRCK;
    config.sdout_pin = PIN_SDOUT;

    config.mode = I2S_CONFIG_MODE_MODE_Master;
    config.sample_width = I2S_CONFIG_SWIDTH_SWIDTH_16BIT;

    config.mck_setup = NRF_I2S_MCK_32MDIV8;
    config.ratio = NRF_I2S_RATIO_512X;
    config.channels = NRF_I2S_CHANNELS_RIGHT;

    err_code = nrf_drv_i2s_init(&config, data_handler);
    APP_ERROR_CHECK(err_code);



    // // Enable transmission
    NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_ENABLE << I2S_CONFIG_TXEN_TXEN_Pos);

    // // Configure data pointer
    NRF_I2S->TXD.PTR = (uint32_t)&sine_table2[0];
    NRF_I2S->RXTXD.MAXCNT = sizeof(sine_table2) / sizeof(uint32_t);

    nrf_gpio_cfg_output(LED);
    nrf_gpio_cfg_input(Button, NRF_GPIO_PIN_PULLUP);

    NRF_I2S->ENABLE = 1;


    NRF_I2S->TASKS_START = 1;

    for (;;)
    {

    if(nrf_gpio_pin_read(Button) == 0)
    {
    nrf_gpio_pin_clear(LED);
    //printf("Button is Pressed \r\n");
    }
    else
    {
    nrf_gpio_pin_set(LED);
    //printf("Button is Released \r\n");
    }

    // Wait for an event.
    //__WFE();
    // Clear the event register.
    //__SEV();
    // __WFE();

    //NRF_LOG_FLUSH();

    }
    }

    Thank you

    David

Children
  • Hi,

    Have you seen our I2S example in the SDK? It shows how you can use the driver to stop a transfer after the a specific number of data has been transferred. 

    regards

    Jared

  • Hi Jared

    Yes I have taken a look at the code but don't really understand it, I have attached my latest code and have  excluded from the build the nrfx_i2s the program compiles now without issue.

    The problem is when I run the program it seems to go immediately to the interrupt and doesn't play my file at all.

    I have confirmed this in debug mode it goes immediately to the Interrupt.

    can you please assist.

    #include <stdio.h>
    #include "nrf_drv_i2s.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"

    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"

    #include <nrf.h>

    #include "sounds.h"

    #define PIN_MCK (41) //P1.09
    #define PIN_BCLK (40) //P1.08
    #define PIN_LRCK (38) //P1.06
    #define PIN_SDOUT (39) //P1.07

    #define Button 11
    #define LED 13


    int main(void)
    {
    uint32_t err_code = NRF_SUCCESS;

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("I2S loopback example started.");


    // Enable transmission
    NRF_I2S->CONFIG.TXEN = (I2S_CONFIG_TXEN_TXEN_ENABLE << I2S_CONFIG_TXEN_TXEN_Pos);

    // Enable MCK generator
    NRF_I2S->CONFIG.MCKEN = (I2S_CONFIG_MCKEN_MCKEN_ENABLE << I2S_CONFIG_MCKEN_MCKEN_Pos);

    // MCKFREQ = 4 MHz
    NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV8 << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos;

    // Ratio = 64
    NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_512X << I2S_CONFIG_RATIO_RATIO_Pos;

    // Master mode, 16Bit, left aligned
    NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_MASTER << I2S_CONFIG_MODE_MODE_Pos;
    NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16BIT << I2S_CONFIG_SWIDTH_SWIDTH_Pos;
    NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_LEFT << I2S_CONFIG_ALIGN_ALIGN_Pos;

    // Format = I2S
    NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S << I2S_CONFIG_FORMAT_FORMAT_Pos;

    // Use stereo
    NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_RIGHT << I2S_CONFIG_CHANNELS_CHANNELS_Pos;

    // Configure pins
    NRF_I2S->PSEL.MCK = (PIN_MCK << I2S_PSEL_MCK_PIN_Pos);
    NRF_I2S->PSEL.SCK = (PIN_BCLK << I2S_PSEL_SCK_PIN_Pos);
    NRF_I2S->PSEL.LRCK = (PIN_LRCK << I2S_PSEL_LRCK_PIN_Pos);
    NRF_I2S->PSEL.SDOUT = (PIN_SDOUT << I2S_PSEL_SDOUT_PIN_Pos);

    NRF_I2S->ENABLE = 1;

    // Configure data pointer
    NRF_I2S->TXD.PTR = (uint32_t)&sine_table2[0];
    NRF_I2S->RXTXD.MAXCNT = sizeof(sine_table2) / sizeof(uint32_t);

    //Enable interrupt and IRQ
    NRF_I2S->INTENSET = I2S_INTENSET_TXPTRUPD_Enabled << I2S_INTENSET_TXPTRUPD_Pos;
    NRF_I2S->EVENTS_TXPTRUPD = 0;
    //NVIC_EnableIRQ(I2S_IRQn);


    nrf_gpio_cfg_output(LED);
    nrf_gpio_cfg_input(Button, NRF_GPIO_PIN_PULLUP);

    // Start transmitting I2S data
    NRF_I2S->ENABLE = 1;
    NRF_I2S->TASKS_START = 1;

    //nrf_delay_ms(1200);
    NVIC_EnableIRQ(I2S_IRQn);

    for (;;)
    {

    //if(nrf_gpio_pin_read(Button) == 0)
    //{
    // nrf_gpio_pin_clear(LED);
    // // Start transmitting I2S data
    // //NRF_I2S->ENABLE = 1;
    // //NRF_I2S->TASKS_START = 0;
    // //printf("Button is Pressed \r\n");
    //}
    //else
    //{
    // nrf_gpio_pin_set(LED);
    // // Start transmitting I2S data
    // //NRF_I2S->ENABLE = 0;
    // //NRF_I2S->TASKS_START = 1;
    // //printf("Button is Released \r\n");

    //}

    // // Wait for an event.
    // //__WFE();
    // // Clear the event register.
    // //__SEV();
    // // __WFE();

    ////NRF_LOG_FLUSH();


    }
    }

    void I2S_IRQHandler(void)
    {
    if (NRF_I2S->EVENTS_TXPTRUPD == 1)
    {
    NRF_I2S->EVENTS_TXPTRUPD = 0;
    NRF_I2S->TASKS_STOP = 1;
    nrf_delay_ms(100);
    }
    }

    Kind Regards

    David

  • Hi,

    You're mixing the usage of the driver and writing directly to the peripheral. All calls that starts with NRF_I2S-> is omitting the driver and writing directly to the driver. I suggest that you clean up your code and remove all parts that write directly to the peripheral and only use the driver.

    regards

    Jared 

  • Hi 

    That is the problem, I don't know how to Write it using the driver.

    I found this code online and it worked but not for a single shot, you gave me the code with an interrupt handler as above but that doesn't work.

    The code you recommended (I2S example in the SDK),  does not use an interrupt handler I don't understand it.

    Regards

    David

  • Hi

    I have used the driver to config the device but I still have 4 lines of code that are bare bones can you please assist me in converting them to use the driver. Please bare in mind this is the first time I have used your product/code.  my code is below

    #define PIN_MCK (41) //P1.09
    #define PIN_BCLK (40) //P1.08
    #define PIN_LRCK (38) //P1.06
    #define PIN_SDOUT (39) //P1.07


    static void data_handler(nrf_drv_i2s_buffers_t const * p_released,uint32_t status)
    {

    }


    int main(void)
    {
    uint32_t err_code = NRF_SUCCESS;

    nrf_gpio_cfg_output(LED);
    nrf_gpio_cfg_input(Button, NRF_GPIO_PIN_PULLUP);

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;

    config.sck_pin = PIN_BCLK;
    config.lrck_pin = PIN_LRCK;
    config.sdout_pin = PIN_SDOUT;

    config.mode = I2S_CONFIG_MODE_MODE_Master;
    config.sample_width = I2S_CONFIG_SWIDTH_SWIDTH_16BIT;

    config.mck_setup = NRF_I2S_MCK_32MDIV8;
    config.ratio = NRF_I2S_RATIO_512X;
    config.channels = NRF_I2S_CHANNELS_RIGHT;

    err_code = nrf_drv_i2s_init(&config, data_handler);
    APP_ERROR_CHECK(err_code);


    // sine_table2[8192] from sounds.h
    // Configure data pointer
    NRF_I2S->TXD.PTR = (uint32_t)&sine_table2[0];
    NRF_I2S->RXTXD.MAXCNT = sizeof(sine_table2) / sizeof(uint32_t);


    NRF_I2S->ENABLE = 1;
    NRF_I2S->TASKS_START = 1;


    for (;;)
    {
    __WFE();
    }


    }

    Regards

    David

Related