Hallo Forum, viele SPI Slaves (beispielsweise ADCs) haben ein Registerkonzept implementiert. Mit dem ersten Byte, welches der Master an den Slave sendet, wird bestimmt ob der Zugriff lesend oder schreibend ist und auf welche interne Register des ADCs man zugreifen möchte. Im nächsten Byte bekommt man dann entweder den Inhalt des Registers oder kann selbst etwas reinschreiben. Auf diese Weise kann der Zustand eines relativ komplexen Geräts recht elegant konfiguriert werden. Zu meinem Problem: Ich möchte einen SPI-Slave entwerfen, der denselben internen Registeraufbau besitzt, damit der Master meinen Slave elegant konfigurieren kann. Das Problem ist nun, dass die Antwort des Slaves vom ersten empfangenen Byte abhängen würde. Kann man mit einem STM32 einen Interrupt nach dem ersten empfangenen Byte aufrufen und die entsprechenden Daten noch während des SPI-Zugriffs bereitstellen? Eine geringe Latenz des Interrupts könnte durch ein paar Nullbytes ausgeglichen werden. Kann man das so lösen oder kommt dann die Mikrocontrollerpolizei? Sonderlich elegant scheint es nicht zu sein. Gibt es andere, bewährte Alternativen für diesen Fall? Grüße, Stefan
Stefan H. schrieb: > Kann man das so lösen oder kommt dann die Mikrocontrollerpolizei? > Sonderlich elegant scheint es nicht zu sein. Gibt es andere, bewährte > Alternativen für diesen Fall? Warum sollte das nicht elegant sein? Welche andere Lösung würde dir einfallen? Genauso und nicht anders geht's aus meiner Sicht. "Unelegant" wird's, wenn die Anforderungen zu hoch sind. > Zu meinem Problem: Ich möchte einen SPI-Slave entwerfen, der denselben > internen Registeraufbau besitzt, damit der Master meinen Slave elegant > konfigurieren kann. Das Problem ist nun, dass die Antwort des Slaves vom > ersten empfangenen Byte abhängen würde. Kann man mit einem STM32 einen > Interrupt nach dem ersten empfangenen Byte aufrufen und die > entsprechenden Daten noch während des SPI-Zugriffs bereitstellen? Eine > geringe Latenz des Interrupts könnte durch ein paar Nullbytes > ausgeglichen werden. Wichtig ist erstmal, wie schnell dein SPI-Master taktet. 50MHz wäre n bisschen arg schnell, es kommt drauf an, was du vorhast - prinzipiell so langsam wie möglich, so schnell wie nötig. Aus der Hüfte geschossen fallen mir zwei Ansätze ein: 1) komplett Interruptgesteuert: nach jedem Byte wertest du aus, ob's Kommando (bzw. Schreib-/Leseadresse) oder Daten sind. Für's Schreiben ist es relativ einfach, die Schreibadresse geht als Offset auf einen Pointer, nachfolgende Bytes werden an diesen Pointer geschrieben und dieser dann inkrementiert. Lesen funktioniert im Prinzip genauso, nur dass du hier bereits beim Setzen des Pointers auch gleich ausliest, damit den Tx-Buffer füllst und auch hier den Pointer inkrementierst. Beim nächsten Interrupt jeweils dann schreiben/lesen. Das ganze jeweils solange wie das /CS-Signal aktiv ist, d.h. das deaktivieren des /CS-Signals bedeutet, dass ein komplettes Paket gelesen/geschrieben wurde. 2) Zugriff per DMA: das ist vielleicht etwas aufwendiger zu implementieren, aber für höhere SPI-Taktraten ggf. noch etwas wirkungsvoller. Hier verwendest du verkettete Transaktionen. Das erste Byte kannst du noch im Interrupt abarbeiten, um zu erkennen, ob du lesen/schreiben willst. Für den DMA-Zugriff hast du dann zwei Transaktionen, SPI->RAM und RAM->SPI. Die empfangene Adresse setzt du dann als Quell- bzw. Zieladresse ein. Wenn deine Implementierung vorsieht, dass auch die Anzahl zu lesender/schreibender Bytes übermittelt wird, dann hast du auch die Anzahl der Bytes, die in der jeweiligen Transaktion übertragen werden sollen, ansonsten musst du es wieder am /CS-Signal festmachen. Soll gelesen werden, startest du die Transaktion per Software für's erste Byte, nachfolgende Bytes sollen dann per DMA über das SPI-Interruptsignal in Hardware getriggert werden. Für's Schreiben setzt du die Transaktion direkt auf den Hardwaretrigger. Ich kenne leider die Eigenschaften der STM32-DMA-Controller nicht im Detail, und du schreibst nicht, welchen STM32 genau du verwendest. Bei einem PSoC kann man den DMA-Controller so einstellen, dass in einer Transaktion mit mehreren Bytes jedes weitere Byte erst einen Trigger bekommen muss, damit es transferiert wird (die andere Variante ist Trigger für's erste Byte und danach alle Bytes so schnell wie möglich direkt nacheinander, aber das scheidet ja als Slave aus). Ich vermute, den STM32 kann man auch genauso einstellen. Die kritische Phase ist das Aufsetzen der Transaktion durch den DMA-Controller, also das Einrichten der Adresse, etc. Das braucht die meiste Zeit, der eigentliche Transfer der Bytes brauchen weniger Zeit (Achtung, PSoC-Wissen, auch hier die Vermutung, dass es beim STM32 nicht anders ist). In beiden Fällen würde ich den von dir erwähnten Registeraufbau auch im RAM so abbilden. Also nicht einzelne Variablen, die du dann anhand der Auswertung der übermittelten Adresse selektieren musst, sondern ein Array bzw. struct, welches den Registeraufbau abbildet. Das hat den Vorteil, dass du die übermittelte Adresse direkt als Offset verwenden kannst (vorausgesetzt, dass alle Elemente die gleiche Breite haben -> wenn du gemischte Breiten brauchst, dann teile sie in Low/High-Bytes/Words auf). Als Vorschlag würde ich dir empfehlen, das erstmal interruptgesteuert zu machen, aber schön kurz und knackig: der Interrupt kümmert sich nur um den Transfer der Daten von/zu den "Registern". Wenn sich da was geändert hat, dann signalisiert du das dem Hauptprogramm über ein Flag, und das Hauptprogramm übernimmt dann die Änderungen. Und wenn gelesen wird, dann darf währenddessen das Hauptprogramm die Register nicht verändern, sondern muss warten bis das Lesen abgeschlossen wurde. Kann man ebenfalls über ein Flag realisieren. Ich hoffe es war einigermaßen verständlich, wenn nicht, nochmal nachfragen. Ralf
Hallo Ralf, danke für die Rückmeldung. Ich denke dass ich es verstanden habe und werde es ausprobieren. Ich melde mich wieder. Stefan
>in Hardware getriggert werden. >Für's Schreiben setzt du die Transaktion direkt auf den Hardwaretrigger. >Ich kenne leider die Eigenschaften der STM32-DMA-Controller nicht im >Detail, und du schreibst nicht, welchen STM32 genau du verwendest. Bei >einem PSoC kann man den DMA-Controller so einstellen, dass in einer >Transaktion mit mehreren Bytes jedes weitere Byte erst einen Trigger >bekommen muss, damit es transferiert wird (die andere Variante ist >Trigger für's erste Byte und danach alle Bytes so schnell wie möglich >direkt nacheinander, aber das scheidet ja als Slave aus). Ich vermute, >den STM32 kann man auch genauso einstellen. HW Trigger bei STM32 für externe Peripherie scheint zumindest nicht bei allen Varianten zu gehen. Siehe auch Beitrag "STM32 SPI DMA - Overrun error"
Hi, ich stehe vor dem gleichen Problem. Ich würde das wie oben beschrieben komplett interrupt-gesteuert machen. Hast du dazu schon was fertig und könntest den Code teilen? Dann müsste ich das Rad nicht neu erfinden =) wäre super! Viele Grüße, Michael
Hat dein STM SPI einen FIFO? Würde damit erheblich leichter gehen.
Stefan H. schrieb: > Ich möchte einen SPI-Slave entwerfen, der denselben > internen Registeraufbau besitzt Viele ADCs haben ein krudes Datenformat, das möchte man sich nicht ohne Not antun. Am einfachsten ist folgendes Protokoll: Befehlsbyte, Dummybyte, Antwortbyte[s]. Dann hat der Slave eine ganze Bytezeit Zeit, die Antwort zu basteln.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.