This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Need I2S help

Hi there,

I'm just trying to start to code my project. I want to stream 48k 16 bit audio from one nrf52840 dongle to the other one. I only need one way transfer.

I have looked at every example I could find but still dont seem to get how to send the packets to the radio and over the wireless connection.

Is there anyone that can help get me started with some simple no frills code.

I'm using Segger and sdk v17.

I would be most grateful if someone could assist me here.  Once I get the streaming part working successfully I think I can work out how to do the other things I need but this I2S is very tricky it seems to know what to do. It needs to be a steady stream.

Kind regards,

Dam076

Parents
  • Hi 

    Are you planning to do any compression of the audio stream, or do you want to send raw data?

    You should be able to handle the raw data stream if the link is good, but you won't have a lot of overhead to handle packet loss. 

    If you are planning to do something proprietary (ie not Bluetooth) I would recommend having a look at the nrf_esb library. Then you don't have to spend time on low level radio setup, but can instead focus on integrating the I2S sensor. 

    There are some examples in the SDK showing how to use the nrf_esb library, in the following folder:

    \nRF5_SDK_17.0.2_d674dde\examples\proprietary_rf

    Best regards
    Torbjørn

Reply
  • Hi 

    Are you planning to do any compression of the audio stream, or do you want to send raw data?

    You should be able to handle the raw data stream if the link is good, but you won't have a lot of overhead to handle packet loss. 

    If you are planning to do something proprietary (ie not Bluetooth) I would recommend having a look at the nrf_esb library. Then you don't have to spend time on low level radio setup, but can instead focus on integrating the I2S sensor. 

    There are some examples in the SDK showing how to use the nrf_esb library, in the following folder:

    \nRF5_SDK_17.0.2_d674dde\examples\proprietary_rf

    Best regards
    Torbjørn

