Zephyr I2S support in NCS 1.8.0, 1.9.1

Hi,

I see that there is Zephyr I2S support in in NCS 1.8.0 (and onward), but I can't locate any reliable documentation for the API.

I have an I2S example (based on https://github.com/andenore/NordicSnippets/blob/master/examples/i2s_master/main.c) that compiles and works in 1.8.0 - but it's clearly not using the zephyr driver.

Even though I've got 'CONFIG_I2S=y' in prj.conf the zephyr.dts entry is

i2s0: i2s@40025000 {
compatible = "nordic,nrf-i2s";
#address-cells = < 0x1 >;
#size-cells = < 0x0 >;
reg = < 0x40025000 0x1000 >;
interrupts = < 0x25 0x1 >;
status = "disabled";
label = "I2S_0";
};

Note that status is 'disabled'

What I want to do is play short (one to two second) messages pre-recorded as 8 bit monaural raw .wav file. I'm comfortable with the file formats and the transitions I need to make to get the .wav data into arrays to present to I2S. 

Initialize I2S, then present relatively small chunks (on the order of 128 samples) to I2S until I've exhausted the .Wav file.

Logically I want to use two 128 byte RAM buffers, loading one with sample data, starting the I2S playback of that buffer while I load the other buffer, then switching to the other buffer when the I2S playback of the first is finished, continuing until I've exhausted the .wav data is exhausted.

Any help you can give me would be appreciated.

Thanks in advance.

Kent Overton

Parents
  • Torbjørn,

    Sorry for the long delay.

    I've fiddled around with this for quite a while and still am having issues.

    I found another zephyr echo sample at https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/drivers/i2s/litex/src/main.c and adapted it to my environment.

    I've loaded my current (sort of working) project to google drive as a zip file. You can find it here.

    https://drive.google.com/file/d/1sG6R2IZME1Hjaj9Kxq3LO-EfpPFzT6IS/view?usp=sharing

    This version plays a  big 8bit PCM sample (lathe.h),  in my case routing it to a Maxim Integrated MAX98357A DAC with a Class D amplifier.

    There are a couple of things.

    In the original program the  

          ret = i2s_trigger(host_i2s_tx_dev, I2S_DIR_TX, I2S_TRIGGER_START);     

            at line 94 of my code was before the program main loop - in my case the

           while (lathe_raw_size>sampleptr) { 

         }

         After some investigation I found that issuing a I2S_TRIGGER_START to a que that           was empty (had never had data written to it with a i2s_write() put the driver into an           ERROR state. Once there has been a i2s_write, the TRIGGER_START works just as       expected.

    This sort of works - but the replay is "scratchy". While running the program there are hundreds of messages in the debug terminal (I'm using Segger) that all look like

    [0m[00:00:08.228,973] [0m<dbg> i2s_nrfx.supply_next_buffers: Next buffers: 0x20000788/(nil)[0m
    [1;31m--- 8 messages dropped ---
    [0m[00:00:08.241,088] [0m<dbg> i2s_nrfx.supply_next_buffers: Next buffers: 0x200007c8/(nil)[0m
    [1;31m--- 8 messages dropped ---

    I'm not sure, but I think that this is telling me that I'm supplying buffers faster than the I2S driver can consume them.

    Finally, at the end you]ll see that I issue a TRIGGER_DRAIN and then a TRIGGER_STOP. I would expect this to stop data transferring out over  the I2S channel, but it doesn't seem to.

    I'm using  nRF Connect SDK v1.9.1 in the Segger environment.

    Any light you can shed will be greatly appreciated.

Reply
  • Torbjørn,

    Sorry for the long delay.

    I've fiddled around with this for quite a while and still am having issues.

    I found another zephyr echo sample at https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/drivers/i2s/litex/src/main.c and adapted it to my environment.

    I've loaded my current (sort of working) project to google drive as a zip file. You can find it here.

    https://drive.google.com/file/d/1sG6R2IZME1Hjaj9Kxq3LO-EfpPFzT6IS/view?usp=sharing

    This version plays a  big 8bit PCM sample (lathe.h),  in my case routing it to a Maxim Integrated MAX98357A DAC with a Class D amplifier.

    There are a couple of things.

    In the original program the  

          ret = i2s_trigger(host_i2s_tx_dev, I2S_DIR_TX, I2S_TRIGGER_START);     

            at line 94 of my code was before the program main loop - in my case the

           while (lathe_raw_size>sampleptr) { 

         }

         After some investigation I found that issuing a I2S_TRIGGER_START to a que that           was empty (had never had data written to it with a i2s_write() put the driver into an           ERROR state. Once there has been a i2s_write, the TRIGGER_START works just as       expected.

    This sort of works - but the replay is "scratchy". While running the program there are hundreds of messages in the debug terminal (I'm using Segger) that all look like

    [0m[00:00:08.228,973] [0m<dbg> i2s_nrfx.supply_next_buffers: Next buffers: 0x20000788/(nil)[0m
    [1;31m--- 8 messages dropped ---
    [0m[00:00:08.241,088] [0m<dbg> i2s_nrfx.supply_next_buffers: Next buffers: 0x200007c8/(nil)[0m
    [1;31m--- 8 messages dropped ---

    I'm not sure, but I think that this is telling me that I'm supplying buffers faster than the I2S driver can consume them.

    Finally, at the end you]ll see that I issue a TRIGGER_DRAIN and then a TRIGGER_STOP. I would expect this to stop data transferring out over  the I2S channel, but it doesn't seem to.

    I'm using  nRF Connect SDK v1.9.1 in the Segger environment.

    Any light you can shed will be greatly appreciated.

Children
  • Hi 

    It seems the log is overloaded with messages, since you are calling into the I2S library very often. Can you try and disable logging and see if it makes a difference to the scratchiness? 

    Could you try to send larger amounts of data in each i2s_write (256 bytes for instance) and see if it works better?

    If you issue TRIGGER_DRAIN it should not be necessary to also run TRIGGER_STOP, but it seems odd that the output would continue even after issuing both these commands. 

    If nothing else works could you try to make your test sample a very simple sound (such as a simple triangle or sine wave), to make it easier to analyse what is going on with the playback?
    Then you could plot the output sound on a scope, in order to see what is happening. 

    Best regards
    Torbjørn

  • Yeah!

    I took out logging and made the buffers 256 uint16_t (512 bytes) and saw a huge improvement.

    I have an issue with the i2s_trigger.

    TRIGGER_DRAIN and TRIGGER_STOP only seem to work when the I2S_STATE is RUNNING. If it isn't RUNNING STOP or DRAIN put the device in an error mode from which there seems to be no way to recover.

    I2S_TRIGGER_DROP works.

Related