Forum: Mikrocontroller und Digitale Elektronik Gesicherter SPI Stream Linux <--> uC


von Michael S. (msb)


Lesenswert?

Ein PIC32 soll verschiedene Unteraufgaben für ein OMAP3 basiertes Linux 
System übernehmen. In meinem aktuellen Fall sind das einen CAN Bus 
bedienen, über zwei I2C Schnittstellen mit vier Touch Panels 
kommunizieren (2 pro I2C) und ein paar einfache GPIO Aktionen.

Nachdem es Datenverkehr in unregelmässigen Zeitabständen in beide 
Richtungen gibt, würde ich gern eine gesicherte Stream Kommunikation, 
quasi wie ein TCP Stream aufbauen.
Das wäre auch eine wiederverwendbare Lösung.
Allerdings ist das mit einer SPI nicht ganz trivial und es muss ja auch 
irgend einen Handshake-Mechanismus beinhalten, um sicherzustellen, dass 
der Slave auch kommunikationsbereit ist. Auch ein guter permanenter 
Durchsatz und eine pünktliche Ereignisübermittlung im <= 10ms Bereich 
ist wichtig, wobei die Linux CPU nicht zu sehr gestresst werden sollte.

Gibt es so etwas schon, oder hat hier jemand Erfahrung mit solch einer 
Kommunikation?

von Michael S. (msb)


Lesenswert?

Ein erster Ansatz ist folgender:


fixed block size, e.g. 64 byte
block can contain any number of complete data items

struct tDataItem
{
   tByte SequenceNo;
   tByte CRC8;
   tByte TargetProcess;
   tByte Cmd;
   tByte Len;
   tByte Data[];
};

SequenceNo:
    high nibble is negated low nibble
    0 for no data
    1..15 cyclic numbering of DataItems

GPIO to simplify and speed up communication
    Linux-->uC: PrepareForCommunication
    Linux-->uC: MasterDataAcceptanceToggle
    uC-->Linux: DataAvailable
    uC-->Linux: ReadyToCommunicate
    uC-->Linux: SlaveDataAcceptanceToggle

Master will communicate
     when he has data to transmit or
     when slave raises DataAvailable

Master requests transmission with raising PrepareForCommunication

Slave activates SPI DMA and signals readyness by raising 
ReadyToCommunicate
(could be replaced by a very short delay)

Both sides evaluate received blocks and toggle 
Master/SlaveDataAcceptanceToggle when block was valid.
Without toggle, the same block would be retransmited

von Michael S. (msb)


Lesenswert?

Ist eine solche Datenübertragung per SPI so ungewöhnlich?

von Peter D. (peda)


Lesenswert?

Ja.

Ich würde CAN nehmen oder RS-232.

von holger (Gast)


Lesenswert?

>Ich würde CAN nehmen oder RS-232.

>quasi wie ein TCP Stream aufbauen.

Oder gleich Ethernet. Dann passt das mit TCP schon;)

>Allerdings ist das mit einer SPI nicht ganz trivial

SPI ist sowas von trivial. Eigentlich eines der
einfachsten Interfaces überhaupt.

>Ist eine solche Datenübertragung per SPI so ungewöhnlich?

Nö, ich frag mich nur was du eigentlich von uns willst?
Mach einfach. Wird schon passen wenn du ein Hardwarehandshake
sowieso schon angepeilt hast.

von Peter D. (peda)


Lesenswert?

Das Problem an SPI ist, daß es eine hohe Interruptlast bewirkt, da oft 
nicht gepuffert.

Wenn aber beide Seiten das SPI per DMA oder Event System
d.h. ohne CPU-Last bedienen können, dann könnte man es nehmen.

Allerdings wird das Protokoll recht krude werden, da SPI bidirektional 
arbeitet. Der Slave sendet also immer die Antwort auf das vorherige 
Paket wärend der Master das nächste Paket sendet, viel Spaß dabei.


CAN hätte den Vorteil, daß es einem einen riesen Rucksack an 
Protokollsoftware schon abnimmt. Einfacher als mit CAN gehts nicht.

von holger (Gast)


Lesenswert?

>Allerdings wird das Protokoll recht krude werden, da SPI bidirektional
>arbeitet. Der Slave sendet also immer die Antwort auf das vorherige
>Paket wärend der Master das nächste Paket sendet, viel Spaß dabei.

Nicht zwangsläufig. Der Master kann sein Paket auch komplett absetzen
ohne das der Slave auf jedes Byte eine Antwort geben muss.
Man kann das sehr einfach gestalten.

