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


von sl (Gast)


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:
1
uint32_t idle_tick = 0;
2
uint32_t cur_tick;
3
4
void idle(void) {
5
6
  while(1) {
7
    idle_tick++;
8
    cur_tick = tick;
9
    while((tick-cur_tick) < 2000);
10
  }
11
}


Nicht funktionierende Funktion:
1
uint32_t idle_tick = 0;
2
3
void idle(void) {
4
  uint32_t cur_tick;
5
6
  while(1) {
7
    idle_tick++;
8
    cur_tick = tick;
9
    while((tick-cur_tick) < 2000);
10
  }
11
}

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


Code zum Taskwechsel:
1
PendSV_Handler:
2
   mrs r0, psp
3
   ldr  r3, =current_task
4
   ldr  r2, [r3]
5
   stmdb r0!, {r4-r11}
6
   str r0, [r2]
7
   stmdb sp!, {r3, r14}
8
   bl task_get_current
9
   ldmia sp!, {r3, r14}
10
   ldr r1, [r3]
11
   ldr r0, [r1]
12
   ldmia r0!, {r4-r11}
13
   msr psp, r0
14
   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

von (prx) A. K. (prx)


Lesenswert?

volatile vergessen

von sl (Gast)


Lesenswert?

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

sl

von (prx) A. K. (prx)


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.

von sl (Gast)


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:
1
stack_t idle_stack[256], main_stack[256];
2
3
void ResetHandler(void)
4
{
5
    unsigned long *pulSrc, *pulDest;
6
7
    //
8
    // Copy the data segment initializers from flash to SRAM in ROM mode
9
    //
10
    pulSrc = &_sidata;
11
    for(pulDest = &_sdata; pulDest < &_edata; )
12
    {
13
        *(pulDest++) = *(pulSrc++);
14
    }
15
16
    //
17
    // Zero fill the bss segment.
18
    //
19
    for(pulDest = &_sbss; pulDest < &_ebss; )
20
    {
21
        *(pulDest++) = 0;
22
    }
23
24
    SystemInit();
25
26
    task_create(&main_task, "main", main, &main_stack[255], 0, 0);
27
    task_create(&idle_task, "idle", idle, &idle_stack[255] , 0, 0);
28
    current_task = &idle_task;
29
    next_task    = &main_task;
30
31
    SysTick_Config(100000);
32
    
33
    start_rtos();
34
35
    // Should never be reached
36
    while(1);
37
}

SysTickHandler:
1
volatile uint32_t tick = 0;
2
3
void SysTick_Handler(void) {
4
  tick++;
5
  *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
6
}

Task-Funktionen:
1
typedef uint32_t stack_t;
2
3
typedef struct _task_t{
4
  volatile stack_t *stack_top;  /* current stack top */
5
  stack_t *stack;          /* start of the stack */
6
  struct _task_t *next;
7
  struct _task_t *pre;
8
} task_t;
9
10
task_t *current_task = (task_t*) 0;
11
task_t    *next_task = (task_t*) 0;
12
13
static stack_t *create_init_stack(stack_t *stack_top, void *code, void *param) {
14
  *stack_top = INITIAL_XPSR;
15
  stack_top--;
16
  *stack_top = ((stack_t)code) |1;  /* PC */
17
  stack_top--;
18
  *stack_top = 0;  /* LR */
19
  stack_top -= 5;  /* R12, R3, R2 and R1. */
20
  *stack_top = 0/*(stack_t) param*/;  /* R0 */
21
  stack_top -= 8;  /* R11, R10, R9, R8, R7, R6, R5 and R4. */
22
23
  return stack_top;
24
}
25
26
void task_create(task_t *task, const char *name, void *code, stack_t *stack, void *param, uint32_t prio) {
27
  task->stack = stack;
28
  task->prio = prio;
29
  task->stack_top = create_init_stack(stack, code, param);
30
  current_task = task;
31
}
32
33
void task_get_current(void) {
34
  task_t *tmp = current_task;
35
  current_task = next_task;
36
  next_task = tmp;
37
}

Main-Task:
1
int main() {
2
3
  uint32_t current_tick;
4
5
  dogm_init();
6
7
  GPIO1_OUT(0); // Ausgänge zum Steuern der Motordrehrichtung
8
  GPIO1_OUT(1);
9
10
  LPC_PWM1->PR  =   25;      // timer runs at 25 MHz / 5 = 5 MHz
11
  LPC_PWM1->PC  =   0;      // prescale counter to 0
12
  LPC_PWM1->TC  =   0;      // reset timer to 0
13
  LPC_PWM1->MR0 = 100;    // PMW base frequency = 5 MHz / 100 = 50 KHz
14
  LPC_PWM1->MR1 =  50;      // Match 1
15
  LPC_PWM1->MCR =   2;      // reset TC on MR0
16
  LPC_PWM1->PCR = (1<<9);    // enable PWM1 outputs
17
  LPC_PWM1->LER =  3;    // enable PWM0 - PWM6 match latch (reload)
18
  LPC_PWM1->TCR =  0x09;    // enable PWM mode and start timer
19
20
  GPIO1_SET(0);
21
  GPIO1_CLR(1);
22
23
  while(1) {
24
    dogm_clear();
25
    dogm_set_cursor(0);
26
    dogm_string(itoa(idle_tick, tmp_str, 10));
27
    GPIO1_SET(0);
28
    GPIO1_CLR(1);
29
    current_tick = tick;
30
    while((tick-current_tick) < 2000);
31
    GPIO1_CLR(0);
32
    current_tick = tick;
33
    while((tick-current_tick) < 1000);
34
    GPIO1_SET(1);
35
    current_tick = tick;
36
    while((tick-current_tick) < 2000);
37
    GPIO1_SET(0);
38
    current_tick = tick;
39
    while((tick-current_tick) < 1000);
40
  }
41
42
  return 0;
43
}

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

von Falk B. (falk)


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

von (prx) A. K. (prx)


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.

von (prx) A. K. (prx)


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.

von sl (Gast)


Angehängte Dateien:

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

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
Noch kein Account? Hier anmelden.