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.
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.
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.
mov Time, cnt'setup time delayadd Time, cntadd
waitcnt Time, wait ' value doesn't matterxorouta, ledmask
mov Time, cnt'setup time delayadd Time, cntadd
waitcnt Time, wait
jmp #:loop
ctra_ long%01010 << 26 + 27'mode + APIN %01010
cntadd long2_400_000'2_400_000 visible blink rate, below is solid LEDs
wait long0'<< doesnt matter what this is 0 to 2b
Ledmask long%10_00000000_00000000' 17
cnt_ res1
new res1
old res1
temp res1
Time res1
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.
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 movdira, ledmask
mov Time, cntadd Time, #9' stop waitcnt from locking up
:loop waitcnt Time, cntadd ' settle for Time+N*cntaddxorouta, ledmask
jmp #:loop
cntadd long2_400_000
ledmask long |< 17
Time res1
Note, it waits first on dst then - on the way out - adds src to dst.
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.
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 bitorg
entry movctra, ctra_ 'establish mode and start countermovfrqa, #1'increment for each edge seenmov time, CNT'initialize CNT to Time if neededadd time, BitLen ' setup LRCLK time accountingordira, ledmask
mov $, #0wz, nr'clear any set z' Start Loop to dither 384 * 44100 to 8 ticks per bitclock
:loop mov new, phsa'record new countcmp new, BitLen wz, wc'384 / 48 bits per sample = 8 ticksif_aeorouta, ledmask
'add delay if required, then shorten loop time to compensate for loss due to clocks in ASMmov time, CNTadd time, cntadd
waitcnt TIME, cntadd
if_aexorouta, ledmask
if_aemovphsa, #0jmp #:loop
ctra_ long%01010 << 26 + 27'mode + APIN %01010
cntadd long2_400_000'value used for visible blink using LED as debug at home
BitLen long2_400_000' Use 8 for bit rate 384 / 48bits
Ledmask long |< 17
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 23then 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 outone 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 outone 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
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.
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:
DATORG0'Begin at Cog RAM addr 0
DAC mov parm, PAR' COPT PAR to asm PARMrdlong temp, parm ' COPY the pin config PAR to PARM in ASMadd parm, #4' GET VAR POSITION of LeftPtrrdlong LeftDataaddr, parm ' COPY LEFTPTR ADDRESS IN ASMadd parm, #4' GET VAR POSITION of RightDataPtrrdlong RightDataaddr, parm ' COPY RightDataPTR ADDRESS IN ASM' SET PIN DIRECTION'or DIRA, bclkMSKorDIRA, LRClkMSK
orDIRA, DataInMask 'data in to Dacordira, ledmask ' DEBUG ONLY REMOVE LED LATER'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' SET LRCLOCK HIGH to startmov OutPut, LRClkMSK '###SETUP LR establish OutputmovOUTA, OutPut '###DRIVE LR HIGHorouta, ledmask ' DEBUG ONLY REMOVE LED LATERWAITPEQ HIGH, bclkMSK ' park here till bitclock startsWAITPEQ LOW, bclkMSK ' Wait for Bitclock LOWandn OutPut, LRClkMSK '###SETUP LR LOWmovOUTA, 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 sendWAITPEQ HIGH, bclkMSK ' Wait for Bitclock HIGHWAITPEQ LOW, bclkMSK ' Wait for Bitclock LOW
:loop ' GET THE L E F T WORDrdlong LeftData, LeftDataaddr ' read LEFT datashl LeftData, #8' shift LeftData 8 assumes a 16bit valmov 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, #1WC' shift out one data bit (MSB first)muxc OutPut, DataInMask ' ###SETUP DatamovOUTA, OutPut ' ###DRIVE DataWAITPEQ HIGH, bclkMSK ' 1-23 BitCLocks of Left phaseWAITPEQ LOW, bclkMSK ' Wait for Bitclock LOWADD LeftData, halfperiod 'testdjnz n, #:LeftDatalp ' loop23 times decrement N and jmp if N > 0'LR change at LSBor OutPut, LRClkMSK ' ###SETUP LR HIGH' Send LSB 24th bit and LR Changercl LeftData, #1WC' shift out one data bit (MSB first)muxc OutPut, DataInMask ' ###SETUP DatamovOUTA, OutPut ' ###DRIVE Data''''''or outa, ledmask ' DEBUG ONLY REMOVE LED LATERWAITPEQ HIGH, bclkMSK ' 24 BitCLocksWAITPEQ LOW, bclkMSK ' Wait for Bitclock LOW'GET THE R I G H T WORDrdlong RightData, RightDataaddr ' read RIGHT datashl RightData, #8' assumes 16 bit originalmov n, #23' SHIFT OUT LeftData 24BITS
:RightDatalp rcl RightData, #1WCmuxc OutPut, DataInMask ' ###SETUP DatamovOUTA, OutPut ' ###DRIVE DataWAITPEQ HIGH, bclkMSK ' 1-23 BitCLocks of Right phaseWAITPEQ LOW, bclkMSK 'djnz n, #:RightDatalp
'LR change at LSBandn OutPut, LRClkMSK ' ###SETUP LR LOW' Send 24th bit after LR Changercl RightData, #1WCmuxc OutPut, DataInMask
movOUTA, OutPut ' *###DRIVE LR''''''andn outa, ledmaskWAITPEQ HIGH, bclkMSK ' 24 TickWAITPEQ 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
Comments
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.
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.
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.
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.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
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
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