Forum: Mikrocontroller und Digitale Elektronik phasenverschobene PWM mit STM32F103C3


von Gunnar F. (gufi36)


Angehängte Dateien:

Lesenswert?

Hi Leute, eine Frage an die STM32-Spezialisten:
Ich möchte einen Wechselrichter bauen, in dem eine Vollbrücke
mit phasenverschobener PWM gesteuert wird.
Im Skript Leistungselektronik von Prof. Joachim Böcker heißt das
PWM für 4QS mit versetzter Taktung. Die beiden Abbildungen 
4QuadrantenStellerX.png zeigen das Prinzip.
Ich brauche keine komplementären Ausgänge, weil mein Brückentreiber die 
in Hardware mit Totzeit erzeugt.

Ansatz Nr. 1 war auf STM32F103C8, den Timer1 auf 500Hz in PWM Mode 1 
laufen zu lassen und die Werte aus einer Sinus-Tabelle per DMA in das 
CCR1 Register zu laden.
Das Update Event triggert den DMA, nur beim downcounting Underflow. 
(Center Aligned PWM)
Das hat funktioniert, anbei ein Bild des Verlaufes.
Aber wie kriege ich eine 180° phasenverschoben modulierte PWM hin?
Per DMA auf dem CortexM3 kann ich immer nur ein Wort holen lassen, also 
kein Burst-DMA. Richtig?

Jetzt dachte ich alternativ, kann ich zwei synchronisierte Timer laufen 
lassen. Aber wie?
Ich könnte den Master (TIM1) den Slave TIM2 starten lassen, beim ersten 
Overflow. Dann laufen beide Timer "180° phasenverschoben" und ich könnte 
wie in der Abbildung 4QuadrantenSteller2 meine PWM erzeugen.
Aber für DMA liegt ja mein Output Trigger schon auf Underflow fest! Wie 
kann ich den TIM2 also dann starten?

Und was ich leider gar nicht verstehe: Der Advanced Timer1 hat ja eben 
schon 3 komplementäre Outputs und ich lese überall von 3-phase PWM. Aber 
über die drei CCRX-Register kann ich ja nur drei Pulsweiten definieren, 
aber keine Phasenverschiebung? Oder Denkfehler?

Ich habe mir heute einen Wolf gesucht, nach 3-phase Motor Control, wo 
der Timer eben drei Phasen mit 120° Verschiebung erzeugen soll, habe 
aber keine Info gefunden, wie das zu machen ist.

Wer kann helfen?
Merci!

von Uwe Bonnes (Gast)


Lesenswert?

Nein, innerhalb einer Timers kannst Du keine Phasenverschiebung 
erzeugen. Evt klappt es mit mehreren verkoppelten Timer, wo Du ueber 
Compare Events die PWM Timer zeitversetzt startest. Einfacher geht es 
mit den HR Timer in manchen neuere Chips, z.B. F334.

von Georg H. (gerontec)


Lesenswert?

Ich empfehle irgend einen ATTiny oder ATmega mit 3 freien PWM Pin's und 
3 freien 10-bit AD feedback pins zu verwenden, das folgende habe ich auf 
60Hz konfiguriert, die gewünschte Frequenz kannst Du mit PWM_PRESCALER 
ändern.
Drei PWM's auf einem Chip 120 Grad versetzt in SYNC zu halten dürfte ja 
kein Problem sein.

config.h:
// PWM_PRESCALER determines the carrier frequency of the PWM signal. The 
PLL runs at 64 MHz,
// and the prescaler divides it down: f_carrier = 64 MHz / 
(2^(PWM_PRESCALER - 1))
// Min: 1
// Max: 15
#define PWM_PRESCALER 15

// PWM_MAX_DUTY determines the resolution of the PWM signal, which in 
turn determines the
// output frequency. f_output = f_carrier / PWM_MAX_DUTY
// Min: 2
// Max: 255
#define PWM_MAX_DUTY 65

// PWM duty resolution allows for duty cycle to be adjusted in 
increments smaller than
// 1. If the duty cycle PWM is not a whole number.
// Min: 1
// Max: 100
#define PWM_DUTY_RESOLUTION 100

