Ich versuche mich an der Ansteuerung eines FU-ICs mittels Stm32f103C8.
Anbei die main.c der ersten lauffähigen Version.
Frage zur Deadtime: Diese braucht es beim Umschalten von positiver auf
negative Halbwelle, damit es keinen Kurzschluss gibt. Bei meiner
Sinustabelle ist der erste Wert der positiven Halbphase Null. Also von
48 Werten sind nur 23 größer alws null. Dadurch kann es zwichen den um
24 Steps versetzten Halbphasen niemals zu einem Kurzschluss kommen.
Kann man die Totzeitberechnung dann einfach weglassen?
grundschüler schrieb:> Kann man die Totzeitberechnung dann einfach weglassen?
Warum macht du es dir so schwer? Timer 1 und Timer 8 im STM32F103 sind
Advanced Timer und haben jeweils 3 PWM Kanäle mit komplementären
Ausgängen und einem Deadband Unit pro PWM. Ein einziger Timer erzeugt
ohne Klimmzüge alle 3 Phasen mit einstellbarer Totzeit.
Je nach Gehäuse hat evtl. nur ein Timer der beiden alle Anschlüsse
herasugeführt, aber das findest du anhand des Datenblattes schnell raus.
Matthias S. schrieb:> Warum macht du es dir so schwer?
Gerade einfach hast du es dir mit dem AVR ja auch nicht gemacht. Am
einfachsten wäre es, deinen code zu nehmen und keine Fragen mehr zu
stellen. Ich habe da ein Verständnisproblem von dem ich nicht weiß, ob
es an mir (wahrscheinlich) oder ob es an deinem code (unwahrscheinlich)
liegt. Ich will halt wissen, wie es funktioniert.
Der Stm-Tim1 ist sehr komplex. Es gibt fertigen code -
https://arm-stm.blogspot.de/2015/01/3-phase-sinusoidal-pulse-width.html
- den ich noch nicht ausprobiert habe.
Mit tim2, tim3, + tim4 geht es halt sehr einfach weil genug
Rechenleistung da ist und weil dise tims einfach zu handeln sind. Also
mache ich es mir eher so einfach wie möglich.
grundschüler schrieb:> Gerade einfach hast du es dir mit dem AVR ja auch nicht gemacht.
So einfach wie möglich. Der kleine AVR8 hat nun mal keinen Timer mit 3
PWM Kanälen, sondern nur 3 Timer mit je 1 PWM Kanal. Deswegen die
Klimmzüge beim 3 Phasen Generator.
Die STM32 und XMega hingegen haben fertige Blöcke für den Betrieb von
Motoren, die man nur benutzen muss.
grundschüler schrieb:> Also> mache ich es mir eher so einfach wie möglich.
Nö. Mit einem Advanced Timer brauchst du nur eine ISR, um alles zu
laden. Mein BLDC Antrieb mit Sinusmodulation auf dem STM32 ist deutlich
unkomplizierter als der gleiche Antrieb lt. AVR447. Vllt. portiere ich
den 3-Phasen Generator mal aufs VL Discovery - die liegen hier im Moment
sowieso nur rum.
@grundschüler
Hier ein Ansatz von St, den ich nur mal vorsichtshalber gezogen habe.
http://www.st.com/en/embedded-software/stsw-stm32100.html
Die beschriebene Software habe ich in einen chinesischen Forum gefunden,
aber noch nicht evaluiert. Sind zwei *.exe. Die würden nach genauer
Untersuchung verlangen. Deswegen kein Link.
Hier mal der Versuch, alles in den advanced timer zu packen
/Ukmschaltung nur eine Phase. Ich brauche ja 6 um jeweils 60° versetzte
Halbphasen. Tim1 hat aber nur 3*2+1 channel. Ganz zufrieden bin ich mit
dem Ergebnis noch nicht. Nach dem Umschalten scheint der abgeschaltete
Channel nachzuschwingen.
Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut. Code
für den Timer ist hier:
https://gitlab.com/higaski/stm32f405_vfd/blob/master/Src/Periph/pwm.c
Deadtime hab ich damals keine gebraucht, da die in Hardware realisiert
war. Jeder brauchbare Treiber bietet aber mittlerweile solche Optionen
an.
Vincent H. schrieb:> Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut.
Sieht allerdings mehr nach einem BLDC Antrieb für Motoren mit
Hallsensoren aus.
Der STM32F1xx hat eine Deadtime Unit:
1
voidUpdateDTI(u8deadTime){
2
TIM_BDTRInitTypeDefTIM_BDTRInitStructure;
3
4
TIM_BDTRStructInit(&TIM_BDTRInitStructure);
5
/* Automatic Output enable, Break, dead time and lock configuration*/
Der Timer 1 Interrupt ist bei mir motorspezifisch, aber das Prinzip ist
das gleiche wie beim AVR Frequenzumrichter. Also inco addieren, Zeiger
in die Tabelle berechnen, Werte aus der Tabelle skalieren und dann auf
alle 3 OC Register schicken.
Matthias S. schrieb:> Vincent H. schrieb:>> Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut.>> Sieht allerdings mehr nach einem BLDC Antrieb für Motoren mit> Hallsensoren aus.> Der STM32F1xx hat eine Deadtime Unit:>
1
>
2
>voidUpdateDTI(u8deadTime){
3
>TIM_BDTRInitTypeDefTIM_BDTRInitStructure;
4
>
5
>TIM_BDTRStructInit(&TIM_BDTRInitStructure);
6
>/* Automatic Output enable, Break, dead time and lock configuration*/
Woran soll man das sehen?
Ich seh keine Initialisierung für Hallsensoren?
Drehgeber hab ich damals glaub ich benutzt, aber die sind woanders
initialisiert.
Hab mir meinen Code grad nochmal angesehn und die Deadtime ist sogar
drin... auch wenn meine Treiber die damals wie gesagt inkludiert hatten.
Matthias S. schrieb:> Vincent H. schrieb:>> Woran soll man das sehen?>> Du erwähnst die Messung des Motorstroms im Programm und durchläufst die> für BLDC typischen 6 Sektoren.
Achso, ja der Eindruck täuscht. Die "6 Sektoren" entstehen durch die
Schaltzeiten der Brücke und bilden die möglichen Zustände aller 6
Schalter ab. Je nachdem welche Schalter gerade offen bzw. zu sind, wird
ein anderer Phasenstrom gemessen.
Vielen Dank für die Beiträge.
Vincent H. schrieb:> Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut.
Wenn ichs richtig verstehe, werden die Halbbrücken blockweise - also
nicht mit einem trägerfrequenzmodulierten Sinus angesteuert?
Matthias S. schrieb:> Als Hilfe poste ich dir mal die Init von Timer 1 für 3 PWM Kanäle:
Ich würde ja deinen avr-code komplett auf arm umsetzen, wenn ich ihn
verstehen würde.
Nach meinem Konzept wird die positive Halbbrücke jeder Phase sinusförmig
mit einem Ausgang angesteuert während der korrespondierende Ausgang der
negativen Halbbrücke aus ist und keinen Puls generiert. Ich brauche
jeweils 6 unterschiedliche Werte aus der Sinetable.
Nach deinem code
1
InsertDeadband(tempU,&compareHigh,&compareLow);
2
OCR0A=compareHigh;
3
OCR0B=compareLow;
scheinen beide Halbbrücken gleichzeitig invertiert angesteuert zu
werden? Du brauchst nur 3Werte aus der Sinetable.
Ist mein Konzept grundsätzlich falsch?
grundschüler schrieb:> Nach deinem code> InsertDeadband(tempU, &compareHigh, &compareLow);> OCR0A = compareHigh;> OCR0B = compareLow;> scheinen beide Halbbrücken gleichzeitig invertiert angesteuert zu> werden? Du brauchst nur 3Werte aus der Sinetable.
Richtig 3 Werte, 'InsertDeadband()' berechnet die Werte für compareHigh
und compareLow aus tempU. Das gleiche passiert gleich darauf auch für
tempV und tempW.
Beim STM32 kannst du darauf verzichten, wenn du das DTI benutzt - das
Dings fügt von alleine eine Totzeit zwischen den low und High Ausgängen
ein.
Du musst auch leglich CCR1 schreiben und nicht wie beim AVR OC0A und
OC0B.
Die Kernroutine im Timer1 Interrupt sieht dann so aus:
1
uint8_ttempU,tempV,tempW;
2
{
3
uint8_tsineTablePtr;
4
AdjustSineTableIndex(sineTableIncrement);
5
// Add sine table offset to pointer. Must be multiplied by 3, since one
6
// value for each phase is stored in the table.
7
sineTablePtr=(uint8_t)(sineTableIndex>>8)*3;
8
tempU=sineTable[sineTablePtr++];
9
if(GetDesiredDirection()==DIRECTION_REVERSE)
10
{
11
tempV=sineTable[sineTablePtr++];
12
tempW=sineTable[sineTablePtr];
13
}
14
else
15
{
16
tempW=sineTable[sineTablePtr++];
17
tempV=sineTable[sineTablePtr];
18
}
19
}
20
/* Scale sine modulation values to the current amplitude
grundschüler schrieb:> Also ist mein 6-werte-Ansatz grundsätzlich falsch?
Er ist unnötig redundant. Sowohl die AVR Software als auch der STM32
brauchen nur 3 Werte. Der AVR macht daraus mit InsertDeadband() zwei
Werte (für High und Low) und beim STM32 machts das DTI und die gewählte
Polarität der PWM Ausgänge aus einem Wert pro Phase.
Matthias S. schrieb:
Dein code läuft ja bei mir auf einem m328. Ich werd mir das mal mit
einem la anschauen, was da an Werten konkret rauskommt. Der
6-werte-Modus hat halt den Vorteil, dass er den Sinus direkt nachbildet
und unkompliziert zu programmieren ist.
grundschüler schrieb:> Vielen Dank für die Beiträge.>> Vincent H. schrieb:>> Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut.>> Wenn ichs richtig verstehe, werden die Halbbrücken blockweise - also> nicht mit einem trägerfrequenzmodulierten Sinus angesteuert?
Nein, der Code verwendet nur keine Sinus-Tabelle, erzeugt aber genauso
einen Drehvektor. In Zeile 316 steht der Sinus sogar als Funktionsaufruf
drin. Ein STM32F405 hat mehr als genug Saft um die nötigen Sinus-Werte
"on demand" zu berechnen. (sogar in double...)
Ob das jetzt sinnvoll ist oder nicht, sei mal dahingestellt.
grundschüler schrieb:> Der> 6-werte-Modus hat halt den Vorteil, dass er den Sinus direkt nachbildet> und unkompliziert zu programmieren ist.
Ich sehe das nicht so als Vorteil. Denn du bist dann fix auf Totzeit
etc. festgelegt.
Vincent H. schrieb:> Ein STM32F405 hat mehr als genug Saft um die nötigen Sinus-Werte> "on demand" zu berechnen.
Sicher richtig, vor allem, wenn man die Hardware FPU benutzt. Wir
spielen hier in der Liga STM32F1nn, wo man das leider nicht so hat und
meist auch nur mit 25MHz taktet.
Matthias S. schrieb:> Wir> spielen hier in der Liga STM32F1nn
Das stm32f426-disco kostet unter 30€. Angesichts des Aufwands - den wir
ohnehin alle betreiben - sollten 30€ für die bestmögliche mcu kein
Hindernis sein.
Ich hatte mir für das avr-Projekt extra einen 328pb - mit zusätzlichen
Timern - zugelegt.
Vincent H. schrieb:> In Zeile 316 steht der Sinus sogar als Funktionsaufruf> drin.
Ich werde deinen code auch mal ausprobieren.