Forum: Mikrocontroller und Digitale Elektronik Timer bei STM32 im OC Modus


von STM32 (Gast)


Lesenswert?

Hallo,

ich möchte gerne unterschiedliche Frequenzen mit dem STM32-Controller 
erzeugen und dafür einen Timer im OC-Modus nutzen und auf die 
HAL-Bibliothek zurückgreifen.

Irgendwie stehe ich dabei aber auf dem Schlauch, wie ich nun erstens den 
Registerwert des Timers auslesen kann und zweitens einen definierten 
Wert auf das OC-Register draufaddieren kann, damit der Timer nach einer 
definierten Zeit erneut auslöst.


Funktional ist es so aufgebaut:
1
* brief This function handles TIM1 global Interrupt.
2
*/
3
void TIM4_IRQHandler(void)
4
{
5
  /* USER CODE BEGIN TIM1_IRQn 0 */
6
7
  /* USER CODE END TIM1_IRQn 0 */
8
  HAL_TIM_IRQHandler(&htim1);
9
  /* USER CODE BEGIN TIM1_IRQn 1 */
10
11
  /* USER CODE END TIM1_IRQn 1 */
12
}


Der eigentliche HAL_TIM_IRQHandler(&htim1) liegt in der HAL-Bibliothek 
"stm32f4xx_hal_tim.c" und soll nicht verändert werden!
Das ist eine gesetzte Anforderung, die ich als gegeben hinnehmen muss.

Um mein Vorhaben um zu setzen, muss ich folglich meine Modifikation im 
Usercode vor oder nach dem Aufruf der Funktion einbringen und neue Werte 
in die OC Register schreiben bzw. durch Vergleich mit dem Zählerwert 
erstmal berechnen, was da nun reingehört.
Nun stellen sich mir da zwei Schwierigkeiten in den Weg:

1. Woher weiß ich am Punkt des Usercodes, welcher Channel nun den OC 
Interrupt ausgelöst hat?
Welche Funktion aus der HAL-Bibliothek könnte ich dafür nutzen, um diese 
Information zu bekommen?

2. Mit welcher Funktion kann ich den aktuellen Stand des OC Registers 
sowie den aktuellen Stand des Timers auslesen?

Da ich alle 4 Kanäle gelichzeitig nutze, möchte ich den Timer permanent 
hochzählen lassen und immer wenn der jeweilige IR auslöst für den 
zugehörigen IR eine Konstante auf den OC wert drauf addieren.

Kann mir da einer auf die Sprünge helfen?

von STM32 (Gast)


Lesenswert?

...ist der beschriebene Weg irgendwie untypisch, dass ich da keine 
einfache Lösung in der HAL Bibliothek finde?

Was ich Kurzform möchte:
Lese in der ISR das OCR (Auslösewert) und das CR (Zählerstand), schreibe 
den Wert OCR_NEU+CR in das OCR Register und definiere damit den nächsten 
Auslösezeitpunkt.

Ich kann mir nicht vorstellen, dass dies mit der HAL Bibliothek nicht 
einfach möglich sein sollte.

Wie erreiche ich mit den gegebenen Mitteln dieses Ziel am ehesten, oder 
muss ich dafür irgendeine andere Betriebsart des Zählers wählen?

von W.S. (Gast)


Lesenswert?

STM32 schrieb im Beitrag #4763641:
> Ich kann mir nicht vorstellen, dass dies mit der HAL Bibliothek nicht
> einfach möglich sein sollte.

Ob du dir etwas vorstellen kannst oder nicht, ist (frei nach Einstein) 
dem Universum schnurz.

Deine Vorgabe, daß da irgend eine ominöse Interruptfunktion aus einer 
noch ominöseren HAL-Bibliothek unbedingt zu verwenden sei, ist 
Mumpitz. Entweder du kippst das ganze Konzept und stellst es auf 
richtige Füße oder du solltest es besser bleiben lassen.

Die allermeisten STM32 haben so reichlich an Timern, daß du für vier 
Ausgangskanäle jeweils einen separaten Timer verwenden kannst. Die 
brauchen dann nicht mal einen Interrupt, denn das Durchschalten auf 
einen Pin geht bei m.W. allen Timern.