// By default, if PWM duty cycle is not a whole number it will be 
rounded to the nearest
// whole number. If dithering is enabled, it will interpolate between 
adjecent whole numbers
// according in accordance with the fractional part.
// #define ENABLE_DITHERING

// The PWM signal will bottom out at PWM_DUTY_LOWER_LIMIT even if the 
feedback voltage is above desired
// point.
// Min: 0
// Max: PWM_MAX_DUTY - 1
#define PWM_DUTY_LOWER_LIMIT 5

// The PWM signal will max out at PWM_DUTY_UPPER_LIMIT even if the 
feedback voltage is below desired
// point. This is a crude way to limit the load current.
// Min: 1
// Max: PWM_MAX_DUTY
#define PWM_DUTY_UPPER_LIMIT 60

// PWM duty will be adjusted by the step size on every new reading.
// Min: 1 / PWM_DUTY_RESOLUTION
// Max: 255
#define PWM_STEP_SIZE 0.05

// Whether to invert the outgoing PWM singal
//#define PWM_INVERT

// The window size for the moving average of ADC readings for feedback 
voltage. Larger window allows
// for more resolution at the expense of adjustment lag.
// Min: 1
// Max: 64
#define WINDOW_SIZE 1

// PWM duty cycle will not change if the feedback reading is within the 
hysteresis range of the desired voltage.
// The unit is 1/1024 of the reference voltage selected.
// Min: 0
// Max: 1024
#define HYSTERESIS 0

// If MONITOR_ISR is set, PB0 will be brought high during the interrupt 
handler,
// allowing the ADC timings to be measured.
#define MONITOR_ISR

// Choose between internal 2.56V and internal 1.1V reference voltage for 
the ADC. Note that internal
// 2.56V reference requires VCC of at least 3V. If none are defined, VCC 
is used.
//#define USE_2V56_REFERENCE
#define USE_1V1_REFERENCE

main.c:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include "config.h"


uint8_t cycle = 0;
uint8_t pwmCycle = 0;
int32_t dutyCycle = 0;
int32_t adcMovingAverage = 0;
uint16_t avgBuffer[WINDOW_SIZE] = {0};

volatile int32_t targetVoltage = 512 * WINDOW_SIZE;

#define _PWM_STEP_SIZE ((int32_t)(PWM_STEP_SIZE * PWM_DUTY_RESOLUTION))
#define _PWM_DUTY_UPPER_LIMIT ((int32_t)(PWM_DUTY_UPPER_LIMIT * 
PWM_DUTY_RESOLUTION))
#define _PWM_DUTY_LOWER_LIMIT ((int32_t)(PWM_DUTY_LOWER_LIMIT * 
PWM_DUTY_RESOLUTION))

ISR(ADC_vect) {
#ifdef MONITOR_ISR
   PORTB |= (1 << PB0);
#endif
    // Calculate moving average of ADC readings
    uint8_t adcLow = ADCL;
    uint16_t adcReading = ADCH << 8 | adcLow;
#if WINDOW_SIZE == 1
    #define _ADC_VALUE adcReading
#else
    adcMovingAverage += adcReading;
    adcMovingAverage -= avgBuffer[cycle];
    avgBuffer[cycle] = adcReading;
    #define _ADC_VALUE adcMovingAverage
#endif

    int32_t target = targetVoltage;
    if (_ADC_VALUE < target - (HYSTERESIS * WINDOW_SIZE) && dutyCycle <= 
_PWM_DUTY_UPPER_LIMIT - _PWM_STEP_SIZE)
    {
       dutyCycle += _PWM_STEP_SIZE;
    }
    else if (_ADC_VALUE > target + (HYSTERESIS * WINDOW_SIZE) && 
dutyCycle >= _PWM_DUTY_LOWER_LIMIT + _PWM_STEP_SIZE)
    {
       dutyCycle -= _PWM_STEP_SIZE;
    }
#ifdef ENABLE_DITHERING
    // Dither the PWM duty cycle to allow for higher resolution
    OCR1A = (uint8_t)(dutyCycle / PWM_DUTY_RESOLUTION)
        + (dutyCycle % PWM_DUTY_RESOLUTION < pwmCycle ? 1 : 0);
#else
    OCR1A = (uint8_t)((dutyCycle + (PWM_DUTY_RESOLUTION/2)) / 
PWM_DUTY_RESOLUTION);
#endif

#if WINDOW_SIZE != 1
    cycle = (cycle + 1) % WINDOW_SIZE;
#endif
    pwmCycle = (pwmCycle + 1) % PWM_DUTY_RESOLUTION;

#ifdef MONITOR_ISR
    PORTB &= ~(1 << PB0);
#endif
}

