Hallo, ich möchte bei einem Atxmega128A1 einen Frequenzgenerator über den DMA laufen lassen. Hierzu soll der DMA bei jedem TCC0 Interrupt einen Wert an den Port (an welchem ein DAC angeschlossen ist) ausgeben. Das funktioniert auch soweit. Jedoch ist mir aufgefallen, dass die Interruptserviceroutine den Prozessor beeinflusst. Wenn die die 3 Zeilen der ISR herrausnehme, kann man den Timer ändern wie man will, am die Zeit in der der DMA die Werte rausschickt ändert sich nicht. Kann mir irgendwer weiterhelfen? void init_TIMER_DMA (void) { PMIC.CTRL=0x07; //Enable all IRQs PORTA.DIR=0xff; EVSYS.CH0MUX=0xc0; // Event0 = TCC0 OVFL // initialize TCC0 Counter TCC0.CTRLB=0x00; // normal count TCC0.PER=40; // top count value TCC0.CTRLA=0x00; // counter stop //Interrupt konfigurieren (Highlevel Interrupt) TCC0.INTCTRLA = 0x03; //* initialize DMA chanel 0 DMA.CTRL = DMA_CH_ENABLE_bm; // Aktivieren Single Buffer, Burst Size 1Byte DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_TRANSACTION_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTRELOAD_BURST_gc | DMA_CH_DESTDIR_INC_gc; DMA.CH0.TRIGSRC = 0x40; //trigger source TCCo overflow DMA.CH0.DESTADDR0 =(uint8_t)(((uint16_t)&PORTA.OUT)>>0)&0xFF; DMA.CH0.DESTADDR1 =(uint8_t)(((uint16_t)&PORTA.OUT)>>8)&0xFF; DMA.CH0.DESTADDR2 =0; sei(); } ISR(TCC0_OVF_vect) { } void start_dma(void) { DMA.CH0.TRFCNT = 256; DMA.CH0.SRCADDR0 =(uint8_t)(((uint16_t)&sinus)>>0) & 0xFF; DMA.CH0.SRCADDR1 =(uint8_t)(((uint16_t)&sinus)>>8) & 0xFF; DMA.CH0.SRCADDR2 =0; DMA.CH0.CTRLA = 0xA4; // Aktivieren, Wiederholen, 1 Byte, Single TCC0.CTRLA=0x01; // start counter }
TCC0.CTRLD=0x08; bei der INIT habe ich noch folgende Zeile vergessen, funktioniert trotzdem nicht.
Hallo,
> DMA.CH0.TRIGSRC = 0x40; //trigger source TCC0 overflow
hier legst du fest, wann der DMA loslegen soll.
Die Interruptserviceroutine kann leer oder für andere Funktionen im
Programm genützt werden. Nicht aber zum Starten der DMA-Routine. Sie
wird hier gestartet: DMA.CH0.TRIGSRC = 0x40.
Mit dem Oszi oder einer Led kann man aber das zeitliche Verhalten der
Interruptserviceroutine testen.
Zum Beispiel:
PORTD.DIRTGL |= PIN3_bm; // Toggle Als Ausgang festlegen
ISR(TCC0_OVF_vect)
{
PORTD.OUTTGL |= PIN3_bm; // Toggle am Ausgang
}
Gruß xmega
Das Problem ist, dass das Timer Overflow Flag nicht zurück gesetzt wird, wenn keine ISR gestartet wird. Somit läuft der DMA auf hochtouren. Am liebsten würde ich aber ganz auf die ISR verzichten, welchen Sinn hat sonst der DMA? dann könnte ich den Port auch in der ISR ansteuern.
Hallo, Ro Bret schrieb: > Somit läuft der DMA auf hochtouren Setze for jedem Ausgabebefehl: while( !DMA.CH0.CTRLB & (DMA_CH_ERRIF_bm | DMA_CH_TRNIF_bm)); Die Schleife wartet solange, bis der DMA seine Daten gesendet hat. Siehe auch mein lauffahiges Programm als Anhang! Gruß xmega
Vielen Dank für die schnellen Antworten.... habe schon eine andere Lösung, ich nutze den DMA Channel 1 um über den selben Timer-EVENT das Interruptflag des Timer zurück zu setzen....so funktionierts, ohne reserven der CPU zu verschwenden.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.