Ich muss den Thread noch mal nach oben holen, weil ich gerade etwas Zeit gefunden habe mich damit zu beschaeftigen und etwas Rat gebrauchen koennte. :)
Zuerst mal die Probleme hier treten mit verschiedenen Programmen auf. Ich denke daher nicht das sie an einem Programmierfehler in einem bestimmten Programm liegen. Im folgenden betrachten wir aber nur ein Programm!
1 |
int main()
|
2 |
{
|
3 |
SystemInit48HSI(); //Systemclock auf 48Mhz setzen
|
4 |
pwm_init(); //PWM Initialisieren fuer 300khz an PA1 und PA2
|
5 |
uart_write(buffer, 0); //Bullshit, dazu später mehr!
|
6 |
while(1);
|
7 |
}
|
Hier noch mal mein Hardfault handler
1 |
void HardFault_Handler(void)
|
2 |
{
|
3 |
|
4 |
//Port PA2 als Ausgang für LED initialisieren
|
5 |
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA;
|
6 |
GPIOA->CFGLR &= ~(0xf<<(4*2));
|
7 |
GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*2);
|
8 |
|
9 |
//LED blinkt so grob 5x pro Sekunde mit LED an PA2.
|
10 |
volatile int i;
|
11 |
doof:
|
12 |
GPIOA->BSHR = (1<<2); // PA2 = grüne LED auf High setzen
|
13 |
i=100000; while(i-- > 0);
|
14 |
GPIOA->BSHR = (1<<16) | (1<<(16+2)); //grüne LED auf low=aus setzen
|
15 |
i=100000; while(i-- > 0);
|
16 |
goto doof;
|
17 |
|
18 |
|
19 |
}
|
Uebersetze ich das und lade das mit dem Debugger in mein Testboard so passiert das erwartete. Der in pwm_init() initialisierte Timer gibt mir ein PWM/Rechteck an PA1 und PA2 aus. Die CPU selber bleibt in der whileschleife stehen. Alles wie erwartet.
Die Zeile:
uart_write(buffer, 0);
gibt einen Buffer von 0Byte aus. Macht also nix!
Kommentiere ich die aus so wird mein Programm um ein paar hundert Byte kleiner weil der Compiler erkennt das diese Funktionen die dahinter haengen nicht aufgerufen werden. Eine der nicht genutzten Funktionen liegt im Flash-Speicher vor main. Hier mal ein Ausschnitt aus dem mapfile mit uart_write
1 |
*(.text.*)
|
2 |
.text.uart_getFifoSend
|
3 |
0x00000000000000a0 0x2e /tmp/ccvJfodc.ltrans0.ltrans.o
|
4 |
.text.startup.main
|
5 |
0x00000000000000ce 0x216 /tmp/ccvJfodc.ltrans0.ltrans.o
|
6 |
0x00000000000000ce main
|
7 |
.text.USART1_IRQHandler
|
8 |
0x00000000000002e4 0x6c /tmp/ccvJfodc.ltrans0.ltrans.o
|
und hier ohne:
1 |
*(.text.*)
|
2 |
.text.startup.main
|
3 |
0x00000000000000a0 0x1b4 /tmp/ccPdPsYu.ltrans0.ltrans.o
|
4 |
0x00000000000000a0 main
|
5 |
.text.USART1_IRQHandler
|
6 |
0x0000000000000254 0x84 /tmp/ccPdPsYu.ltrans0.ltrans.o
|
Im zweiten Fall bin ich mir ziemlich sicher das mein "main" garnicht mehr aufgerufen wird. Der CH32 wirft einen HardFault und ich sehe meine LED blinken die ich dort im Handler ansteuere.
Auch wenn ich vor der Uartaufruf einen while(1) einfuege funktioniert das Programm nicht mehr. Grund dafuer ist das der Compiler erkennt das uart_write nicht aufgerufen wird und alle ungenutzten Funktionen aus dem Programm wirft. Spiele ich aber etwas mit den Compileroptionen
-flto -ffunction-sections -fdata-sections
Llaesst er den Code drin und das Programm laeuft wieder.
Funktion und Nichtfunktion haengt also davon ab an welcher Stelle main im Programm steht! Das erstaunt mich! Dabei wird main aus dem startupCode aufgerufen:
1 |
//Sprung nach Main
|
2 |
__set_MEPC( (uint32_t)main );
|
3 |
// set mepc to be main as the root app.
|
4 |
asm volatile( "mret\n" );
|
Ich sehe nicht wieso das manchmal gehen soll und wieso manchmal nicht!
Aber es kommt noch besser! All das gesagte gilt immer wenn ich das lauffaehige Programm ueber den angeschlossenen Debugger in die MCU reinlade.
1 |
./minichlink -3w ./template.bin flash -b
|
Dabei ist meine TestPlatine die ganze Zeit am Debuger angeschlossen und wird auch von diesem mit Spannung versorgt. Ziehe ich die Platine ab und steck sie wieder an, oder versorge sie extern mit Spannung, funktioniert das Programm auch nicht mehr richtig. Ich lande dann wieder im Hardfaulthandler!
Ein paar brilliante Ideen wie man da weiter kommt? :)
Vanye