int main(void) {
    PORTB = 0;

#ifdef MONITOR_ISR
    DDRB = (1 << PB1) | (1 << PB0);
#else
    DDRB = (1 << PB1);
#endif

    // PLL setup
    // =========

    PLLCSR |= (1 << PLLE); // PLL enable

    // PLOCK must be set before asynchronous mode can be enabled
    while (!(PLLCSR & (1 << PLOCK)))
        ;

    PLLCSR |= (1 << PCKE); // Enable asynchronous mode

    // PWM setup
    // =========

    TCCR1 =
        (1 << CTC1) |   // Reset the counter after it reaches OCR1C
        (1 << PWM1A) |  // Set PWM comparator for OCR1A
        ((PWM_PRESCALER & 0b1111) << CS10) |   // No prescaler, run at 
full 64 MHz
#ifdef PWM_INVERT
        (1 << COM1A1) | // Set PB1 after counter reaches OCR1A
        (1 << COM1A0);  // Set PB1 after counter reaches OCR1A
#else
        (1 << COM1A1) | // Clear PB1 after counter reaches OCR1A
        (0 << COM1A0);  // Clear PB1 after counter reaches OCR1A
#endif

    OCR1A = 0;
    OCR1C = PWM_MAX_DUTY;

    // ADC setup
    // =========

    ADMUX =
        (0 << ADLAR) | // right shift result
#if defined(USE_2V56_REFERENCE)
        (1 << REFS2) |
        (1 << REFS1) |
        (0 << REFS0) |
#elif defined(USE_1V1_REFERENCE)
        (0 << REFS2) |
        (1 << REFS1) |
        (0 << REFS0) |
#endif
        (0 << MUX3) | // use ADC2 for input (PB4)
        (0 << MUX2) | // use ADC2 for input (PB4)
        (1 << MUX1) | // use ADC2 for input (PB4)
        (0 << MUX0);  // use ADC2 for input (PB4)
    ADCSRB =
        (0 << ADTS0) | // ADC free running mode
        (0 << ADTS1) | // ADC free running mode
        (0 << ADTS2);  // ADC free running mode
    ADCSRA =
        (1 << ADEN) |
        (1 << ADATE) |
        (1 << ADIE) |
        (1 << ADPS1) |
        (1 << ADPS2) | // ADC prescaler is 64
        (1 << ADSC);

    sei();

    // All the magic happens in the ISR.
    for (;;) {
        set_sleep_mode(SLEEP_MODE_IDLE);
        sleep_mode();
    }
}

von Gunnar F. (gufi36)


Lesenswert?

Hi, danke für die Beiträge!
Allerdings möchte ich aus verschiedenen Gründen bei STM32 bleiben.
Habe jetzt schon wieder Stunden vergeudet, beim Versuch, über die HAL 
zwei Timer Kanäle mit HAL_TIM_PWM_START_DMA(....) mit Zeiger auf zwei
Sinustabellen zu starten. Es ist zum Kotzen, denn Kanal1 läuft wie 
erwartet, Kanal2 gibt zwei kurze Pulse ab, dann nichts mehr.
Habe auf eevblog gelesen, man dürfe die nicht direkt nacheinander 
starten, aber ein Delay(500) dazwischen hilft nicht. Wenn ich zuerst 
Kanal2 starte, ist das Ergebnis auch dasselbe! Auch Warten in einer 
While( ...== HAL_BUSY) hilft nicht. Ich bin ratlos.
Ob das Bugs in der HAL sind, oder mein BluePill eine Fälschung (gekauft 
2018), keine Ahnung.
Ich kann das auch nochmal mit einem original STM32F1 DISCOVERY Board 
testen.
Aber Alternative ist einfach, auf DMA zu verzichten und im Interrupt 
Callback neue Werte in die CCR Register zu schreiben.
Aber so ärgerlich, wieviel Zeit und Nerven mich das schon wieder 
gekostet hat!
Bei Interesse kann ich die Sourcen oder auch das ganze Projekt posten.