Children
  • Thanks for your reply. 

    I have looked at ESB but I'm still having trouble working out how to successfully link the I2S buffer with the packet pointer and understanding how the code detects the buffer has changed so that i automatically triggers the raidio to send the new packet. Would you be able to assist with that area. I have figured that the radio needs to stay on and not turn off between packets. Also I am unsure on the correct value of block_Words so that I2S doesnt glitch. Any coding help to link I2S with the radio directly, on both the TX and the RX will help greatly, Cheers

  • No compression. 2 MBIT should be ample throughput as 48k 16bit audio needs around 1,5 MBIT. Also I'm struggling to understand how the Queue works in the code because the audio stream is obviously slower than the RF-RF connection so, how does it pause and then start sending again when the buffer starts to empty? I will need a small buffer, no error correction and no ACK to achieve the lowest latency possible. Then if I have any headroom, I can possibly add CRC if needed but given the low latency specs I require and the likely possibily that any 'correction' will drastically slow down the stream, I dont think its going to be useful. It would be great if there was some type of interpolation of audio samples in the event that there is a CRC error but I fear that is going to be very complicated. But my theory would be to average out the 'before' error sample and the 'after' error sample, average the 2 samples and then replace the sample in the buffer that is detected as corrupt with the 'averaged' value,..  This should eliminate any glitch and cause minimal auditory changes. I guess mathematically this is not hard, I just need help working out what flag will be set to indicate that specific packet has a CRC error and then call the error correction function to replace the value in the buffer. Hope that makes sense. 

  • Hi

    damo76 said:
    I have looked at ESB but I'm still having trouble working out how to successfully link the I2S buffer with the packet pointer and understanding how the code detects the buffer has changed so that i automatically triggers the raidio to send the new packet.

    When working on a project like this I would recommend breaking the development up into smaller blocks, and handle one task at a time. 

    First off you need to get the I2S transfer to/from your sensor working properly, which you can do based on the peripheral/i2s example in the SDK. Since you refer to block_words I assume you have looked at this example already?

    I would recommend setting up a stream with your sensor on the input side, and log the data coming in (or use the debugger to verify it) to check if the data looks ok. 

    Once you have good data coming in from the sensor you can start to pass it on to the ESB library in order to have it sent over the air. 

    I am not quite sure what you mean about the code detecting the buffer has changed?
    Whenever the i2s driver has emptied/filled a buffer, the data_handler callback will be triggered in your application to inform you of this. 

    The p_released argument is a pointer to the buffer that was just read and/or written, and in the case of incoming data you have to move the RX data from this buffer to the ESB library. 

    damo76 said:
    I have figured that the radio needs to stay on and not turn off between packets.

    This is not supported by the nrf_esb library. In most applications you want to receive an ACK after each TX packet, and as such the library will always disable the radio after each sent packet (so that it can be enabled in RX mode to receive the ACK). 

    It is possible to keep the radio active between packets and not use any ACK, but the library would need changes to support this. 

    damo76 said:
    Also I am unsure on the correct value of block_Words so that I2S doesnt glitch.

    In essence this is determined by how fast your application can respond to I2S interrupts, which depends on how many higher priority interrupts there are in the system and how long they could take to execute in the worst case. 

    Without having run any tests myself I would expect 64 or more to be plenty, but this is application dependent. 

    Have you had issues with glitches?

    damo76 said:
    Any coding help to link I2S with the radio directly, on both the TX and the RX will help greatly, Cheers

    Not sure what you mean about linking the I2S directly. While it is theoretically possible to assign the radio and the I2S to the same physical RAM buffer, this is not supported by any of the drivers, and I wouldn't recommend going down this path ;)

    You should have plenty of CPU time available to do a quick copy between buffers, so that you can move the I2S data into and out of the esb_payload_t buffers used by the esb library. Then you only need to add some code on top of the I2S driver and the nrf_esb library to pass data between them. 

    damo76 said:
    No compression. 2 MBIT should be ample throughput as 48k 16bit audio needs around 1,5 MBIT.

    2 Mbps is the on-air bitrate. The actual throughput is lower, mainly because of packet overhead (preamble, address, ESB header and CRC) and radio startup times. You might be able to push the ESB library up to about 1.5Mbps bi-directional bitrate, but this is assuming zero packet loss. You will have no overhead to do retransmission in case of lost packets, which means the link will not be very robust if you have interference from other 2.4GHz radios in the area (WiFi for instance). 

    damo76 said:
    Also I'm struggling to understand how the Queue works in the code because the audio stream is obviously slower than the RF-RF connection so, how does it pause and then start sending again when the buffer starts to empty?

    Essentially you need to implement a FIFO (or at minimum a double buffer, which is essentially just a FIFO with 2 elements). Once the I2S driver has filled up one element of the FIFO you can pass this over to the ESB stack. The ESB stack won't do anything unless it has some data in its own internal buffer, so the timing will be controlled by how often the application passes data to it. 

    damo76 said:
    I will need a small buffer, no error correction and no ACK to achieve the lowest latency possible. Then if I have any headroom, I can possibly add CRC if needed but given the low latency specs I require and the likely possibily that any 'correction' will drastically slow down the stream, I dont think its going to be useful.

    A 16-bit CRC doesn't add a lot of overhead to the packet, unless you send very short packets, and sending short packets is not good in terms of data throughput. 

    The advantage of having CRC included even if you don't plan to do any error correction is that you will know if there are any bit errors in the packet. From an application point of view it might be interesting to know whether or not you are receiving correct data. 

    damo76 said:
    It would be great if there was some type of interpolation of audio samples in the event that there is a CRC error but I fear that is going to be very complicated. But my theory would be to average out the 'before' error sample and the 'after' error sample, average the 2 samples and then replace the sample in the buffer that is detected as corrupt with the 'averaged' value,..  This should eliminate any glitch and cause minimal auditory changes. I guess mathematically this is not hard, I just need help working out what flag will be set to indicate that specific packet has a CRC error and then call the error correction function to replace the value in the buffer.

    The radio applies a CRC check on the whole packet, which means you don't know exactly which of the samples are affected. A faulty CRC could mean that all the samples in the packet are invalid, if you are unlucky. Unless you are talking about sending a single on air packet for every sample?

    In general I know that handling corrupted data for audio is not easy, as the human ear is very good at picking up certain kinds of distortions in the sound (such as a single sample with a huge offset in the value). 

    Best regards
    Torbjørn

  • Thanks for your help so far. If I was to use the radio library directly and use ->PACKETPTR  will this pointer accept a pointer to an array or only a single 32bit variable? If it will accept an array, how do I code it correctly and how do I tell the radio how many 32bit words to send via RF?

  • Also, is it possible to use EASYDMA to have the IS2 buffer auto copy to the Radio buffer using interupts when the I2S buffer fills up, and if so are you able to help with a simple example, keeping in mind that this I2S buffer will be constantly filling and needing to be copied and freed to allow the next I2S words to collect in the buffer. Would double buffering work in this case, and again if so, are you able to provide a very simple example? Thanks again. The learning curve here is enormous. All I want to do is send I2S over the radio link lol. cheers

Related