www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem beim Multitasking (ARM Cortex M3)


Autor: sl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich versuche gerade für den LPC1768 Multitasking zu programmiert und nun 
habe ich folgendes Problem:

Ich habe zur Zeit zwei Tasks, eine die nur eine Variable inkrementiert 
und eine Große, die einen Motor steuert und den Wert der Variable aus 
der ersten Task auf dem Display ausgibt. So weit funktioniert alles 
problemlos. Doch sobald ich die erste Task erweitere hängt die ganze 
Software. Ich habe festgestellt, dass die Software dann hängt, wenn ich 
eine lokale Variable verwende:

Funktionierende Funktion:
uint32_t idle_tick = 0;
uint32_t cur_tick;

void idle(void) {

  while(1) {
    idle_tick++;
    cur_tick = tick;
    while((tick-cur_tick) < 2000);
  }
}


Nicht funktionierende Funktion:
uint32_t idle_tick = 0;

void idle(void) {
  uint32_t cur_tick;

  while(1) {
    idle_tick++;
    cur_tick = tick;
    while((tick-cur_tick) < 2000);
  }
}


Code zum Starten der ersten Task:
svc_handler_wrapper:
  ldr  r3, =current_task
  ldr r1, [r3]
  ldr r0, [r1]
  ldmia r0!, {r4-r11}
  msr psp, r0
  orr r14, r14, #0x04
  bx r14


Code zum Taskwechsel:
PendSV_Handler:
   mrs r0, psp
   ldr  r3, =current_task
   ldr  r2, [r3]
   stmdb r0!, {r4-r11}
   str r0, [r2]
   stmdb sp!, {r3, r14}
   bl task_get_current
   ldmia sp!, {r3, r14}
   ldr r1, [r3]
   ldr r0, [r1]
   ldmia r0!, {r4-r11}
   msr psp, r0
   bx r14

Das die Funktion mit lokaler Variable nicht funktioniert kann meines 
Erachtens nicht an der Stackgröße liegen, da ich der Funktion 256 Byte 
als Stack zur Verfügung stelle.
Im Voraus schon einmal danke für die Hilfe.

sl

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
volatile vergessen

Autor: sl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Leider nicht. Ich habe es gerade probiert und es hat nicht geholfen. 
Trotzdem danke für die Hilfe.

sl

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
War auch nur ein Schuss ins Blaue, denn du hast ja vorsichtshalber fast 
alles vom Quellcode weggelassen, was hier relevant ist.

Anders ausgedrückt: Fehler in Zeile 42.

Autor: sl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, dann liefere ich jetzt die anderen relevanten Funktionen noch nach. 
Ich wollte zuerst nicht zu viel posten, um nicht gleich alle im Forum 
abzuschrecken.

Resetfunktion:

stack_t idle_stack[256], main_stack[256];

void ResetHandler(void)
{
    unsigned long *pulSrc, *pulDest;

    //
    // Copy the data segment initializers from flash to SRAM in ROM mode
    //
    pulSrc = &_sidata;
    for(pulDest = &_sdata; pulDest < &_edata; )
    {
        *(pulDest++) = *(pulSrc++);
    }

    //
    // Zero fill the bss segment.
    //
    for(pulDest = &_sbss; pulDest < &_ebss; )
    {
        *(pulDest++) = 0;
    }

    SystemInit();

    task_create(&main_task, "main", main, &main_stack[255], 0, 0);
    task_create(&idle_task, "idle", idle, &idle_stack[255] , 0, 0);
    current_task = &idle_task;
    next_task    = &main_task;

    SysTick_Config(100000);
    
    start_rtos();

    // Should never be reached
    while(1);
}


SysTickHandler:

volatile uint32_t tick = 0;

void SysTick_Handler(void) {
  tick++;
  *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}

Task-Funktionen:

typedef uint32_t stack_t;

typedef struct _task_t{
  volatile stack_t *stack_top;  /* current stack top */
  stack_t *stack;          /* start of the stack */
  struct _task_t *next;
  struct _task_t *pre;
} task_t;

task_t *current_task = (task_t*) 0;
task_t    *next_task = (task_t*) 0;

static stack_t *create_init_stack(stack_t *stack_top, void *code, void *param) {
  *stack_top = INITIAL_XPSR;
  stack_top--;
  *stack_top = ((stack_t)code) |1;  /* PC */
  stack_top--;
  *stack_top = 0;  /* LR */
  stack_top -= 5;  /* R12, R3, R2 and R1. */
  *stack_top = 0/*(stack_t) param*/;  /* R0 */
  stack_top -= 8;  /* R11, R10, R9, R8, R7, R6, R5 and R4. */

  return stack_top;
}

void task_create(task_t *task, const char *name, void *code, stack_t *stack, void *param, uint32_t prio) {
  task->stack = stack;
  task->prio = prio;
  task->stack_top = create_init_stack(stack, code, param);
  current_task = task;
}

