www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik I2S am DAC mit AVR unt Interrupt.


Autor: Claudio H. (Firma: BLS-Electronics) (hedie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen...

Ich habe hier einen DAC genauer gesagt einen MAX9850...

Dieser hat ein I2S Interface bzw ist auch anders konfigurierbar.

Meine Konfiguration sieht so aus, das der DAC auf die steigende Flanke 
des BitClockes (BCLK) die Daten Seriell mit MSB First am SDIN Eingang 
erwartet...

Es werden 16Bit übertragen, danach wird der Kanal (Rechts / Links) 
gewechselt (LRCLK High->Low) und das ganze beginnt von vorn!

Ich habe den MAX9850 so konfiguriert, das er im Master moder arbeitet.
Damit erzeugt er die Signale BCLK und LRCLK selbst.

Ich habe beide mit InterruptPIN's verbunden.

BCLK auf INT1 auf steigende Flanke Triggernd
LRCLK auf PCINT0 da jeder Flanken wechsel entscheidend ist!

Das BCLK Signal ist 3MHz schnell
LRCLK 8KHz

Mein Controller: Attiny2313 mit 12MHz Takt. Damit wird auch der MAX9850 
getaktet.

Meine Frage nun...
ich möchte gerne sehr einfache PCM sounds wiedergeben.
Zu beginn wollte ich einfach mal einen Test Ton erzeugen.
Dazu habe ich folgenden Code:

unsigned char ucData = 0xAA;
unsigned char ucShift = 0;

ISR(PCINT_vect)                // Kanal Wechsel
{
    ucShift = 0;
}

ISR(INT1_vect)                // BCLK Steigende Flanke!
{
  if((ucData << ucShift) & 0x80)
  {
    SDIN_1;  //SDIN auf high
  }
  else
  {
    SDIN_0;  //SDIN auf Low
  }
  ucShift++;
}

Doch leider hat SDIN immer High...
Obwohl ja eigentlich immer wieder 0xAA gesendet werden sollte.
Wo steckt hier wohl der Fehler?

Danke schonmal

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Claudio Hediger schrieb:

> Wo steckt hier wohl der Fehler?

Mindestens bei den fehlenden volatile bei der Datendefinition.

Autor: Magnus M. (magnetus) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Claudio Hediger schrieb:
> Ich habe beide mit InterruptPIN's verbunden.
>
> BCLK auf INT1 auf steigende Flanke Triggernd
> LRCLK auf PCINT0 da jeder Flanken wechsel entscheidend ist!
>
> Das BCLK Signal ist 3MHz schnell
> LRCLK 8KHz
>
> Mein Controller: Attiny2313 mit 12MHz Takt. Damit wird auch der MAX9850
> getaktet.

(...)

> Doch leider hat SDIN immer High...
> Obwohl ja eigentlich immer wieder 0xAA gesendet werden sollte.
> Wo steckt hier wohl der Fehler?

Rechne mal nach wie viele Takte zwischen zwei steigenden BCLK-Flanken 
für die Abarbeitung deines Interrupts zur Verfügung stehen...

Gruß,
Magnetus

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Damit das auch nur ansatzweise schnell genug die Daten aus dem 
Controller bekommt, würde ich versuchen, den ATtiny als SPI-Slave an den 
I2S anzuschließen. Der sollte sich so konfigurieren lassen, dass man 
zumindest 8 Bit am Stück ohne zusätzliche Softwareaktion rausschicken 
kann.

Grüße,

Peter

Autor: Kurt Harders (Firma: KHTronik) (kurtharders)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie magnetus schrieb: bei 3MHz BCLK und 12MHz Takt des ATTiny hast Du 
maximal 4 Zyklen Zeit für die Abfrage und Speicherung. Da die 
Interrupterkennung auch etwas Zeit braucht, und der Sprung zur 
Interruptroutine auch, wirst Du Dich mit zwei Befehlen begnügen müssen 
:-).
Aber mal zum Tempo: wenn Du mit 48kHz wandelst und 16 Bit Auflösung 
verwendest, lande ich bei 1,5MHz für BCLK. Das ist zwar auch noch knapp, 
aber ohne Interrupt durch Polling der Pins eventuell machbar.
Auf jeden Fall musst Du Dir den Assembleroutput des Compilers anschauen, 
um die Takte zu zählen.

