Hallo zusammen, ich möchte einen Zustandsautomaten für das 1Wire-Protokoll programmieren. Er soll über Timer-Interrupts "im Hintergrund" laufen. Klassisch würde man in der Interrupt-Service-Routine (ISR) bei jedem Interrupt den Zustand des Zustandsautomaten in einer switch-case-Anweisung herausfinden. Der eigentliche Code ist aber oft nur ganz kurz: - Setzte den neuen Timer-Wert - Setze ein Bit - Setze den nächsten Zustand Damit die ISR so schnell wie möglich abgearbeitet wird, würde ich gern auf die (verhältnismäßig) umfangreiche switch-case-Anweisung verzichten und bei "Setze den nächsten Zustand" einfach den Interrupt-Pointer - je nach Zustand - verbiegen. Ist das eine Schnapsidee oder gar üblich? Ich habe mit Google nix dazu gefunden. Mich interessiert allgemein, wie das geht. Speziell möchte ich es erstmal mit dem MSP430 versuchen. Hier liegen die Vektoren m.E. im Flash und können zur Laufzeit nicht geändert werden, oder? Es gibt im Netz ein Beispiel, wie man Code ins RAM kopiert, dort könnte man dann die Adressen überschreiben. http://e2e.ti.com/support/microcontrollers/msp430/f/166/p/199206/710443.aspx Alternativ könnte man versuchen, mit Funktions-Pointern in C zu arbeiten, aber meine ersten Versuche hat der Compiler nicht akzeptiert <<a value of type "int (*)(void)" cannot be used to initialize an entity of type "volatile int">>. Bevor ich nun alles ausprobieree, wollte ich mal wissen, was Ihr meint, wie man das am besten macht.
Gast
#3161687
Torsten C. schrieb: > Klassisch würde man in der Interrupt-Service-Routine (ISR) bei jedem > Interrupt den Zustand des Zustandsautomaten in einer > switch-case-Anweisung herausfinden. [...] > Damit die ISR so schnell wie möglich abgearbeitet wird, würde ich gern > auf die (verhältnismäßig) umfangreiche switch-case-Anweisung verzichten > und bei "Setze den nächsten Zustand" einfach den Interrupt-Pointer - je > nach Zustand - verbiegen. > > Ist das eine Schnapsidee oder gar üblich? Ich würde mal sagen, das der Sinngehalt schlicht davon abhängt, wie umfangreich der Switch-Block ist. Sobald das "verbiegen" des Interruptvektors billiger wird, macht es Sinn, diesen Mechanismus auch zu benutzen. Ist doch logisch. Allerdings: Nur in Assembler sieht man ohne Probleme, was billiger ist.
Wie kommst Du darauf, daß ein Switch-Case teuer sein muß? Hast Du Dir den erzeugten Assembler schonmal angesehen? Überlaß derartige Optimierungen mal besser dem Compiler. Was dagegen teuer ist, sind Funktionspointer in Interrupts. Der Compiler muß dann sämtliche Scratchpadregister sichern, da er nicht weiß, welche durch den indirekten Aufruf zerstört werden. Vielleicht muß er auch erst nen großen Stackframe anlegen.
Gast
#3161744
Es ist überhaupt kein Problem die Funktionszeiger in einem Array abzulegen und später über ihren Index aufzurufen. Das geht mit allem Drum-Und-Dran wie Parameterübergabe und -rückgabe.
c-hater schrieb: > Allerdings: Nur in Assembler sieht man ohne Probleme, was billiger ist. Hmmm, OK, ich habe in Assembler nachgeschaut: Switch Case: 12 Takte + 4 weitere für jedes weitere "case" Call + Return: 7 Takte Also eindeutig Funktionszeiger. amateur schrieb: > Es ist überhaupt kein Problem … Danke für's Mut machen. :-) Ich hab's probiert, es geht! Die LED an PORT1.0 blinkt, die CPU ist aus (Low-Power-Mode) und die StateMachine toggelt im Hintergrund:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
Mit dem asm(" CALL &StateFunc+0") verhindere ich, dass der Compiler alle
Register auf dem Stack zwischenspeichert.
amateur schrieb:
> … die Funktionszeiger in einem Array
> abzulegen und später über ihren Index aufzurufen.
Darin sehe ich gegenüber dem o.g. Beispiel keinen Zusatz-Nutzen.
Jetzt werde ich mich mal an das 1Wire-Protokoll machen.
Das wird wahrscheinlich besser als bei I²C, wo ich in einer dämlichen
while-Schleife auf das Löschen des Start-Bits warte, um das Stop-Bit zu
setzen.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.