Forum: Mikrocontroller und Digitale Elektronik Verzweiflung mit LPC, CORTEX M3 und FreeRTOS


von Ludwig S. (big_l)


Lesenswert?

Hallo alle zusammen...

seit einer gefühlten Ewigkeit nun schon versuche ich verzweifelt auf 
einem LPC1549(Cortex M3 von NXP) FreeRTOS zum laufen zu bringen - Es 
will einfach nicht funktionieren:

Dazu einiges zu meinen Fehlern:
Ich verlang ja noch garnicht viel: in meiner main() steht irgendwann der 
Befehl "vTaskStartScheduler" was eigentlich dazu führen sollte das der 
Scheduler einen Idle-TAsk erstellt der damit beschäftigt ist, "idle" zu 
sein.

Wenn ich "vTaskStartScheduler" in der main stehen habe, dann springt 
mein programmzeiger sofort in den hard_fault_handler ohne überhaupt die 
funktion zu erreichen. Wenn ichs dann mal auskommentiere funktioniert 
alles ganz normal: in der main() gehts los und da endet er dann 
irgendwann in einer while(1) schleife...

Ich bin mir ziemlich sicher das die ganze Sache ihren Ursprung in der 
Priorityverteilung in der FreeRTOSCOnfig.h hat. Ehrlich gesagt habe ich 
auch nicht ganz gerafft: so wie ich das verstanden hab ist es bei einem 
cortex prozessor immer gut wenn man in der eben genannten Config für 
configKERNEL_INTERRUPT_PRIORITY den Wert 255 angibt, also die niedrigste 
priorität. Aber was genau bitte gebe ich jetzt 
configMAX_SYSCALL_INTERRUPT_PRIORITY an??? Wie kommt der Kernel 
überhaupt zum SYSTICK Handler und durch welche Bedingungen wird eigtl 
der Hard_FAULT_HANDLER ausgelöst? Welche Interrupts benutzt der Kernel 
überhaupt?

Ich weiß irgendwie nicht weiter... Hier auf Arbeit konnte mir bisher 
auch keiner Helfen

ich bin dankbar für jede noch so kleine hilfe...

von Martin (Gast)


Lesenswert?

Du musst schauen, dass im Startup file der Handler für den SV call auch 
korrekt die Funktion im RTOS aufruft, und nicht ein standard Handler 
aufgerufen wird.

von Ludwig S. (big_l)


Lesenswert?

meinst du die startup file von lpcExpresso? also in meinem fall die 
cr_startup_lpc15xx.c? Also die Handler sind ja da alle definiert...
du sagst DIE rtos funktion... welche denn? Sry wenn ich ein bisschen 
langsam bin...

von Martin (Gast)


Lesenswert?

irgendwo steht sowas wie:

__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMI_Handler               ; NMI Handler
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     MemManage_Handler         ; MPU Fault Handler
                DCD     BusFault_Handler          ; Bus Fault Handler
                DCD     UsageFault_Handler        ; Usage Fault Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVC_Handler               ; SVCall Handler
                DCD     DebugMon_Handler          ; Debug Monitor 
Handler
                DCD     0                         ; Reserved
                DCD     PendSV_Handler            ; PendSV Handler
                DCD     SysTick_Handler           ; SysTick Handler


Anstatt SVC_Handler und PendSV_Handler muss aber irgendwas wie 
"RTOS_SVC..." stehen, falls es nicht schon so ist bei dir

von Martin (Gast)


Lesenswert?

Special note to ARM Cortex-M users: ARM Cortex-M3, ARM Cortex-M4 and ARM 
Cortex-M4F ports need FreeRTOS handlers to be installed on the SysTick, 
PendSV and SVCCall interrupt vectors. The vector table can be populated 
directly with the FreeRTOS defined xPortSysTickHandler(), 
xPortPendSVHandler() and vPortSVCHandler() functions respectively, or, 
if the interrupt vector table is CMSIS compliant, the following three 
lines can be added to FreeRTOSConfig.h to map the FreeRTOS function 
names to their CMSIS equivalents:

#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

von Ludwig S. (big_l)


Lesenswert?