von Georg H. (gerontec)


Lesenswert?

OK, da bin ich gespannt, mit dem STM32 wird das ein harter Job für timer 
freaks, ich habe auf die nirgendwo eine Lösung gefunden.

A single STM32 timer usually has multiple channels (4, 6, or whatever 
found in the datasheet). Therefore, using a single timer you can 
independently generate multiple PWM signals with different duty cycles 
of course, but they'll share the same timing (same frequency), and all 
of them will be in sync.

Dagen gibt es für andere Chips seit 2012 Lösungen:
von Matthias S. (Firma: matzetronics) (mschoeldgen)
04.06.2012 07:23

AVR447 beschreibt, wie man 3 Timer im ATMega 48/88/168 synchronisieren
kann, falls die GTCCR Features nicht vorhanden sind. Die 3-Phasen PWM
ist dann sehr brauchbar und braucht keinerlei externe Hardware. Habe
hier gerade einen kleinen (700-1000 Watt) FU programmiert, den ich evtl.
mal in einem Artikel vorstelle, wenn die GUI fertig ist. Der
angeschlossene Motor jedenfalls schnurrt schon wie ein Kätzchen :-)

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Angehängte Dateien:

Lesenswert?

Wen du 3 CC Register hast kannst du doch:
MODE= Continue Up to CC0
CC0=(PWM Period) Dauer
CC1=(PWM 0°) Set/Reset
CC2=(PWM 180°)Reset/Set
dan hast du am CCOut1 und CCOut2 die um 180° Phasenverschobenen 
Ausgänge?

73 55

: Bearbeitet durch User
von Gunnar F. (gufi36)


Lesenswert?

Hi Patrick, danke aber ich brauche ja nicht zwei invertierte PWM Kanäle. 
Das bietet TIM1 von sich aus schon. Ich muss statt dessen mit 180Grad 
verschobener Sinustabelle vergleichen.

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Gunnar F. schrieb:
> Ich muss statt dessen mit 180Grad
> verschobener Sinustabelle vergleichen.

Dazu setzt du ein Indexierten 8Bit Autoincrement Pointer auf die 
Tabelle, und lädst mit jedem Interupt des CC0 die Nächste Position 
deiner Tabelle Ideal machst du die Tabelle 256(8 Bit PWM) oder 128(16 
Bit PWM) Zeilen lang und indexierst sie mit 8 Bit
Dann gibt's einen Automatischen Rollover
CC1= Index 1 und
CC2= mit Index 2.
Dann kannst du jede Beliebige Phasenverschiebung realisieren.

: Bearbeitet durch User
von Gunnar F. (gufi36)


Angehängte Dateien:

Lesenswert?

ok, das meinte ich ja damit, auf DMA zu verzichten und neue CCR in der 
Interrupt Routine zu laden.
Und das funktioniert auch schon!
Die Interrupts lösen nur hier bei Over- und Underflow aus. tbc..

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Georg H. schrieb:
> Dagen gibt es für andere Chips seit 2012 Lösungen:
> von Matthias S. (Firma: matzetronics) (mschoeldgen)
> 04.06.2012 07:23

Ich habe die AVR447 auch auf den kleinen STM32F100RB portiert, der auf 
dem VLDiscovery Board ist, allerdings natürlich auf den Advanced Timer 
mit den bis zu 4 CC Kanälen. Die Anwendung von DMA ist völlig unnötig, 
weil selbst bei den lulligen 24MHz des STM32F100 das Nachladen der CC 
Register im Timeroverflow überhaupt keine Rechenleistung erfordert. 
Benutzt man einen F103 o.ä., relativiert sich das noch mehr.
Macht man sich also 2 Tabellen, die die für das System des Herrn 
Professors passen, lädt man die im Overflow Interupt in CCA und CCB 
(oder welche auch immer) und ist bereits fertig.
Die Herausforderung bei AVR447 ist ja die variable Summenfrequenz, die 
der TE anscheinend gar nicht braucht.

