Hallo, Ich versuche aktuell anhand eines Beispiels aus dem "STM32L0xx_Snippets_Package_V1.2.0" meine Hardware zum Laufen zu kriegen und da z.B. erstmal eine PWM zu generieren. Ich habe den Code aus der main.c minimal angepasst. Doch es scheitert an dieser SysTick-Initialisierung. Bis zur while-Schleife kommt der Controller gar nicht, da er im HardFault landet. Wenn ich im Debugging bin, dann wird auch die eine markierte Zeile irgendwie nicht ausgeführt, da man dort keinen Breakpoint erstellen kann. Ich habe eigentlich eine Hardware-Klasse erstellt, in der dann die Funktionen zur Initialisierung sämtlicher Peripherie ausgeführt werden, aber auch der entsprechende Aufruf hatte keine Breakpointmöglichkeit direkt nach SysTick_Config. Für mich echt rätselhaft... Wenn ich Stepover bei der SysTick_Config mache, geht das Programm dann in die ARM-Datei zur entsprechenden Funktion. Der Code dort ist aber ausgegraut, obwohl in der stm32l0xx.h das "#define __Vendor_SysTickConfig 0U" gesetzt ist, dass diese Funktion ja braucht. Wäre euch sehr dankbar, wenn ihr da für Erleuchtung bei mir sorgen könntet. Gruß Hannes
:
Bearbeitet durch User
Poste mal dein ganzes Projekt inklusive *.ioc Datei, dazu noch den Controller und/oder Board, dann lässt sich das einfacher nachvollziehen. Wenn beim Debuggen eine Zeile scheinbar nicht ausgeführt wird liegt es meistens daran dass dein Compiler diese so weg- optimiert hat dass sie nicht separat ausgeführt werden kann. Abhilfe schafft die Optimierungsstufe des Compilierens auf Null zu setzen.
Der angehängte Code entspricht nicht dem Screenshot main_snippet.png. Der arm-gcc hat zum Debugging eine besondere Optimierungsstufe -Og. Das scheint der Stufe -O1 sehr ähnlich zu sein. Mit beiden Varianten kann ich meine Programme weitgehend (nicht 100% jede Zeile) einzeln durch steppen. Probiere beide mal aus. Eventuell bringt dich das Tutorial von Professor Laurent Latorre besser voran. Er verwendet einen F0, der ist aber dem L0 ziemlich ähnlich. https://www.pomad.fr/PoMAD/stm32 Oder meins: http://stefanfrings.de/stm32/stm32l0.html
Also es ist ein STM32L011G4 auf meinem PCB, mit dem ich eine RGB-LED per PWM steuern möchte. Meine IDE ist das CrossStudio von Rowley. Die Optimization hatte ich schon auf "Debugging" und das Level auf 3 gesetzt. Im Debugging seh ich auch, dass nach "init_clocks" die main-Schleife wieder gestartet wird. Wenn ich dass einfach laufen lasse kommt dann irgendwann der HardFault.
Johannes H. schrieb: > Die Optimization hatte ich schon auf "Debugging" und das Level auf 3 > gesetzt. Ich denke, mit "Debugging" bettest du die Debugger Symbole in die elf Datei ein, die Voraussetzung sind dass man überhaupt im C Quelltext debuggen kann. Level 3 ist zu viel zum Debuggen. Da baut der Compiler einiges so stark um, dass der Assembler-Code strukturell nicht mehr mit dem C-Quelltext vergleichbar ist. Nimm wie gesagt Level 1 oder g. Wenn das nicht klappt nimm Level 0. https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
Johannes H. schrieb: > Doch es scheitert an dieser SysTick-Initialisierung. > Bis zur while-Schleife kommt der Controller gar nicht, da er im > HardFault landet. Tja, das kommt davon, wenn man zu viele Symbole in verschiedensten Dateien hat und die dann lustig miteinander verquirlt. Also: zuerst brauchst du einen Interrupt-Handler für den Systick. Und der muß EXAKT namensgleich sein zu dem Defaulthandler im Startupcode. Und dazu brauchst du eben noch eine kleine Initialisierfunktion. Am ehesten ist beides zusammen in einer separaten Quelldatei aufgehoben. Ohne Inline. Hier mal ein Beispiel (war für einen STM32F103):
1 | void __irq SysTick_Handler (void) |
2 | {
|
3 | ...
|
4 | }
|
5 | |
6 | void Systemtick_Init (void) |
7 | { Ticks = iTicks = SecTicks = 0; // diverse Zähler ablöschen |
8 | SYST_RVR = (F_Platform/1000)-1; |
9 | SYST_CSR = 7; |
10 | }
|
Wie man sehen kann, sind die Abhängigkeiten von anderen Quelltexten recht minimiert (Name der ISR, Plattform-Frequenz, Name der HW-Register), so daß Fehler durch nicht zusammenpassende externe Referenzen weniger wahrscheinlich sind. Was die beiden Register RVR und CSR betrifft, die gehören zum Cortex und sind zumeist auch nur in den Unterlagen von ARM dokumentiert. W.S.
Systick Handler ist doch vorhanden. Verwirrend sind nur die zwei Startup Codes. Welche benutzt der Rowley Linker da? Bei weak und C++ muss man auch höllisch aufpassen. Es gibt keine Fehler beim Kompilieren/Linken, die Funktionen werden einfach nicht aufgerufen weil die C++ Funktion anders heißt und dann nicht die weak Funktion ersetzt.
J. S. schrieb: > Verwirrend sind nur die zwei Startup > Codes. Welche benutzt der Rowley Linker da? Normalerweise verlinkt ein Linker genau die Objektdateien, die man ihm angibt. Ich nehme mal an, daß der "Rowley Linker" das ebenfalls tut. Was da noch schief gehen könnte, wäre die Extraktion des eigentlichen Maschinencodes aus dem vom Linker produzierten .ELF File. Beim Keil mit seinem FromElf ist das kein Problem, aber wenn jemand den GCC benutzt, dann kann es durchaus sein, daß man nicht alles an Code erwischt. Hängt von der Namensgebung der Sektionen ab. Obendrein hatte ich damals den Ärger beim GCC und ARM7TDMI, daß Funktionseinsprünge von Funktionen im .thumb Modus als ARM-Labels in den Objektdateien standen, so daß der Linker zwischen Thumb und nochmal Thumb Anpaßcode Thumb-->Arm eingebaut hatte, was natürlich zum sofortigen Absturz führte. Aber wir sind ja inzwischen bei den Cortexen. W.S.
Bei solchen Problemen hilft es immer sehr, sich den Assembler-Code anzuschauen, hier also von der main-Funktion. Und dann auf Assembler-Ebene jede Instruktion einzeln durchgehen und schauen wo es crasht. Dann hat man keine Probleme mit "nicht existentem" Code, weil der Assembler-Code halt genau das ist, was auf dem Controller landet. Johannes H. schrieb: > Bis zur while-Schleife kommt der Controller gar nicht, da er im > HardFault landet. Wie ist denn da der Backtrace? W.S. schrieb: > Tja, das kommt davon, wenn man zu viele Symbole in verschiedensten > Dateien hat und die dann lustig miteinander verquirlt. Man fragt sich, wie komplexe Projekte mit vielen Tausenden Symbolen funktionieren können. W.S. schrieb: > Beim Keil mit > seinem FromElf ist das kein Problem, aber wenn jemand den GCC benutzt, > dann kann es durchaus sein, daß man nicht alles an Code erwischt. Eher unwahrscheinlich, wenn man über den Debugger flasht, denn er weiß genau welche Sections benötigt werden. Außer man hat im Linker-Script die Section-Flags verändert. W.S. schrieb: > Obendrein hatte ich damals den Ärger beim GCC und ARM7TDMI, daß > Funktionseinsprünge von Funktionen im .thumb Modus als ARM-Labels in den > Objektdateien standen, Das passiert nicht wenn man korrekt kompiliert. Bei Assembler muss man Funktionen als solche deklarieren, mit ".type MeineFunction, %function" damit der Assembler weiß dass es kein lokales Sprung-Label ist und daher das Thumb-Bit in der Adresse gesetzt sein muss.
:
Bearbeitet durch User
1 | while( (RCC_CFGR_SWS & RCC_CR_HSIRDY) == 0){ //wait for HSI is ready |
die beiden RCC_* sind doch #defines mit einem Wert ungleich 0? Also wartet er hier nicht und in der zweiten Warteschleife auch nicht. Die Umschaltung funktioniert trotzdem, dafür sorgt die Hardware. Das printf("HERE\n"); wird nicht ausgeführt, die Taktumschaltung passiert in weniger als 1 Sekunde. Also gibt es undefiniertes return from main(). Oder nicht?
Bauform B. schrieb: > die beiden RCC_* sind doch #defines mit einem Wert ungleich 0? Stimmt, die Bedingungen der beiden while-Schleifen machen überhaupt keinen Sinn. Allerdings ist "RCC_CFGR_SWS & RCC_CR_HSIRDY" immer 0, daher macht der Compiler da eine Endlosschleife draus. Die wird dann nur mittels des Timeout unterbrochen, sodass der HSI zwar aktiviert wird, aber die Umschaltung nicht erfolgt. Versuch's mal so:
1 | int init_clocks() |
2 | {
|
3 | uint32_t tickstart; |
4 | tickstart = tick; |
5 | RCC->CR |= RCC_CR_HSION | RCC_CR_HSIDIVEN; //enable HSI and divide by 4 --> 4MHz |
6 | while( (RCC->CR & (RCC_CR_HSIRDY | RCC_CR_HSIDIVF)) != (RCC_CR_HSIRDY | RCC_CR_HSIDIVF)){ //wait for HSI and divider ready |
7 | if( (tick - tickstart) > HSI_TIMEOUT_VALUE ) |
8 | return ERROR_HSI_TIMEOUT; |
9 | }
|
10 | |
11 | tickstart = tick; |
12 | RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW_Msk | RCC_CFGR_HPRE_Msk)) | RCC_CFGR_SW_HSI | RCC_CFGR_HPRE_3 ; //set HSI as sysclock source in sysclock MUX and AHB prescaler to 2 |
13 | while( (RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSI){ //wait for HSI is selected |
14 | if( (tick - tickstart) > HSI_TIMEOUT_VALUE ) |
15 | return ERROR_HSI_TIMEOUT; |
16 | }
|
17 | |
18 | // Optional: Disable MSI to save power
|
19 | RCC->CR &= ~RCC_CR_MSION; |
20 | |
21 | return 0; |
22 | }
|
:
Bearbeitet durch User
@Niklas & Bauform vielen Dank euch fürs genaue Hinschauen! Natürlich lag es daran, dass mein Code den Registerwert gar nicht ausgelesen hat. Düdümm... @Steve mit Debug Level 1 kann ich keine Breakpoints mehr aktivieren. Erst ab Stufe 2 ist das hier möglich obwohl in der Erläuterung "Line Number Debugging..." steht. @J.S. Es ist die "STM32_Startup.s". Ich hatte erst die falsche vom MxCube Code Generator ausgewählt und das zip dann überschrieben. Ich dachte, das wird komplett neu erstellt.
Johannes H. schrieb: > @Steve mit Debug Level 1 kann ich keine Breakpoints mehr aktivieren. > Erst ab Stufe 2 ist das hier möglich obwohl in der Erläuterung "Line > Number Debugging..." steht. OK, das ist wohl nicht der Optimier-Level den ich meinte. Offenbar nutzt deine IDE einen anderen Compiler (als gcc). Der Debug Build müsste dein Problem automatisch lösen (siehe Screenshot). Es gibt eine Einstellung zum Optimiert-Level, die ist vielleicht falsch. Siehe https://www.rowleydownload.co.uk/maxq/documentation/index.htm?https://www.rowleydownload.co.uk/maxq/documentation/hcc_option_optimization_level.htm
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.