Hi zusammen,
ich versuche im Moment, in Anlehnung an FreeRTOS, einen preemptiven
Scheduler zu erstellen.
Das generelle Vorgehen ist mir klar, nur leider komme ich immer in den
Default Handler anstatt meine Funktion.
Hier mein Code:
1
#include"stm32f4xx.h"
2
3
volatileunsignedlong*StackPointer;
4
5
voidTask1()
6
{
7
staticinti=0;
8
i++;
9
}
10
11
intmain(void)
12
{
13
unsignedlongStack[128];
14
inti;
15
for(i=0;i<=127;i++)
16
{
17
Stack[i]=2;
18
}
19
StackPointer=&Stack[127];
20
/* Set xPSR to an initial value */
21
*StackPointer=(unsignedlong)0x01000000L;
22
StackPointer--;
23
/* Set PC */
24
*StackPointer=(unsignedlong)&Task1;
25
StackPointer--;
26
/* Set LR */
27
*StackPointer=0;
28
/* Space for r12,r3,r2,r1,r0 */
29
StackPointer-=6;
30
/* Set exec return to an initial value, return to thread mode from PSP, non-floating-point */
31
*StackPointer=(unsignedlong)0xFFFFFFFDL;
32
/* Space for r11-r4 */
33
StackPointer-=8;
34
35
__asmvolatile(
36
" ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */
37
" ldr r0, [r0] \n"
38
" ldr r0, [r0] \n"
39
" msr msp, r0 \n"/* Set the msp back to the start of the stack. */
40
" cpsie i \n"/* Globally enable interrupts. */
41
" svc 0 \n"/* System call to start first task. */
42
" nop \n"
43
);
44
45
while(1)
46
{
47
}
48
}
49
50
voidSVC_Handler(void)
51
{
52
__asmvolatile("LDR r0, =StackPointer\n");
53
__asmvolatile("LDR r0, [r0]\n");
54
__asmvolatile("LDMIA r0!, {r4-r11, LR}\n");
55
__asmvolatile("MSR PSP, r0\n");
56
__asmvolatile("ORR lr, lr, #4\n");
57
__asmvolatile("BX lr\n");
58
}
Zum Code:
In dieser Implementierung versuche ich erstmal nur einen Stack irgendwo
aufzusetzen und auf diesen umzuschalten, also den ersten Prozess zu
starten.
In den SVCall gelange ich, die Register R4-R11 werden richtig gepopt und
der LR wird auf 0xFFFFFFFDL gesetzt um vom PSP aus zu starten.
Nun meine Frage: Werden die Register R0-R3,R12 und PC nach dem "BX LR"
nicht wieder hergestellt? Dies kann ich nicht beobachten.
Ich hoffe mir kann jemand helfen.
Wenn man das deklariert:
volatile unsigned long * StackPointer;
Ist es wohl die aller erste Variable im RAM, wohl bei der Adresse
0x20000000.
Nun ein:
StackPointer--
dann ist man bei der Adresse 0x1FFFFFFC
>> Hard Fault Exception.
Hi Markus,
mit StackPointer = &Stack[127];
setze ich den StackPointer zuvor auf einen "gültigen" Bereich
(liegt dann bei 0x200010B0).
Das Setzen der einzelnen Werte in diesen Stack funktioniert und ich kann
es im Debugger Schritt für Schritt nachprüfen. Wie gesagt das popen der
Register aus diesem Stack funktioniert ebenfalls. Erst nach BX LR kommt
es zum Hard Fault.
Btw. die For-Schleife habe ich nur eingebaut um zu prüfen das beim popen
die Register wirklich auf einen anderen Wert gesetzt werden.
Hallo,
Ich programmiere auch gerade einiges im Assembler für den M4.
Der Befehlt BX LR ist ein indirekter jump.
in LR muß dann eine gültige Adresse + 1 (Beim thumb2-Befehlssatz
notwendig) stehen.
Foglich wäre dein Wert 0xFFFFFFFD ja OK, aber laut Datenblatt vom STM
ist dort (0xfffffffc) weder RAM noch FLASH!
Also erfolgt zurecht die exception.
Hallo Fritz,
dieser Code-Snippet ist eine Kopie von FreeRTOS, da scheint es auch zu
klappen.
Im Cortex-M4 Generic User Guide steht zudem:
EXC_RETURN = 0xFFFFFFFD
"Return to Thread mode, exception return uses non-floating-point state
from
the PSP and execution uses PSP after return."
Diesen Wert soll man ins Link-Register setzen, welcher dann beim
Rücksprung ins PC geladen wird. Nun weiß ich nicht ob letzteres wirklich
funktioniert, aber im FreeRTOS ist es genau so implementiert.
Also ich gehe davon aus das der Mikrocontroller weiß das dies keine
Adresse ist, sondern dem Kommando entspricht. So klingt es zumindenst im
User Guide.
Hallo David ich bins nochmal,
Habe mir deinen Code in die Crosswork-IDE geladen und dasselbe Problem
wie du.
Was mir aufgefallen ist, dass du den Stackframe den du am Anfang nach
main
StackPointer = &Stack[127];
/* Set xPSR to an initial value */
*StackPointer = (unsigned long)0x01000000L;
StackPointer--;
/* Set PC */
*StackPointer = (unsigned long)&Task1;
StackPointer--;
/* Set LR */
*StackPointer = 0;
/* Space for r12,r3,r2,r1,r0 */
StackPointer -= 6;
/* Set exec return to an initial value, return to thread mode from
PSP, non-floating-point */
*StackPointer = (unsigned long)0xFFFFFFFDL;
/* Space for r11-r4 */
StackPointer -= 8;
mit
" svc 0 \n" /* System call to start first task. */
zerstörst.
Danach ist die &Task1-Adresse überschrieben.
Hoffe das hilft dir weiter.
Wäre nett wenn du uns weiter informierst.
Hallo Fritz,
vielen Dank für dein Bemühen!
Du hattest Recht. Ich habe mich wohl vom Debugger beirren lassen, da die
Adresse von Task1 trotz svc im Memory Browser hinterlegt war. Ich habe
nun den Stack Array global definiert und jetzt klappt es!
Manchmal sieht man den Wald vor lauter Bäumen nicht... Danke
Fritz schrieb:> Foglich wäre dein Wert 0xFFFFFFFD ja OK, aber laut Datenblatt vom STM> ist dort (0xfffffffc) weder RAM noch FLASH!
Sprungbefehle in diesen Adressbereich haben eine besondere Bedeutung,
nämlich als Exception-Return Befehle.