Ich bin glaub ich zu doof oder schlicht betriebsblind.
Ich bekomme USART1 auf dem STM32F030F4P6 einfach nicht hin ... und ich
weiß nicht warum.
Gefühlt hab ich die entsprechenden Abschnitte im Datenblatt bereits 20
mal gelesen ...
Als serielle Schnittstellenpins sollen PA9 und PA10 verwendet werden.
Auch die Überlegung, dass die Portpins des Chips hinüber sind (immerhin
hab den 20 pol. SMD Chip auf Adapter gelötet und kann immer was
passieren) glaub ich nicht, weil ich auf den Pins eine LED blinken
lassen kann.
Ich finde hier den Fehler einfach nicht:
Außer dass die Pins PA9 und PA10 permanente High-Pegel (mit Scope
kontrolliert) haben, geschieht nix.
Hardware:
BOOT0 ==> GND
OSC_IN und OSC_OUT ==> offen (kein Quarz)
NRST ==> +3,3V
VDDA ==> +3,3V (mit 47 uF gegen GND)
VDD ==> +3,3V (mit 10 uF gegen GND)
Upload-Tool: Chinaclone ST-Link-V2 oder ST-Link eines Nucleo-Boards
Wäre nett wenn mir auf die Sprünge geholfen werden könnte, im Anhang
alle in der Toolchain verwendeten Dateien.
... ich dachte ich schalte den Clock hiermit ein:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
Bin ich jetzt vollkommen daneben? (Ich werde mir das Startupfile noch
mal ansehen)
Äh, den USART RX möchte man als Input haben. Da ist Push-Pull Output
IMHO falsch.
Der Stack wird im Linker Skript auf 0x20000FFF gesetzt, laut ARM ABI
muss der aber durch 8 teilbar sein, 0x20001000 wäre besser. Das könnte
Dir mit (Hard) Fault aussteigen, lass mal eine LED blinken.
Ich habe im Hard Fault Handler immer eine spezielle LED Blink Sequenz
drin, damit ich Programmierfehler gleich mitbekomme.
... im Hardfault-Handler LED blinken lassen ist gute Idee, das werde ich
machen.
Den Stack im Linker hatte ich absichtlich auf 0x20000fff weil das die
höchste Adresse des Ram's ist... werde ich wieder auf 0x20001000 ändern.
Hmmm, den RX hatte ich ursprünglich auf Input gehabt (und wieder
geändert) weil ich grundsätzlich erst einmal "etwas sehen" wollte, also
erst einmal nur schicken (also Ausgang).
Irgendwie ist der Wurm drin und ich bin knapp dran, mir ein Discovery
oder ein Nucleo-Board mit STM32F0xx zu kaufen um dann mal mit
"offiziellen" Beispielen zu spielen und zu vergleichen.
Grundsätzlich versteh ich aber nicht wo der Hund begraben liegt.
Dennoch vielen Dank, die Idee im Hardfault es blinken zu lassen als
Anzeige dass was falsch läuft ist gut !
Hi,
ich hab leider grade keine Zeit, deinen Code genauer zu studieren, aber
im Anhang findest du mal eine funktionierende UART-Init etc.
Das ganze basiert auf der UART-Lib von hier:
http://mikrocontroller.bplaced.net/wordpress/
Ich hab das notwendige einigermaßen angepasst auf den STM32F0
Inhalt der main():
Uwe Bonnes schrieb:> Wer schaltet die GPIO Clock ein? Vermutlich GPIO_Init(). Dann geht> GPIO_PinAFConfig() zuvor ins Leere...
Falsch
Ralph S. schrieb:> ... ich dachte ich schalte den Clock hiermit ein:>> RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
Richtig
Jim M. schrieb:> Äh, den USART RX möchte man als Input haben. Da ist Push-Pull Output> IMHO falsch.
Irrelevant, da die Ports als Alternate Function konfiguriert werden.
Termi schrieb:> Fehlt wohl noch die SystemInit();
Wird in der Startup.s aufgerufen
Termi schrieb:> ach und eine kleine Pause nach dem senden von 'x' würde ich auch> einbauen.
Braucht es nicht, da auf freien Buffer gewartet wird:
Ralph S. schrieb:> while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
Ich habe mir dein Programm nun eine weile angeschaut, die
Initialisierung passt und es scheint nichts zu fehlen.
Du hast doch einen Debugger. Sag doch mal, was in den USART1-Registern
steht (Adresse 0x40013800 bis 0x4001382B) und in den GPIOA-Registern
(Adresse 0x48000000 bis 0x4800002B). Dann sieht man evtl eine falsche
konfiguration.
Ralph S. schrieb:> Irgendwie ist der Wurm drin und ich bin knapp dran, mir ein Discovery> oder ein Nucleo-Board mit STM32F0xx
Ja, da ist tatsächlich der Wurm drin. Aber nicht im Prozessor, sondern
in deinem Programm.
Ich hab schon so unsäglich oft den Leuten gepredigt, daß sie ihre
verdammten Konfigurationen selber machen sollen und zu diesem Zwecke
die im RefMan genannten Register in gehöriger Weise SELBST setzen
mögen. Aber dann lese ich als Allererstes bei dir
USART_InitStructure.USART_BaudRate = ...
und bin wieder mal ... grmpff. Kannst du das nicht komplett bleiben
lassen??
Hier mal ein Auszug au einem anderen Programm:
1
// erstmal die benötigten Takte einschalten
2
RCC_AHBENR=(1<<17)|// Port A enable
3
(1<<18)|// Port B enable
4
(1<<19)|// Port C enable
5
(1<<20)|// Port D enable
6
(1<<22);// Port F enable
7
8
RCC_APB2ENR=(1<<16)|// TIM15 enable
9
(1<<14)|// USART1 enable
10
1;// Sys Cfgen
11
12
RCC_APB1ENR=(1<<23)|// USB
13
(1<<21)|// I2C1
14
(1<<17)|// USART2 enable
15
(1<<2)|// TIM4 enable
16
(1<<1)|// TIM3 enable
17
1;// TIM2 enable
Jetzt noch ein Auszug, wegen des Takt-Aufsetzens:
1
// USB erstmal passiv schalten
2
GPIOA_BSRR=(1<<15);/* PA15 von Hand auf High setzen wg. Transistor + 1k5 an D+ */
3
4
monitor(1);
5
6
// Takt aufsetzen: System = 72 MHz
7
RCC_CIR=0;// keine Interrupts für PLL usw.
8
RCC_CR=0x83|(1<<16);// Resetwerte, interner 8 MHz RC-Oszi ein und Quarzoszi ein
9
10
while((RCC_CR&2)==0)// warten auf ready vom RC-Oszi
11
{monitor(2);}
12
13
// RCC_CFGR vorläufig setzen
14
RCC_CFGR=(7<<24)|// 7 = PLL:2 an MCO = PA.8 zur Beobachtung per Oszillograf
15
(1<<22);// USBPRES, vermutlich 72MHz/1.5-->48MHz
16
17
// so, eigentlich sollte jetzt der interne 8 MHz RC-Oszi den Takt angeben
18
RCC_CR&=~(1<<24);// PLL aus, um sie einstellen zu können
19
RCC_CFGR2=0;// Clock für ADC aus, Vorteiler für PLL auf 1:1
20
RCC_CFGR3=(1<<22)|// Clock für Timer + UART's auf SysClk Takt
21
(1<<20)|
22
(1<<18)|
23
(1<<16)|
24
1;
25
26
// RCC_CFGR fertig setzen bis auf PLL-Auswahl
27
RCC_CFGR=(1<<16)|// Quarz-Oszi als Input für PLL
28
(4<<11)|// APB2 Vorteiler auf :2 (72-->36 MHz)
29
(4<<8)|// APB1 Vorteiler auf :2 (72-->36 MHz)
30
(0<<17)|// Quarz nicht :2 teilen vor der PLL
31
(4<<18)|// PLL Teiler: 4--> x6, also 12MHz*6-->72MHz
32
(7<<24)|// 7 = PLL:2 an MCO = PA.8 zur Beobachtung
33
(1<<22)|// USBPRES, vermutlich 72MHz/1.5-->48MHz
34
0;
35
36
// warten auf Quarz-Oszillator
37
while(!(RCC_CR&(1<<17)))// warten auf ready vom ext. Quarz-Oszi
38
{monitor(3);}
39
40
// PLL einschalten und warten auf Einschwingen
41
RCC_CR|=(1<<24);// PLL einschalten
42
while(!(RCC_CR&(1<<25)))// warten auf ready von PLL
43
{monitor(4);--i;}
44
45
// wichtig: die nötigen Waitstates einschalten
46
FLASH_ACR=0x32;// 2 Waitstates ab 48 MHz
47
48
// Finale
49
RCC_CFGR=(RCC_CFGR&0xFFFFFF00)|2;// mutig die PLL als Systemtakt einschalten
50
51
monitor(5);
52
53
// Restbedenken: an MCO = PA.8 liegen jetzt 36 MHz an.
54
// Man kann dies jetzt oszillografieren, sollte es aber dann abschalten,
55
// falle es nicht wirklich gebraucht wird
56
// Alternative: MCO erst garnicht einschalten
57
58
}
59
60
/* ende */
Und noch ein Auszug, diesmal vom UART-setup
1
dwordInitSerial1(longbaudrate)/* liefert tatsächliche Baudrate zurück */
So. den Interrupthandler wirst du ja hoffentlich zuwege bringen, ebenso
die Basis-Funktionalität, z der ich hier nur den Header poste - sonst
wird's für den Rest der Welt zu langweilig:
1
externdwordInitSerial1(longbaudrate);/* liefert tatsächliche Baudrate zurück */
externvoidV24TxDone1(void);/* warten bis Sendepuffer geleert ist */
So. Jetzt fang an, es richtig zu machen - und zwar so, daß du weißt, was
tatsächlich abgeht - bei dieser elenden ST-Lib weißt du es nämlich
nicht, was du ganz weit oben bereits deutlich gezeigt hast.
W.S.
W.S. schrieb:> So. Jetzt fang an, es richtig zu machen - und zwar so, daß du weißt, was> tatsächlich abgeht - bei dieser elenden ST-Lib weißt du es nämlich> nicht, was du ganz weit oben bereits deutlich gezeigt hast.
... dann setz ich mich mal hin und wühl mich durch die Register... was
ich eigentlich vermeiden wollte. Hrmpf... (aber letztlich hat der W.S.
Gast wohl recht... und wenn ich überleg wieviel Zeit draufgegangen ist,
hätte ich wohl gleich die Register nehmen sollen)...
Wird aber wohl auch n bissi dauern ...