Autor: Claudio H. (Firma: BLS-Electronics) (hedie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für eure Antworten....


Kurt Harders schrieb:
> Aber mal zum Tempo: wenn Du mit 48kHz wandelst und 16 Bit Auflösung
> verwendest, lande ich bei 1,5MHz für BCLK. Das ist zwar auch noch knapp,
> aber ohne Interrupt durch Polling der Pins eventuell machbar.
> Auf jeden Fall musst Du Dir den Assembleroutput des Compilers anschauen,
> um die Takte zu zählen.

Theoretisch hast du recht... Ich habe übrigens nur eine Samplingfrequenz 
von 8KHz

Doch leider gibt der MAX mir die 3MHz vor...

Das Signal Sieht etwa so aus
     ___________________________
____|                             |__________ LRCLK
____||||__________________________||||_______ BCLK

Man sieht also das BCLK sehr schnell ist im vergleich zum LRCLK
Wenn ich den MAX jedoch in den Slave Mode Versetze, dann muss ich diese 
Signale ja selbst erzeugen und das würde nochmals länger dauern...

Peter Diener schrieb:
> Damit das auch nur ansatzweise schnell genug die Daten aus dem
> Controller bekommt, würde ich versuchen, den ATtiny als SPI-Slave an den
> I2S anzuschließen. Der sollte sich so konfigurieren lassen, dass man
> zumindest 8 Bit am Stück ohne zusätzliche Softwareaktion rausschicken
> kann.

Das klingt interessant... Müsste ich mal testen...
Doch da hätte ich dennoch noch das problem das ich z.B. die Daten nicht 
mehr von einer Speicherkarte holen könnte.

Autor: Kurt Harders (Firma: KHTronik) (kurtharders)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Claudio Hediger schrieb:
> Das Signal Sieht etwa so aus
>      ___________________________
> ____|                             |__________ LRCLK
> ____||||__________________________||||_______ BCLK
>
> Man sieht also das BCLK sehr schnell ist im vergleich zum LRCLK

Das sieht mir aber stark nach einer Betriebsart für >2 Kanäle aus. Mit 
welcher Master-Clock betribst Du den DAC?

Autor: Claudio H. (Firma: BLS-Electronics) (hedie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kurt Harders schrieb:
> Das sieht mir aber stark nach einer Betriebsart für >2 Kanäle aus. Mit
> welcher Master-Clock betribst Du den DAC?

Hallo Kurt

Da hast du recht... Es ist ein Stereo DAC

MasterClock ist 12MHz
Der DAC erzeigt die Signale BCLK und LRCLK selbst. Ich dachte mir das 
ich damit mehr zeit zum bereitstellen der Daten habe im AVR. Da ich ja 
diese Signale nicht selbst erzeugen muss.

Wäre ja schon spannend wenn es klappen würde und der Tiny ein I2S Signal 
erzeugen könnte :)

Achjaa die 4 | Striche beim BCLK stehen für 16 Clocks dieser Leitung.
Es wird somit 16Bit Audio erwartet. Das ist das niedrigste was dieser 
DAC kann.

Autor: Kurt Harders (Firma: KHTronik) (kurtharders)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Claudio Hediger schrieb:
> Achjaa die 4 | Striche beim BCLK stehen für 16 Clocks dieser Leitung.
> Es wird somit 16Bit Audio erwartet. Das ist das niedrigste was dieser
> DAC kann.

Und wie viele Takte ist dann die Pause bis zur Flanke LRCLK?

Autor: Claudio H. (Firma: BLS-Electronics) (hedie)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Kurt Harders schrieb:
> Und wie viele Takte ist dann die Pause bis zur Flanke LRCLK?

Es sind ca. 55us

Ich habe nun mal mit dem Oszilloskop ein paar Bilder gemacht...

Bild1 zeigt das gesamte Signal
Bild2 zeigt die Pause bis zum Flankenwechsel von LRCLK nach 16 BCLK 
Clocks
Bild3 zeigt die Frequenz von BCLK

Gelb: LRCLK
Blau: BCLK

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Damit der DAC etwas damit anfangen kann, müssen BitClock, LRClock und 
MasterClock phasensynchron sein. Das erreichst Du nur, wenn der Tiny an 
derselben Taktleitung mit dem DAC hängt und der Code im Tiny absolut 
laufzeitsynchron läuft. Alle Clocks müssen immer präsent sein und dürfen 
weder aussetzen, noch einen Jitter von >1 MasterClock aufweisen.

Siehe hier:
Beitrag "SD-Karten-Wave-Recorder"

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Anbei mal eine Anwendung für den T2313, der von einem XMEGA parallel 
angesteuert wird. Stammt aus obigem Projekt.

.include "tn2313def.inc"

.def  Null    =r2


.def  Left1    =r4
.def  Left2    =r5

.def  Right1    =r7
.def  Right2    =r8

.def  Temp    =r16
.def  TempH    =r17
.def  Temp3    =r18



;PortD
.equ  SData    =3      ;I2S-data
.equ  LRCK    =4      ;I2S-wordclock, Left low, Right high
.equ  LED      =6      ;LED on PortD







;**********************************************************************************
.org $0000


RESET:
;init Stackpointer
 ldi  Temp, low (RAMEND)
 out  SPL, Temp

;init Watchdog
 wdr
 in   Temp, WDTCR
 ori  Temp, (1<<WDCE) | (1<<WDE)
 out  WDTCR, Temp
 ldi  Temp, 7                      ;Watchdog Time-Out ~ 2 sec.
 out  WDTCR, Temp

;clear SRAM 
 clr  XH
 ldi  XL, $60
 clr  Temp

_CLSR:
 st    X+, Temp
 cpi  XL, $DF
 brne  _CLSR

 clr Null

;init Ports 
 ldi  Temp,  0b00000000      ;Data in from main controller
 ldi   TempH, 0b00000000
 out  DDRB, Temp
 out   PortB, TempH                    

 ldi  Temp,  0b01001000      ;Control Lines I2S    
 ldi   TempH, 0b01000000
 out  DDRD, Temp                    
 out   PortD, TempH  


;reads I2S data 
GetI2S:
 ldi  Temp, 41
  
_GI2S1:
 sbic  PinD, LRCK      
 rjmp  _GI2S1

_GI2S2:
 sbis  PinD, LRCK      
 rjmp  _GI2S2
 
 
_Wait32Bit:
 dec  Temp
 brne  _Wait32Bit
 
 bst   Left2, 7
 bld  Temp, SDATA

 sbis  PinD, LRCK      ;Synchronize to falling edge of WordClock (left channel)
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 

_GI2S3:
 out  PortD, Temp
 clr  Temp
 bst   Left2, 6
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left2, 5
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left2, 4
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left2, 3
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left2, 2
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left2, 1
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left2, 0
 bld  Temp, SDATA
 out  PortD, Temp

 clr  Temp
 bst   Left1, 7
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left1, 6
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left1, 5
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left1, 4
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left1, 3
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left1, 2
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left1, 1
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Left1, 0
 bld  Temp, SDATA
 out  PortD, Temp
 nop
 nop
 nop
 out  PortD, Null
 
 nop
 nop
 nop 
 nop 
 nop
 nop
 nop
 nop
 nop
 nop
 nop
 nop
   
 in    Left2, PinB
 nop
 nop
 nop
 nop
 nop
 nop
 in    Left1, PinB
 nop
 nop
 nop
 nop
 nop
 nop
 in    Right2, PinB
 nop
 nop
 nop
 nop
 nop
 nop
 in    Right1, PinB


 nop      ;synchronize to right frame
 nop
 nop
 nop
 nop
 nop
 nop
 nop

 nop
 nop
 nop
 nop
 nop
 nop
 nop
 nop

 nop
 nop
 nop
 nop
 nop
 nop
 nop
 nop

 nop
 nop
 


 
 clr  Temp
 bst   Right2, 7
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right2, 6
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right2, 5
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right2, 4
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right2, 3
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right2, 2
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right2, 1
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right2, 0
 bld  Temp, SDATA
 out  PortD, Temp

 clr  Temp
 bst   Right1, 7
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right1, 6
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right1, 5
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right1, 4
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right1, 3
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right1, 2
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right1, 1
 bld  Temp, SDATA
 out  PortD, Temp
 clr  Temp
 bst   Right1, 0
 bld  Temp, SDATA
 out  PortD, Temp
 nop
 nop
 nop
 out  PortD, Null
 
 sbi  PortD, LED
 nop
 nop
 nop
 nop
 nop
 nop

 nop
 nop
 nop
 nop
 nop
 nop
 nop
 nop

 nop
 nop
 nop
 nop
 nop
 nop
 nop
 nop

 nop
 nop
 nop
 nop
 nop
 nop
 nop
 nop
 

 wdr

 nop
 nop
 nop
 nop
 nop
 nop

 nop
 nop
 nop
 nop
 nop 
 nop
 nop
 nop

 nop
 nop
 nop
 nop
 cbi  PortD, LED
 clr  Temp
 
 bst   Left2, 7
 bld  Temp, SDATA

 sbis  PinD, LRCK      ;Synchronize to falling edge of WordClock (left channel)
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3
 sbis  PinD, LRCK      
 rjmp  _GI2S3

Autor: Claudio H. (Firma: BLS-Electronics) (hedie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Knut Ballhause schrieb:
> Damit der DAC etwas damit anfangen kann, müssen BitClock, LRClock und
> MasterClock phasensynchron sein. Das erreichst Du nur, wenn der Tiny an
> derselben Taktleitung mit dem DAC hängt

Vielen Dank für deinen Code

Ja der Tiny hängt am selben MCLK wie der DAC

Autor: Claudio H. (Firma: BLS-Electronics) (hedie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Claudio Hediger schrieb:
> Knut Ballhause schrieb:
>> Damit der DAC etwas damit anfangen kann, müssen BitClock, LRClock und
>> MasterClock phasensynchron sein. Das erreichst Du nur, wenn der Tiny an
>> derselben Taktleitung mit dem DAC hängt
>
> Vielen Dank für deinen Code
>
> Ja der Tiny hängt am selben MCLK wie der DAC

jetzt muss ich doch nochmal was fragen,

Also du benutzt den Attiny2313 nur als Parallel -> I2S Wandler richtig?

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Claudio Hediger schrieb:
> Also du benutzt den Attiny2313 nur als Parallel -> I2S Wandler richtig?

Genau, weil viel mehr ist nicht drin. Allerdings kannst Du in den 
"NOP"-Sequenzen auch Daten von einer anderen Quelle schaufeln und über 
I2S ausgeben. Der T2313 ist im Beispiel übrigens auch ein Slave, der 
sich an der LRCK des Masters orientiert. Der Code ist so getimed, dass 
per BitClock-Low des I2S ein Bit ausgegeben wird. Dies wird über die 
Sync-Schleife am Anfang erreicht. In der Mainloop wird diese 
Synchronität durch die exakte Laufzeit des Codes nicht mehr verlassen.

Autor: Claudio H. (Firma: BLS-Electronics) (hedie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Knut Ballhause schrieb:
> Genau, weil viel mehr ist nicht drin. Allerdings kannst Du in den
> "NOP"-Sequenzen auch Daten von einer anderen Quelle schaufeln und über
> I2S ausgeben. Der T2313 ist im Beispiel übrigens auch ein Slave, der
> sich an der LRCK des Masters orientiert. Der Code ist so getimed, dass
> per BitClock-Low des I2S ein Bit ausgegeben wird. Dies wird über die
> Sync-Schleife am Anfang erreicht. In der Mainloop wird diese
> Synchronität durch die exakte Laufzeit des Codes nicht mehr verlassen.

weshalb hast du kein ParallelIN SerialOut Register verwendet?

z.B. 74HC165

Das macht ja eigentlich genau das selbe... Man muss nur am Clock eingang 
den BitClock anhängen und um das Propagation Delay zu umgehen invertiert 
man den Eingang. So das auf eine Fallende BitClock Flanke das Bit 
geshiftet wird und mit der Steigenden übernimmt der DAC das Bit... Das 
müsste doch eigentlich gehen oder?

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, ich wuerd den Wandler als Slave laufenlassen und das Timing der 
Signale im Bitbang modus machen.

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Claudio Hediger schrieb:
> weshalb hast du kein ParallelIN SerialOut Register verwendet?
>
> z.B. 74HC165
>
> Das macht ja eigentlich genau das selbe...

Nicht ganz. Die Controller sind über die Firmware in der Lage, 
verschiedene Protokolle auszugeben/anzunehmen, zum Beispiel I2S, Left 
Justified, Right Justified oder DSP-Protokoll. Ausserdem sind 
verschiedene Bitbreiten pro Frame möglich. Erfolgreich getestet habe ich 
bis 20 Bit, die restliche Laufzeit geht für das Datenschaufeln drauf. 
Diskrete Bauelemente sind da etwas statisch und ich hatte genug T2313 
herumliegen.

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
O.. oha Jetzt ! schrieb:
> Also, ich wuerd den Wandler als Slave laufenlassen und das Timing der
> Signale im Bitbang modus machen.

Wie meinen? Es ist für den Controller einfacher, ein Slave zu sein, da 
sonst noch das Timing für die Clocks in den Code müsste, was 
laufzeitbedingt nicht geht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.