>CAN hätte den Vorteil, daß es einem einen riesen Rucksack an
>Protokollsoftware schon abnimmt. Einfacher als mit CAN gehts nicht.

CAN hat den riesen Nachteil das in einem Paket nur 8 Byte
Nutzdaten versendet werden können. Der Aufwand für grössere
Pakete ist viel höher als mit einer einfachen SPI Verbindung.
Wenn die Entfernung zwischen Master und Slave klein ist
(ein paar Zentimeter) kann man SPI mit einigen MHz betreiben.
Da sieht CAN einfach nur noch alt aus.

von Peter D. (peda)


Lesenswert?

holger schrieb:
> Der Master kann sein Paket auch komplett absetzen
> ohne das der Slave auf jedes Byte eine Antwort geben muss.

Dann verschwendest Du Bandbreite bzw. mußt die doppelte Taktfrequenz 
nehmen.
Es senden immer beide Seiten, daher wäre es uneffektiv, wenn einer immer 
nur Dummy-Bytes sendet.

Können Dein PIC und der Linuxer denn nun SPI-DMA?

holger schrieb:
> CAN hat den riesen Nachteil das in einem Paket nur 8 Byte
> Nutzdaten versendet werden können.

Und was ist der Nachteil daran?
Wir übertragen ohne Probleme längere Datenströme über CAN, z.B. ganze 
Firmwareupdates. Der SW-Aufwand ist lächerlich, einfach ne Paketnummer 
mitzählen und gut. Dafür entfällt SW für CRC, ACK, Handshake, Error usw.

von holger (Gast)


Lesenswert?

>> Der Master kann sein Paket auch komplett absetzen
>> ohne das der Slave auf jedes Byte eine Antwort geben muss.
>
>Dann verschwendest Du Bandbreite bzw. mußt die doppelte Taktfrequenz
>nehmen.
>Es senden immer beide Seiten, daher wäre es uneffektiv, wenn einer immer
>nur Dummy-Bytes sendet.

Ist doch egal wenn die Bandbreite sowieso nicht genutzt wird.

>> CAN hat den riesen Nachteil das in einem Paket nur 8 Byte
>> Nutzdaten versendet werden können.
>
>Und was ist der Nachteil daran?

Das der ganze Protokoll Overhead noch mal genau so viel frisst.
Man hat nur die Hälfte Bandbreite für Nutzdaten. Also erzähl mir
nichts von Verschwendung.

>Der SW-Aufwand ist lächerlich, einfach ne Paketnummer
>mitzählen und gut. Dafür entfällt SW für CRC, ACK, Handshake, Error usw.

Bei SPI ist der Softwareaufwand noch lächerlicher.
CRC können die meisten SPI Module auch schon per Hardware.
Bis du dein CAN Modul mal initialisiert hast hab ich schon
das erste Megabyte Daten übertragen;)

von Juergen G. (jup)


Lesenswert?

Ich hab da auch lange drueber nachgedacht wie ich das am besten mache.

Ich mach das jetzt mit SPI (beim linux ein kernel modul mit userland 
interface) und CRC.
Da geht das Bit per Bit in Hardware und das sichern des Bytes in 
Software, beim Linux und beim uC. Beim Linux hat das SPI einen eigenen 
Buffer auf Kernel ebene, der Kernel sagt mir dann wann die Uebertragung 
(in meinem Fall eine Pause in der Uebertragung) fertig ist.
Die Datenpackete sind (bis MaxBytes) unterschiedlich gross, je nach dem 
wieviel mal der Master am SCK wackelt.
Wenn der Slave was zu sagen hat wackelt er an einem zusaetzlichen Pin 
der beim Linux eine ISR anspringt, es wird ein "Funktions"-Byte 
uebertragen was dem Master sagt was er zu tun hat.

von Michael S. (msb)


Lesenswert?

Erst mal Danke für eure Anregungen und Kommentare

Hier ein paar Antworten auf eure Fragen:
- Ja, beide Seiten haben DMA
- Hardware CRC für die SPI existiert nicht
- es ist eine kurze on-Board Verbindung die man mit 10MBit/s betreiben 
kann
- es muss schon SPI sein, im aktuellen Projekt ist der PIC quasi die CAN 
Schnittstelle für den OMAP

>>Allerdings ist das mit einer SPI nicht ganz trivial
>SPI ist sowas von trivial. Eigentlich eines der
>einfachsten Interfaces überhaupt.

Auf der untersten Ebene gebe ich Dir recht, aber ich spreche von einem 
höheren Protokoll und das ist alles andere als einfach über SPI zu 
implementieren.

>>Ist eine solche Datenübertragung per SPI so ungewöhnlich?
>Nö, ich frag mich nur was du eigentlich von uns willst?
>Mach einfach. Wird schon passen wenn du ein Hardwarehandshake
>sowieso schon angepeilt hast.

Ich möchte nicht das Rad neu erfinden. Da gibt es bestimmt schon 
Lösungen. Auch frage ich mich wie viel Hardware Handshake sinnvoll und 
notwendig ist.

Einen uC für ein Linux System arbeiten zu lassen und dabei die gut 
verfügbare SPI zu benutzen scheint mir sinnvoll und in vielen Fällen 
anwendbar. So ein PIC kann Dinge, die gehen auf einer Linux CPU nicht 
oder zumindest nicht so gut.

von Strubi (Gast)


Lesenswert?

Hi Michael,

ich habe öfters solche Sachen zwischen FPGA und Linux-Host gemacht. 
Bewährt hat sich meist ein einfaches Registerprotokoll. GPIOs als 
Handshake einzusetzen kann u.U. haarig werden, Du musst das auf jeden 
Fall im Kernel-Space (eigener Treiber) machen, sonst gibts "Race 
conditions", d.h. ein GPIO wird ev. gesetzt, bevor der SPI-Transfer 
abgeschlossen ist.
Oder alles pur eventbasiert (mit Interrupts) lösen.
Ich habe mir jeweils die Zeit fürs Auslesen eines Status-Registers 
gegönnt. Wenn Daten da sind, wird dann der entsprechende Block 
ausgelesen.
Grüsse,
- Strubi

von Michael S. (msb)


Lesenswert?

@strubi:
Ja, es soll ein interuptgesteuertes Kernelmodul werden.
Mit dem FPGA kannst Du eine Registeraddressierung gut machen (haben wir 
schon öfters getan) aber mit einem uC als Slave ist das schwierig. Da 
geht das nur mit 2 Transfers. Und man muss auch höllisch aufpassen, dass 
man den Slave nicht unvorbereitet anspricht. Will man noch 
Fehlerkorrektur implementieren, dann kommt ohne Zusatzleitungen noch 
mindestens ein weiterer Transfer dazu.

Ich hatte gehofft es gibt hier eine Art Standardlösung für SPI, aber 
bisher habe ich leider nichts brauchbares gefunden.

von Peter D. (peda)


Lesenswert?

Michael S1. schrieb:
> aber mit einem uC als Slave ist das schwierig.

Einen praxistauglichen Einsatz eines MC als SPI-Slave habe ich noch nie 
gesehen, wird wohl seinen Grund haben.
Die Slave sind immer nur dumme Device (ADC, DAC, Schieberegister) oder 
FPGA/ASIC.

Als Verbindung zwischen 2 MCs ist aber die UART auch gut geeignet. Mußt 
mal prüfen, ob man 2MBaud oder mehr einstellen kann.

von Michael S. (msb)


Lesenswert?

Ich habe ja auch ein paar Zweifel ob das mit vertretbarem Aufwand eine 
stabile Lösung wird, aber ich habe in der aktuellen Situation nur SPI 
zur Verfügung.
Allerdings sehe ich auch Chancen solch eine Lösung öfters einzusetzen.

@Jürgen:
Ich kann zwar keine Userlandlösung einsetzen, weil sich kernel driver an 
den SPI Paketdienst hängen werden, aber ich bin trotzdem an Deinen 
Erfahrungen interessiert.
Ein paar Fragen wäred: Läuft das bei Dir stabil? Welchen Durchsatz und 
welche Latenzzeiten hast Du? Benutzt Du Halbduplex?

