¿Cómo puedo escribir datos A/D de alta velocidad en una tarjeta SD?

Quiero usar un microcontrolador y un convertidor A/D para realizar un registro de datos de alta frecuencia (~100 kHz) a largo plazo (mínimo de cinco segundos de búfer, en bucle hasta que se active). Parece que una buena forma de hacerlo es con una tarjeta SD. Sé que hay diferentes formas de acceder a una tarjeta SD, incluso directamente a través de SPI. También creo que se puede escribir en un sistema de archivos o directamente en la tarjeta sin un sistema de archivos. También me preocupa que las escrituras tengan que cubrir sectores completos en lugar de byte por byte, o que las escrituras interfieran con la operación continua de A/D, pero es posible que esas no sean preocupaciones válidas.

Actualmente estoy usando chips dsPIC 33, lo que me da velocidades de instrucción de ~60 MIPS; Estoy dispuesto a cambiar a una familia de controladores diferente si es necesario.

100 kHz no es alta frecuencia y cinco segundos no es a largo plazo. La tarjeta SD vieja más horrible que se ejecuta con el bus SPI normal escribirá sus datos.
Primero verifique si la velocidad de escritura puede o no manejar teóricamente su flujo de datos. Luego verifique cuál es el búfer de RAM máximo que puede usar para escribirlo en ráfagas. Entonces miraría cómo puedo descargar estas ráfagas al DMA asíncrono.
5 segundos * 100 kHz * 2 (<-nyquist) = 1 mega de profundidad de memoria de muestra. ¿8 bits? Obtenga más de 1M de RAM. 16 bits? Obtenga más de 2M de RAM, etc. ¿Por qué más de? Pila y uso general de la memoria. Nunca use flash para ejecutar búferes, búferes circulares, etc. ¿Por qué? Resistencia de escritura -> 10000 ~ 50000 veces parece mucho, pero ejecutar continuamente a 100 kHz también genera mucho. Se tarda menos de una semana a tiempo completo en desgastar por completo una nueva unidad flash si no se tiene cuidado.
¿Cuántos datos necesita registrar a 100 kHz? 1 byte? 2 bytes? ¿4 bytes? 1024 bytes?
Solo resulta el convertidor A/D, así que dos bytes como máximo.

Respuestas (2)

Es posible que no pueda hacer esto con un PIC33, y casi seguro que no con cualquier PIC33. Algunas tarjetas flash 'desaparecen' durante largos períodos de tiempo (decenas de milisegundos o más) a pesar del alto rendimiento, esta latencia puede matarlo con un pequeño microcontrolador porque se quedará sin memoria RAM.

Si permite el almacenamiento en búfer durante 200 ms (lo que debería ser seguro), necesitará 20 000 palabras de memoria, que es posible que un PIC33 no tenga (los miembros más grandes de la familia tienen 48 000 x 8, por lo que si su ADC toma dos bytes, son 40 000, y presumiblemente su programa necesita algo de RAM.

A 100,000 muestras/segundo, tampoco podrá procesar mucho los datos, solo tómelos. Sugiero usar RAM. Y tendría potencia de procesamiento de sobra si usara un ARM con una SDRAM externa o incluso una RAM en serie.

Estoy de acuerdo: la latencia de las tarjetas SD, incluso las de alta velocidad, es terrible. Los de alto rendimiento para cámaras funcionan mejor, pero solo si puede escribir en bloques grandes.
Hmm, bastante bien... Creo que el tiempo de ocupación máximo de SDHC es de 250 ms según las especificaciones (aunque he visto 500 ms) y el tiempo de ocupación máximo de SDXC es de 500 ms. Fui miembro de la asociación de tarjetas SD hace años, así que leí las especificaciones SDHC pero no las especificaciones SDXC...

He hecho esto antes, pero no recuerdo todos los detalles. Usé el sistema de archivos Fat y hubo algún tipo de enfoque diferente, solía transferir un bloque de datos de 512 bytes. Pero puedo decirle lo que necesita con seguridad: un búfer circular, el mío era de 16k bytes. Cuando muestrea en ISR, escribe en un búfer y luego incrementa el puntero de escritura, cuando la diferencia entre el puntero wr y el rd supera los 512 bytes, escribe esos bytes en una SD e incrementa el puntero rd. De todos modos, esto es antiguo, sin uso de transferencia DMA, solo un ejemplo. Al crear el búfer curcular, use el tamaño del búfer con potencia de 2, busque las matemáticas que se usan con los punteros rd y wr, se simplifica gracias a la propiedad de transferencia de números binarios, en cualquier cálculo necesita aplicar máscara: & ( tamaño-1) que es 2^N-1, en mi caso N=14 -> tamaño del búfer circular=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
                {
                }
          }