void task_get_current(void) {
  task_t *tmp = current_task;
  current_task = next_task;
  next_task = tmp;
}

Main-Task:
int main() {

  uint32_t current_tick;

  dogm_init();

  GPIO1_OUT(0); // Ausgänge zum Steuern der Motordrehrichtung
  GPIO1_OUT(1);

  LPC_PWM1->PR  =   25;      // timer runs at 25 MHz / 5 = 5 MHz
  LPC_PWM1->PC  =   0;      // prescale counter to 0
  LPC_PWM1->TC  =   0;      // reset timer to 0
  LPC_PWM1->MR0 = 100;    // PMW base frequency = 5 MHz / 100 = 50 KHz
  LPC_PWM1->MR1 =  50;      // Match 1
  LPC_PWM1->MCR =   2;      // reset TC on MR0
  LPC_PWM1->PCR = (1<<9);    // enable PWM1 outputs
  LPC_PWM1->LER =  3;    // enable PWM0 - PWM6 match latch (reload)
  LPC_PWM1->TCR =  0x09;    // enable PWM mode and start timer

  GPIO1_SET(0);
  GPIO1_CLR(1);

  while(1) {
    dogm_clear();
    dogm_set_cursor(0);
    dogm_string(itoa(idle_tick, tmp_str, 10));
    GPIO1_SET(0);
    GPIO1_CLR(1);
    current_tick = tick;
    while((tick-current_tick) < 2000);
    GPIO1_CLR(0);
    current_tick = tick;
    while((tick-current_tick) < 1000);
    GPIO1_SET(1);
    current_tick = tick;
    while((tick-current_tick) < 2000);
    GPIO1_SET(0);
    current_tick = tick;
    while((tick-current_tick) < 1000);
  }

  return 0;
}


Ich hoffe der Code ist einigermaßen verständlich. Leider sehen im Moment 
sehen die einzelnen Codeabschnitte noch ziemlich zusammengewürfelt aus.

Jede Task für sich allein funktioniert. Deshalb denke ich, dass der 
Fehler irgendwo im Taskwechsel liegt und dass sich das Problem nur dann 
bemerkbar macht, wenn beide Tasks lokale Variablen verwenden, die auf 
dem Stack abgelegt werden.

sl

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  sl (Gast)

>Ok, dann liefere ich jetzt die anderen relevanten Funktionen noch nach.
>Ich wollte zuerst nicht zu viel posten, um nicht gleich alle im Forum
>abzuschrecken.

Hast du aber. Lies mal was über Netiquette und poste demnächste 
lange Quelltexte als Anhang.

Zu deinem eigentlichen Problem hilft dir ggf. der Artikel 
Multitasking.

MFG
Falk

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jede Variable, die in mehr als einer Task verwendet wird, sollte 
eigentlich volatile sein. So auch idle_tick. Kann dazu führen, dass in 
der Hauptschleife immer der gleiche Wert angezeigt wird - hier aber 
aufgrund der dogm Funktionen vermutlich nicht.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das gilt an sich auch für current_task und next_task. Oftmals 
funktioniert es auch ohne volatile und manche Experten (?) schaffen es, 
dank etwas Glück ein Tasking-System komplett ohne volatile zu 
fabrizieren, allerdings hängt man dann etwas davon ab, wie gross 
Blickwinkel und Fähigkeiten des Compilers sind.

Autor: sl (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@ falk

Ok, die Netiquette hätte ich mir durchlesen sollen. Den Source habe ich 
jetzt in einer kommentierten Version angehängt. Der Artikel zum 
Multitasking hat mir leider nicht weitergeholfen.

@ A.K.

Die anderen Variablen müssen natürlich auch volatile sein, das ist so 
definitive falsch, das Problem behebt es aber nicht.

Ich habe das Ganze jetzt nochmal getestet:

-Wenn ich nur eine Task laufen lasse, funktioniert alles problemlos.
-Wenn ich in beiden Tasks lokale Variablen verwende bleibt das Programm 
stehen, eine Exception tritt allerdings keine auf. Der Prozessor bleibt 
im Threadmode.
-Rufe ich in beiden Tasks Funktionen auf, kommt es zu einer 
Hardfault-Exception.
-Tausche ich die beiden Tasks kommt es zu einer HardFault-Exception.

Ich kann mir das nur dadurch erklären, dass beim Starten der ersten Task 
etwas mit dem Stack schiefgeht. Werden in einer Task nur Register 
verwendet geht es problemlos. Werden aber in beiden Tasks Funktionen 
aufgerufen, der Inhalt der Register also auf dem Stack 
zwischengespeichert, oder lokale Variablen auf dem Stack allokiert, 
kommt es zum Fehler. Also muss der Stack doch das Problem sein, oder? 
Hab ich in der Funktion svc_handler_wrapper (system.asm) irgendeinen 
Fehler übersehen?

Schon mal danke für die Hilfe.

mfg sl

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.