von Strubi (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Einen praxistauglichen Einsatz eines MC als SPI-Slave habe ich noch nie
> gesehen, wird wohl seinen Grund haben.

Das geht nach meiner Erfahrung nur gut, wenn der Chip DMA kannund sofort 
bei einem "pumped transfer" (gleichzeitig rein/raus) unmittelbar mit 
einem ersten Statusbyte antworten kann.D.h. sobald der SPI CS low geht, 
muss der Solave-uC sofort scharfgeschaltet sein.

Ansonsten kann das ein rechter "Hack" werden. Oder man kriegt es eben 
sauber im Kernel-Space mit Hilfe von GPIOs gelöst. Der Software-Aufwand 
ist aber erheblich und weil es eben ein rechter Hack ist und u.U. 
Stabilitätsprobleme macht (der SPI-Code in Linux ist nicht grade das 
gelbe vom Ei was Timing angeht), hätte ich wiederum eher an i2c gedacht 
(da gibts immerhin einen Handshake), aber das ist vielleicht wieder 
nicht schnell genug...

Juergen G. schrieb:
> Wenn der Slave was zu sagen hat wackelt er an einem zusaetzlichen Pin
> der beim Linux eine ISR anspringt, es wird ein "Funktions"-Byte
> uebertragen was dem Master sagt was er zu tun hat.

Damit drehst Du ja quasi die Master/Slave-Rolle um. Habe festgestellt, 
dass das solche "attention"-Soft-Interrupts recht Protokoll-Overhead 
verursachen und auch einige Stolperfallen bereithalten. Und mit vielen 
Soft-Handshake-Phasen ("Biste bereit?" - "ja, bereit" - "Ok, ich rede 
jetzt") plus sauberen Timeout-Bedingungen dass das Ding nicht hängt, 
wirds ganz schön komplex.

Da gibts so viele Varianten und wenige Lösungswege, die sich arg am 
konkreten Problem orientieren, deshalb fürchte ich, dass es keine 
super-effiziente Patentlösung von der Stange gibt. SPI mit Linux ist 
einfach kein Spass..
Bis meine angepeilte SPI-GPIO-Kombination richtig sauber tat, hat es 
erst mal einen neuen Xenomai-basierten Treiber gebraucht :-/

Trotzdem: Viel Erfolg :-)

von Juergen G. (jup)


Lesenswert?

Strubi schrieb:
> Xenomai-basierten Treiber gebraucht :-/

oops, Asche auf mein Haupt, das hatte ich ganz vergessen zu erwaehnen.

Ich habe mehrere Anwendungsgebiete wo ich uC-SPI mit Linux-SPI laufen 
lasse. Einige sind zeitkritisch, andere nicht. Aber alle arbeiten nach 
dem selben Prinzip.
Bei den zeitkritischen Systemen arbeitet das Linux mit einem Xenomai 
Kernel und entsprechendem SPI Kernel Modul.

Das der uC immer Slave ist und an einem Pin wackeln muss wenn er was zu 
sagen hat, hat verschiedene Gruende.
Zum einen habe ich es nicht geschafft den Linux SPI mit vernuenftiger 
Latenz als Slave zu implementieren. Wenn er als Master laeuft weiss ich 
bei definierten (MaxBytes) und (BlockTime) was die laengste Zeit zur 
Uebertragung ist und kann unkritische Prozesse auf dem Linux ausblocken.
Wenn der Chip auf dem das Linux laeuft DMA am SPI hat ist das eine 
leichte Uebung, die Uebertragung laeuft immer Duplex und ich muss (durch 
Queues) sicher stellen das im uC und Linux keine Race Condition 
entsteht.
Bis jetzt ist mir das bei meinen Anwendungen immer gelungen und die 
Latenzen gehen ohne Xenomai nie >10ms  mit Xenomai kommt man auf < 100us 
mit einem 700MHz Linux. Letzteres setzt aber vorraus das man weiss was 
im System alles vor sich geht.

von Michael S. (msb)


Lesenswert?

@strubi
I2C auf 400KHz würde reichen, aber habe ich leider nicht zur Verfügung.

@Jürgen
Hat Deine Lösung  eine geprüfte Übertragung (crc, xor, o.ä.), mit 
Wiederholung wenn notwendig?

von Juergen G. (jup)


Lesenswert?

Michael S1. schrieb:
> Hat Deine Lösung  eine geprüfte Übertragung

Bei kritischen Anwendungen wie Maschinencontrollern haengt an jeder 
Uebertragung ein CRC dran.
In diesem Fall verwende ich unterschiedliche Buffer (das ist ein und der 
selbe Speicherbereich mit unterschiedlichem Index)
Die Queues stellen sicher, das auf ein gesendetes Packet ein Error folgt 
falls es einen gibt, wenn ein Packet ohne oder mit anderem 
Speicher-Index kommt, war die vorherige Uebertragung erfolgreich und der 
Speicher wird frei gegeben.

Das mag fuer einige Anwendungen recht blauaeugig sein, bei mir reicht es 
aber aus.

Das eigentliche Problem was "Michael S1" hat, OMAP mit Linux + CAN am 
externen uC oder SPI CAN-Controller, hat mir auch viel Kopfschmerzen 
bereitet und bestimmt drei Wochen Arbeit gekostet, ohne 
zufriedenstellende Resultate.

Ich hab das dann mit SocketCAN auf dem OMAP gemacht.
Laeuft das CAN mal auf dem OMAP kann auch der uC mit CAN daherkommen und 
die Welt ist wieder in Ordnung.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.