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.
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.
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 | #include <msp430.h> |
2 | void SMState_1(void); |
3 | void SMState_2(void); |
4 | void(*StateFunc)(void) = &SMState_1; |
5 | int main(void) { |
6 | // Initialisierung übersprungen
|
7 | _BIS_SR(GIE); // Low-Power-Mode mit Interrupts |
8 | LPM0; |
9 | }
|
10 | void SMState_1(void) { |
11 | CCR0 = 0x4321; |
12 | P1OUT |= BIT0; |
13 | StateFunc = &SMState_2; |
14 | }
|
15 | void SMState_2(void) { |
16 | CCR0 = 0x1234; |
17 | P1OUT &= ~BIT0; |
18 | StateFunc = &SMState_1; |
19 | }
|
20 | #pragma vector=TIMER0_A0_VECTOR
|
21 | __interrupt void Port_1(void) { |
22 | //StateFunc(); // das wären 30 Takte mehr
|
23 | asm(" CALL &StateFunc+0 ;"); |
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.
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.