Das hatte ich ja auch schon mal probiert, also das mit den #defines.. 
geht immernoch nicht! Obwohl ich mir gerade die Frage ob ichs vllt 
einfach an der falschen Stelle definiert hatte. Sowie ich 
vTaskSTartScheduler() in der main stehen hab gehts ohne umweg in den 
hard_fault_handler... das spricht doch eigentlich für einen heap bzw 
speicher fehler oder?

von Ludwig S. (big_l)


Lesenswert?

OK ich hab die #defines jetzt in die port.c gepackt und jetzt werde ich 
zwar nicht mehr in den hard_fault_handler geschickt aber dafür wird 
springt der mein programm nach vTaskStartScheduler() weiter... soll 
heißen er erreicht code nach vTaskStartScheduler()... das darf doch 
eigtl garnicht sein - hin oder her das ich noch keinen Task created 
hab... oder irre ich mich

von martin (Gast)


Lesenswert?

ich würde mal einen task erstellen

von Ludwig S. (big_l)


Lesenswert?

Ok es funktioniert jetzt tatsächlich halbwegs! Ich habe einen Task 
erstellt der nix tut bis auf das er in einer while(1) Schleife endet. 
Und siehe da: wenn ich dort einen breakpoint setze, kommt er tatsächlich 
dort an! JIPPIE das is das aufregendste, was die letzten 2 Wochen 
passiert ist.
Leider ist immernoch alles sehr wacklig... manchmal wird 
(komischerweise) der vTaskStartScheduler() mehrere mal aufgerufen bevor 
es in den eigtl Task geht. Ich vermute mal hier wird der Watchdog-Timer 
dazwischen funken... und nach einer weile lande ich dann doch wieder im 
Hard_Fault_Handler. Außerdem funktionert alles auch nur bei bestimmten 
heapx.c dateien. Im Moment bin ich bei Heap1... Bei den Demo-Projekten 
haben alle Heap3.c genommen, aber da lande ich wieder im 
Hard_FAULT_HANDLER...

Also Danke Martin du hast mir schon sehr geholfen! Ich hoffe mir kann 
auch noch auf den letzten paar Metern geholfen werden... Das wär super!

von Jojo S. (Gast)


Lesenswert?

Es gibt doch auch beispielcode für ähnliche CPUs, zB LPC1769, ist das 
nicht ein besserer Einstieg?

von Ludwig S. (big_l)


Lesenswert?

Ja das stimmt. Die hatte ich ja vorher auch schon probiert bzw die Demos 
adaptiert dabei kam aber immer dasselbe heraus. Seitdem Martin das mit 
den #defines erklärt hatte läufts tatsächlich auch schon besser. Ich 
hatte gerade eben nochmal Sachen aus den Demos ausprobiert, allerdings 
bekam ich dabei wieder amoklaufende Programmzeiger...
Irgendwas geht auf jeden Fall noch gehörig schief. Ich hab meine 
FreeRTOSConfig.h soweit runterreduziert, das wirklich absolut keine 
Sonderfunktionen "angeschaltet" sind. Es ist quasi der reine Kernel. 
Aber trotzdem ist bisher immernoch alles die reinstform von 
"undefiniertem Verhalten"
Ich weiß auch immernoch nicht genau, was diese 
configMAX_SYSCALL_INTERRUPT_PRIORITY jetzt genau angibt. Ne Priorität - 
das ist klar! Aber was für eine?
Weiß das zufällig jemand genauer?

von Jojo S. (Gast)


Lesenswert?

Suche mal in den Freertos Quellen nach diesem Define. Da war was mit der 
höchsten die Freertos benutzt und da darf keine andere Rtos Funktion 
ausgeführt werden. Wenn man in diesem Fehler landet auf dem Callstack in 
die aufrufende Funktion gehen, da sind Kommentare im Quelltext zur 
Konfiguration.
Habe die Quellen selber gerade nicht griffbereit.

von Jojo S. (Gast)


Lesenswert?

Beim Heap muss man noch konfigurieren wieviel das Rtos verwalten soll. 
Das wird dann in der heap1/2/3 benutzt. Es darf nur eine von den dreien 
im Projekt aktiv sein, sind halt verschiedene Verwaltungsstrategien und 
man kann hier die optimale wählen. Die Tasks, Queues usw. Holen den 
Speicher über diese Funktionen und Rtos muss deshalb genug haben, es 
gibt auch eine Abfragefunktion dazu.

von Martin (Gast)


Lesenswert?

configMAX_SYSCALL_INTERRUPT_PRIORITY ist dafür da, dass die Interrupts 
nicht global deaktiviert werden sondern nur die RTOS Interrupts.

Der Wert darf nicht 0 sein, da die Priorität 0 nicht deaktiviert werden 
kann beim Cortex.

Du setzt den Wert auf irgendwas zwischen 0xE0 und 0x20. Dein M3 hat drei 
Prioritätsbits, 0bxxx00000. Daher die höhsten drei bits, also 5,6,7 
geben die Priorität an. 0xE0 = 0b11100000 ist die niedrigeste Priorität. 
0b00100000 ist die höchste. 0b00000000 ist noch höher, soll aber nicht 
verwendet werden.

Wenn du jetzt "entercritical" aufrufst, wird das Basepri register auf 
den wert configMAX_SYSCALL_INTERRUPT_PRIORITY gesetzt. Damit werden alle 
Interrupts von RTOS gesperrt, aber andere Interrupts können noch 
ausgeführt werden.

von Ludwig S. (big_l)


Lesenswert?

Alles klar dankeschön! Das hat mich schon sehr viel weitergebracht. 
Leider hat sich im nachhinein herausgestellt dass das Hauptproblem - ich 
trau es mir garnicht zu sagen - ein falsch ausgewählter Chip war 
klatsch

Trotzdem war das schon alles sehr hilfreich. Ich habe mir gedacht das 
ich jetzt einfach mal ein Tutorial hier ins Forum schreibe Beitrag für 
Beitrag... das wäre ja dann auch für andere interessant! Und je nachdem 
was ich dann für quatsch erzhähle und auch richtig schreibe kann man das 
dann hier kommentieren...

von Ludwig S. (big_l)


Lesenswert?

Tutorial Teil 1 - Die Verzeichnisstruktur

Ich erstelle ein Projekt in meiner Entwicklungsumgebung, in diesem Fall 
mit LPCXpress von NXP. Dabei wähle ich ein LPCOpen Projekt, weil keine 
Lust hab mit den Adressen herumzuwirtschaften. Somit übernehme ich die 
Strukturen von den bereitgestellten cmsis Bibliotheken.

Anschließend übernehme ich die Verzeichnis- und Dateistruktur von der 
aktuellsten FreeRTOS Version und intigriere sie in mein Projekt. Im 
Falle meines LPCXpress Projekts erstelle ich mir einen Ordner names 
"FreeRTOS" und entlade dort meine Verzeichnisstruktur (einschließlich 
Dateien die nicht zwangsläufig zum Kernel gehören)

meinProjekt\FreeRTOS\croutine.c
meinProjekt\FreeRTOS\event_groups.c
meinProjekt\FreeRTOS\list.c
meinProjekt\FreeRTOS\queue.c
meinProjekt\FreeRTOS\taks.c
meinProjekt\FreeRTOS\timers.c
meinProjekt\FreeRTOS\include\

Zusätzlich natürlich die Dateien für die Portierung meines benutzten 
Mikrocontrollers, einem NXP LPC1547 mit einem ARM Cortex M3 Prozessor.
Mein Compiler in LPCXpress ist mehr oder weniger ein GCC Compiler 
weswegen ich mich für

FreeRTOS\Source\portable\GCC\ARM_CM3\

entscheide. Den Ordner (samt Inhalt natürlich) übernehme ich mit in mein 
"FREERTOS" Verzeichnis, also:

FreeRTOS\portable\GCC\ARM_CM3\port.c
FreeRTOS\portable\GCC\ARM_CM3\portmacro.h

Alles anderen Ordner im "Source" Ordner kann ich weglassen.

Da ich einem CM3 beackern will, füge ich in der port.c noch

#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

ein, weil dort die Handler für RTOS definiert bzw ersetzt werden.

Da ich am Anfang das OS kennen lernen möchte, versuche ich natürlich 
alles so stabil und einfach wie möglich zu halten. Deswegen hole ich mir 
die

