2017-01-29 7 views
3

Ich versuche zu lernen, wie man einen grundlegenden SPI-Treiber schreibt und unten ist die Probe-Funktion, die ich geschrieben habe.SPI Linux Treiber

Was ich versuche, hier zu tun ist, richten Sie das spi Gerät für Fram (datasheet) und verwenden Sie den spi_sync_transfer()api description den Hersteller id aus dem Chip zu erhalten.

Wenn ich diesen Code ausführen, kann ich die Daten auf dem SPI-Bus mit Logikanalysator sehen, aber ich kann es nicht mit dem RX-Puffer lesen. Fehle ich hier etwas? Könnte mir bitte jemand dabei helfen?

static int fram_probe(struct spi_device *spi) 
{ 
    int err; 
    unsigned char ch16[] = {0x9F,0x00,0x00,0x00};// 0x9F => 10011111 
    unsigned char rx16[] = {0x00,0x00,0x00,0x00}; 

    printk("[FRAM DRIVER] fram_probe called \n"); 

    spi->max_speed_hz = 1000000; 
    spi->bits_per_word = 8; 
    spi->mode = (3); 

    err = spi_setup(spi); 
     if (err < 0) { 
      printk("[FRAM DRIVER::fram_probe spi_setup failed!\n"); 
      return err; 
     } 
    printk("[FRAM DRIVER] spi_setup ok, cs: %d\n", spi->chip_select); 
    spi_element[0].tx_buf = ch16; 
    spi_element[1].rx_buf = rx16; 

    err = spi_sync_transfer(spi, spi_element, ARRAY_SIZE(spi_element)/2); 
    printk("rx16=%x %x %x %x\n",rx16[0],rx16[1],rx16[2],rx16[3]); 

    if (err < 0) { 
     printk("[FRAM DRIVER]::fram_probe spi_sync_transfer failed!\n"); 
     return err; 
    } 

    return 0; 
} 
+0

Hier sind viele Probleme mit diesem Code. Vor allem ist es kein SPI-Treiber. Zweitens müssen Sie verstehen, wie Sie mit SPI im Kernel und im Benutzerbereich kommunizieren.Drittens müssen Sie lernen, wie der SPI-Bus auf Hardwareebene funktioniert. Was signalisiert es und wie werden sie im Laufe der Zeit verändert? – 0andriy

+0

Der Kernel hat zwei Arten von Treibern, die man SPI-Treiber nennen könnte. Dies scheint die Sondenfunktion eines 'spi_driver' zu sein, die durch Registrieren eines' struct spi_driver' mit 'module_spi_driver()' erzeugt wird. Also denke ich, es ist durchaus vernünftig, es einen SPI-Treiber zu nennen. Die andere Art wäre ein Master-Treiber, definiert durch eine 'struct spi_master' und registriert mit' spi_register_master() '. – TrentP

+0

@TrentP, Dies ist nicht SPI Master-Treiber, ich stehe behoben. – 0andriy

Antwort

1

spi_element ist in diesem Beispiel nicht deklariert. Sie sollten das zeigen und auch, wie alle Elemente dieses Arrays gefüllt sind. Aber nur durch den Code, der da ist, sehe ich ein paar Fehler.

Sie müssen den len Parameter von spi_transfer einstellen. Sie haben den TX- oder RX-Puffer ch16 oder rx16 zugewiesen, jedoch nicht die Länge des Puffers.

Sie sollten alle Felder, die nicht in spi_transfer verwendet werden, auf Null setzen.

Wenn Sie die Länge auf vier setzen, senden Sie nicht den richtigen Befehl gemäß dem Datenblatt. RDID erwartet einen einen Byte-Befehl, nach dem vier Bytes der Ausgabedaten folgen. Sie schreiben einen Byte-Befehl vier in Ihrer ersten Übertragung und dann lesen vier Datenbytes. Das tx_buf in der ersten Übertragung sollte nur ein Byte sein.

Und schließlich ist die Anzahl der Übertragungen als letztes Argument zu spi_sync_transfer() falsch angegeben. Es sollte in diesem Fall 2 sein, weil Sie zwei, spi_element[0] und spi_element[1] definiert haben. Sie könnten ARRAY_SIZE() verwenden, wenn spi_element zum Zweck dieser Nachricht deklariert wurde und Sie alle Übertragungen im Array senden möchten.

Betrachten Sie dies als eine Möglichkeit, die spi_transfers besser auszufüllen. Es kümmert sich darum, Felder, die nicht verwendet werden, auf Null zu setzen, definiert die Übertragungen auf eine leicht zu erkennende Weise und die Änderung der Puffergrößen oder der Anzahl der Übertragungen wird automatisch in dem verbleibenden Code berücksichtigt.

const char ch16[] = { 0x8f }; 
char rx16[4]; 
struct spi_transfer rdid[] = { 
    { .tx_buf = ch16, .len = sizeof(ch16) }, 
    { .rx_buf = rx16, .len = sizeof(rx16) }, 
}; 
spi_transfer(spi, rdid, ARRAY_SIZE(rdid)); 

Da Sie einen Bereich haben, sollten Sie überprüfen, dass diese Operation unter einem einzigen Chip-Select-Puls passiert. Ich habe mehr als einen Linux-SPI-Treiber gefunden, der einen Fehler hat, der die Chipauswahl auslöst, wenn dies nicht der Fall ist. In einigen Fällen löst das Umschalten von TX auf RX (wie oben beschrieben) einen CS-Impuls aus. In anderen Fällen wird ein CS-Impuls für jedes Wort (hier 8 Bits) von Daten erzeugt.

Eine andere Sache, die Sie ändern sollten, ist dev_info(&spi->dev, "device version %d", id)' und auch dev_err(), um Nachrichten zu drucken. Dies fügt den Gerätenamen auf eine Standardweise anstelle Ihres hartcodierten, nicht standardmäßigen und inkonsistenten "[FRAME DRIVER] ::" - Textes ein. Und legt die Ebene der Nachricht entsprechend fest.

Erwägen Sie auch, die Gerätebaumstruktur in Ihrem Treiber zu unterstützen, um Geräteeigenschaften zu lesen. Dann können Sie beispielsweise die SPI-Busfrequenz für dieses Gerät ändern, ohne den Kernel-Treiber neu zu erstellen.

+0

Vielen Dank für Ihre Erklärung und Hilfe. Ich habe die Funktionen so geändert, wie du es vorgeschlagen hast und es scheint mir zu geben, was ich erwarte. Vielen Dank !! –