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:
1 | unsigned char ucData = 0xAA;
| 2 | unsigned char ucShift = 0;
| 3 |
| 4 | ISR(PCINT_vect) // Kanal Wechsel
| 5 | {
| 6 | ucShift = 0;
| 7 | }
| 8 |
| 9 | ISR(INT1_vect) // BCLK Steigende Flanke!
| 10 | {
| 11 | if((ucData << ucShift) & 0x80)
| 12 | {
| 13 | SDIN_1; //SDIN auf high
| 14 | }
| 15 | else
| 16 | {
| 17 | SDIN_0; //SDIN auf Low
| 18 | }
| 19 | ucShift++;
| 20 | }
|
Doch leider hat SDIN immer High...
Obwohl ja eigentlich immer wieder 0xAA gesendet werden sollte.
Wo steckt hier wohl der Fehler?
Danke schonmal
Claudio Hediger schrieb:
> Wo steckt hier wohl der Fehler?
Mindestens bei den fehlenden volatile bei der Datendefinition.
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
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
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.
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.
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?
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.
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?
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
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"
Anbei mal eine Anwendung für den T2313, der von einem XMEGA parallel
angesteuert wird. Stammt aus obigem Projekt.
1 | .include "tn2313def.inc"
| 2 |
| 3 | .def Null =r2
| 4 |
| 5 |
| 6 | .def Left1 =r4
| 7 | .def Left2 =r5
| 8 |
| 9 | .def Right1 =r7
| 10 | .def Right2 =r8
| 11 |
| 12 | .def Temp =r16
| 13 | .def TempH =r17
| 14 | .def Temp3 =r18
| 15 |
| 16 |
| 17 |
| 18 | ;PortD
| 19 | .equ SData =3 ;I2S-data
| 20 | .equ LRCK =4 ;I2S-wordclock, Left low, Right high
| 21 | .equ LED =6 ;LED on PortD
| 22 |
| 23 |
| 24 |
| 25 |
| 26 |
| 27 |
| 28 |
| 29 | ;**********************************************************************************
| 30 | .org $0000
| 31 |
| 32 |
| 33 | RESET:
| 34 | ;init Stackpointer
| 35 | ldi Temp, low (RAMEND)
| 36 | out SPL, Temp
| 37 |
| 38 | ;init Watchdog
| 39 | wdr
| 40 | in Temp, WDTCR
| 41 | ori Temp, (1<<WDCE) | (1<<WDE)
| 42 | out WDTCR, Temp
| 43 | ldi Temp, 7 ;Watchdog Time-Out ~ 2 sec.
| 44 | out WDTCR, Temp
| 45 |
| 46 | ;clear SRAM
| 47 | clr XH
| 48 | ldi XL, $60
| 49 | clr Temp
| 50 |
| 51 | _CLSR:
| 52 | st X+, Temp
| 53 | cpi XL, $DF
| 54 | brne _CLSR
| 55 |
| 56 | clr Null
| 57 |
| 58 | ;init Ports
| 59 | ldi Temp, 0b00000000 ;Data in from main controller
| 60 | ldi TempH, 0b00000000
| 61 | out DDRB, Temp
| 62 | out PortB, TempH
| 63 |
| 64 | ldi Temp, 0b01001000 ;Control Lines I2S
| 65 | ldi TempH, 0b01000000
| 66 | out DDRD, Temp
| 67 | out PortD, TempH
| 68 |
| 69 |
| 70 | ;reads I2S data
| 71 | GetI2S:
| 72 | ldi Temp, 41
| 73 |
| 74 | _GI2S1:
| 75 | sbic PinD, LRCK
| 76 | rjmp _GI2S1
| 77 |
| 78 | _GI2S2:
| 79 | sbis PinD, LRCK
| 80 | rjmp _GI2S2
| 81 |
| 82 |
| 83 | _Wait32Bit:
| 84 | dec Temp
| 85 | brne _Wait32Bit
| 86 |
| 87 | bst Left2, 7
| 88 | bld Temp, SDATA
| 89 |
| 90 | sbis PinD, LRCK ;Synchronize to falling edge of WordClock (left channel)
| 91 | rjmp _GI2S3
| 92 | sbis PinD, LRCK
| 93 | rjmp _GI2S3
| 94 | sbis PinD, LRCK
| 95 | rjmp _GI2S3
| 96 | sbis PinD, LRCK
| 97 | rjmp _GI2S3
| 98 | sbis PinD, LRCK
| 99 | rjmp _GI2S3
| 100 | sbis PinD, LRCK
| 101 | rjmp _GI2S3
| 102 | sbis PinD, LRCK
| 103 | rjmp _GI2S3
| 104 | sbis PinD, LRCK
| 105 | rjmp _GI2S3
| 106 | sbis PinD, LRCK
| 107 | rjmp _GI2S3
| 108 | sbis PinD, LRCK
| 109 | rjmp _GI2S3
| 110 |
| 111 |
| 112 | _GI2S3:
| 113 | out PortD, Temp
| 114 | clr Temp
| 115 | bst Left2, 6
| 116 | bld Temp, SDATA
| 117 | out PortD, Temp
| 118 | clr Temp
| 119 | bst Left2, 5
| 120 | bld Temp, SDATA
| 121 | out PortD, Temp
| 122 | clr Temp
| 123 | bst Left2, 4
| 124 | bld Temp, SDATA
| 125 | out PortD, Temp
| 126 | clr Temp
| 127 | bst Left2, 3
| 128 | bld Temp, SDATA
| 129 | out PortD, Temp
| 130 | clr Temp
| 131 | bst Left2, 2
| 132 | bld Temp, SDATA
| 133 | out PortD, Temp
| 134 | clr Temp
| 135 | bst Left2, 1
| 136 | bld Temp, SDATA
| 137 | out PortD, Temp
| 138 | clr Temp
| 139 | bst Left2, 0
| 140 | bld Temp, SDATA
| 141 | out PortD, Temp
| 142 |
| 143 | clr Temp
| 144 | bst Left1, 7
| 145 | bld Temp, SDATA
| 146 | out PortD, Temp
| 147 | clr Temp
| 148 | bst Left1, 6
| 149 | bld Temp, SDATA
| 150 | out PortD, Temp
| 151 | clr Temp
| 152 | bst Left1, 5
| 153 | bld Temp, SDATA
| 154 | out PortD, Temp
| 155 | clr Temp
| 156 | bst Left1, 4
| 157 | bld Temp, SDATA
| 158 | out PortD, Temp
| 159 | clr Temp
| 160 | bst Left1, 3
| 161 | bld Temp, SDATA
| 162 | out PortD, Temp
| 163 | clr Temp
| 164 | bst Left1, 2
| 165 | bld Temp, SDATA
| 166 | out PortD, Temp
| 167 | clr Temp
| 168 | bst Left1, 1
| 169 | bld Temp, SDATA
| 170 | out PortD, Temp
| 171 | clr Temp
| 172 | bst Left1, 0
| 173 | bld Temp, SDATA
| 174 | out PortD, Temp
| 175 | nop
| 176 | nop
| 177 | nop
| 178 | out PortD, Null
| 179 |
| 180 | nop
| 181 | nop
| 182 | nop
| 183 | nop
| 184 | nop
| 185 | nop
| 186 | nop
| 187 | nop
| 188 | nop
| 189 | nop
| 190 | nop
| 191 | nop
| 192 |
| 193 | in Left2, PinB
| 194 | nop
| 195 | nop
| 196 | nop
| 197 | nop
| 198 | nop
| 199 | nop
| 200 | in Left1, PinB
| 201 | nop
| 202 | nop
| 203 | nop
| 204 | nop
| 205 | nop
| 206 | nop
| 207 | in Right2, PinB
| 208 | nop
| 209 | nop
| 210 | nop
| 211 | nop
| 212 | nop
| 213 | nop
| 214 | in Right1, PinB
| 215 |
| 216 |
| 217 | nop ;synchronize to right frame
| 218 | nop
| 219 | nop
| 220 | nop
| 221 | nop
| 222 | nop
| 223 | nop
| 224 | nop
| 225 |
| 226 | nop
| 227 | nop
| 228 | nop
| 229 | nop
| 230 | nop
| 231 | nop
| 232 | nop
| 233 | nop
| 234 |
| 235 | nop
| 236 | nop
| 237 | nop
| 238 | nop
| 239 | nop
| 240 | nop
| 241 | nop
| 242 | nop
| 243 |
| 244 | nop
| 245 | nop
| 246 |
| 247 |
| 248 |
| 249 |
| 250 | clr Temp
| 251 | bst Right2, 7
| 252 | bld Temp, SDATA
| 253 | out PortD, Temp
| 254 | clr Temp
| 255 | bst Right2, 6
| 256 | bld Temp, SDATA
| 257 | out PortD, Temp
| 258 | clr Temp
| 259 | bst Right2, 5
| 260 | bld Temp, SDATA
| 261 | out PortD, Temp
| 262 | clr Temp
| 263 | bst Right2, 4
| 264 | bld Temp, SDATA
| 265 | out PortD, Temp
| 266 | clr Temp
| 267 | bst Right2, 3
| 268 | bld Temp, SDATA
| 269 | out PortD, Temp
| 270 | clr Temp
| 271 | bst Right2, 2
| 272 | bld Temp, SDATA
| 273 | out PortD, Temp
| 274 | clr Temp
| 275 | bst Right2, 1
| 276 | bld Temp, SDATA
| 277 | out PortD, Temp
| 278 | clr Temp
| 279 | bst Right2, 0
| 280 | bld Temp, SDATA
| 281 | out PortD, Temp
| 282 |
| 283 | clr Temp
| 284 | bst Right1, 7
| 285 | bld Temp, SDATA
| 286 | out PortD, Temp
| 287 | clr Temp
| 288 | bst Right1, 6
| 289 | bld Temp, SDATA
| 290 | out PortD, Temp
| 291 | clr Temp
| 292 | bst Right1, 5
| 293 | bld Temp, SDATA
| 294 | out PortD, Temp
| 295 | clr Temp
| 296 | bst Right1, 4
| 297 | bld Temp, SDATA
| 298 | out PortD, Temp
| 299 | clr Temp
| 300 | bst Right1, 3
| 301 | bld Temp, SDATA
| 302 | out PortD, Temp
| 303 | clr Temp
| 304 | bst Right1, 2
| 305 | bld Temp, SDATA
| 306 | out PortD, Temp
| 307 | clr Temp
| 308 | bst Right1, 1
| 309 | bld Temp, SDATA
| 310 | out PortD, Temp
| 311 | clr Temp
| 312 | bst Right1, 0
| 313 | bld Temp, SDATA
| 314 | out PortD, Temp
| 315 | nop
| 316 | nop
| 317 | nop
| 318 | out PortD, Null
| 319 |
| 320 | sbi PortD, LED
| 321 | nop
| 322 | nop
| 323 | nop
| 324 | nop
| 325 | nop
| 326 | nop
| 327 |
| 328 | nop
| 329 | nop
| 330 | nop
| 331 | nop
| 332 | nop
| 333 | nop
| 334 | nop
| 335 | nop
| 336 |
| 337 | nop
| 338 | nop
| 339 | nop
| 340 | nop
| 341 | nop
| 342 | nop
| 343 | nop
| 344 | nop
| 345 |
| 346 | nop
| 347 | nop
| 348 | nop
| 349 | nop
| 350 | nop
| 351 | nop
| 352 | nop
| 353 | nop
| 354 |
| 355 |
| 356 | wdr
| 357 |
| 358 | nop
| 359 | nop
| 360 | nop
| 361 | nop
| 362 | nop
| 363 | nop
| 364 |
| 365 | nop
| 366 | nop
| 367 | nop
| 368 | nop
| 369 | nop
| 370 | nop
| 371 | nop
| 372 | nop
| 373 |
| 374 | nop
| 375 | nop
| 376 | nop
| 377 | nop
| 378 | cbi PortD, LED
| 379 | clr Temp
| 380 |
| 381 | bst Left2, 7
| 382 | bld Temp, SDATA
| 383 |
| 384 | sbis PinD, LRCK ;Synchronize to falling edge of WordClock (left channel)
| 385 | rjmp _GI2S3
| 386 | sbis PinD, LRCK
| 387 | rjmp _GI2S3
| 388 | sbis PinD, LRCK
| 389 | rjmp _GI2S3
| 390 | sbis PinD, LRCK
| 391 | rjmp _GI2S3
| 392 | sbis PinD, LRCK
| 393 | rjmp _GI2S3
| 394 | sbis PinD, LRCK
| 395 | rjmp _GI2S3
| 396 | sbis PinD, LRCK
| 397 | rjmp _GI2S3
| 398 | sbis PinD, LRCK
| 399 | rjmp _GI2S3
| 400 | sbis PinD, LRCK
| 401 | rjmp _GI2S3
| 402 | sbis PinD, LRCK
| 403 | rjmp _GI2S3
|
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
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?
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.
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?
Also, ich wuerd den Wandler als Slave laufenlassen und das Timing der
Signale im Bitbang modus machen.
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.
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|