Das Lesen von mehr als 35 Bytes aus dem SPI-Flash führt zu einer Zeitüberschreitung des Treibers und zu korrupten Ergebnissen

Ich habe SPI-Flash an mein Linux-Board (imx 233-basiert) angeschlossen, das in seinem SPI-Bus läuft. Ich habe den Kernel und den SPI-Bus und den Flash-Chip dafür konfiguriert.

Der Blitz befindet sich derzeit auf einem Steckbrett. Bevor ich versuchte, unter Linux zu arbeiten, habe ich es separat versucht und kann mit einem FT2232H-Chip (FT2232-Breakout-Board von DangerousPrototypes.com) lesen und schreiben, wie ich möchte. Allerdings musste ich beim Linux-Board Pull-up-Widerstände (10k) in die Dateneingänge und Datenausgänge einbauen, sonst wurde der Chip nicht richtig erkannt.

Mein eigentliches Problem ist, dass ich jetzt versuche, nur rohen Flash über den mtd-Treiber zu lesen, und alles scheint korrekt zu sein, wenn ich weniger als 35 Bytes lese. Sofort, wenn ich mehr als 35 Bytes (36 oder mehr) lese, beschwert sich der Treiber über DMA-Fehler:

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

Auch in diesem Fall sind die meisten (wenn nicht alle) Bytes falsch. Das Lesen von weniger als 35 Bytes wird "sofort" (kein Timeout) zurückgegeben, und alle gelesenen Bytes sind korrekt.

Mein C-Code stammt direkt aus dem MTD-Lesebeispiel:

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;
} 

Das Timeout passiert "wie erwartet" (10 Sekunden) in 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));

Irgendwelche Ideen, was falsch sein könnte? Ich bin nicht so gut mit Elektronik, also bitte alle Vorschläge sind willkommen.

Wenn Sie ein Oszilloskop haben, zeigt Ihnen das, was auf den Daten-/Taktleitungen vor sich geht.
Auf der Softwareseite besteht ein möglicher Grund für fehlerhafte Daten nicht darin, dass etwas beschädigt war, sondern darin, dass der readSystemaufruf zurückgegeben wurde -1. Sie ignorieren den Rückgabewert, und daher gibt Ihre Schleife in diesem Fall nicht initialisierte Daten aus dem Array mit variabler Länge aus.
könnte ein Problem mit der Taktung sein, versuchen Sie, die Taktfrequenz zu verringern und sehen Sie, ob es hilft. Später, wenn Sie vom Steckbrett wechseln, können Sie möglicherweise die Taktrate erhöhen.
John, ich habe ein Oszilloskop und werde überprüfen, was ich davon sehen kann. Aber der Speicher ist begrenzt, und normalerweise kann man nur die ersten paar Nachrichten sehen. Kaz, Sie haben 100% Recht, ich sollte es überprüfen. Obwohl das Problem immer noch irgendwo unter der Lesefunktion liegt. Miceuz, danke für deinen Vorschlag, ich werde mich darum kümmern.

Antworten (2)

Ich denke, es ist ein Problem mit dem SPI-Treiber. Funktioniert es immer noch nicht mit dem 3.7-Upstream-Kernel? Dort wurden viele Fixes angewendet.

Hallo Marex, tatsächlich arbeite ich an dem Upstream-Treiber (gemäß unserer Diskussion in den Freescale-Foren), ich werde Ihre Vorschläge von dort aus ausprobieren und mal sehen, ob ich Ihnen bei der Untersuchung der Grundursache helfen kann! Danke!
patchwork-mail1.kernel.org/patch/1910641 Patch ist auf Linux 3.8.4 nicht vorhanden, wurde aber zu Linux 3.9.4 hinzugefügt.

Das ist kein Elektronikproblem. Auf einem SPI-Bus hat der Master die vollständige Kontrolle über das Timing jeder initiierten Übertragung. Insbesondere bei einer Leseoperation kann das Slave-Gerät fehlerhafte Daten oder überhaupt keine Daten zurückgeben, aber es hat keinen Einfluss darauf, ob die Übertragung abgeschlossen ist oder nicht.

Mit anderen Worten, der DMA-Timeout-Fehler, den Sie erhalten, ist ausschließlich ein Problem innerhalb des Linux-Kernels oder des spezifischen Treibers, den Sie verwenden. In jedem Fall wird eine genauere Antwort viel mehr Details von Ihnen erfordern: Welchen Flash-Chip verwenden Sie? Welches CPU-Board verwendest du? Welche Linux-Distribution verwendest du? Wie lauten die Versionsnummern des Kernels und aller Kernelmodule und/oder Gerätetreiber, die Sie verwenden? Hast du Links, wo diese Artikel zu finden sind?

Das ist jedoch nicht die ganze Geschichte; Während der Slave den Zeitpunkt einer einzelnen Übertragung nicht ändern kann, kann eine vollständige Operation das Abfragen des Status des Slaves umfassen, und das Warten darauf, dass dieser einen Bereitschaftszustand erreicht, kann Dinge verzögern.
Es ist ein fairer Punkt, aber das würde sich nicht als "DMA-Zeitüberschreitung" (dh auf der Hardware-Übertragungsebene) zeigen, sondern als eine Art Protokoll-Zeitüberschreitung auf höherer Ebene identifiziert werden.
David, vielen Dank für deine Antwort! Mein Flash-Chip ist SST25VF064 (Microchip) und mit dem Olinuxino-Maxi-Board (von Olimex) verbunden. Ich verwende keine bestimmte Distribution, aber ich baue ein einfaches Dateisystem auf Basis von busybox. Die Linux-Version ist 3.7, die neueste von Freescales Mainline ( github.com/Freescale/linux-mainline/branches ).
Außerdem bin ich wirklich neu in diesem Bereich, also könnte ich genauso gut irgendwo einen Anfängerfehler haben. Derzeit habe ich meinen Chip nur in dtsi definiert und Unterstützung für diesen bestimmten Flash-Chip zu m25p80.c hinzugefügt (nur 32 Mbit Flash war da, ich habe gerade den JEDEC aus dem Datenblatt (0xbf254b) überprüft und die Anzahl der Sektoren auf 128 verdoppelt, ich frage mich, ob das richtig ist?)