btw: Was stellst du dir eigentlich unter HAL (Hardware Abstraction 
Layer) vor? Soweit ich das sehen kann, erledigt weder die unsägliche 
ST-Lib noch diese ominöse HAL-Lib etwas derartiges. Eine echte 
HW-Abstraktion geht so, daß die Schnittstelle zum aufrufenden Programm 
hardwareunabhängig ist, also daß man sich da nicht drum scheren muß, was 
für HW drunter liegt. Bei Speichermedien (SD z.B.) wäre das das Lesen 
und Schreiben von Sektoren im zugehörigen logischen LW, bei seriellen 
Verbindungen wäre das das schiere Senden und Empfangen von Daten und 
ggf. das Einstellen von Baudraten und sonst NICHTS! Aber hier? Da soll 
angeblich etwas abstrahiert werden und du mußt dennoch die HW anfassen - 
entweder direkt oder indirekt. Das ist keine HAL. Also laß diesen 
Schmonz einfach weg, befasse dich mit den Registern der Hardware direkt 
und mache damit, was du eigentlich tun mußt.


W.S.

von STM32 (Gast)


Lesenswert?

Hallo,

Danke für die Antwort, obgleich du ja augenscheinlich die HAL garnicht 
einsetzt.

HAL steht für Hardware Abstraction Layer, das ist richtig. Bei den 
meisten Elementen der Controller kommt man damit auch relativ einfach 
zum Ziel und wie beschrieben hatte ich gehofft, dass der Anwengungsfall 
einen variablen Wert auf das OCR drauf zu addieren ein bin meinen Augen 
typisches Szenario wäre, so dass ich diese Aufgabe gerne mit der HAL 
erschlagen hätte.

Vielleicht hat ja jemand tatsächlich genügend Erfahrung in der Anwendung 
der HAL, dass mein Anliegen damit ev. doch gelöst werden kann?

von aSma>> (Gast)


Lesenswert?

STM32 schrieb im Beitrag #4763588:
> ich möchte gerne unterschiedliche Frequenzen mit dem STM32-Controller
> erzeugen und dafür einen Timer im OC-Modus nutzen und auf die
> HAL-Bibliothek zurückgreifen.

Nun schau mal ins Datenblatt. Da gibt es "nicht" allzuviele Register.
z.B. Timer 1:
1
TIM1->ARR;          //(auto) preload register, Periode
2
  TIM1->CNT;          //der counter!
3
TIM1->PSC;          //Teiler, zusätzlich gibt es noch einen clock divisor
4
  TIM1->CCR1 bis 4;  //duty, Tastgrad

Wie man hier unschwer erkennen kann, lässt sich mit einen Timer nur 
"eine" Periode erstellen und dafür aber 4 verschiedenen duty cycle.
1
Dann gibt es noch:
2
UIF: Update interrupt flag
3
 This bit is set by hardware on an update event. It is cleared by software.
4
0: No update occurred.
5
1: Update interrupt pending. This bit is set by hardware when the registers are updated:
6
 At overflow or underflow and if the UDIS=0 in the TIMx_CR1 register.
7
 When CNT is reinitialized by software using the UG bit in TIMx_EGR
8
usw.

Beispiel:
72MHZ Takt:
1
TIM1->PSC = 1100-1;
2
3
uint16_t pmw = 0xffff;
4
TIM1->ARR = pmw;
5
  TIM1->CCR1 = pmw>>1; //50% duty
6
  TIM1->CNT // Momentane Zustand vom Zähler
7
so jetzt kannst du die pwm von 0 bis 65,5khz ändern.

> Ich kann mir nicht vorstellen, dass dies mit der HAL Bibliothek nicht
> einfach möglich sein sollte.

Geht schon. Nur dann muss man 2 mal die Datenblätter lesen. Wozu!?

Wenn man schon bei Einstein sind: Man sehen, ob er sich mit der 
menschlichen Dummheit geirrt hat.

von Dennis (Gast)


Lesenswert?