: Bearbeitet durch User
von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Gunnar F. schrieb:
> Die Interrupts lösen nur hier bei Over- und Underflow aus.
Der Timer muss im Continue UP-Mode Laufen (nicht Up/Down)
Du musst Flankengesteuert (Hi/Low) IRQ mit dem CC0 setzen,
Dann wird der Interrupt nur bei jedem (TCTR xxx->0) ausgelöst...
oder reden wir aneinander Vorbei?

: Bearbeitet durch User
von Gunnar F. (gufi36)


Lesenswert?

Patrick L. schrieb:
> Der Timer muss im Continue UP-Mode Laufen (nicht Up/Down)
> Du musst Flankengesteuert (Hi/Low) IRQ mit dem CC0 setzen,
> Dann wird der Interrupt nur bei jedem (TCTR xxx->0) ausgelöst...
> oder reden wir aneinander Vorbei?
Das scheint mir fast so. Beim STM32F103C8 (Fehler imTitel!) kenne ich 
nur die Modi Upcounting, Downcounting und Center Aligned (up/down).
Und ein TCTR Register finde ich da auch nicht?

von Alex -. (alex796)


Lesenswert?

Gunnar F. schrieb:
> Und was ich leider gar nicht verstehe: Der Advanced Timer1 hat ja eben
> schon 3 komplementäre Outputs und ich lese überall von 3-phase PWM. Aber
> über die drei CCRX-Register kann ich ja nur drei Pulsweiten definieren,
> aber keine Phasenverschiebung? Oder Denkfehler?
>
> Ich habe mir heute einen Wolf gesucht, nach 3-phase Motor Control, wo
> der Timer eben drei Phasen mit 120° Verschiebung erzeugen soll, habe
> aber keine Info gefunden, wie das zu machen ist.

Ich kenne das von den C2000 DSPs von TI so, dass man pro Phase EIN PWM 
peripheral verwendet. Für einen 3Phasen Wechselrichter (oder 
Gleichrichter) werden entsprechend 3 PWM peripherals verwendet. Auf die 
STM32 Welt übertragen würdest du 3 Timer verwenden.

Ich habe mir gerade das Reference manual vom STM32F411 angeschaut. Dort 
würde ich intuitiv die drei dedizierten Timer (z.B. TIM2, TIM3, TIM4) 
für einen 3Phasen Wechselrichter verwenden. TIM2 entspräche Phase 1, 
TIM3 entspräche Phase 2, TIM4 entspräche Phase 3.
Alle 3 Timer haben ihren eigenen Carrier, der allerdings 
synchronisiert/phasengleich ist, so dass alle 3 Timer effektiv denselben 
Carrier sehen. Es gibt eine einzige ISR (z.B. TIM2), in der die DREI 
neuen Referenzsignale für den nächsten Taktzyklus berechnet wird. Anbei 
ein Codeschnipsel meiner ISR vom C2000 von einem Multilevel 
Wechselrichter. ePWM2 ist ein dedizierstes PWM Modul. ePWM6 ist ein 
zweites dedizierstes PWM Modul. epwm2_isr dient als ISR für die 
Generierung des neuen Referenzsignals und der PWM ermittelung. In der 
STM32F411 Welt wäre das z.B. TIM2 und TIM3.
1
__interrupt void epwm2_isr(void)
2
{
3
  AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0;
4
  if(RESULTS_BUFFER_SIZE <= resultsIndex)
5
  {
6
    resultsIndex = 0;
7
    bufferFull = 1;
8
  }
9
10
  // Calculates the duty cycle
11
  index_a=(phase_a>>22);
12
  t_A = M*sin(i*2*pi/steps)*PRD;
13
14
15
  if(phase_a  < PHASE_180)
16
  {
17
    EPwm6Regs.CMPA.bit.CMPA=PRD;
18
    EPwm2Regs.CMPA.bit.CMPA=M*sin(i*2*pi/steps)*PRD;
19
  }
20
  else
21
  {
22
    EPwm2Regs.CMPA.bit.CMPA=0;
23
      EPwm6Regs.CMPA.bit.CMPA = M*sin(i*2*pi/steps)*PRD+PRD;
24
  }
25
26
  phase_a=phase_a+phase;
27
  i++;
28
  if(i==steps)
29
  {
30
    i=0;
31
  }
32
    // Clear INT flag for this timer
33
    EPwm2Regs.ETCLR.bit.INT = 1;
34
    // Acknowledge this interrupt to receive more interrupts from group 3
35
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
36
}

