Jake A
Jake A

Reputation: 135

Why does f_write cause the program to freeze on pi pico?

I'm making an audio recorder with a pi pico along with an SD card connected via SPI. Core0 gets samples from the ADC and sends them to core1 which handles SD writing. I've isolated the issue to f_write. I commented to mark the problematic section. Note that when I comment out that section the code runs as expected otherwise it freezes. The file shows up on the SD but it is empty.

This is the section of code from core1 that is causing the issue.

START_REC, STOP_REC, and QUIT are just #define's of numbers larger than the adc range (4096<)

void core1_main()
{
  sleep_ms(1000); // ensures there is no conflict with core0 when working w/ LCD
  bool brk = false;
  uint buf_size = 32000;
  uint16_t data_buffer[buf_size];
  uint buf_pos = 0;
  uint bytes_read = 0;
  uint val = 0;
  
  FRESULT fr;
  FATFS fs;
  FIL fil;
  unsigned short file_num = 0;
  char filename[20];
  filename_gen(&filename[0], file_num);

  // Init sd driver
  if (!sd_init_driver())
    {
      clrLCD();
      setString("!INIT");
      posCursor(12, 1);
      brk = true;
    }

  // mount sd
  fr = f_mount(&fs, "0:", 1);
  if (fr != FR_OK)
    {
      clrLCD();
      setString("!MOUNT");
      posCursor(12, 1);
      brk = true;
    }

  // open file for writing
  fr = f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS);
  if (fr != FR_OK)
    {
      clrLCD();
      setString("!F OPEN");
      posCursor(12, 1);
      brk = true;
    }

  if (!brk)
    {
      setString("Ready.");
    }

  bool rec = false;
  while (!brk)
    {
      val = multicore_fifo_pop_blocking();

      switch (val)
    {
    case QUIT:
      brk = true;
      break;
    case START_REC:
      if (!rec)
        {
          rec = true;
        }
      break;
    case STOP_REC:
      if (rec)
        {
              rec = false;
        }
      break;
    default:
      if (val < 4096)
        {
          data_buffer[buf_pos] = val;
          buf_pos++;
        }
      
        if (buf_pos > buf_size - 1)
          {
            // problematic section
            fr = f_write(&fil, data_buffer, buf_size*2, &bytes_read);
            if (fr != FR_OK)
              {
                clrLCD();
                setString("!F WRITE");
                posCursor(12, 1);
                rec = false;
              }
            f_sync(&fil); // flush sync. Prevents data loss if program fails before f_close
            // end of problematic section
            buf_pos = 0;
          }
      break;
    }
      
    }
  f_close(&fil);
  // unmount drive
  f_unmount("0:");
}

Another thing to note is that fr seemingly returns FR_OK or crashes beforehand because the LCD does not display "!F WRITE".

Upvotes: 0

Views: 142

Answers (1)

Jake A
Jake A

Reputation: 135

The solution was to pass in the pointer to the data buffer in f_write() and lower the buffer size to 512 or 1024.

void core1_main()
{
  sleep_ms(1000);
  bool brk = false;
  uint buf_size = 512;
  uint16_t data_buffer[buf_size];
  uint buf_pos = 0;
  uint bytes_read = 0;
  uint val = 0;
  
  FRESULT fr;
  FATFS fs;
  FIL fil;
  unsigned short file_num = 0;
  char filename[20];
  filename_gen(&filename[0], file_num);

  // Init sd driver
  if (!sd_init_driver())
    {
      clrLCD();
      setString("!INIT");
      posCursor(12, 1);
      brk = true;
    }

  // mount sd
  fr = f_mount(&fs, "0:", 1);
  if (fr != FR_OK)
    {
      clrLCD();
      setString("!MOUNT");
      posCursor(12, 1);
      brk = true;
    }

  // open file for writing
  //file_num++;
  //filename_gen(&filename[0], file_num);
  fr = f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS);
  if (fr != FR_OK)
    {
      clrLCD();
      setString("!F OPEN");
      posCursor(12, 1);
      brk = true;
    }

  if (!brk)
    {
      setString("Ready.");
    }

  bool rec = false;
  while (!brk)
    {
      val = multicore_fifo_pop_blocking();

      switch (val)
    {
    case QUIT:
      brk = true;
      break;
    case START_REC:
      if (!rec)
        {
          rec = true; // rec value is a bit redundant but will be useful later
        }
      break;
    case STOP_REC:
      if (rec)
        {
          rec = false;
        }
      break;
    default:
      if (val < 4096)
        {
          data_buffer[buf_pos] = val;
          buf_pos++;
        }
      
      if (buf_pos >= buf_size)
        {

          if (rec)
            {
              fr = f_write(&fil, &data_buffer, buf_size*2, &bytes_read);
              if (fr != FR_OK)
                {
                  getFSerr(fr);
                  rec = false;
                }
              f_sync(&fil); // flush sync. Prevents data loss if program fails before f_close
            }
              buf_pos = 0;
        }
      break;
    }
      
  }
  f_close(&fil);
  // unmount drive
  f_unmount("0:");
}

Upvotes: 1

Related Questions