I2S to USB microphone received data is periodically garbage (nRF Connect SDK v2.6.1)

Hi,

I'm trying to use an nRF52840 dev kit as an I2S-to-USB microphone, but I've been running into a problem where the recorded audio is periodically unusable.

To debug, I connected another nRF52840 dev kit to act as an I2S slave. It simply delivers a repeating sawtooth waveform.

I can receive this on my primary dev board and send it to the host PC over a USB audio interface. Here's what I record in Audacity:

As you can see, the sawtooth is clearly visible, but every 6000 samples or so, I see these strange spikes. I think the problem lies with the USB transfer, because I've done some quick checks to make sure the received I2S data is as expected.

To transmit data over USB, I use the following function:

bool write_to_usb(struct net_buf *buffer, size_t size){
	int ret;

	if (!buffer || !size) {
		LOG_ERR("BUFF NULL!");
		/* This should never happen */
		return 1;
	}

	/* Check if OUT device buffer can be used for IN device */
	if (size == usb_audio_get_in_frame_size(mic_dev)) {
		ret = usb_audio_send(mic_dev, buffer, size);
		if(ret){
			net_buf_unref(buffer);
			return 1;
		}
	} else {
		LOG_ERR("In frame not equal to size. Found %d, expected %d", usb_audio_get_in_frame_size(mic_dev), size);
		net_buf_unref(buffer);
		return 1;
	}

	return 0;
}

This function is called from my nrfx I2S handler:

struct net_buf *buf = net_buf_alloc(&netbuf_pool, K_NO_WAIT);
if(buf){
	int16_t* rx_aud = (int16_t*) p_released->p_rx_buffer;

	// Copy data from I2S to USB audio
	for(int i = 0; i < SAMPLES_PER_CHUNK; i++){
		net_buf_add_le16(buf, rx_aud[i]);
	}
	write_to_usb(buf, CHUNK_SIZE_BYTES);
}

The net buffer pool is initialized like so:

NET_BUF_POOL_DEFINE(netbuf_pool, 50, CHUNK_SIZE_BYTES, 0, NULL);

Am I using the net buffer incorrectly here?

I've attached the project files for both dev boards for reference.

i2s_out.zipi2s_in_usb_audio.zip

Parents
  • Hi!

    I've attached the project files for both dev boards for reference.

    Could you add a explanation on how you connect the 2 DKs together?

  • Apologies for the oversight and thank you for your help. 

    I will refer to the DK that relays I2S samples to USB as DK1, and to the other one as DK2. I connect pins together with jumper cables. Specifically, I connect:

    P0.26 on DK1 to P0.26 on DK2 (SCK to SCK)

    P0.27 on DK1 to P0.27 on DK2 (LRCK to LRCK)

    P1.08 on DK1 to P1.08 on DK2 (SDIN to SDOUT)

    GND of DK1 to GND of DK2

    Both DKs are powered over the microUSB connector at the short edge of the board. I connect my host PC to DK1 over the other microUSB connector as well to interface with the USB audio device.

    I hope this helps. Let me know if you need any other information.

    Edit: After reading a bit more, it might be related to the fact that the nRF52 can't provide an exact 48kHz sampling rate. In Zephyr, the default sampling rate for the USB Audio Device Class is 48kHz, but there should be a way to change it. Howver, I believe this functionality was added in v3.6, while nRF Connect SDK v2.6.1 uses Zephyr v3.5.

    If I change the I2S sampling rate to a frequency that *can* be generated by the I2S module, like 8kHz, I don't observe these spikes anymore, though as expected recording happens 6 times slower (because the USB device thinks it's running at 48kHz, when really its providing samples at 8kHz).

    Is my reasoning correct here? Are there any possible workarounds? 

Reply
  • Apologies for the oversight and thank you for your help. 

    I will refer to the DK that relays I2S samples to USB as DK1, and to the other one as DK2. I connect pins together with jumper cables. Specifically, I connect:

    P0.26 on DK1 to P0.26 on DK2 (SCK to SCK)

    P0.27 on DK1 to P0.27 on DK2 (LRCK to LRCK)

    P1.08 on DK1 to P1.08 on DK2 (SDIN to SDOUT)

    GND of DK1 to GND of DK2

    Both DKs are powered over the microUSB connector at the short edge of the board. I connect my host PC to DK1 over the other microUSB connector as well to interface with the USB audio device.

    I hope this helps. Let me know if you need any other information.

    Edit: After reading a bit more, it might be related to the fact that the nRF52 can't provide an exact 48kHz sampling rate. In Zephyr, the default sampling rate for the USB Audio Device Class is 48kHz, but there should be a way to change it. Howver, I believe this functionality was added in v3.6, while nRF Connect SDK v2.6.1 uses Zephyr v3.5.

    If I change the I2S sampling rate to a frequency that *can* be generated by the I2S module, like 8kHz, I don't observe these spikes anymore, though as expected recording happens 6 times slower (because the USB device thinks it's running at 48kHz, when really its providing samples at 8kHz).

    Is my reasoning correct here? Are there any possible workarounds? 

Children
No Data
Related