
|
Sie befinden sich hier: Elektronik / ATMega SPI Performance Tuning /
Für die Anbindung des ENC28J60 über SPI suchte ich eine Möglichkeit, einen Datenblock möglichst effizient über SPI zu transferieren. Die von einfachste Variante sieht etwa so aus: void enc28j60_write_memory(uint8_t *buff, uint8_t count) {
Mit GCC compiliert ergibt das folgenden Assemblercode: c2: fc 01 movw r30, r24 Dieser Code sieht eigentlich recht gut aus. Dennoch entstehen beim Transfer recht lange Pausen zwischen 2 Bytes, wie die Auswertung mit dem Logikanalysator zeigt. Umgruppierung der BefehleEs ist zu sehen, dass nach dem Setzen des Statusregisters durch den ATMega noch einige Befehle abgearbeitet werden müssen, bis das nächste Byte ausgegeben wird. Die Idee ist jetzt, diese Befehle möglichst zu überspringen: void enc28j60_write_memory(uint8_t *buff, uint8_t count) {
Hieraus ergibt sich folgender Assembler-Code: 000000c2 <enc28j60_write_memory>: Wenn ich das Datenblatt richtig interpretiere, sollte SPIF immer gesetzt sein, wenn keine Interrupts benutzt werden und SPI gerade keine Daten überträgt, der Code sollte also eigentlich funktionieren. Zur Sicherheit müsste man nach der While-Schleife eigentlich auch noch eien Abfrage auf das SPIF-Bit einbauen. Vorladen des RegistersEin Blick auf den Assembler-Code im letzten Abschnitt zeigt, dass zwischen abgeschlossenem Senden des letzten Bytes und Senden den nächsten Byte noch ein Register geladen werden muss (r24), welches dann an den SPI-Port geschickt wird. Diese Befehle lassen sich jedoch auch vor der Abfrage des SPIF-Bits erledigen. Also wird der C-Code nochmals wie folgt modifiziert (man braucht nicht selbst Assembler zu programmieren!) void enc28j60_write_memory(uint8_t *buff, uint8_t count) {
Dies wird zu folgendem Assembler-Code compiliert: 000000c2 <enc28j60_write_memory>: Besser dürfte es nicht mehr werden, denn nun erfolgt die Ausgabe des nächsten Bytes direkt nachdem das gelöschte SPIF-Bit erkannt wurde (Zeile d2). Die SPI-Kommunikation ist nochmals etwas schneller geworden, wie das Bild zeigt.
WarteschleifeDie "brutale" Variante wäre es, nicht das SPIF-Bit abzufragen, sondern einfach ein paar "NOP"-Befehle einzufügen. Ob dies jedoch unter allen Umständen korrekt funktioniert, ist mir nicht bekannt, daher halte ich persönlich von dieser Lösung nichts. FazitBei performance-kritischen Programmteilen lohnt sich ein Blick auf den erzeugten Assembler-Code unbedingt, selbst wenn man selbst nicht in Assembler programmiert, erkennt man teilweise doch Optimierungspotential. Die Optimierung funktioniert hier, weil man es praktisch mit einem Multithreading-Programm zu tun hat. Nur wird der 2.Programmthread - nämlich die Ausgabe der einzelnen Bits auf dem SPI-Port - nicht selbst implementiert, sondern ist schon in der Hardware des ATMega implementiert. Hier gilt es, die Zeit, die der Controller für das Senden benötigt, möglichst effizient im eigenen Programm auszunutzen - also so viele "nützliche" Befehle wie möglich während dieser Zeit abzuarbeiten.
Archivierte SeiteDiese Seite wurde archiviert, d.h. sie wird nicht mehr aktiv gepflegt und die Informationen entsprechen unter Umständen nicht mehr dem aktuellen Stand. |