[Zephyr I2S] Play sound from SD Card got error: Next buffers not supplied on time

I'm working with nRF52840, my function will read wav file from SD card and play it using Zephyr I2S driver. My source code about playing sound in below.

The strange is the code only work if I has the line "LOG_INF("[PLAYING] Read bytes: %d", the_read_bytes);"

If I comment the line, the I2S throw error in log: i2s_nrfx: Next buffers not supplied on time.

If I uncomment the line, the I2S work normally, and it play whole a song

Please someone can explain what wrong in my source code ?

#define THE_BLOCK_SIZE            4 * 1024
#define THE_NUMBER_OF_BLOCK       8
#define THE_NUMBER_OF_INIT_BUFFER 4

K_MEM_SLAB_DEFINE(the_i2s_mem_slab, THE_BLOCK_SIZE, THE_NUMBER_OF_BLOCK, 4);

// Init function
static void do_init_i2s(void) {
  struct i2s_config the_config = {
      .word_size = 16U,
      .channels = 2U,
      .format = I2S_FMT_DATA_FORMAT_I2S,
      .frame_clk_freq = 44100,
      .block_size = THE_BLOCK_SIZE,
      .timeout = 2000,
      .options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER,
      .mem_slab = &the_i2s_mem_slab,
  };
  int error = i2s_configure(the_i2s_device, I2S_DIR_TX, &the_config);
  if (error) {
    LOG_ERR("Configure I2S failed: %d", error);
  }
}

static void do_play_sound_from_sd(char *the_file_path) {
  struct fs_file_t the_file;
  do_open_file(the_file_path, &the_file);

  bool the_i2s_started = false;
  uint8_t the_number_of_init_buffer = 0;

  while (1) {
    void *the_tx_mem_block;

    int error = k_mem_slab_alloc(&the_i2s_mem_slab, &the_tx_mem_block, K_NO_WAIT);
    if (error) {
      LOG_ERR("Failed to allocate TX block: %d", error);
      break;
    }

    ssize_t the_read_bytes = fs_read(&the_file, the_tx_mem_block, THE_BLOCK_SIZE);
    if (the_read_bytes <= 0) {
      LOG_INF("End file");
      k_mem_slab_free(&the_i2s_mem_slab, the_tx_mem_block);
      break; // done when end of file
    }
    
    // LOG_INF("[PLAYING] Read bytes: %d", the_read_bytes);

    error = i2s_write(the_i2s_device, the_tx_mem_block, THE_BLOCK_SIZE);
    if (error) {
      k_mem_slab_free(&the_i2s_mem_slab, the_tx_mem_block);
      LOG_ERR("Failed to write data: %d", error);
      break;
    }

    the_number_of_init_buffer++;
    if (the_number_of_init_buffer == THE_NUMBER_OF_INIT_BUFFER &&
        the_i2s_started == false) {
      // make sure to filled THE_NUMBER_OF_INIT_BUFFER before starting i2s
      LOG_INF("Start I2S: %d", the_number_of_init_buffer);
      the_i2s_started = true;
      i2s_trigger(the_i2s_device, I2S_DIR_TX, I2S_TRIGGER_START);
    }
  }

  i2s_trigger(the_i2s_device, I2S_DIR_TX, I2S_TRIGGER_STOP);
  do_close_file(&the_file);
}

Parents
  • Hi, 

    Thanks for reaching out regarding this issue. I noticed there’s already an in-depth discussion on this topic:

    Zephyr I2S: Next buffers not supplied on time

    Have you had a chance to follow the advice mentioned there?

    If the suggestions provided in that discussion don’t resolve your issue, please let me know, and I’ll be happy to assist further.

    Best regards,
    Charlie

  • The topic: Zephyr I2S: Next buffers not supplied on time is not my issue. But I found the problem:

    It seems the max-frequency of SPI is not enough fast. After change the max frequency of SPI in devicetree from 5M to 8M, it works:

    &spi1 {
        // max-frequency = <DT_FREQ_M(5)>;
        max-frequency = <DT_FREQ_M(8)>;
    };

    Although it works, I still have no idea why with the 5M SPI max-frequency and add the log make it works.

Reply
  • The topic: Zephyr I2S: Next buffers not supplied on time is not my issue. But I found the problem:

    It seems the max-frequency of SPI is not enough fast. After change the max frequency of SPI in devicetree from 5M to 8M, it works:

    &spi1 {
        // max-frequency = <DT_FREQ_M(5)>;
        max-frequency = <DT_FREQ_M(8)>;
    };

    Although it works, I still have no idea why with the 5M SPI max-frequency and add the log make it works.

Children
No Data
Related