Ich versuche gerade die Timer vom STM32F103 zu verstehen. Ich habe auch
erfolgreich ein Togglesignal an einem der Pins ausgeben können. Ich
nutze den Timer 2 Channel 4. Die unten gezeigte Initialisierung bringt
ihn auch dazu ein Signal am Pin PA3 (T2_CH4) auszugeben, wobei ich es
aber am Pin PB11 (TIM2_CH4) erwartet habe. Kann man das irgendwie
umschalten?
Das zweite Phänomen ist aber für mich noch unverständlicher. Schreibe
ich in den Prescaler etwas anderes als 2 (probiert mit 1, 3, 20, 100)
passiert gar nichts mehr. Wieso dies? Was mache ich falsch?
Zum Testen habe ich das gleiche mal mit Timer 3 parallel laufen lassen.
Derselbe Effekt, Prescaler 2 geht, alles andere nicht. Das Hauptprogramm
läuft weiter, stürzt also nicht ab. Der Fehler tritt nur bei dem Timer
auf dessen Prescaler ungleich 2 ist. Ist also TIM2 auf 2 und TIM3 auf
drei, läuft TIM2 aber TIM3 nicht.
Die Beiden Pin Initialisierungen sind nur drin weil es anscheinend zwei
TIM2_CH4 Ausgänge gibt und ich nicht weiß wie man welchen auswählt
(s.o.)
Ergänzung:
Füge ich nach TIM_TimeBaseInit die folgende Zeile ein, nimmt er den
Prescaler aus dieser Zeile und alles funktioniert. Ist da etwa ein solch
gravierender Bug in der Standard Peripheral Library? Wenn ja, gibts noch
mehr?
Die Pin-Umschaltung beim F1 ist etwas umständlich, du musst du den Takt
für AFIO einschalten und dann den Gewünschten Remap machen. Welchen du
brauchst steht im Reference Manual unter GPIO in den AFIO Register
Definitionen. Für TIM2 CH4 auf PB11 wäre das entweder Partial Remap 2
oder Full Remap.
Thorsten E. schrieb:> Ist da etwa ein solch> gravierender Bug in der Standard Peripheral Library?
Das lässt sich leicht prüfen in dem du die Deklaration von der
TIM_TimeBaseInit öffnest. Dort sollte irgendwo
1
/* Set the Prescaler value */
2
TIMx->PSC=TIM_TimeBaseInitStruct->TIM_Prescaler;
stehen. Wenn es dort nicht steht is irgend etwas faul...
Grundsätzlich kann man sich angewöhnen, jede Struct vor zu
initialisieren:
Es wird immer eigenartiger. Ich habe gerade bemerkt, dass nach dem
Einschalten auch meine Variante mit dem eingefügten "TIM2->PSC=1;" nicht
startet. Erst nach dem Flashen startet es. Der Timer der auf Prescaler=2
steht startet auch nach dem PowerOff/On.
In der TIM_TimeBaseInit steht in der Tat die Zuweisung an PSC drin,
ebenso wie die Erzeugung eines UpdateEvents. Auch das vorherige
Initialisieren der TIM_TimeBase_InitStructure hilft nicht.
Muss man vielleicht irgendeine Reihenfolge bei der Initialisierung der
Timer einhalten? Aber wieso ist es dann vom Wert des Prescalers
abhängig? Und wie soll ich sowas debuggen?
Thorsten E. schrieb:> Es wird immer eigenartiger.
Mach doch um gotteswillen deine Hardwareeinstellungen selber, indem du
in die betreffenden Register was reinschreibst und laß den ganzen
ST-Lib-Kram außen vor.
Ich hatte vor einiger Zeit hier schon mal ein Minimalsystem gepostet.
Such einfach mal nach "STM32F103C8T6.ZIP" und guck dir dort die config.c
an. Da hast du den ganzen Systemanlauf mit Portverwendung und Takt und
das alles ohne ST-Zirkus. Ich krame dir mal so als Beispiel eine
Initialisierung von TIM15 heraus, die kannst du dann sinngemäß auf deine
Anwendung ummünzen:
1
NVIC_ISER0=1<<24;// Int erlauben
2
TIM15_CR1=0;// gestoppt, keine Besonderheiten
3
TIM15_CR2=0;
4
TIM15_SMCR=0;// kein Slavemode
5
TIM15_SR=0;// alle pending Ints aus
6
TIM15_DIER=1;// Interrupt nur bei Update
7
TIM15_CCER=0;// Capture/Comp erstmal aus
8
TIM15_CCMR1=(7<<12);// PWM Mode 2 zuerst lo, dann hi
9
10
TIM15_CNT=0;
11
TIM15_PSC=45000;
12
TIM15_ARR=1;// zählt von 0 bis 1
13
TIM15_CCR2=1;// ab 1 --> hi
14
TIM15_BDTR=3<<14;// MOE+AOE .. bei diesem TIM nötig!
15
TIM15_CCER=1<<4;// CC2 enabled
16
17
// und zum Starten
18
TIM15_SR=0;// alle pending Ints aus
19
TIM15_PSC=val_Prescaler;// starten mit Frequenzvorgabe
Ja, habe ich. Nur funktioniert der anscheinend auch nicht richtig:
1. Springt er im Code wild hin und her wenn ich versuche zeilenweise
vorzugehen. Umgebung ist Code::Blocks mit OOCD an einem STLinkV2
2. Ausserdem ist ja momentan der Status, das es nach dem Flashen (und
damit auch nach dem Debuggen) alles läuft, nur nach einem Kaltstart
nicht. Wie soll ich das dann debuggen
Nun habe ich es hinbekommen. Anscheinend hing es irgendwie an den
Optimierungseinstellungen des armgcc. Es war die Option -O2 eingestellt.
Lasse ich die weg, funktioniert es anscheinend.
Dann kann ich mich ja nun dem eigentlichen Problem widmen. :-)
Ich benötige an einem Pin einen Takt von ca. 8MHz. Dieser Takt soll
genau 4096 Impulse ausgeben. Danach dann an einem anderen Pin einen
kurzen Impuls und dann wiederholt sich das Ganze. Wer jetzt ein
Aha-Erlebnis hat: ja es geht um einen TLC5940. Auf dem STM32F103 könnte
man dazu wunderbar zwei Timer kaskadieren.
Leider ist die Zielhardware aber ein LPC2148 und bei dem sind die Timer
nicht kaskadierbar. Also muss ich das per Hand machen:
Einen Timer fest auf die 8MHz Takt einstellen. Einen zweiten auch auf
8MHz und nach 4096 Takten einen Interrupt erzeugen. Die ISR hält dann
den ersten Timer an, erzeugt den BLANK Impuls, schaltet auf die nächste
Anzeigezeile und startet den ersten Timer wieder.
Problem könnte werden, dass die ISR länger braucht als einen 8MHz Takt
und das Ganze dadurch aus dem Tritt kommt. Daher wäre es sinnvoll wenn
der zweite Timer beim Interrupt angehalten wird und die ISR am Ende ihn
wieder startet. Damit starten dann beide Timer (fast) gleichzeitig und
alles ist gut.
Mal sehen ob ich das hin bekomme.
Ich würde mir an deiner Stelle gedanken machen warum das mit einer
Optimierung nicht mehr geht.
Ich hatte einmal ein ähnliches Problem. Beim Debuggen lief alles. Von
-O0 wieder auf -Os plötzlich nicht mehr. Mein SPI-Slave benötigt am Ende
vom letzten Bit zu CS-high 150ns. Die waren dann nicht mehr da. Kurz ein
paar Takte delay mit reingezaubert und alles lief wieder sauber.
Uch würde mir das mit der Optimierung auch nochmal anschauen...
Zum abderen Problem:
Ist im Timer ein Repetition Counter vorhanden? Wann ja, nutze ihn zum
zählen deiner Impulse. Wie lang muss der Blank-Impuls denn sein?
Anscheinend hat der LPC2148 keinen Repetition Counter und auch keine
Möglichkeit, intern zwei Timer zu verbinden um z.B. den einen durch den
anderen zu starten.
Also bleibt nur die reine Softwarelösung. Funktioniert inzwischen auch
soweit (auf dem STM32f103). So richtig schlau werde ich aber nicht aus
den Frequenzen. Mein APB1 Takt läuft auf 72MHz.
Timer 2 tut genau was er soll. Ich habe den Prescaler auf 1 gestellt,
was wohl soviel heißt wie durch zwei teilen. Den Timer Period habe ich
auf eins gestellt, dmit zählt er von 0..1, also zwei Takte. Den
zugehörigen Ausgang auf TOGGLE, der dadurch wieder jeden zweiten Takt
wechselt. Damit ergibt sich eine Taktfrequenz von 9 MHz:
72MHz 2 2 / 2 = 9MHz
Timer 3 musste ich nun auf einen Vorteile von 7 stellen und den
Periodenwert auf 4095, wodurch er 4096 Takte zählt.
Schalte ich damit nun den Timer 2 aus und wieder ein erhalte ich
zwischen zwei Timer 3 Pulsen 4105 Pulse am Timer 2.
Daher habe ich den Periodenwert von Timer 3 nun auf 4085 angepasst und
damit bekomme ich nun exakt 4096 Timer 2 Impulse pro Sequenz. Da ich
beide Timer in der ISR stoppe und starte ist das auch unabhängig von der
Dauer der Aktivitäten innerhalb der BLANK-Phase.
Ich hätte erwartet, dass ich für das gewünschte Ergebnis den Vorteiler
von Timer 3 auf 8 hätte stellen müssen.
Naja, du wirst eine gewissen Latenz vom Interrupt bis zur Ausführung der
ISR haben. Wenn du den Prescaler auf 7 stellst, wird durch 8 geteilt.
Zum Prescalerwert im Register wird immer noch eine 1 dazu addiert.