Hallo,
ich versuche gerade USART2 auf dem Evalboard Nucleo-F401RE zum Laufen zu
bringen. Die LED leuchtet, und wenn ein USART-Interrupt ausgelöst wird,
soll sie ausgehen. Einfach um zu sehen, dass der Sprung in die ISR
funktioniert. Aber sie geht nicht aus, irgendetwas fehlt. Ich habe schon
dutzende howtos durchgelesen, der Code unten ist das Ergebnis. Aber es
will nicht. Wenn ich ein Zeichen schicke, kommt auf der RX-Leitung auch
etwas an, das sehe ich am Oszi.
Tycho B. schrieb:> Manmanman, es ist echt mühsam nach Atmel
Du machst es aber auch ausgesprochen verkompliziert und unleserlich.
Abgesehen davon gehört der ganze Kram in eine searate Handler-Quelle, wo
nur die eigentlichen Benutz-Funktionen herausgucken und wo die beiden
Datenströme gepuffert werden.
Ich hab hier schon des öfteren mal funktionable Handler für serielle
Schnittstellen der diversen STM32Fxxx gepostet, also rate ich dir: such
mal danach.
W.S.
Tycho B. schrieb:> Ich dachte bis jetzt, dass NVIC etwas> von der HAL ist. Manmanman, es ist echt mühsam nach Atmel...
Du kannst ja auch CMSIS verwenden^^ Bare-Metal würde ich bei solchen
Kalibern eh vermeiden :)
Tycho B. schrieb:> NVIC etwas> von der HAL ist.
Nene, nix HAL, das ist sogar Standard für alle Cortex-M.
Ein simples
1
NVIC_EnableIRQ(USART2_IRQn);
sollte dafür sorgen das es läuft. Man könnte auch noch eine
Interrupt-Priorität angeben aber wenn man das nicht macht, läuft der
einfach mit der höchsten Priorität.
Mampf F. schrieb:> Du kannst ja auch CMSIS verwenden^^
Genau diese NVIC_EnableIRQ-Funktion ist ein Bestandteil von CMSIS und
wird über den Header "core_cm4.h" bereitgestellt, der wiederum von
"stm32f4xx.h" eingebunden wird.
Mampf F. schrieb:> Du kannst ja auch CMSIS verwenden^^ Bare-Metal würde ich bei solchen> Kalibern eh vermeiden :)
Er verwendet CMSIS. Und CMSIS ist bare metal.
> solchen Kalibern
Das ist nur ein F401RE, das Manual hat weniger als 1000 Seiten, das UART
Kapitel nur 50.
Und die muss er eh lesen, ob er nun HAL verwendet oder nicht, nur bei
letzterem muss er noch mehr lesen und noch beides unter einen Hut
bringen, bzw das im einen gelesene im anderen wiederfinden. Verdreifacht
den Aufwand.
Bernd K. schrieb:> Er verwendet CMSIS. Und CMSIS ist bare metal.
Ah okay, sorry für den Mist, den ich geschrieben habe :)
Dachte, CMSIS wär schon kein Bare-Metal mehr ... Aber stimmt, die paar
Funktionen die Registerzugriffe wrappen kann man auch nicht als
Middle-Ware ansehen :)
Aber so ganz klar war das dem TE wohl auch nicht, da er ja sogar sowas
wie NVIC_EnableIRQ vermeiden wollte und dachte, das würde bereits zu HAL
gehören :)
Bernd K. schrieb:> Das ist nur ein F401RE
Für mich zählen alle (mir bekannten ARMs) zu den "Kalibern" xD
Christopher J. schrieb:> Tycho B. schrieb:>> NVIC etwas>> von der HAL ist.>> Nene, nix HAL, das ist sogar Standard für alle Cortex-M.>
Klares Jein! S.U.
> Ein simples>>
1
> NVIC_EnableIRQ(USART2_IRQn);
2
>
>> sollte dafür sorgen das es läuft. Man könnte auch noch eine> Interrupt-Priorität angeben aber wenn man das nicht macht, läuft der> einfach mit der höchsten Priorität.>
Nur zur korinthenverdauungsauscheidungsdienenden Klärung (bin mir
sicher, dass Du das weisst): Der NVIC ist zwar Bestandteil des Cortex
Kerns, aber die Anzahl der unterstützten Interruptprioritäten ist
chipabhängig (von 3 bis 8 bit, also 8 bis 255 Prios möglich). Deswegen
ist die NVIC Initialisierung so ein Zwischending zwischen Kernel und
Chip und damit CMSIS und HAL (merkt man z.B. sehr schmerzhaft am
FreeRTOS Portierungslayer bei der Initialisierung der
Prioritätsbarrieren).
Tycho B. schrieb:> volatile uint16_t IIR;
Das muss übrigends nicht volatile sein. Das setzt du ja nur einmal im
Interrupt.
P.S.: Ich würde noch ggf. anmerken immer die Pullups definiert zu
setzen. Die sind nicht immer alle aus. PA_13, PA_14, PA_15 und PB_4 sind
zumindest beim F411 anders beschaltet im reset. Ist jetzt hier
allerdings nicht das Problem.
W.S. schrieb:> Abgesehen davon gehört der ganze Kram in eine searate Handler-Quelle, wo> nur die eigentlichen Benutz-Funktionen herausgucken und wo die beiden> Datenströme gepuffert werden.
ist klar, es ist nur ein Minimalbeispiel, mit dem ich starte
Christopher J. schrieb:> Ein simples> NVIC_EnableIRQ(USART2_IRQn);>> sollte dafür sorgen das es läuft.
Das hat gestern schon nicht funktioniert. Wenn ich die Zeile einsetze,
dann ist die LED aus. Ich dachte, es liegt daran, dass er, warum auch
immer, gleich in die ISR springt. LED_OFF(); in der ISR auskommentiert,
LED bleibt trotzdem aus. Scheinbar hängt er sich auf an dieser Stelle.
Kann einer bestätigen, dass BRR=0x54 mit 84 MHz 1MBaud entspricht?
Vielleicht
0x54 ist korrekt wenn da kein Teiler für APB2 eingestellt wurde.
Aber deswegen sollte er ja nicht nicht in den Interrupt springen. (Kein
Tippfehler, doppelte Verneinung)
Vielleicht testeweise mal das DR pollen? 1MBaud ist auch recht viel. Ich
kam bei meinem Nucleo nicht stabil über 250k.
Ruediger A. schrieb:> die Anzahl der unterstützten Interruptprioritäten ist> chipabhängig (von 3 bis 8 bit, also 8 bis 255 Prios möglich)
Völlig richtig. Deswegen gibt es z.B. auch in der corecm4.h eine dicke
Warnung, falls es nirgendwo ein #define __NVIC_PRIO_BITS gibt. Das muss
der Hersteller setzen, da ARM ja nicht wissen kann wie viele Bits der
Hersteller jetzt implementiert hat. Der ganze sonstige Kram steht in der
corecmX.h, z.B.:
Ruediger A. schrieb:> Deswegen> ist die NVIC Initialisierung so ein Zwischending zwischen Kernel und> Chip und damit CMSIS und HAL (merkt man z.B. sehr schmerzhaft am> FreeRTOS Portierungslayer bei der Initialisierung der> Prioritätsbarrieren).
Von den Innereien von FreeRTOS habe ich absolut null Ahnung und habe das
auf einem STM32 auch noch nie genutzt. Ich kann mir aber nicht erklären
wieso FreeRTOS da zwingend irgendwas aus dem HAL von ST brauchen sollte.
Alles was für FreeRTOS von Bedeutung sein sollte (nämlich die Anzahl der
Prioritätsbits) sollte per #define im CMSIS-Header stehen (stm32f4xx.h
bzw. stm32f401xe.h). Das wiederum heißt natürlich nicht, das ST nicht
seine eigenen NVIC-Funktionen im HAL implementieren kann und es dem
Nutzer nahe legt diese auch zu nutzen, obwohl das eigentlich völlig
unnötig ist, weil der NVIC bis auf die Prioritätsbits innerhalb der
jeweiligen Cortex-M Familie exakt gleich ist und alle nötigen Funktionen
bereits in der corecmX.h drin stehen.
Tycho B. schrieb:> Wenn ich die Zeile einsetze,> dann ist die LED aus. Ich dachte, es liegt daran, dass er, warum auch> immer, gleich in die ISR springt. LED_OFF(); in der ISR auskommentiert,> LED bleibt trotzdem aus. Scheinbar hängt er sich auf an dieser Stelle.
Dazu fallen mir zwei Gründe ein ...
- der Interrupt-Handler existiert nicht. Der ARM springt in einen
Fault-Handler und bleibt dort.
- du verwendest C++ und hast den Handler nicht 'extern "C"' deklariert.
Bei meinen ersten Starts mit dem STM32 hatte ich zum Glück schon einen
Debugger, da war das Problem dann schnell gefunden :)
if((tmpreg&(1<<5))!=0)LED_OFF();//Read data register not empty
in der for-schleife funktioniert auch nicht
(This bit is set by hardware when the content of the RDR shift register
has been transferred to the USART_DR register. An interrupt is generated
if RXNEIE=1 in the USART_CR1 register.)
Mampf F. schrieb:> du verwendest C++ und hast den Handler nicht 'extern "C"' deklariert
Im eclipse-wizzard habe ich c-Projekt ausgewählt.
Christopher J. schrieb:>> Ruediger A. schrieb:>> Deswegen>> ist die NVIC Initialisierung so ein Zwischending zwischen Kernel und>> Chip und damit CMSIS und HAL (merkt man z.B. sehr schmerzhaft am>> FreeRTOS Portierungslayer bei der Initialisierung der>> Prioritätsbarrieren).>> Von den Innereien von FreeRTOS habe ich absolut null Ahnung und habe das> auf einem STM32 auch noch nie genutzt. Ich kann mir aber nicht erklären> wieso FreeRTOS da zwingend irgendwas aus dem HAL von ST brauchen sollte.> Alles was für FreeRTOS von Bedeutung sein sollte (nämlich die Anzahl der> Prioritätsbits) sollte per #define im CMSIS-Header stehen (stm32f4xx.h> bzw. stm32f401xe.h). Das wiederum heißt natürlich nicht, das ST nicht> seine eigenen NVIC-Funktionen im HAL implementieren kann und es dem> Nutzer nahe legt diese auch zu nutzen, obwohl das eigentlich völlig> unnötig ist, weil der NVIC bis auf die Prioritätsbits innerhalb der> jeweiligen Cortex-M Familie exakt gleich ist und alle nötigen Funktionen> bereits in der corecmX.h drin stehen.
Sorry, war missverständlich ausgedrückt. FreeRTOS braucht weder HAL noch
CMSIS. Der Fall FreeRTOS sollte nur demonstrieren, wie die
Zwischenstellung der NVIC zwischen Kern und Chip Falltüren bereiten
kann. FreeRTOS setzt eine Barriere zwischen den Interruptprioritäten,
unterhalb derer Interrupthandler Systemfunktionen benutzen dürfen;
ausserdem müssen für den SysTick ISR und den SysCall ISR Prioritäten
vergeben werden (i.d. Regel lowest). Daraus und der variablen Shiftgröße
zwischen FreeRTOS IRQ Prioritäten und Cortex Prioritäten ergeben sich
eine Menge subtiler Möglichkeiten, das System falsch aufzusetzen.
Details sind aber etwas zu OT here.
Sorry und danke fürs Nachhaken, dieser Subthread darf nun gerne zu
gunsten des Originalanliegens vom TO abgeschlossen werden!
Tycho B. schrieb:> USART2->BRR=0x54; // 1MBaud
Die letzten vier Bits im BRR sind Nachkommastellen. Wenn du durch 84
teilen willst solltest du
USART2->BRR = (0x54 << 4);
nehmen. So bist du um den Faktor 16 zu schnell, also in etwa bei 16
MBaud :D
Christopher J. schrieb:> Wenn du durch 84> teilen willst
USART_DIV=f_ck/(Baud*8*2) wenn OVER8 Null ist
Für eine Baudrate von 1 MBaud ist USART_DIV=5,25
Daraus ergibt sich Mantissa=5
Fraction=16*0,25=4
also USART_BRR=0x54
so habe ich mir das hergelitten.
Dass 0x54 gerade 0d84 ist, ist Zufall.
Tycho B. schrieb:> Christopher J. schrieb:>> Wenn du durch 84>> teilen willst>> USART_DIV=f_ck/(Baud*8*2) wenn OVER8 Null ist> Für eine Baudrate von 1 MBaud ist USART_DIV=5,25> Daraus ergibt sich Mantissa=5> Fraction=16*0,25=4> also USART_BRR=0x54> so habe ich mir das hergelitten.>> Dass 0x54 gerade 0d84 ist, ist Zufall.
Du hast natürlich recht. Was ich geschrieben habe ist Schwachsinn.
Geistige Umnachtung meinerseits...
Habe es gerade mal ausprobiert und bei mir lande ich im
USART2_IRQHandler, wenn ich das __enable_irq(); durch ein
NVIC_EnableIRQ(USART2_IRQn); ersetze.
__enable_irq() und __disable_irq() sind lediglich funktionen, die global
interrupts sperren, bzw. diese Sperre aufheben. Wohl so ein bisschen wie
bei AVR mit sei() und cli().
Christopher J. schrieb:> Habe es gerade mal ausprobiert und bei mir lande ich im> USART2_IRQHandler, wenn ich das __enable_irq(); durch ein> NVIC_EnableIRQ(USART2_IRQn); ersetze.
Hast du etwas in der startup_stm32.s etwas eigetragen?
So was wie
.word USART2_IRQHandler
an der Stelle für den Interrupt 38, also mitten zwischen den ganzen
.word 0
und für NVIC_EnableIRQ(USART2_IRQn); brauch ich noch
#include <core_cm4.h>
richtig?
Nico W. schrieb:> War schon ganz verwirrt. Hab nochmal meinen Code rausgesucht. Wenn OVER8> aus ist, sollte 0x54 korrekt sein.
Habe mir das Oszi-Signal dekodieren lassen bei einer '0', wenn ich also
USART2->DR='0' belade. Er erkennt eine Bitrate von 190,623 kbit/s. 1Mbit
mit 0x54 stimmt also auch irgendwie nicht.
das ist putzig, habe system_stm32f4xx.h eingebunden, aber die
system_stm32f4xx.c nicht dazugelegt. nirgends gabs Gemeckere. Jetzt
finde ich heraus, dass die SystemInit(), die aus startup_stm32.s
gestartet wird, hier definiert ist. Super. Eingebunden, PLL_M von 25 auf
16 geändert, kompiliert, juhu, jetzt ist die Baudrate 250.000, also
immer noch Faktor 4 zuwenig. Aber immerhin. Ich sehe zwar nun 12 Errors
in der system_stm32f4xx.c, aber es lässt sich alles kompilieren und
ausführen. Ach ja, die Fehler tauchen nur auf wenn man auf die Datei
system_stm32f4xx.c in Eclipse klickt. Sonst ist alles wunderbar und
keine Fehler. So wünscht man sich eine Entwicklungsumgebung.
Ja, ich weiss, dass ist ein ziemlich idiotischer Fehler meinerseits,
aber dass der Linker nichts sagt, naja, so was wie "deklaration
gefunden, definition nicht" oder so
Nun, anscheinend fehlt etwas:
Field 'VTOR' could not be resolved
Im AVR Studio war nur #include "avr/interrupt.h" notwendig. Wie soll ich
jetzt rauskriegen was da noch fehlt?
Tycho B. schrieb:> ist klar, es ist nur ein Minimalbeispiel, mit dem ich starteTycho B. schrieb:> das ist putzig, habe system_stm32f4xx.h eingebunden, aber die> system_stm32f4xx.c nicht dazugelegt. nirgends gabs Gemeckere.
Jaja. Du hast herumprobiert, aber du weißt noch immer nicht, was du
eigentlich getan hast.
Nochmal mein Rat:
Halte den Umfang der möglichen Verwirrungen so klein wie möglich.
Also wenn du nicht wirklich ganz genau weißt, was du da so alles "mal
eben" einbindest und was du in dessen Folge dann in dein Projekt
hineinkriegst, dann unterlasse all solche Einbindungen.
Das Gleiche gilt für das Verwenden irgend welcher IDE's. Meine Erfahrung
ist, daß eigentlich alle IDE's sehr dazu neigen, in völlig falsch
verstandener Vorsorglichkeit einem alle möglichen Dinge wie
Kommandozeilenparameter, Includefiles, eigene Startupcodes und mehr
unterzujubeln, so daß man bei nicht funktionierender Firmware sich erst
mal nach der tatsächlichen Ursache totsuchen muß. Auch aus diesem Grunde
bestehen meine Projekte aus einer Batchdatei, wo alle Aufrufe von
Compiler, Assembler, Linker usw. dediziert drinstehen - eben damit mit
keine IDE unerwünscht dazwischen kommt.
Und wenn du denn schon irgenwelches Zeugs einbinden willst, dann schau
dir an, was dieses Zeugs klammheimlich hinter sich her reinzieht.
Und nochwas: Solche bescheuerten "Minimalbeispiele" solltest du dir
verkneifen. Setz dich lieber mit nem Stück Papier hin und skizziere dir
dort einen richtigen Treiber und dessen Schnittstelle(n) zum aufrufenden
Programm hin. Das ist ein Stückchen Strategie, was sich allemal lohnt.
genial drauflos zu tippen, ist hingegen Murks.
W.S.
W.S. schrieb:> Und nochwas: Solche bescheuerten "Minimalbeispiele" solltest du dir> verkneifen. Setz dich lieber mit nem Stück Papier hin und skizziere dir> dort einen richtigen Treiber und dessen Schnittstelle(n) zum aufrufenden> Programm hin. Das ist ein Stückchen Strategie, was sich allemal lohnt.> genial drauflos zu tippen, ist hingegen Murks.>> W.S.
+1
W.S. schrieb:> Das Gleiche gilt für das Verwenden irgend welcher IDE's. Meine Erfahrung> ist, daß eigentlich alle IDE's sehr dazu neigen, in völlig falsch> verstandener Vorsorglichkeit einem alle möglichen Dinge wie> Kommandozeilenparameter, Includefiles, eigene Startupcodes und mehr> unterzujubeln
Das gilt leider auch ganz besonders für das "GNU ARM Eclipse Plugin",
falls du dieses verwenden solltest. Völlige Obfuskation des
Build-Systems, was leider geradezu nach Problemen schreit.
Ein minimales Makefile-Projekt mit funktionierender HSI-Konfiguration
für ein Nucleo-F401 findest du z.B. hier:
https://github.com/prof7bit/bare_metal_stm32f401xe
Wenn du den MCO-Ausgang des ST-Link als HSE nutzen willst, dann kannst
du dir mal die SystemInit hier anschauen (HSE Konfiguration im
Bypass-Mode):
https://github.com/ChristianRinn/bare_metal_stm32f411xe/blob/master/src/STM32F411XE/gcc_startup_system.c#L60
Letzteres ist zwar für ein Nucleo F411 aber es sollte eins zu eins
übertragbar sein.
W.S. schrieb:> Und nochwas: Solche bescheuerten "Minimalbeispiele" solltest du dir> verkneifen. Setz dich lieber mit nem Stück Papier hin und skizziere dir> dort einen richtigen Treiber und dessen Schnittstelle(n) zum aufrufenden> Programm hin. Das ist ein Stückchen Strategie, was sich allemal lohnt.> genial drauflos zu tippen, ist hingegen Murks.
Diesen Ratschlag kann ich so nicht annehmen. Ich weiß ganz genau wie der
Treiber aussehen wird, wie ich ihn programmiere, welche sind die
Schnittstellen usw. Danke der Fürsorge. Wenn ich aber von einem 1284p
komme, und auf ein völlig neues System umsteige, dann fange ich an mit
einem blinky.c. Und dann schaue ich zu, dass ich Interrupts aktivieren
kann, und diese auch angesprungen werden. Und erst dann fange ich an
irgendetwas zu programmieren. Das geht quasi nicht anders, und du machst
es genau so, bin ich mir sicher. Der große Plan in allen Ehren, wenn ich
aber nicht schaffe, dass die ISR feuert, dann ist Schluss. So einfach
ist das.
Wie gesagt, bei 1284p war es interrupt.h, nichts weiter. Ich habe mir
für den STM32 die freie Umgebung, die auch wohl vom Hersteller
unterstützt wird, runtergeladen und installiert, System Workbench nennt
sich die. Dann den wizzard gestartet, c-Projekt, mein Eval-Board
ausgewählt. Ich möchte hardwarenahe programmieren, also rumgestöbert,
#include <stm32f4xx.h> brauche ich, ok. Ich dachte es ist so ähnlich wie
interrupt.h. In den Ordner inc reinkopiert. Jetzt will die
#include "core_cm4.h"
#include "system_stm32f4xx.h"
#include <stdint.h>
hm, bläht sich ja auf dachte ich, aber ok, die fehlenden in inc
reinkopiert. Überall nach beispielen für LED blinken gesucht - gefunden,
auch verstanden, ok, blinkt. Irgendwo gelesen, dass der virtuelle
com-Port als usart2 vorhanden ist, super. Komplettes Protokoll mit ISRs
auf dem 1284 läuft ja schon, muss ich portieren. Nach Beispielen für
ISRs gesucht, deutlich schwieriger, viele Umgebungen, CMSIS, HAL,
verschiedene Evalboards F1, F3, F4. Irgend ein Beispiel gefunden,
verstanden, probiert. Funktioniert nicht. Wie ich es probiert habe steht
weiter oben. Und dann dieser CUBE-Scheiss, wollte ich nicht, aber was
solls, vielleicht kann ich da was rausziehen. Installiert, projekt
kreiert, files erstellt. Maaan, das ist ja Wahnsinn was da an overhead
produziert wird! Versucht durch die Funktionen mich durchzuklicken, um
die richtige Reihenfolge und die nötigen Registerzugriffe
rauszubekommen, eingesetzt, funktioniert nicht.
Was ist jetzt falsch an diesem Vorgehen? Was soll ich mir auf Papier
nochmal aufmalen, wenn die ISR nicht angesprungen wird?
PS. Dass Minimalbeispiele bescheuert sind höre ich zum ersten Mal.
// warten auf Bestätigung, dass SYSCLK auf HSI läuft
17
while((RCC->CFGR&0x0000000C)!=0);
18
19
// Bits 0 bis 2 "freiräumen"
20
FLASH->ACR&=0xFFFFFFF8;
21
22
// 2 Wait States konfigurieren
23
FLASH->ACR|=0x00000002;
24
25
// AHB-Prescaler auf 1 (prescaler off)
26
RCC->CFGR&=0xFFFFFF0F;
27
28
// Bits 10 bis 15 "freiräumen"
29
RCC->CFGR&=0xFFFF03FF;
30
31
// Bits 10 bis 12 auf 100 und Bits 13 bis 15 auf 000
32
//APB1/2 und APB2/1
33
RCC->CFGR|=0x00001000;
34
35
// PLL und PLLI2S ausschalten
36
RCC->CR&=0xFAFFFFFF;
37
38
// Bits 0 bis 5 "freiräumen"
39
RCC->PLLCFGR&=0xFFFFFFC0;
40
41
// Bits 0 bis 5 auf den passenden Prescaler einstellen (binär)
42
//F_HSI ist 16000000L
43
RCC->PLLCFGR|=(F_HSI/2000000L)&0x0000003F;
44
45
// Bits 6 bis 14 sowie Bits 16 und 17 "freiräumen" -> implizit P = 2
46
RCC->PLLCFGR&=0xFFFC803F;
47
48
// N = 168 setzen in Bits 6 bis 14
49
RCC->PLLCFGR|=(168L<<6)&0x00007FC0;
50
51
// Bits 24 bis 27 "freiräumen"
52
RCC->PLLCFGR&=0xF0FFFFFF;
53
54
// Wert Q = 7 in Bits 24 bis 27
55
RCC->PLLCFGR|=0x07000000;
56
57
// HSI über Bit 16 in RCC_CR einschalten
58
RCC->CR|=0x00000001;
59
60
// Warten bis HSI an ist
61
while((RCC->CR&0x00000002)==0);
62
63
// PLL-Modul über Bit 24 einschalten
64
RCC->CR|=0x01000000;
65
66
// Warten bis PLL stabil (Bit 25)
67
while((RCC->CR&0x02000000)==0);
68
69
// PLL als Taktquelle für SYSCLK auswählen (10 in Bits 0 und 1 des RCC_CFGR)
70
RCC->CFGR&=0xFFFFFFFC;// "freiräumen"
71
RCC->CFGR|=0x00000002;// "10" schreiben
72
73
// warten bis die SYSCLK umgestellt ist (Bits 2 und 3 müssen 10 werden)
74
while((RCC->CFGR&0x0000000C)!=0x00000008);
75
}
Damit messe ich eine Baudrate von 500k, Faktor 2 zuwenig. Es liegt wohl
daran, dass USART2 am APB1-Bus hängt, und dieser läuft mit der halben
Frequenz. Für die Berechnung von USART_DIV=f_ck/(Baud*8*2) muss für f_ck
42MHz genommen werden. (BRR=0x2A)
P müsste afaik auf 4 stehen für 84MHz.
Also:
16MHz / 8 = 2MHz (HSI / M)
2MHz * 168 = 336MHz (HSI / M * N)
336MHz / 4 = 84MHz (HSI / M * N / P)
Das gepostete Beispiel läuft auf 168MHz.
Ok, Interrupt läuft und sendet, allerdings wie oben geschrieben mit
500k.
Um den Takt zu testen ist mir nichts besseres eingefallen, als
LED_ON();
LED_OFF();
mit dem Oszi aufzunehmen.
Das Resultat ist ziemlich langsam, 4MHz oder so. Das verstehe ich nicht.
Jemand eine Idee?
Tycho B. schrieb:> Ich habe mir> für den STM32 die freie Umgebung, die auch wohl vom Hersteller> unterstützt wird, runtergeladen und installiert, System Workbench nennt> sich die. Dann den wizzard gestartet, c-Projekt, mein Eval-Board> ausgewählt. Ich möchte hardwarenahe programmieren, also rumgestöbert,> #include <stm32f4xx.h> brauche ich, ok. Ich dachte es ist so ähnlich wie> interrupt.h. In den Ordner inc reinkopiert. Jetzt will die> #include "core_cm4.h"> #include "system_stm32f4xx.h"> #include <stdint.h>> hm, bläht sich ja auf dachte ich, aber ok, die fehlenden in inc> reinkopiert. Überall nach beispielen für LED blinken gesucht - gefunden,> auch verstanden, ok, blinkt.
Deine Herangehensweise ist der meinigen diametral entgegengesetzt.
Wie man auf deine Weise zu einer sauberen Firmware kommen kann, ist mir
schleierhaft.
Also: Wie ich an sowas rangehe:
1. Falls vorhanden, die "zielchip".h anschauen, ob die mir ausreichend
gefällt. Wenn nicht, dann editiere ich sie, um mißfälliges Zeugs
rauszuschmeißen oder ich mache mir selber eine anhand des RefMan's. Hier
gibt es zwar jemanden, der alle, die nicht klaglos das Zeugs fressen,
was ihnen vorgeworfen wird, zu Idioten erklärt, die "nicht alle Tassen
im Schrank haben", aber mit solchen Kindereien kann ich leben.
2. Ich mache mir nen zum Chippassenden Startupcode, zumeist besteht das
Ganze darin, die Interrupt-Vektoren zu überprüfen und die RAM-Bereiche
passend zu setzen.
3. Dann sehe ich zu, mir einen Konfigurations-Unit zu machen, wo ich
sowohl den Takt, als auch die Pins und die Taktversorgung der
Peripherie-Cores aufsetze. Ist eben chip- und applikations-abhängig.
4. Dann sollte der Chip erstmal loslaufen und wo es nen benutzbaren
U(S)ART gibt, mache ich mir nen passenden Treiber dazu, das läuft
ebenfalls auf das dezente Modifizieren eines bereits im Portfolio
befindlichen Treibers hinaus.
UND:
Ab da kann man mit dem Chip kommunizieren und der Grundstock ist gelegt.
Aber hier und da ein #include mal probehalber setzen oder "überall nach
Beispielen" suchen - das ist schlichtweg Obermurks.
Wenn du Erfolg haben willst, dann gewöhne dich um und gehe deine Sachen
systematisch an.
W.S.
Tycho B. schrieb:> Um den Takt zu testen ist mir nichts besseres eingefallen, als> LED_ON();> LED_OFF();> mit dem Oszi aufzunehmen.> Das Resultat ist ziemlich langsam, 4MHz oder so. Das verstehe ich nicht.> Jemand eine Idee?
Dass funktioniert beim STM auch schlecht. Der Zugriff auf den Port muss
durch verschiedene Clock-Crossings und über verschiedene Busse. Das
dauert alles seine Zeit. Zudem weiß man nie, wie der Compiler/der
Prozessor selbst bestimmte Dinge abläuft. Da kommt selten was
brauchbares raus.
Dieses "Ich setze ein bit" und 1 Takt später isses am Ausgang
funktioniert so nur bei kleinen Controllern wie den AVRs
Als ersten Schnelltest konfiguriere den Systick, mach einen Blinker im
Sekundentakt. Wenn der langsamer als 1 mal pro Sekunde blinkt ist
schonmal was faul. Dann konfiguriere den UART mit den aus dem Manual
errechneten Baudratenteilerwerten und sende 0x55. Wenn die gemessene
Baudrate nicht stimmt ist entweder Deine Rechnung falsch oder in Deiner
Taktkonfiguration ist noch irgendwo der Wurm drin.
Bernd K. schrieb:> Als ersten Schnelltest konfiguriere den Systick, mach einen Blinker im> Sekundentakt.
Ok, kriege einen Puls von 2 ms anstelle von 1 ms, dh. 42 MHz. Schon drei
mal die Settings durchgegangen, auch mit Cube Projekt erstellt,
Konfiguration siehe oben, Punkt für Punkt diesen Wahnsinn durchgegangen.
Ohne Erfolg, ich schreibe dieselben Werte in die Register wie Cube (aber
nicht in der Reihenfolge).
@Tyco B.
Wie du an deinen Fragen selbst sehen kannst, mag deine Vorgehensweise
für AVRs halbwegs passen aber für "modernere" Controller driftet das
eher ab richtung "übles Bastlerniveau". Profis arbeiten wesentlich
systematischer. Im Datenblatt / RefMan das betreffende Kapitel lesen,
verstehen, implementieren, debuggen, testen, fertig. Was genau ist so
schwer daran???
Statt dessen spielst du mit dem Cube rum... Das ist von ST für die -
nennen wir sie mal semi-Programmierer Informatiker Bastler -
gedacht.
Kleines Beispiel: schon mal das "clock tree" angeschaut??? Falls ja, so
sollte sich deine "Faktor 2 -Frage" schnell erledigt haben. Alternativ:
ein Profi nimmt auch mal ein MCO-Ausgang und misst einfach nach was auf
dem Chip passiert...
AVRs sind tolle Mikrocontroller, keine Frage. Aber gerade die
"AVR-Profis" fallen hier oft auf durch Ignoranz und mangelnde
Bereitschaft die Doku durchzulesen bzw. es zu verstehen. Statt dessen
wird gerne gefragt (und nach Kräften gebastelt) aber die Antworten
werden dann nach eigenem Gusto verworfen, falls diese nicht dem eigenen
AVR-fixiertem Weltbild entsprechen (siehe z.B. die Reaktion aus die
Antwort von W.S. weiter oben).
Tycho B. schrieb:> Diesen Ratschlag kann ich so nicht annehmen. Ich weiß ganz genau wie der> Treiber aussehen wird, wie ich ihn programmiere, welche sind die> Schnittstellen usw. Danke der Fürsorge. Wenn ich aber von einem 1284p> komme, und auf ein völlig neues System umsteige, dann fange ich an mit> einem blinky.c. Und dann schaue ich zu, dass ich Interrupts aktivieren> kann, und diese auch angesprungen werden. Und erst dann fange ich an> irgendetwas zu programmieren. Das geht quasi nicht anders, und du machst> es genau so, bin ich mir sicher. Der große Plan in allen Ehren, wenn ich> aber nicht schaffe, dass die ISR feuert, dann ist Schluss. So einfach> ist das.
Sorry, aber das ist bullshit. Kommt vermutlich aus der Zeit, als noch
die Bastler keinen Debugger kannten, sondern alles mit ISP auf den
Controller geschmissen haben. Wenn es nicht funktioniert hat, so hat man
am Code rumgeändert bis es funktionierte. (Mir ist bis heute ein Rätsel,
weshalb JTAG nie von den Bastern angenommen wurde, das hatte sogar schon
der olle Mega32.)
Beim STM32 hast du SWD/JTAG und einige Spezialregister (z.B. DBGMCU) zum
Debuggen. Lerne sie kennen und nutze sie. Damit erledigt sich dein
"Blinky" von ganz alleine (Englischkenntnisse, Fachwissen und
Beherrschung von C vorausgesetzt).
Ich habe vergessen das 22te Bit PLLSRC in RCC->PLLCFGR zu löschen, damit
war HSE Oszillator als Eingang ausgewählt, welcher mit dem ST-Link-Takt
von 8 MHz verbunden ist.
Hartmut D. schrieb:> (Mir ist bis heute ein Rätsel,> weshalb JTAG nie von den Bastern angenommen wurde, das hatte sogar schon> der olle Mega32.)
Nee, mir ist das durchaus kein Rätsel.
Kennst du noch den ollen 'Wiggler'? Das war zwar eine billige Lösung,
aber dennoch eine einzige Katastrophe. Hat nie zuverlässig geklappt.
Die Alternative wäre gewesen, sich einen stink-überteuerten richtigen
JTAG-Adapter zu kaufen. Lauterbach oder Hitex (Tantino oder so ähnlich)
und Konsorten.
Kurzum, für JTAG gab es nie etwas, das man sich als Bastler mal eben so
leisten konnte. Und auch heutzutage sieht es damit mau aus, wenn man mal
die Vollversionen der einschlägigen Hersteller anguckt. Da sind Preise
in der 400..700€ Region durchaus üblich. Jaja, der JLink-Edu oder die
diversen XYZLink-OB sind heutzutage endlich da, auch die Dinger vom
Chinesen. Aber das war vor 15 oder 20 Jahren überhaupt nicht so.
W.S.
Angeblich waren die Dragons zwar empfindlich (wobei meine erste und
einzige nach ca. 10 AVR-Projekten immernoch einwandfrei funktioniert
ohne jegliche externe Schutzbeschaltung o.ä.) aber relativ günstig
verfügbar. Meinen hatte ich damals bei Schukat geholt für 36,50 EUR (mit
MwSt. und Lieferung waren es dann 43,44 EUR.) War OK und man konnte
damit arbeiten.
Wie ist es eigentlich mit input capture Eingang im TimerX, z.B. Timer2
channel 1. Wenn ich im DM00096844 Abb. 17 mir anschaue, dann kann man
jeden Eingang auf die alternate function AF1 mappen. Im Cube wizzard ist
es für Timer2_CH1 nur PA0, PA5 und PA15.
Tycho B. schrieb:> dann kann man> jeden Eingang auf die alternate function AF1 mappen.
Nein, das steht dort nicht. Dort steht, dass für man für jeden Pin die
AF1-x im Register aktivieren kann. Welche AF auf den jeweiligen Pin
liegen steht im Datenblatt, nicht im RefMan.
Noch eine Verständnisfrage: Wenn ich UART2 ohne Flusskontrolle benutze,
sind dann die Pins CTS (Pin A0) und RTS trotzdem belegt und können nicht
mehr von z.B. Timer2 input capture (Pin A0) belegt werden?
UART2 läuft, wenn ich aber die Clock von Timer2 aktiviere, dann sendet
UART2 nichts mehr. Im Cube sehe ich den Konflikt, da ich aber die
Flusskontrolle nicht benutze, dachte ich, dass Cube evtl. nur eine
Warnung ausgibt.
Tycho B. schrieb:> Noch eine Verständnisfrage: Wenn ich UART2 ohne Flusskontrolle benutze,> sind dann die Pins CTS (Pin A0) und RTS trotzdem belegt und können nicht> mehr von z.B. Timer2 input capture (Pin A0) belegt werden?
Das wird ja wohl von deiner Initialisierung abhängen.
In der SPL gibt es die Möglichkeiten
Würde man also keine HardwareFlowControl wählen müssten nach
allen was ich bis jetzt erfahren habe, diese Pins auch frei
sein. Denn nur das was man initialsiert ist auch belegt.
Aber du hast uns ja nicht gezeigt wie du deinen UART2 initialsierst.
Sicher ist die Alernate Function des betreffenden Pins auch noch
ein Thema.
Tycho B. schrieb:> Im Cube sehe ich den Konflikt
-----^^^^----------
Tycho B. schrieb:> Initialisirung USART2 bare metal
------------------------^^^^^^^^^^-----
STM Apprentice schrieb:> -----^^^^----------
Cube benutze ich nur zur Visualisierung, oder gehe den generierten Code
durch um zu verstehen wie es bare metal läuft.
Die Initialisierung steht im ersten Beitrag, es steht auch drin:
1
/* Clear CTSE and RTSE bits, hardware flow control disabled */
Tycho B. schrieb:> Die Initialisierung steht im ersten Beitrag,
... die ja falsch sein kann da du Probleme dazu gemeldet hast.
Seitdem ist einiges Wasser die Donau hinuntergelaufen und wer
weiss was du inzwischen mit deinem Code gemacht hast ...
STM Apprentice schrieb:> Seitdem ist einiges Wasser die Donau hinuntergelaufen und wer> weiss was du inzwischen mit deinem Code gemacht hast ...
das stimmt
Tycho B. schrieb:> /* Write to USART CR2 */> WRITE_REG(USART2->CR2, (uint32_t)tmpreg);
Ganz allgemein sehe ich diese aufgerufene Funktion nicht.
Warum hier extra eine Setz-Funktion wenn alles so "bare
metal" sein soll?
Wenn deine Funktion (oder ist es ein Macro?) WRITE_REG
32 Bit schreibt, könnte da etwas schiefgehen? In der SPL
wird (immer?) 16 Bit geschrieben, auch wenn die temp-
Variablen 32 Bit sind.
STM Apprentice schrieb:> Ganz allgemein sehe ich diese aufgerufene Funktion nicht.> Warum hier extra eine Setz-Funktion wenn alles so "bare> metal" sein soll?
weil ich es aus einem Beispiel rauskopiert habe und nicht extra zu
USART2->CR2 &=~ (USART_CR3_RTSE | USART_CR3_CTSE);
geändert habe.
Makro:
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
STM Apprentice schrieb:> Würde man also keine HardwareFlowControl wählen müssten nach> allen was ich bis jetzt erfahren habe, diese Pins auch frei> sein. Denn nur das was man initialsiert ist auch belegt.
Ich habe in der ISR vom Timer2 den TIM_SR_CC1IF Flag nicht gelöscht und
blieb dort hängen, deswegen hat UART2 nicht funktioniert. Die Warnung in
Cube hat mich irritiert, daher dachte ich es liegt daran.
Die sind wirklich lustig. Da hatte der Praktikant anscheinend Langeweile
und hat angefangen in bester Anfängermanier seine "nützlichen"
Lieblingsmakros zu definieren, so überflüssig wie selten was, nach einer
halben Stunde haben sie ihn dann aber anscheinend dort wieder abgezogen
und stattdessen zum Kaffeekochen verurteilt. Leider wurde danach
vergessen diesen albernen Unfug wieder zu entfernen.
Bernd K. schrieb:> (__CLZ(__RBIT(VAL)))
Dreifachverkettete Makros um Nullen zu zählen, mit denen man am Anfang
initialisiert hat. Ich glaube es ist code obfuscation, damit man Cube
als black box benutzt.
Ich habe gelesen, dass der interne Oszillator mit bis zu ±3% Abweichung
behaftet ist, und messe mit SysTick an Stelle von eingestellten 2ms
1,9757ms, also eine Abweichung von 1,2%. Das ist also in Ordnung.
Was mich aber wundert ist der Jitter, also die Standardabweichung, die
beträgt 1µs über 10.000 Samples gemessen. Ist das normal, dass der
RC-Oszillator diese Instabilität hat? Ich habe keine Angaben dazu
gefunden.
Moin,
Bernd K. schrieb:> Die sind wirklich lustig. Da hatte der Praktikant anscheinend Langeweile
Ja wenn dem mal so waere. Es gibt da verschiedene Seuchen, zB AUTOSARS:
Und diesen Haufen braune Masse muss man dann tatsaechlich verwenden.
Naja, zum Glueck nicht immer.
Tycho B. schrieb:>> (__CLZ(__RBIT(VAL)))>> Dreifachverkettete Makros um Nullen zu zählen, mit denen man am Anfang> initialisiert hat. Ich glaube es ist code obfuscation, damit man Cube> als black box benutzt.
Findest Du? Also das Macro "kehrt" doch nur ein (1 << n) "um", sodass
man n wieder herausbekommt. Aus einem Register zum Bleistift. Also soo
schlecht finde ich das POSITION_VAL() Macro nun auch nicht. Oder
verstehe ich deinen Einwand falsch?
Darth Moan schrieb:> Findest Du? Also das Macro "kehrt" doch nur ein (1 << n) "um", sodass> man n wieder herausbekommt. Aus einem Register zum Bleistift. Also soo> schlecht finde ich das POSITION_VAL() Macro nun auch nicht. Oder> verstehe ich deinen Einwand falsch?
Vielleicht hast du ja recht und ich sehe nicht den effektiven
Einsatzzweck. Mein Einwend war, dass n ja schon bekannt ist, also als
#define. Deswegen, um n herauszubekommen, kann man gleich n nehmen, ist
ja schon definiert...
Tycho B. schrieb:> Gerade darüber nochmal gestolpert. Ich dachte bis jetzt, dass NVIC> etwas von der HAL ist. Manmanman, es ist echt mühsam nach Atmel...
Wieso? Auch Atmels Cortexe bedürfen der Initialisierung des NVIC.
Moin,
Tycho B. schrieb:> Deswegen, um n herauszubekommen, kann man gleich n nehmen, ist> ja schon definiert...
Ja stimmt, in dem Fall macht es natuerlich keinen Sinn, das Macro
zu nehmen. Vielleicht bin ich da schon zu sehr vorgeschaedigt, dass
mir mancherlei sinnloses Zeug schon gar nicht mehr auffaellt.
Rainer S. schrieb:>> GPIOA->OSPEEDR |= ( 0b11 << 4); // USART2 Tx (PA2) High speed
0b0111
>> Richtig so? Einmal 0b11 und dann 0b0111?
Sorry, der Kommentar ist falsch, (copy&paste aus einem Beispiel für
einen anderen µC)
Rainer S. schrieb:>> GPIOA->MODER |= (0b10 << 6); // USART2 Rx (PA3) Analog
mode
>> Analog Mode ???
Dasselbe, der Kommentar ist falsch
00: Input (reset state)
01: General purpose output mode
10: Alternate function mode
11: Analog mode
go for gold schrieb:> Warum volatile für diese lokale Variable?Nico W. schrieb:> Das muss übrigends nicht volatile sein. Das setzt du ja nur einmal im> Interrupt.Tycho B. schrieb:> ja, war nur von irgendwoher rauskopiert.
STM32F401RET, mit aktivieretem USART2
In CubeMX finde ich für TIM2 Channel4 einen Konflikt mit USART2, wegen
Doppelbelegung des Pins PA3. Es gibt aber die Auswahl "Input Capture
indirect mode". Was ist das? Suche in Google und RM0368 haben nichts
brauchbares geliefert.
Du kannst die Timer Inputs zum Teil remappen, d.h. du kannst TIM2 Ch4 so
konfigurieren, dass er als Input-Pin, den Pin nutzt der normalerweise
für Ch3 zuständig ist. Entsprechende Doku findest du im RefMan wenn du
dir die Beschreibung für CC4S im TIMx_CCMR2 anschaust. Wenn du nach CC1S
suchst findest du auch noch allgemein gehaltene Beispiele und Diagramme
(am Beispiel von Ch1).
Christopher J. schrieb:> Du kannst die Timer Inputs zum Teil remappen,
Ich möchte alle vier Input Capture units des Timer2 benutzen, damit ist
TI3 mit der dritten Input capture unit belegt.
TIM2_CH4 liegt auf PA3 und lässt sich nicht weiter remappen, nur
"indirect mode" geht. Deswegen meine Frage, was das überhaupt ist.
Tycho B. schrieb:> Christopher J. schrieb:>> Du kannst die Timer Inputs zum Teil remappen,>> Ich möchte alle vier Input Capture units des Timer2 benutzen, damit ist> TI3 mit der dritten Input capture unit belegt.
Sorry wenn ich mich missverständlich ausgedrückt habe: Dieser "indirect
mode" ist nichts anderes als das du durch entsprechende Konfiguration
der CCxS Bits im CCMRy dafür sorgst, dass z.B. Timer 2 Ch3 an TI 4
anliegt. Mit dem "remappen" von (alternativen) Pin-Funktionen hat das
umkonfigurieren der CCxS Bits nichts zu tun. Wenn du alle Kanäle nutzen
willst bringt dir das aber nichts, da musst du wohl oder übel einen
anderen Timer nehmen.
Tycho B. schrieb:> das ist putzig, habe system_stm32f4xx.h eingebunden, aber die> system_stm32f4xx.c nicht dazugelegt. nirgends gabs Gemeckere. Jetzt> finde ich heraus, dass die SystemInit(), die aus startup_stm32.s> gestartet wird, hier definiert ist. Super. Eingebunden, PLL_M von 25 auf> 16 geändert, kompiliert, juhu, jetzt ist die Baudrate 250.000, also> immer noch Faktor 4 zuwenig.
Dieser Beitrag ist zwar schon einen Monat her, jedoch möchte ich der
Vollständigkeit einen Patch der system_stm32f4xx.h erwähnen, weil
bereits viele dieses PLL_M-Problem hatten.
Nämlich, dort wo standardmäßig steht:
1
#define PLL_M 25
folgendes stattdessen einfügen:
1
#if defined (STM32F401RE) // STM32F401 Nucleo Board with 8 MHz crystal (84 MHz)
2
#define PLL_M 8
3
#define PLL_N 336
4
#define PLL_P 4
5
#define PLL_Q 7
6
#elif defined (STM32F411RE) // STM32F411 Nucleo Board with 8 MHz crystal (100 MHz)
7
#define PLL_M 8
8
#define PLL_N 400
9
#define PLL_P 4
10
#define PLL_Q 7
11
#elif defined (STM32F407VG) // STM32F4 Discovery Board with 8 MHz crystal (168 MHz)
12
#define PLL_M 8
13
#define PLL_N 336
14
#define PLL_P 2
15
#define PLL_Q 7
16
#else
17
#error unknown STM32
18
#endif
Sind STM32F401RE, STM32F411RE oder STM32F407VG gesetzt, werden die
jeweiligen µCs mit dem jeweils maximal möglichen Takt konfiguriert.
Die jeweiligen Werte kann man komfortabel mit dem Tool STM32CubeMX
ermitteln. Den Rest muss man ja nicht nutzen.
Ich würde den PLL_M auf 4 setzen für weniger jitter. Siehe auch im RM
oder Datenblatt. Bin mir grade nicht mehr so sicher wo das stand. Dann
natürlich auch den PLL_N entsprechend anpassen (halbieren).