Forum: Mikrocontroller und Digitale Elektronik STM32: SysTick_Config


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Johannes H. (Firma: Kreatronik) (menschenskind)


Angehängte Dateien:

Lesenswert?

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
von uff basse (Gast)


Lesenswert?

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.

von Stefan F. (stefanus)


Lesenswert?

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

: Bearbeitet durch User
von Johannes H. (Firma: Kreatronik) (menschenskind)


Angehängte Dateien:

Lesenswert?

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.

von Steve van de Grens (roehrmond)


Lesenswert?

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

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

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.

von J. S. (jojos)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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
von Bauform B. (bauformb)


Lesenswert?

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?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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
von ... (Gast)


Lesenswert?

> startet mit HSI

Weil ST es auch so tut.

von Johannes H. (Firma: Kreatronik) (menschenskind)


Angehängte Dateien:

Lesenswert?

@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.

von Stefan F. (stefanus)


Angehängte Dateien:

Lesenswert?

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

: 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.