W.S. schrieb:
> Also laß diesen
> Schmonz einfach weg, befasse dich mit den Registern der Hardware direkt
> und mache damit, was du eigentlich tun mußt.

Wie Recht du hast...

Aber die heutigen "Bachelors" und "Master" (die sich übrigens allesamt 
für vollwertige Ingenieure halten...) mögen die Hardware nicht und auch 
das Datenblatt lesen (bzw. im nächsten Schritt sogar zu verstehen) ist 
viel zu kompliziert und viel zu viel verlangt. Da soll alles schön 
einfach per Bibliothek / HAL ansprechbar sein ansonsten können die 
Jünglinge damit nichts anfangen.

von m.n. (Gast)


Lesenswert?

aSma>> schrieb:
> Wie man hier unschwer erkennen kann, lässt sich mit einen Timer nur
> "eine" Periode erstellen und dafür aber 4 verschiedenen duty cycle.

Wenn man so blind durch die Datenblätter läuft, kann man auch gleich 
wieder HAL verwenden.
Pro OCR kann man bei freilaufendem Timer eine Frequenz erzeugen - 
geschickterweise mit direktem Registerzugriff, wie es W.S. angedeutet 
hat.

von aSma>> (Gast)


Lesenswert?

Man muss auch ehrlich sein. Die Timer sind schon ein wenig komplex. Es 
gibt halt sehr viele Einstellungsmöglichkeiten, deswegen gibt es auch 
Appnotes: AN2581 (stm32f10x)

Mit "oc toggle" (siehe Beispiele ST) kannst in der ISR pro timer 4 
verschiedene Frequenzen/Perioden erzeugen.

von W.S. (Gast)


Lesenswert?

m.n. schrieb:
> Pro OCR kann man bei freilaufendem Timer eine Frequenz erzeugen

hehe, da knurrt der Blindenhund!

Also, das übliche Szenario ist ja so, daß man einen Vorteiler hat, der 
irgend einen verdammten Takt abkriegt und seinerseits das eigentliche 
Timer-Register mit seinem Output taktet. Parallel zu diesem 
Timer-Register können dann 1 oder mehrere Vergleichsregister liegen, die 
man mit Werten laden kann und die eine Schaltaktion auslösen, wenn das 
Timer-Register gleich oder größer wird als so ein Vergleichsregister.

So.

Das ganze ist also zyklisch, also kann man erstmal nur mehrere Signale 
unterschiedlicher Phasenlage erzeugen, aber keine unterschiedlichen 
Frequenzen! Das könnte man nur dadurch, daß man mit jeder Schaltaktion 
per Interrupt das Vergleichsregister neu setzt - ABER: ob sowas 
überhaupt geht, hängt davon ab, wie die Vergleichsoperation im Detail 
funktioniert. Ist sie statisch auf Gleichheit, dann geht es, sonst 
nicht, weil man sonst ja mit dem Neusetzen sich das Ausgangssignal 
kaputtmacht.

Genau deshalb hatte ich dem TO nahegelegt, für jeden seiner Ausgänge 
einen separaten Timer zu verwenden.

W.S.

von m.n. (Gast)


Lesenswert?

W.S. schrieb:
> m.n. schrieb:
>> Pro OCR kann man bei freilaufendem Timer eine Frequenz erzeugen
>
> hehe, da knurrt der Blindenhund!

Was hast Du denn gestern gegessen, daß Du jetzt knurren mußt.


> Genau deshalb hatte ich dem TO nahegelegt, für jeden seiner Ausgänge
> einen separaten Timer zu verwenden.

Völlig überflüssig; Du hast das Datenblatt vom STM32xxx nicht gelesen!

STM32 schrieb im Beitrag #4763588:
> Da ich alle 4 Kanäle gelichzeitig nutze, möchte ich den Timer permanent
> hochzählen lassen und immer wenn der jeweilige IR auslöst für den
> zugehörigen IR eine Konstante auf den OC wert drauf addieren.
>
> Kann mir da einer auf die Sprünge helfen?

Mache es so! Damit gehen Perioden von einigen µs bis zu x-beliebigen 
großen Zeiten. Programmbeispiele habe ich leider nur für AVR8, falls Du 
Interesse hast.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.