Banana PI (Allwinner A20): SPI

Gast #4583268
Hallo,

ich habe ein Codebeispiel geschrieben, mit dem man unter Linux den 
SPI-Bus durch das Setzen von Registern steuert.
Den Weg über den Linux-Treiber:
1
system ("modprobe spi-sun7i");
2
spiDevice = open ("/dev/spidev0.0" , O_RDWR));
3
...
wollte ich nicht nehmen, weil ich bestimmte Timings nicht einhalten 
konnte.
Im konkreten Fall habe ich einen MCP3208 an SPI0 gehängt (an SS0).


Ich finde, aus dem Datenblatt des Allwinner A20 lässt sich die 
Funktionweise, wann welches Bit geschrieben wird, nicht erkennen.
Ein Beispiel habe ich im Internet auch nicht gefunden. Deshalb 
veröffentliche ich hier meinen Code.
Da werden sicherlich noch irgendwo Fehler sein.
(Datenblatt: https://linux-sunxi.org/A20 -> User Manual)

Derzeit läuft der SPI auf 2.5MHz (wenn ich richtig gemessen habe).
Mit der Methode ist die Framelänge maximal 64 Byte, danach ist der 
TX-Fifo voll.

LG Andreas
Angehängte Dateien:
Gast
Hi,

ich habe vor einiger einmal versucht, ein TFT-Display über SPI mit dem 
BananaPro zu verbinden. Das hat auch funktioniert, war aber viel zu 
langsam, weil der SPI-Controller zwischen den einzelnen Bytes eine sehr 
lange Pause eingebaut hat, die sich nicht verkürzen ließ. Die Länge der 
Pause blieb immer gleich unabhängig vom SPI-Clock. Ich habe da viel Zeit 
reingesteckt aber das Problem nicht gelöst.

Hast Du eine ähnliche Erfahrung? Beim Raspberry tritt das Problem nicht 
auf.
Gast
Was meinst du mit Pause, dass das Clock-Signal stehen geblieben ist 
zwischen den Bytes?

Bei mir sind die Bytes alle direkt nacheinander übertragen wurden.
Das Problem bei Benutzung des Linux-Treibers war, dass nachdem das CS0 
gesetzt wurde ca. 10µs vergangen sind, bis er angefangen hat zu senden. 
Nach dem Senden sind nochmal ca. 15µs vergangen (siehe Bild).

Wie lang ist bei dir die Pause zwischen 2 Bytes und wie viele Bytes 
verschickst du mit einem Burst?


Beim Oszi-Bild, wie es bei mir vorher (mit Linux-Treiber) aussah:
Die obere Kurve ist Channel-Select (0-Aktiv). Die untere ist das 
Clock-Signal, leider durch Aliasing nicht so gut erkennbar. Aber man 
sieht, wann die Clock aktiv ist und wann nicht.
Den Cursor kannst du ignorieren.
Angehängte Dateien:
Gast
Hi,

> Das Problem bei Benutzung des Linux-Treibers war, dass nachdem das CS0
> gesetzt wurde ca. 10µs vergangen sind, bis er angefangen hat zu senden.
> Nach dem Senden sind nochmal ca. 15µs vergangen (siehe Bild).

Genau das war das Problem, ist schon eine Weile her, deswegen hatte ich 
es nicht mehr genau in Erinnerung. Ich habe das Problem hier bschrieben: 
Beitrag "SPI Chipselect-Delay auf Banana PI" (unter einem anderen 
Nickname).


Das ganze hat dazu geführt, dass ich das Display am BananaPro nicht 
nutzen konnte, weil viel zu langsam. Die Übertragung eines kompletten 
Framebuffers war eine Angelegenheit von einigen Sekunden.

Verstehe ich das richtig, dass diese Verzögerung bei Deiner eignen 
Implementierung nicht auftritt?
Gast
Ich habe das Betriebsystem Bananian.

Bei meinem Code tritt das Problem nicht auf.
Die Verzögerung zwischen zwei Übertragungen ist bei mir ca. 4µs. Ich 
nehme an, die entsteht durch meinen Code (Schreiben in TX-FIFO, lesen 
vom RX-FIFO, usw).

Wenn du diesen Code einsetzt, vergleich mal mit dem Datenblatt, ob die 
Bits im Config-Register sinvoll gesetzt sind. :p

Zum DMA:
In dieser Implementierung des Treibers wird der DMA-Modus eingesetzt, 
wenn mehr als 64-Bytes übertragen werden:
http://dl.cubieboard.org/parteners/waveshare/Source_Code/a20-cubieboard-dvk/driver%20source/spi-sun7i.c
Funktion: sun7i_spi_xfer
Ich weiß nicht, ob das der tatsächlich eingesetzte Treiber ist. Ich bin 
auch kein Treiberexperte.

Da das Programm beim Aufruf von ioctl(...) unterbrochen wird, bis die 
Übertragung fertig ist, finde ich, dass man sich den DMA dann auch 
sparen kann. Schließlich dauert das Übertragen viel länger, als Bytes 
durch den Prozessor zu schleifen.
Wenn man mehr als 64 Bytes übertragen möchte, könnte man während der 
Übertragung noch Bytes in den TX-FIFO schreiben und aus dem RX-FIFO 
lesen (damit er nicht überläuft).

Im verlinkten Treiber wird erst das Start-Burst-Bit gesetzt und danach 
die Bytes in den TX-FIFO geschoben.

Ist meine Meinung dazu.
Gast
Ok, danke für Deine Hinweise. Ich werde Deinen Sourcecode mal anpassen 
und testen. Wäre ja cool, wenn das doch noch funktionieren würde.

Ich bin mittlerweile zu der Einsicht gekommen, dass DMA in meinem Fall 
ohnehin nicht sinnvoll ist. Das TFT-Display hat ein Parallel-interface, 
das über ein Schieberegister mit dem SPI-Bus verbunden ist. Man schreibt 
dann erst das Schieberegister über SPI (16bit) und dann wird über einen 
Impuls auf einem GPIO der Wert in den Displaycontroller übertragen. 
Danach muss man ohnehin einen neuen SPI-Transfer aufsetzen für die 
nächsten beiden Bytes.

Mit dem gleichen SPI-Takt läft das auf einem Raspberry so schnell, dass 
man sogar Videos abspielen kann (mit geringer Framerate), aber auf dem 
BananaPro war das wie gesagt schnarchlangsam, und das nur, weil die 
Verzögerung nach dem CS0 um ein Vielfaches länger war als die 
eigentliche Übertragung.

Anfangs dachte ich, das geht so langsam, weil kein DMA verwendet wird, 
aber der eigentliche Grund ist das CS0-Delay.

Also danke nochmal.
Gast
Ok, ich habe Deinen Code mal getestet. Saubere Sache, ich messe zwischen 
CS->low und dem ersten Clock jetzt ca. 700ns, die ganze Übertragung 
eines 16Bit-Wertes dauert jetzt 7us gegenüber 45us vorher. Wobei diese 
Zeit jetzt hauptsächlich vom SPI-Clock bestimmt wird und nicht mehr von 
dieser unsinning großen Delay am Anfang. Mit einem höheren SPI-Clock 
sollte das also noch schneller werden. Das sieht alles sehr gut aus.

Ich frage mich nur, wieso sich der Linux-Treiber so unsinnig verhält. 
Vielleicht liegt irgendwo im spi_sun7i-Modul ein Hund begraben, denn 
dort werden anscheinend die Register-Settings im A20 gemacht. Das müsste 
ich jetzt mal mit Deinen Settings vergleichen. Also jetzt erstmal 
Datenblatt inhalieren.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.