La lectura de SPI flash de más de 35 bytes provoca el tiempo de espera del controlador y los resultados se corrompen

He conectado SPI flash a mi placa Linux (basada en imx 233) ejecutándose en su bus SPI. He configurado el kernel, el bus SPI y el chip flash.

El flash se encuentra actualmente en una placa de prueba. Antes de intentar trabajar en Linux, lo intenté por separado y puedo leer y escribir como quiero con un chip FT2232H (placa de conexión FT2232 de dangerprototypes.com). Sin embargo, en la placa Linux, tuve que agregar resistencias pull-up (10k) en las líneas de entrada y salida de datos; de lo contrario, el chip no se reconocía correctamente.

Mi problema real es que ahora estoy tratando de leer flash sin procesar a través del controlador mtd, y todo parece correcto, si leo menos de 35 bytes. Inmediatamente, si leo más de 35 bytes (36 o más), el controlador se queja del error de DMA:

[  521.700000] mxs-spi 80034000.ssp: DMA transfer timeout
[  521.700000] spi_master spi32766: failed to transfer one message from queue

Además, cuando esto sucede, la mayoría de los bytes (si no todos) serán incorrectos. La lectura de menos de 35 bytes se devolverá "inmediatamente" (sin tiempo de espera) y todos los bytes leídos serán correctos.

Mi código C es directamente del ejemplo de lectura de MTD:

int main(int argc, char * argv[])
{

    if (argc != 2)
    {
    printf("Need arguments how many chars to read\nExiting...\n");
    return 1;
    }

    int amount = atoi(argv[1]);
    printf("reading (%d) chars\n", amount);

    mtd_info_t mtd_info;
    int fd = open("/dev/mtd0", O_RDONLY);
    ioctl(fd, MEMGETINFO, &mtd_info);

    printf("MTD type: %u\n", mtd_info.type);
    printf("MTD total size : %u bytes\n", mtd_info.size);
    printf("MTD erase size : %u bytes\n", mtd_info.erasesize);

    /* read buffer */
    unsigned char buf[amount];

    read(fd, buf, sizeof(buf));

    int i = 0;

    for (i = 0; i < amount; i++)
    {
            printf("%i: %X\n",i,buf[i]);
    }
return 0;
} 

El tiempo de espera ocurre "como se esperaba" (10 segundos) en spi-mxs.c:

drivers/spi/spi-msx.c:
static int mxs_spi_txrx_dma(...):
....
ret = wait_for_completion_timeout(&spi->c, msecs_to_jiffies(SSP_TIMEOUT));

¿Alguna idea de lo que podría estar mal? No soy tan bueno con la electrónica, así que todas las sugerencias son bienvenidas.

Si tiene un osciloscopio, eso le mostrará lo que está pasando en las líneas de datos/reloj.
En el lado del software, una posible razón por la que está viendo datos incorrectos no es porque algo esté dañado, sino porque la readllamada al sistema regresó -1. Ignora el valor devuelto y, en ese caso, su ciclo imprime datos no inicializados de la matriz de longitud variable.
podría ser un problema de reloj, intente reducir la velocidad del reloj y vea si ayuda. Más adelante, cuando pase de la placa de prueba, es posible que pueda aumentar la velocidad del reloj.
John, tengo un osciloscopio y revisaré lo que puedo ver en él. Pero la memoria es limitada y, por lo general, solo se pueden ver los primeros dos mensajes. Kaz, tienes 100% razón, debería comprobarlo... aunque el problema sigue estando por debajo de la función de lectura. Miceuz, gracias por tu sugerencia, lo veré...

Respuestas (2)

Creo que es un problema con el controlador SPI. ¿Sigue sin funcionar con el kernel ascendente 3.7? Allí se aplicaron muchas correcciones.

Hola Marex, de hecho, estoy trabajando en el controlador ascendente (según nuestra discusión en los foros de Freescale), probaré sus sugerencias desde allí y veamos si puedo ayudarlo con la investigación de la causa raíz. ¡gracias!
patchwork-mail1.kernel.org/patch/1910641 El parche no está presente en Linux 3.8.4 pero se agregó a Linux 3.9.4.

Esto no es un problema de electrónica. En un bus SPI, el maestro tiene el control total del tiempo de cualquier transferencia que se inicie. En particular, en una operación de lectura, el dispositivo esclavo puede devolver datos incorrectos o ningún dato, pero no puede afectar si la transferencia se completa o no.

En otras palabras, el error de tiempo de espera de DMA que está recibiendo es completamente un problema dentro del kernel de Linux o el controlador específico que está utilizando. En cualquier caso, una respuesta más específica requerirá muchos más detalles de su parte: ¿Qué chip flash está usando? ¿Qué placa de CPU estás usando? ¿Qué distribución de Linux estás usando? ¿Cuáles son los números de versión del kernel y de los módulos del kernel y/o controladores de dispositivos que está utilizando? ¿Tiene enlaces a donde se pueden encontrar estos artículos?

Sin embargo, esa no es la historia completa; mientras que el esclavo no puede cambiar el tiempo de una transferencia individual, una operación completa puede incluir sondear el estado del esclavo, y esperar a que llegue a un estado listo puede retrasar las cosas.
Es un punto justo, pero eso no aparecería como un "tiempo de espera de DMA" (es decir, en el nivel de transferencia de hardware), se identificaría como un tiempo de espera de protocolo de nivel superior de algún tipo.
Dave, muchas gracias por tu respuesta! Mi chip flash es SST25VF064 (Microchip), y está conectado a la placa Olinuxino maxi (de Olimex). No uso ninguna distribución en particular, pero estoy construyendo un sistema de archivos simple basado en busybox. La versión de Linux es 3.7, es la última de la línea principal de Freescales ( github.com/Freescale/linux-mainline/branches ).
Además, soy realmente nuevo en esto, por lo que también podría tener algún error de novato en alguna parte. Actualmente, solo he definido mi chip en dtsi y he agregado soporte para este chip flash en particular a m25p80.c estaba allí, acabo de verificar el JEDEC de la hoja de datos (0xbf254b) y dupliqué la cantidad de sectores a 128, me pregunto si eso es correcto.)