Shop OBEX P1 Docs P2 Docs Learn Events
High Quality Audio. Prop Dac or other DAC? - Page 2 — Parallax Forums

High Quality Audio. Prop Dac or other DAC?

2»

Comments

  • Mark_TMark_T Posts: 1,981
    edited 2014-01-14 17:07
    Normally you have to keep in perfect synchrony with the master clock or the chip shuts down - you get a certain
    number of MCLKs leeway, so you'll need to resynchronize the the master clock regularly - I found it much
    easier just to run everything from the one clock then WAITCNT/cycle counting/WAITPEQ does all the heavy lifting.

    If the LRCLK and BCLK are generated for you it shouldn't be too hard to sync to them, but I can't see how you'd
    sync without slipping to MCLK.
  • T ChapT Chap Posts: 4,223
    edited 2014-01-14 18:20
    I haven't nailed this down, but a lot of people are using this ES9023 in Asynchronous mode. The data sheet does not specify any method to switch from modes, but I read on one companies literature that uses the DAC that it "locks on to whatever it gets'. Since the master clock the DAC will be seeing is 768*44100, it exceeds the requirement for async. There is no method I can find to switch modes by any means, so apparently the DAC just does lock to whatever it gets. It states that it will accept clocks of 256fs, 384fs, 512fs, 768fs for audio playback of 44100.
    826 x 411 - 127K
  • T ChapT Chap Posts: 4,223
    edited 2014-01-15 08:12
    What about I use Kye's V2 engine and remove the noise shaping plus ctr management lines, and replace the ctr dac control with the I2S routines?

    The first attempt will be to use the DAC as async mode, so no syncing to any clock, just let the PASM code render it's own timing to the DAC.
  • T ChapT Chap Posts: 4,223
    edited 2014-01-18 15:43
    I got a board built today. A few errors on the pcb that are hackable. I didn't get in a few parts( Op amps ) as digikey is having some bad weather. The RTC, SD card, PLL clock are working. Now to start working on how to get some audio out of it from the ES9023 DAC and then Kye's wave player.
    640 x 478 - 120K
  • T ChapT Chap Posts: 4,223
    edited 2014-01-19 11:06
            mov     Time, cnt               'setup time delay
            add     Time, cntadd
            waitcnt Time, wait    ' value doesn't matter
            xor     outa, ledmask
            mov     Time, cnt               'setup time delay
            add     Time, cntadd
            waitcnt Time, wait
            jmp     #:loop
    
    ctra_   long    %01010 << 26 + 27        'mode + APIN  %01010
    cntadd  long    2_400_000   '2_400_000 visible blink rate,  below is solid LEDs
    wait    long    0     '<< doesnt matter what this is 0 to 2b
    Ledmask long    %10_00000000_00000000 ' 17
    cnt_    res     1
    new     res     1
    old     res     1
    temp    res     1
    Time    res     1
    

    Hey guys I am stuck on about 5 hours trying to find out what is going on. I have studied the manual and looked at examples that all show the ADD cntadd value to Time as the first thing to do after moving CNT to TIME. But I also see other values used in the dest value Waitcnt Time, SomeValueHere.

    I have an LED connected, and at the rate shown of 2_400_000 I can still see blinking, below this rate the LED becomes more solid. What is the purpose of the destination value in Waitcnt? I can set it to 0 to any number and it has no effect on the rate of the LED blinking. The waitcnt instruction seems to be ignoring the dest value completely as if it were just a placeholder.
  • kuronekokuroneko Posts: 3,623
    edited 2014-01-19 18:01
    T Chap wrote: »
    I have an LED connected, and at the rate shown of 2_400_000 I can still see blinking, below this rate the LED becomes more solid. What is the purpose of the destination value in Waitcnt? I can set it to 0 to any number and it has no effect on the rate of the LED blinking. The waitcnt instruction seems to be ignoring the dest value completely as if it were just a placeholder.
    The destination value (waitcnt dst, src) is the cnt target at which point the insn is released from its wait state. You're most likely referring to the advancement (source value) which prepares the next target value (dst += src, waitcnt defaults to wr). In your code you manually reset the target (destination) value every time which means any advancement you apply is ignored. Try this (active advance):
    entry           mov     dira, ledmask
    
                    mov     Time, cnt
                    add     Time, #9        ' stop waitcnt from locking up
    :loop           waitcnt Time, cntadd    ' settle for Time+N*cntadd
                    xor     outa, ledmask
                    jmp     #:loop
    
    cntadd          long    2_400_000
    ledmask         long    |< 17
    
    Time            res     1
    
    Note, it waits first on dst then - on the way out - adds src to dst.
  • T ChapT Chap Posts: 4,223
    edited 2014-01-19 18:22
    Yes you are correct I was referring to the Source value not dest. I finally found some discussion on this same exact subject in which Mike Green explained to someone what was going on. The manual should be more clear on this imo. Thanks for the suggestions.
  • T ChapT Chap Posts: 4,223
    edited 2014-01-19 20:59
    This is how far I got today experimenting with how to clock the 24 bits out to the DAC using a master clock input to the Prop at 384 *44100.

    My calculations are, 48 BitClocks per sample for left and right channels at 24 bits each. Each Word Select (LR Clock) phase is 192 master clock ticks each.

    I intend to use a COG for reading the master clock in and outputting a bitclock to the DAC. This COG will likely not do anything else. Then a COG will watch the bitclock output pin, and divide down to produce the LR Clock output. The main COG will run the audio read from SD, and another COG will write the data bits to the DAC watching the bitclockpin and LR clock pin for timing.
    DAT   'Start a Bit Clock  based on external clock @ (384 * 44100 ) / 48 bits per sample
    'each 384 ticks is a full sample (fs) at 44.1k.  384/2 = 192 ticks per channel for
    '24bits, Word Select toggle rate is every 192 ticks.  Bit Clock is 384 / 48 bits = 8 ticks per bit
            org
    entry   mov     ctra, ctra_            'establish mode and start counter
            mov     frqa, #1               'increment for each edge seen
            mov     time, CNT              'initialize CNT to Time if needed
            add     time, BitLen           ' setup LRCLK time accounting
            or      dira, ledmask
            mov     $, #0 wz, nr           'clear any set z
            ' Start Loop to dither 384 * 44100 to 8 ticks per bitclock
    :loop   mov     new, phsa              'record new count
            cmp     new, BitLen   wz, wc   '384 / 48 bits per sample =  8 ticks
    if_ae   or      outa, ledmask
            'add delay if required, then shorten loop time to compensate for loss due to clocks in ASM
            mov     time, CNT  
            add     time, cntadd
            waitcnt TIME, cntadd
    if_ae   xor      outa, ledmask
    if_ae   mov     phsa, #0
            jmp     #:loop
    
    ctra_   long    %01010 << 26 + 27        'mode + APIN  %01010
    cntadd  long    2_400_000    'value used for visible blink using LED as debug at home
    BitLen   long   2_400_000    ' Use 8 for bit rate   384 / 48bits
    Ledmask long    |< 17
    
  • T ChapT Chap Posts: 4,223
    edited 2014-01-20 04:22
    I have tried to convert Mark T's WM8524 DAC code to use on my DAC. His code was Left Justify. I have changed it to I2S format which has the LR clock changing states just before the LSB or the 24 bit data per channel. The next step is to find out how to buffer the audio and have this loop read it. This loop watches the bitclock that is posted above, which is derived from the external master clock. There is some question about my use of waitpeq and waitpne to lock to the bitclock pin. The plan is to try to look at this on the Parallax Logic analyzer in I2S mode later today.
    DAT
                  ORG       0                 'Begin at Cog RAM addr 0
    
    ES9023        mov       parm, PAR        ' COPT PAR to asm PARM
                  rdlong    temp, parm       ' COPY the pin config PAR to PARM in ASM
                  add       parm, #4         ' GET VAR POSITION of LeftPtr
                  rdlong    LeftDataaddr, parm   ' COPY LEFTPTR ADDRESS IN ASM
                  add       parm, #4         ' GET VAR POSITION of RightDataPtr
                  rdlong    RightDataaddr, parm  ' COPY RightDataPTR ADDRESS IN ASM
    
                  ' SET PIN DIRECTION
                  'or        DIRA, mclkMSK
                  'or        DIRA, bclkMSK
                  or        DIRA, LRClkMSK
                  or        DIRA, DataInMask   'data in to Dac
    
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    
                  ' SET LRCLOCK HIGH to start
                  mov       OutPut, LRClkMSK
                  mov       OUTA, OutPut           '___---  L R CLK HIGH
                  mov       zero, #0
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                  'initialize LR and elapse first bitclock
                  WAITPEQ   zero, bclkMSK           ' Wait for Bitclock LOW
                  andn      OutPut, LRClkMSK        ' ---____   L R CLK LOW
                  'First bitclock high after LR Clock change
                  WAITPNE   zero, bclkMSK           ' Wait for Bitclock HIGH  __--
                  '
                  ''''WAITPEQ   zero, bclkMSK           ' Wait for Bitclock LOW   --__
    
                  ' Second bitclock High after LR Change   MSB send
    :loop         'GET THE L E F T WORD
                  rdlong    LeftData, LeftDataaddr     ' read LEFT data
                  shl       LeftData, #8               ' shift LeftData 8  assumes a 16bit val
                  mov       n, #23    'Send 23 then change LR and send 24th
                  ' Start MSB on second bitclock high
    
                  ' SHIFT OUT LeftData 24BITS            start while bitclock is LOW
                  ' RCL Rotate C Left    << Data by n Bits
    :LeftDataloop rcl       LeftData, #1        WC  ' shift out one data bit (MSB first)
                  muxc      OutPut, DataInMask      ' put THIS bit in the RightData pin position
                  WAITPEQ   zero, bclkMSK           ' wait for bclk falling edge
                  mov       OUTA, OutPut            ' _DRIVE_ outputs (LRCLK, DIN, LRCLK)
                  djnz      n, #:LeftDataloop       ' loop23 times
                  'LR change before LSB (bit 24)
                  or        OutPut, LRClkMSK        '___---  L R CLK HIGH
                  ' Send 24th bit after LR Change
                  rcl       LeftData, #1        WC  ' shift out one data bit (MSB first)
                  muxc      OutPut, DataInMask      ' put THIS bit in the RightData pin position
                  WAITPEQ   zero, bclkMSK           ' wait for bclk falling edge
                  mov       OUTA, OutPut            ' _DRIVE_ outputs (LRCLK, DIN, LRCLK)
    
    
                  'GET THE R I G H T WORD
                  rdlong    RightData, RightDataaddr   ' read RIGHT data
                  shl       RightData, #8              ' assumes 16 bit
    
                  mov       n, #23
                  WAITPEQ   zero, bclkMSK           ' wait for the bit clock to be low
    
                  ' SHIFT OUT LeftData 24BITS
    :RightDataloop rcl       RightData, #1      WC
                  muxc      OutPut, DataInMask
                  WAITPEQ   zero, bclkMSK
                  mov       OUTA, OutPut            ' _DRIVE_ outputs (LRCLK, DIN)
                  djnz      n, #:RightDataloop
                  'LR change before LSB (bit 24)
                  andn      OutPut, LRClkMSK        ' ---____  L R CLK LOW
                  ' Send 24th bit after LR Change
                  rcl       RightData, #1       WC
                  muxc      OutPut, DataInMask
                  WAITPEQ   zero, bclkMSK
                  mov       OUTA, OutPut            ' _DRIVE_ outputs (LRCLK, DIN)
    
                  jmp       #:loop                  ' ready for next sample set
    
  • kuronekokuroneko Posts: 3,623
    edited 2014-01-20 04:31
    @T Chap: In post #39, why do you think you need the mov $, #0 wz,nr?
  • T ChapT Chap Posts: 4,223
    edited 2014-01-20 05:41
    Good observation! Well, to be honest when I was experimenting with the waitcnt's and if_a following cmp, I was finding that if there was NO instruction anywhere(ie commenting out the cmp for testing) that included wz or wc, I was seeing that if_a was firing as true. So I searched for info on what may be the states of z and c if no instructions were called to set z or c and couldn't determine if z and c might load in an undefined state as I was witnessing. I was testing with an LED output to watch the waitcnt states to learn how they worked, and just decided to leave in the z and c clear even though I believe that once any instruction includes wz or wc then effect they would be "cleared' by default to whatever the result was. I will take it out after I am finished testing.
  • T ChapT Chap Posts: 4,223
    edited 2014-01-21 07:06
    Just got tones out of the DAC for the first time. The output is super quiet with no data playing and has a nice built in ramping mute/unmute.

    For testing, I have a crude tone generator in the BitClock generator:
    PUB  Start(leftt,rightt)   |  value
      dira[CSEL]~~
      outa[CSEL]~   ' 0 = 768 * 48000   1 = 48000 * 512
      'dira[led]~~
      dira[DACMute]~~
      outa[dacmute]~~  'active low mute
      MasterClockSetup
      cog := 1 + cognew (@entry, @value) 'Launch new cog
      dac.start(@leftptr, @rightptr)  ' start the DAC engine
      'wavplayer
      'wav.setLeftVolume(7)
      repeat
        leftptr  :=  rightptr := %01111111_11111111_11111111
        waitcnt(800 + cnt)
        leftptr  :=  rightptr := %11111111_11111111_11111111
        waitcnt(800 + cnt)
    

    The ES9023DACengine shifts the data left 8 bits, then streams to the DAC in I2S mode. I am still trying to find a way to turn off the noise shaping and counter DAC output on Kye's V2 waveplayer engine, and only use the left and right data to feed my DAC engine.

    Here is the I2S output:
    DAT
                  ORG       0                 'Begin at Cog RAM addr 0
    
    DAC           mov       parm, PAR        ' COPT PAR to asm PARM
                  rdlong    temp, parm       ' COPY the pin config PAR to PARM in ASM
                  add       parm, #4         ' GET VAR POSITION of LeftPtr
                  rdlong    LeftDataaddr, parm   ' COPY LEFTPTR ADDRESS IN ASM
                  add       parm, #4         ' GET VAR POSITION of RightDataPtr
                  rdlong    RightDataaddr, parm  ' COPY RightDataPTR ADDRESS IN ASM
    
                  ' SET PIN DIRECTION
                  'or        DIRA, bclkMSK
                  or        DIRA, LRClkMSK
                  or        DIRA, DataInMask   'data in to Dac
                  or        dira, ledmask      ' DEBUG ONLY   REMOVE LED LATER
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    
                  ' SET LRCLOCK HIGH to start
                  mov       OutPut, LRClkMSK       '###SETUP LR  establish Output
                  mov       OUTA, OutPut           '###DRIVE LR   HIGH
                  or        outa, ledmask          ' DEBUG ONLY   REMOVE LED LATER
                  WAITPEQ   HIGH, bclkMSK          ' park here till bitclock starts
                  WAITPEQ   LOW, bclkMSK           '    Wait for Bitclock LOW
                  andn      OutPut, LRClkMSK       '###SETUP LR   LOW
                  mov       OUTA, OutPut           '###DRIVE LR
                  ''''''andn      outa, ledmask          ' DEBUG ONLY   REMOVE LED LATER
                  ' First bitclock high after LR Clock change
                  ' Sync to 48 transitions on BitClock   24 Left  24 Right
                  ' Second bitclock High after LR Change   MSB send
                  WAITPEQ   HIGH, bclkMSK          ' Wait for Bitclock HIGH
                  WAITPEQ   LOW, bclkMSK           ' Wait for Bitclock LOW
    :loop         ' GET THE L E F T WORD
                  rdlong    LeftData, LeftDataaddr     ' read LEFT data
                  shl       LeftData, #8               ' shift LeftData 8  assumes a 16bit val
                  mov       n, #23                     ' Send 1-23 then change LR and send 24th
                  ' Start Clocking out MSB bit 23 on bitclock high
                  ' First loop is 23 times.  Then change LR clock and send 24th data bit
                  ' SHIFT OUT LeftData 24BITS            start while bitclock is LOW
                  ' RCL= Rotate C Left INTO VALUE 1 bit  this shifts data out
                  ' Data bits and LR Clock Changes on Falling Edge of BitClock
    
    :LeftDatalp   rcl       LeftData, #1        WC  ' shift out one data bit (MSB first)
                  muxc      OutPut, DataInMask      ' ###SETUP Data
                  mov       OUTA, OutPut            ' ###DRIVE Data
                  WAITPEQ   HIGH, bclkMSK           ' 1-23 BitCLocks  of  Left phase
                  WAITPEQ   LOW, bclkMSK            ' Wait for Bitclock LOW
                  ADD       LeftData, halfperiod    'test
                  djnz      n, #:LeftDatalp         ' loop23 times  decrement N and jmp if N > 0
    
                  'LR change at LSB
                  or        OutPut, LRClkMSK        ' ###SETUP LR  HIGH
                  ' Send LSB 24th bit and LR Change
                  rcl       LeftData, #1        WC  ' shift out one data bit (MSB first)
                  muxc      OutPut, DataInMask      ' ###SETUP Data
                  mov       OUTA, OutPut            ' ###DRIVE Data
                  ''''''or        outa, ledmask           ' DEBUG ONLY   REMOVE LED LATER
                  WAITPEQ   HIGH, bclkMSK           ' 24 BitCLocks
                  WAITPEQ   LOW, bclkMSK            ' Wait for Bitclock LOW
    
                  'GET THE R I G H T WORD
                  rdlong    RightData, RightDataaddr   ' read RIGHT data
                  shl       RightData, #8              ' assumes 16 bit original
                  mov       n, #23
                  ' SHIFT OUT LeftData 24BITS
    :RightDatalp  rcl       RightData, #1      WC
                  muxc      OutPut, DataInMask      ' ###SETUP Data
                  mov       OUTA, OutPut            ' ###DRIVE Data
                  WAITPEQ   HIGH, bclkMSK           ' 1-23 BitCLocks  of  Right phase
                  WAITPEQ   LOW, bclkMSK            '
                  djnz      n, #:RightDatalp
                  'LR change at LSB
                  andn      OutPut, LRClkMSK        ' ###SETUP LR    LOW
                  ' Send 24th bit after LR Change
                  rcl       RightData, #1       WC
                  muxc      OutPut, DataInMask
                  mov       OUTA, OutPut            ' *###DRIVE LR
                  ''''''andn        outa, ledmask
                  WAITPEQ   HIGH, bclkMSK           ' 24 Tick
                  WAITPEQ   LOW, bclkMSK            '
    
                  jmp       #:loop                  ' ready for next sample set
    'Falling Edge of Bitclock is where LR/data changes states counting bits 23..0    LR changes before LSB sent
    'Leading Edge of Bitclock clocks in databit to DAC
    
    724 x 290 - 100K
Sign In or Register to comment.