mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Context Switching auf 8051 (xc866) mit SDCC


Autor: krümel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich schreibe im Moment einen kleine Scheduler. FreeRTOS könnte ich zwar 
nehmen, aber ich mache das rein aus Interesse und um was zu lernen. Ich 
verwende einen XC866 von Infineon und programmiere in C mit SDCC.
Unten ist ein Ausschnitt aus dem Programm angehängt. Und im Moment 
schalte ich auch nur zwischen zwei Funktionen hin und her, ohne vorher 
Stack und Register zu sichern. Das kommt noch. Erstmal zu meinem 
Problem:

Meine Lösung zum Funktion umschalten funktioniert zwar, aber ich finde 
Sie nicht besonders schön. Die Adresse der Funktion schreibe ich vor dem 
ASM-Teil in zwei Byte (Low/High) Variablen, auf die ich dann in ASM 
zugreife.
Kann man nich in ASM direkt auf die Funktionsadresse zugreifen? Ich habe 
dann immer Fehler bekommen (falsche Adressierung oder so...). Kann ich 
auf Elemente der Struktur in ASM zugreifen und dazu Variablen als Index 
benutzen? Dann könnte ich direkt auf den Funktionszeiger in dem 
TaskArray zugreifen.


Danke schonmal für die Hilfe
 Krümel

struct xTask {
  ubyte reg[8];
  ubyte PC;
  ubyte SP;
  ubyte stack[xStackSize];
  xPVoidFunc FuncPointer;
};
struct xTask myTaskList[2];


void func1 ( void ) {
  while (1) {
    P1_DATA = 0x20;
  }
}


void func2 ( void ) {
  while (1) {
    P1_DATA = 0x00;
  }
}

void main (void)
{

  myTaskList[0].FuncPointer = func1;
  myTaskList[1].FuncPointer = func2;
}


void T01_viTmr0(void) interrupt T0INT _naked
{

  // USER CODE BEGIN (T01_IsrTmr0,2)
  TF0 = 0;
  
  xGlobalInt_off;
  if(adrL == (ubyte) myTaskList[0].FuncPointer) {
  
  adrL = (ubyte) myTaskList[1].FuncPointer;
  adrH = (unsigned char) ((unsigned int)myTaskList[1].FuncPointer >> 8);
  
  _asm
    mov dptr, #_adrL
    movx a, @dptr
    push acc
    
    mov dptr, #_adrH
    movx a, @dptr
    push acc
  _endasm;
  
  xGlobalInt_on;
  
  _asm
    reti
  _endasm;
  
  } else {  
  
  adrL = (ubyte) myTaskList[0].FuncPointer;
  adrH = (unsigned char) ((unsigned int)myTaskList[0].FuncPointer >> 8);
  
  _asm
    mov dptr, #_adrL
    movx a, @dptr
    push acc
    
    mov dptr, #_adrH
    movx a, @dptr
    push acc
  _endasm;
  
  xGlobalInt_on;
  
  _asm
    reti
  _endasm;
  
  }
  // USER CODE END

} //  End of function T01_viTmr0

Autor: Tobias Plüss (hubertus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal ne Frage, rein weil mich die Thematik interessiert:
was passiert denn, nun, wenn im Interrupt zum Beispiel func1 aufgerufen 
wird. Dann führt der Prozessor ja die Instruktion P1_DATA = 0x20 aus. 
Und nachher? Nachdem func1 beendet ist muss ja nicht zwingend sofort 
wieder ein Timerinterrupt kommen. Mal angenommen, der Timer tickt alle 1 
ms und func1 dauert 1 us - was macht denn der Prozessor in den 
restlichen 999 us, bis der nächste Timerinterrupt kommt?

Übrigens: Es hängt vom verwendeten Compiler ab, ob du aus dem 
Inline-Assembler auf Variablen und Struktur-Member zugreifen kannst. Bei 
einigen Compilern gehts (bei meinem für nen Freescale 68k klappt das), 
beim SDCC jedoch (den ich z.B. für 8051 verwende) gehts irgendwie nicht. 
Ist also von Compiler zu Compiler unterschiedlich....

Autor: krümel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ganze ist ja nur mal eine Machbarkeitsstudie.
Func1 ist doch eine Dauerschleife, d.h. er macht erstmal die ganze Zeit 
nix anderes als den Pin zu setzen. Danach löscht er ihn die ganze Zeit 
wieder.
Mein Hauptptoblem ist ja der Zugriff auf Arrays oder Strukturen in ASM.

Naja, wenn das nicht anders geht muss ich wohl den Offset vom ersten 
Byte an berechnen (so machts der Compiler zumindest).

Tortzdem Danke
 Krümel

Autor: Tobias Plüss (hubertus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Func1 ist doch eine Dauerschleife

Das sehe ich auch. Aber was ich mich frage ist, ob das auch ohne 
Endlosschleife gehen würde?

Autor: krümel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, das geht natürlich. Ich will ja auch später einen "Idle"-Task 
einführen. Der legt dann entweder den Prozessor schlafen um Energie zu 
sparen oder erledigt Aufgaben, die nicht Zeitkritisch sind.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
krümel wrote:
> Das ganze ist ja nur mal eine Machbarkeitsstudie.

Zwischen machbar und sinnvoll gibt es leider oft große Unterschiede.
Du benutzt den externen Memory, also das LARGE Speichermodell. Damit 
reduziert sich schonmal die Geschwindigkeit drastisch. Und 8051-er ohne 
XDATA kannst Du damit garnicht verwenden.

Der 8051 ist eigentlich für Steuerungsaufgaben optimiert, d.h. daß man 
möglichst alle Variablen im sauschnellen IDATA (max 256 Byte) hält.


Ich benutze den 8051 sehr gerne, weil der sehr viel kann, wenn man ihn 
richtig programmiert. Ich mache daher alle Tasks in der Mainloop 
hintereinander. Der Trick ist, daß jede Task selber zur Mainloop 
zurückkehrt, wenn sie grad nichts zu tun hat. Damit brauche ich keinen 
Scheduler und bin sauschnell. Außerdem brauche ich nicht die Übergabe 
von Parametern kapseln, da ja immer die aktuelle Task vollen Zugriff 
hat. Es kann also nicht passieren, daß ne andere Task nen 
Mehrbyte-Parameter unterm Hintern wegändert (außer Interrupts).
Natürlich müssen sich dann manche Tasks merken, wo sie weitermachen 
sollen, wenn sie auf ein Ereignis warten.

Klingt natürlich völlig unspannend und einfach und auch Zeit, SRAM und 
Flash sparend diese Lösung, aber dafür funktioniert sie saugut.


Peter


P.S.:
Ich wil auch dem Compiler nicht ins Handwerk pfuschen, weil das oft 
Ärger geben kann. Daher habe ich in nem C-Programm grundsätzlich Null 
Assembler drin. Und damit bin ich immer gut gefahren.
Ich hab auch nicht die Zeit, mich mit dem Compiler-Internas zu 
beschäftigen. Genau deshalb nehme ich ja C, um mir die ganze Low-Level 
Arbeit zu sparen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.