FreeRTOS\Source\portable\MemMang\heap_3.c

Datei, da diese eine einfache Umsetzung von den C-Befehlen malloc() & 
alloc() beinhaltet. (Steht auf jeden Fall so in der Beschreibung) Daher:

meinProjekt\FreeRTOS\portable\MemMang\heap_3.c

die anderen Heap_x.c dateien entfallen.

Als letztes muss ich noch meine FreeRTOSConfig.h Datei in mein 
Projektverzeichnis anlegen. Hierfür habe ich alle defines die #define 
config... losgehen hineingeschrieben und alle die mit #define 
INCLUDE_...
losgehen. In meinem Fall habe ich die aus der FreeRTOS_Reference_Manual 
zusammengetragen, allerdings gibts die auch in den weiten des Internets 
oder sind Bestandteil der mitgelieferten Demos von FreeRTOS.

Dabei verpasse ich den config_KERNEL_INTERRUPT_PRIORITY den Wert 0xE0, 
da dieser das niedrigste Priority Level haben soll.
configMAX_SYSCALL_INTERRUPT_PRIORITY bekommt den Wert 0xC0 da, weil er 
nicht sonderlich hoch sein soll, aber sich auch kein Priority Level mit 
dem Kernel teilen soll.
Für configMINIMAL_STACK_SIZE wähle ich die Größe des Speichers für den 
IdleTask, der gestartet wird nachdem ich (nachher) den Scheduler starte. 
Ich setze ih auf 128, weil ich das für klein halte, ist aber mehr ein 
Schuss ins Blaue als Ahnung von der Materie.
configMAX_PRIORITIES setze ich auf 7(oder 8??), weil ich drei bits zur 
Priority-Verteilung in meinem LPC15 habe.

Dann setze ich noch meinen CPU Takt(configCPU_CLOCK_HZ auf 12000000), 
weil das die default-Einstellung in meinem Prozessor ist. Die 
Tickrate(configTICK_RATE_HZ) setze ich auf 100, in der Hoffnung das ich 
dann alle 10ms einen Tick bekomme!

Dann wäre da noch configTOTAL_HEAP_SIZE auf 10024 zu setzen, eigtl 
unnötig, da für heap_3.c dieser Wert egal ist. Allerdings will ich 
später auch noch andere Heaps auprobieren und setze daher prophylaktisch 
diesen Wert ein. Woher ich den Wert hab? Von einem anderen Demo Board :)

configMAX_TASK_NAME_LEN setze ich auf 16, weil ich bezweifle das ich 
meinen Tasks mehr als 16 Buchstaben geben werde.

Für INCLUDE_vTaskDelay setze ich 1, da ich diese Funktion später in 
meinem Blinky Projekt benutzen möchte.

Alles andere setze ich auf 0, da ich erstmal so wenig wie möglich 
funktionen aktiviert haben möchte, um das Betriebssystem gründlich 
kennen zu lernen.

Wenn die FreeRTOSConfig.h fertig geschrieben ist, muss ich noch in 
meinen Project-Properties dem Compiler den Weg zu den Header-Dateien 
zeigen(Project->Properties->Settings->Includes)

von Jojo S. (Gast)


Lesenswert?

Nochmal zu den heaps: du kannst alle drei übernehmen. Dann die zwei 
nicht aktiven mit der Option 'exclude from build' (irgendwo in dem 
ellenlangen Kontextmenü).
Früher war im LPCXpresso sogar mal ein Wizard drin um ein FreeRTos 
Projekt zu generieren, das ist aber leider früh über Board gegangen.

von Ludwig S. (big_l)


Lesenswert?

Jojo S. schrieb:
> das ist aber leider früh über Board gegangen.

warum eigtl? Ist doch ne praktische Geschichte und wenns erstmal ist, 
warum dann wieder löschen? Das kapier ich nicht.

Aber gut egal, was ich eigtl wissen wollte ist, hier reden immer alle 
von 3 heap-dateien... ich hab aber 5! ist das einfach nur ein 
versionsunterschied oder hat das einen tieferen sinn?
Und was meinst du mit Kontext-Menü? Also du meinst ja bestimmt in einer 
Header Datei...?!

: Bearbeitet durch User
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.