CH32V003 Resetverhalten

#7880662
Lesenswert?

Ich benutze den CH32V003 im SOT8(!) jetzt schon so ein Jahr fuer diverse kleine Spielereien. Bisher hat alles im grossen und ganze so funktioniert wie ich mir das vorstelle. Aber gelegentlich kam es schon mal zu irgendeinem komischen Verhalten und ich hab das Teil dann mit minichlink -u wieder auf die Beine geholfen.

Aktuell hab ich gerade eine kleine Anwendung laufen die nichts anders macht als mit tim1 300khz erzeugen zu lassen und dies an PC4, PA1 und PA2 auszugeben. Das funktioniert auch! Aber erstaunlich oft haengt sich der Controller beim starten weg! Das Programm laeuft dann direkt nach dem flashen wenn es vom debugger gestartet wird, aber nur sehr gelegentlich nach einem Powercycle in meiner Hardware.

Ich wuerde ja sagen irgendwas stimmt mit meiner Resetbeschaltung nicht, aber der SOT8 hat keinen Reseteingang. Ich hab auch schon minichlink mit -d oder -D probiert ohne das ich da eine Besserung sehen wuerde.

Hab ich da was uebersehen?

Vanye

#7881500
Lesenswert?

Ich hab da wohl wirklich einen Bug der Extraklasse in meinem System. :-D

Mein Programm sieht so aus:

int main() { SystemInit48HSI(); //Systemclock auf 48Mhz setzen
pwm_init(); //PWM Initialisieren fuer 300khz an PA1 und PA2
while(1); }

Das funktioniert IMMER wenn ich es vom Debugger in den STM32V003 reinlade. Stoepsel ich den Debugger an und lasse es ueber mein Labornetzteil laufen, so funktionier es meistens nicht. Aber so jedes 30-40x startet es doch und laeuft dann auch! Wenn es nicht läuft dann kommen komische Impulse aus PA2 raus. (siehe Bild) Kommentiere ich SystemInit48HSI() aendert sich nichts am problematischen Startverhalten, aber wenn es geht dann sind natuerlich die Frequenzen anders weil der Systemtakt niedriger ist.

Als ich damals meine Umgebung aufgesetzt habe, da habe ich ch32fun kopiert und als erstes ein einfaches LED-Blink Programm geschrieben. Das zeigt dieses verhalten nicht! Es startet also immer.

Nehme ich das als Basis und änder das auf obiges main ab, so funktioniert es auch immer! Der Timer gibt also die gewuenschten Signale aus.

Danach hab ich damals etwas am "Design" der Umgebung rumgespielt. Also nur die Libaries kopiert die ich brauche, andere Verzeichnisse, Startup verschlankt, usw. Dabei muss ich wohl einen Fehler gemacht haben der mir nicht aufgefallen ist weil es halt immer problemlos funktioniert wenn es ueber den Debugger gestartet wird. Da muss ich wohl noch mal tief in mich gehen und beide Startupcodes genau vergleichen. Vermutlich initialisiert der Debugger irgendetwas das ich selber vergessen habe. Aber bizarr das es manchmal halt doch funktioniert.

Vanye

Angehängte Dateien:
#7882003
Lesenswert?

Harald A. schrieb:

Weiß nicht, ob es das bei diesem Controller auch gibt

Tut es:

1
1.4.4 Power Supply Monitor
2

3
This product integrates a power-on reset (POR)/power-down reset (PDR) 
4
circuit, which is always in working condition to ensure that the 
5
system is in supply. It works when the power exceeds 2.7V; when VDD 
6
is lower than the set threshold (VPOR/PDR), the device is placed in 
7
the reset state without using an external reset circuit.
8

9
In addition, the system is equipped with a programmable voltage 
10
monitor (PVD), which needs to be turned on by software to compare 
11
the voltage of VDD power supply with the set threshold VPVD.
12
Turn on the corresponding edge interrupt of PVD, and you can 
13
receive interrupt notification when VDD drops to the PVD threshold 
14
or rises to the PVD threshold. Refer to Chapter 4 for the values of 
15
VPOR/PDR and VPVD.

(Seite 5 im Datenblatt CH32V003 V1.7)

#7932971
Lesenswert?

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

#7933077
Lesenswert?

Knifflig. Einen "frischen" CH32V003 hast du schon probiert?

Klar. Hab ja genug. Es liegt nicht an einem defekten CH32V003. Ich hab sogar zwei verschiedene Chargen, einmal in SOT8 und einmal in SOT16. Beide identisches Verhalten.

Ich hab gerade mal eine Ausgabe des mcause Register programmiert, dazu schreibe ich gleich noch was im anderen Thread. Ist vielleicht doof das ich das getrennt habe, aber ist vielleicht auch von allgemeineren Interesse wenn man dieses Register auslesen kann.

Jedenfalls fuehrt das nun dazu das der code mit auskommentierten usart_write immer noch laeuft. Aber nicht wenn ich das Teil neu starte. Dann gibt es Hardfault, noch dazu einen sehr merkwuerdigen.

Aber dazu anderer Thread.

Vanye

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren