Как записать высокоскоростные аналого-цифровые данные на SD-карту?

Я хочу использовать микроконтроллер и аналого-цифровой преобразователь для высокочастотной (~ 100 кГц) долговременной (минимум пятисекундный буфер, цикл до срабатывания) регистрации данных. Похоже, хороший способ сделать это с помощью SD-карты. Я знаю, что есть разные способы доступа к SD-карте, в том числе напрямую через SPI. Я также считаю, что можно писать в файловую систему или напрямую на карту без файловой системы. Я также обеспокоен тем, что записи должны охватывать целые сектора, а не побайтно, или записи, мешающие продолжению операций АЦП, но это может быть неправомерным.

В настоящее время я использую чипы dsPIC 33, что дает мне скорость команд ~ 60 MIPS; Я готов перейти на другое семейство контроллеров, если это необходимо.

100 кГц — это не высокая частота, а пять секунд — это не долго. Самая дрянная старая SD-карта, работающая с обычной шиной SPI, запишет ваши данные.
Сначала проверьте, может ли скорость записи теоретически справиться с вашим потоком данных. Затем проверьте, какой максимальный буфер ОЗУ вы можете использовать, чтобы записывать его пачками. Затем я бы посмотрел, как я могу разгрузить эти пакеты в асинхронный прямой доступ к памяти.
5 секунд * 100 кГц * 2 (<-nyquist) = 1 мегабайт глубины памяти семпла. 8 бит? Получите более 1M оперативной памяти. 16 бит? Получите более 2 МБ ОЗУ и т. д. Почему больше? Стек и общее использование памяти. Никогда не используйте флэш-память для запуска буферов, циклических буферов и т. д. Почему? Запись выносливости -> 10000~50000 раз звучит как много, но непрерывная работа на частоте 100 кГц также генерирует много. Требуется меньше недели полного рабочего дня, чтобы полностью изнашивать новую флешку, если вы не будете осторожны.
Сколько данных вам нужно для регистрации на частоте 100 кГц? 1 байт? 2 байта? 4 байта? 1024 байта?
Просто результаты аналого-цифрового преобразователя, поэтому максимум два байта.

Ответы (2)

Возможно, вы не сможете сделать это с PIC33, и почти наверняка не с любым PIC33. Некоторые флэш-карты «уходят» на длительные периоды времени (десятки миллисекунд и более), несмотря на высокую пропускную способность, эта задержка может убить вас с маленьким микроконтроллером, потому что у вас закончится буферная оперативная память.

Если вы разрешите буферизацию в течение 200 мс (что должно быть безопасным), вам потребуется 20 КБ слов памяти, которых может не быть у PIC33 (самые большие члены семейства имеют 48 КБ x 8, поэтому, если ваш АЦП занимает два байта, это 40 КБ, а предположительно вашей программе требуется немного оперативной памяти.

При 100 000 выборок в секунду вы также не сможете много обрабатывать данные, просто возьмите их. Я бы предложил использовать оперативную память. И у вас была бы избыточная вычислительная мощность, если бы вы использовали ARM с внешней SDRAM или даже последовательной RAM.

Согласен - латентность сд карт, даже скоростных, ужасная. Высокопроизводительные для камер работают лучше всего, но только если вы можете писать большими блоками.
Хм, совершенно верно .. Я думаю, что максимальное время занятости SDHC составляет 250 мс в соответствии со спецификацией (хотя я видел 500 мс), а максимальное время занятости SDXC - 500 мс. Несколько лет назад я был членом ассоциации SD-карт, поэтому я читал спецификации SDHC, но не читал спецификации SDXC...

Я делал это раньше, но не помню всех подробностей. Я использовал файловую систему Fat и там был какой-то другой подход, я использовал для передачи блока данных 512 байт. Но то, что вам нужно, я вам точно скажу: круговой буфер, у меня был 16к байт. Когда вы выполняете выборку в ISR, вы записываете в буфер, затем увеличиваете указатель записи, когда разница между указателем wr и rd превышает 512 байтов, вы записываете эти байты на SD и увеличиваете указатель rd. Во всяком случае, это старо, без использования передачи DMA, просто пример. При создании криволинейного буфера используйте размер буфера степени 2, ищите математику, используемую с указателями rd и wr, это упрощается благодаря свойству бинарных чисел rollover, при любом расчете нужно применять маску: & ( size-1), который равен 2 ^ N-1, в моем случае N = 14 -> размер буфера circ = 2 ^ 14 = 16384.

void AddBuffer (char data) 
{
    CircBuffer[WR_Pointer]=data;
    WR_Pointer++;
    WR_Pointer= WR_Pointer & 16383;
    if (WR_Pointer==RD_Pointer)
    {
          printf("\r\nBuffer overrun\r\n",0);
          stat0_off();
          stat1_on();
          VICIntEnClr = 0xFFFFFFFF;  //clear all interrupts
          fat_flush();
          while(1);
    }
}

char GetBuffer() 
{
  char res;

  if (WR_Pointer==RD_Pointer)
  {
    res=0; // no data available
    printf("\r\nError calling GetBuffer()\r\n",0);
    stat0_off();
    stat1_on();
    VICIntEnClr = 0xFFFFFFFF;  //clear all interrupts
    fat_flush();
    while(1);

  }
  else
  {
    res=CircBuffer[RD_Pointer];
    RD_Pointer++;
    RD_Pointer=RD_Pointer & 16383; 
  }
  return(res);
}

void SD_Card_Log(void)
{
    int j;        
        BufferLength  = WR_Pointer-RD_Pointer;
        BufferLength = BufferLength & 16383;

        if  (BufferLength>=512)                
        {
          for (j = 0; j < 512; j++)          {           
            RX_array1[j] = GetBuffer();        
          } 

          stat0_off();
          stat1_off();

          if (fat_write(handle,RX_array1, 512) < 0)
          {
                while(1) // card failure
                {
                }
          }