procedure DDSstereo;
// DDS-Frequenz in DDSH1 und DDSL1 (rechter Kanal)
// und DDSH2 und DDSL2 (linker Kanal)
// Tabellen-Adressen (ROM-Seite) in TabelleHi (MSBs) und TabelleLow (LSBs)

begin
  asm;
   ; DDS, aus Zeitgründen etwas geschachtelt
    lds  _ACCA, SinusGen.TabellenSeite ; Seiten-Nummer (Adresse) der Sinus-MSBs
    mov  _ACCBHI,_ACCA
    inc  _ACCA                         ; eine 256-Byte-Seite weiter
    mov  _ACCBLO,_ACCA                 ; Seiten-Nummer (Adresse) der Sinus-LSBs
    lds  _ACCB, SinusGen.Phasenversatz
    ldi  _ACCA, $00
    ldi  _ACCB, $00     ;ggf. Phasenversatz ($30=90°) für L/R bei 1 kHz
    mov  _ACCEHI, _ACCA ;Phasen-Akkumulator und Pointer 1. Kanal
    mov  _ACCELO, _ACCA ;Phasen-Akkumulator
    mov  _ACCFHI, _ACCB ;Phasen-Akkumulator und Pointer 2. Kanal
    mov  _ACCFLO, _ACCA ;Phasen-Akkumulator
    mov  _ACCDHI, _ACCA ; 1. Datenbyte
    mov  _ACCDLO, _ACCA ; 1. Datenbyte
    mov  _ACCCHI, _ACCBHI  ; oberes Byte Z-Register auf High-Tabelle
    mov  _ACCCLO, _ACCA ;Z-Pointer nullen

    ldi  _ACCA, 01000010b;  // CTC, Toggle OC1 on Timer1
    out  TCCR0A, _ACCA;     // CTC, Toggle OC1 on Timer1
  DDSinitLoopStereo:
    sbis TIFR0,1
    rjmp  DDSinitLoopStereo ; auf Timer OCF0A warten
    sbi TIFR0,1          ; ... Timer OCF0A Flag löschen

  SinusGen.DDSstereoLoop:
    sbis TIFR0,1
    rjmp  SinusGen.DDSstereoLoop ; auf Timer OCF0A warten
    sbi TIFR0,1          ; ... Timer OCF0A Flag löschen

    sbi PortB,5          ; I2S-Vorimpuls an
    ldi _ACCA, 01010000b ; SPI Einschaltwert laden
    cbi PortB,5          ; I2S-Vorimpuls aus
    out SPCR, _ACCA      ; SPI einschalten

    out SPDR, _ACCDHI    ; vorbereitetes MSB ausgeben
    ; nächstes MSB berechnen
    sbic  PinD,6         ; LRClk Bit high?
    rjmp DDSstereoCh2    ; anderer Kanal

    add  _ACCELO, SinusGen.DDSL1 ; add value to DDS1 accumulator
    adc  _ACCEHI, SinusGen.DDSH1 ; 1
    cpi  _ACCEHI, 192            ; Überlauf nach 192 Stützwerten
    brlo DDSNoSub1
    subi  _ACCEHI, 192
  DDSNoSub1:
    mov  _ACCCLO,_ACCEHI  ; Z=Index für Sinus-Tabelle
    ; Z zeigt nun auf High-Byte der Sinustabelle Kanal 1
    LPM  _ACCDHI, Z       ; MSB in Data-Reg HI

  SPIstereoWaitHi1:
    in _ACCA, SPSR
    sbrs _ACCA,7 ; SPIF?
    rjmp SPIstereoWaitHi1;  ; auf Ende des SPI-Transfer warten

    out SPDR, _ACCDLO     ; letzten Wert ausgeben
    ; nächstes LSB berechnen
    mov _ACCCHI, _ACCBLO  ; oberes Byte Z-Register auf Low-Tabelle
    mov  _ACCCLO,_ACCEHI  ; Z=Index für Sinus-Tabelle
    LPM  _ACCDLO, Z       ; ... LSB in Data-Reg LO
    mov _ACCCHI, _ACCBHI  ; oberes Byte Z-Register auf High-Tabelle

  SPIstereoWaitLow1:
    in _ACCA, SPSR
    sbrs _ACCA,7 ; SPIF?
    rjmp SPIstereoWaitLow1;  ; auf Ende des SPI-Transfer warten
    ldi _ACCA, 0
    out SPCR, _ACCA ; SPI ausschalten
    LDS _ACCA, UCSRA
    sbrs _ACCA,7
    rjmp  SinusGen.DDSstereoLoop; auf Receive warten
    ret

  DDSstereoCh2:
    add  _ACCFLO, SinusGen.DDSL2 ; add value to DDS2 accumulator
    adc  _ACCFHI, SinusGen.DDSH2 ; 1
    cpi  _ACCFHI, 192            ; Überlauf nach 192 Stützwerten
    brlo DDSNoSub2
    subi  _ACCFHI, 192
  DDSNoSub2:
    mov  _ACCCLO,_ACCFHI  ; Z=Index für Sinus-Tabelle
    ; Z zeigt nun auf High-Byte der Sinustabelle Kanal 1
    LPM  _ACCDHI, Z       ; MSB in Data-Reg HI

  SPIstereoWaitHi2:
    in _ACCA, SPSR
    sbrs _ACCA,7 ; SPIF?
    rjmp SPIstereoWaitHi2;  ; auf Ende des SPI-Transfer warten

    out SPDR, _ACCDLO     ; letzten Wert ausgeben
    ; nächstes LSB berechnen
    mov _ACCCHI, _ACCBLO  ; oberes Byte Z-Register auf Low-Tabelle
    mov  _ACCCLO,_ACCFHI  ; Z=Index für Sinus-Tabelle
    LPM  _ACCDLO, Z       ; ... LSB in Data-Reg LO
    mov _ACCCHI, _ACCBHI  ; oberes Byte Z-Register auf High-Tabelle

  SPIstereoWaitLow2:
    in _ACCA, SPSR
    sbrs _ACCA,7 ; SPIF?
    rjmp SPIstereoWaitLow2;  ; auf Ende des SPI-Transfer warten

    ldi _ACCA, 0
    out SPCR, _ACCA ; SPI ausschalten
    LDS _ACCA, UCSRA
    sbrs _ACCA,7
    rjmp  SinusGen.DDSstereoLoop; auf Receive warten
  endasm;
end;

