Zephyr I2S driver MCLK and i2s_state

Working with the nRF52840 and nRF Connect SDK 2.2.0 and developing for hardware with a codec that requires a clock supplied via the MCLK pin from the I2S0 peripheral.

We're using the Zephyr I2S peripheral driver:
https://developer.nordicsemi.com/nRF_Connect_SDK/doc/2.2.0/zephyr/hardware/peripherals/audio/i2s.html

It's working except there doesn't seem to be any way to set up or enable the MCLK signal on the I2S0 peripheral through the I2S API.  The MCLK pin does get assigned correctly from DTS, but when calling the API function i2s_trigger(), where the configuration is applied and the I2S0 peripheral started, MCLK is disabled.  Note that by writing directly to the CONFIG.MCKFREQ and CONFIG.MCKEN registers after the i2s_trigger() call MCLK turns on and runs correctly, and everything else works well through the API.

Is there a way to configure and enable the I2S0 MCLK through the Zephyr I2S API or another Zephyr API?

Second question - the Zephyr I2S API documentation (link above) and header file define the "enum i2s_state" with the states "I2S_STATE_NOT_READY", "I2S_STATE_READY", "I2S_STATE_RUNNING", ... etc.  The API documentation for the API functions says things like "If the interface is in READY state the number of bytes..." and "This trigger can be used in ERROR state only..." etc.

However, we don't see a way in the API to query what the present interface state is.  The enum "i2s_state" doesn't appear anywhere in the API header except for its declaration.

How is the I2S interface state queried?

Thanks & Regards,

Walt

  • Could you show me the correct way to set these registers through code (so no nrfjprog) using only the Zephyr sdk and no NCS/nrfx-specific types/functions? 

  • Hi,

    There are a couple of options: 

    1. Use the NRFX I2S driver instead.
    2. Enable the MCLK directly when using the Zephyr I2S (chip dependent), right after triggering I2S

    For #2 what I got working was a not very pretty and kind of a hack.  If you are not using the 52840 you'll need to check the registers for the chip  you are using

        err = i2s_trigger(st_i2s_dev_tx_ptr, I2S_DIR_BOTH, I2S_TRIGGER_START);
        if (err != 0)
        {
            LOG_ERR("Failed to trigger codec err %d", err);
            return e_status_failed;
        }
    
        // The Zephyr I2S driver doesn't (seem to) support the MCLK pin of the Nordic peripheral.  This pin is not
        // part of the defined I2S bus interface, but provides a master clock signal to codecs that need
        // one.  The exsiting hardware uses it to provide at clock to the codec at 4 MHz.
        //
        // Additionally, the I2S configuration doesn't seem to get applied until i2s_trigger() is called.
    
        if (NRF_I2S0->CONFIG.MCKFREQ != 0x20000000)
        {
            NRF_I2S0->CONFIG.MCKFREQ = 0x20000000;
            LOG_INF("I2S CONFIG.MCKFREQ set.");
        }
    
        if (NRF_I2S0->CONFIG.MCKEN != 1)
        {
            NRF_I2S0->CONFIG.MCKEN = 1;
            LOG_INF("I2S CONFIG.MCKEN set.");
        } 
    

    PS - you'll need the header

    #include <nrfx_i2s.h>

Related