von Alex -. (alex796)


Lesenswert?

Gunnar F. schrieb:
> Ich muss statt dessen mit 180Grad
> verschobener Sinustabelle vergleichen.

Reicht da nicht ein einfacher Vorzeichenwechsel?

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Gunnar F. schrieb:
> Und ein TCTR Register finde ich da auch nicht?

Damit ist das Counterregister selber gemeint wenn der Timer mit CC0 
Zurückgesetzt wird.

Gunnar F. schrieb:
> kenne ich
> nur die Modi Upcounting, Downcounting
Ich kenne den spezifischen STM Nicht aber in denen die ich auf meinem 
EVK Habe kann ich den Timer im Continue Up Mode laufen lassen und mit 
CC0 auf "0" zurücksetzen. Programmiere allerdings in ASM deshalb weiss 
ich den "C" Befehl dazu nicht ausswendig und bin Unterwegs und kann 
daher mit dem Handy nicht nachsachauen.

Kann mir aber nicht vorstellen dass es bei irx einem STM32 nicht gehen 
sollte.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Der STM32F103 hat 2 Advanced Timer (Timer 1 und Timer 8) mit bis zu 6 
PWM Ausgängen lt. Datenblatt (bzw. RM0008 ab Seite 282). Ausserdem einen 
Deadtime Block pro Timer (Seite 307). Damit kann man genauso arbeiten 
wie ich mit dem STM32F100 und es reicht vermutlich sogar einer der 
beiden Timer.

: Bearbeitet durch User
von Alex -. (alex796)


Lesenswert?

Matthias S. schrieb:
> Der STM32F103 hat 2 Advanced Timer (Timer 1 und Timer 8) mit bis
> zu 6
> PWM Ausgängen lt. Datenblatt (bzw. RM0008 ab Seite 282). Ausserdem einen
> Deadtime Block pro Timer (Seite 307). Damit kann man genauso arbeiten
> wie ich mit dem STM32F100 und es reicht vermutlich sogar einer der
> beiden Timer.

Oh wow. Ich hätte mir das Timermodul vom STM32 doch mal genauer angucken 
sollen. Das macht meinen vorigen Text überflüssig.

Guter Hinweis!

Gruß,

von Gunnar F. (gufi36)


Lesenswert?

Danke Euch. Wie geschrieben funktioniert die Sache ohne DMA durchaus, 
nur wird der PeriodElapsed Interrupt doppelt so oft ausgelöst, wie ich 
brauche. Eigentlich soll im Center Aligned Mode1 nur nach Underflow 
ausgelöst werden. Auswerten des DIR-Bits auch bisher ohne Erfolg. Das 
zuletzt gezeigte Foto zeigt das Problem. Die PWM bleibt viel zu lange 
High. Ich bin mal ne Weile raus. Genug graue Haare gewachsen...

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Angehängte Dateien:

Lesenswert?

Ich denke du hast NICHT die Hell-Grüne gezeigte Linie(Bild) sondern 
die Blaue :-S

73 55

: Bearbeitet durch User
von Gunnar F. (gufi36)


Lesenswert?

Patrick L. schrieb:
> Ich denke du hast NICHT die Hell-Grüne gezeigte Linie(Bild) sondern
> die Blaue :-S
>
> 73 55

Richtig, wie in meinem Eröffnungsbeitrag gezeigt,  die dreieckigen. Das 
sind die Timer-CNT Register. Weil ich die aber nicht invertieren kann, 
habe ich zwei Sinustabellen. (eine invertiert)

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Gunnar F. schrieb:
> Weil ich die aber nicht invertieren kann,
> habe ich zwei Sinustabellen. (eine invertiert)

.....Und hast somit doppelt so viele IRQ wie du brauchst :-(

: Bearbeitet durch User
von temp (Gast)


Lesenswert?

Ich finde die DMA Lösung hier auch komisch. Wenn das ein Wechselrichter 
werden soll, muss ja auch die Amplitude verrechnet werden. Im Interrupt 
ist das kein Problem, bei DMA müsste man die Tabelle neu rechnen, ob das 
besser ist sei dahin gestellt

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.