Hi everyone, I'm an EE student at the University of Florida trying to finish up my senior project, an audio DSP dev. board based on the 21065L SHARC interfaced with an AD1838A 24-bit, 96-kHz codec. I have used the application notes on ADI's website, describing interfacing the 21161N to the AD1836 and the 21065L to the AD1819, as a reference for both hardware and software. I'm currently stuck, as I can't seem to get the SHARC to communicate with the codec properly. I would appreciate any help or suggestions if anyone has any experience with this. Please see a description of the problem and code below. Sorry in advance for the long post. Sincerely, Alex Parkinson Senior, Computer and Electrical Engineering University of Florida ahparky@ufl.edu The Situation: The codec has 1 stereo input and 3 stereo outputs, interfaced as master to the DSP in TDM mode. So the codec generates the FSTDM signal once every 20.8us (48 kHz sampling rate) and the bit clock frequency is 12.288 MHz (32 bits/word * 8 channels * fs). The codec sends the left and right ADC data on channels 0 and 4. It receives the DAC data in the following order: DAC_L1, DAC_L2, DAC_L3, empty, DAC_R1, DAC_R2, DAC_R3, empty I've written a program which simply takes the left and right input signals and sends them out on all of the outputs. However, the only output which works is DAC_L3. I've spent the last several days troubleshooting this problem with an oscilloscope (I don't have the money for an emulator), and I have a pretty good understanding of what's going wrong - I just don't know why it's going wrong. The Problem: The DSP DMA transfer begins one bit clock after the assertion of FSTDM (MFD = 1), at which time it sends out the three left channels plus an empty channel. Then, for some reason, the DSDATA line tri-states for the remainder of the frame (four more channels). After that, another FSTDM is generated by the codec, and the SHARC then sends the three right channels plus an empty channel, followed by four tri-stated channels. So the left channel data received by the codec is actually alternating between left and right channel data. I suspect that the same is happening with the input. That is, the processor is only reading the first channel (ADC_L1) of every frame, and is considering the data to be left and right channels. For this reason, the DAC_Lx outputs should all be sending out the correct data (but for the wrong reasons). However, it's only the third channel which is outputting correctly (this may be a problem with the codec - I'm going to check more into that tomorrow). That still doesn't change the fact that the processor is not communicating with the codec correctly. I should also mention that I am able to succesfully communicate with the control registers fo the codec using the other SPORT, but that does not use multichannel mode or DMA chaining. The Code: #include <def21065L.h> /************************************************* * AD1838A Definitions *************************************************/ #define READ_REG 0x0800 #define WRITE_REG 0x0000 #define DAC_CTRL1 0x0000 #define DAC_CTRL2 0x1000 #define DAC_VOL1 0x2000 #define DAC_VOL2 0x3000 #define DAC_VOL3 0x4000 #define DAC_VOL4 0x5000 #define DAC_VOL5 0x6000 #define DAC_VOL6 0x7000 #define RES_REG1 0x8000 #define RES_REG2 0x9000 #define ADC_PEAK0 0xA000 #define ADC_PEAK1 0xB000 #define ADC_CTRL1 0xC000 #define ADC_CTRL2 0xD000 #define ADC_CTRL3 0xE000 #define RES_REG3 0xF000 #define Int_ADC_L1 0 #define Aux_ADC_L2 1 #define Aux_ADC_L3 2 #define Aux_ADC_L4 3 #define Int_ADC_R1 4 #define Aux_ADC_R2 5 #define Aux_ADC_R3 6 #define Aux_ADC_R4 7 #define Int_DAC_L1 0 #define Int_DAC_L2 1 #define Int_DAC_L3 2 #define Aux_DAC_L4 3 #define Int_DAC_R1 4 #define Int_DAC_R2 5 #define Int_DAC_R3 6 #define Aux_DAC_R4 7 /************************************************* * Variable declarations *************************************************/ .section/dm seg_dmda; .var powerdown_AD1838[4] = DAC_CTRL1 | WRITE_REG | 0x004, DAC_CTRL1 | WRITE_REG | 0x004, ADC_CTRL1 | WRITE_REG | 0x080, ADC_CTRL1 | WRITE_REG | 0x080; .var powerdown_rx_buf[4]; .var tx_ctrl_buf[19] = /* Write register commands */ DAC_CTRL1 | WRITE_REG | 0x000, DAC_CTRL1 | WRITE_REG | 0x000, DAC_CTRL2 | WRITE_REG | 0x000, DAC_VOL1 | WRITE_REG | 0x3FF, DAC_VOL2 | WRITE_REG | 0x3FF, DAC_VOL3 | WRITE_REG | 0x3FF, DAC_VOL4 | WRITE_REG | 0x3FF, DAC_VOL5 | WRITE_REG | 0x3FF, DAC_VOL6 | WRITE_REG | 0x3FF, ADC_CTRL1 | WRITE_REG | 0x000, ADC_CTRL1 | WRITE_REG | 0x000, ADC_CTRL3 | WRITE_REG | 0x040, ADC_CTRL2 | WRITE_REG | 0x380, ADC_CTRL2 | WRITE_REG | 0x380, /* Read register commands */ ADC_PEAK0 | READ_REG | 0x000, ADC_PEAK1 | READ_REG | 0x000, ADC_CTRL1 | READ_REG | 0x000, ADC_CTRL2 | READ_REG | 0x000, ADC_CTRL3 | READ_REG | 0x000; .var rx_ctrl_buf[19]; .var tx0_buf[8] = 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000; .var rx0_buf[8]; .var tx0_tcb[8] = 0, 0, 0, 0, 0, 8, 1, tx0_buf; .var rx0_tcb[8] = 0, 0, 0, 0, 0, 8, 1, rx0_buf; .var left_in1; .var right_in1; .var left_out1; .var left_out2; .var left_out3; .var right_out1; .var right_out2; .var right_out3; .var left_ch; .var right_ch; .endseg; /************************************************* * Interrupt Vector Table *************************************************/ .segment/pm seg_rth; nop; nop; nop; nop; /* Reserved */ nop; jump start; rti; rti; /* RSTI reset vector */ nop; nop; nop; nop; /* Reserved */ rti; rti; rti; rti; /* SOVFI stack overflow */ rti; rti; rti; rti; /* TMZHI high timer */ rti; rti; rti; rti; /* VIRPTI vector interrupt */ rti; rti; rti; rti; /* IRQ2I irq2 vector */ rti; rti; rti; rti; /* IRQ1I irq1 vector */ rti; rti; rti; rti; /* IRQ0I irq0 vector */ nop; nop; nop; nop; /* Reserved */ spr0i_svc: jump process_audio_sample; /* SPR0I sport0 rx */ rti; rti; rti; rti; rti; rti; rti; /* SPR1I sport1 rx */ rti; rti; rti; rti; /* SPT0I sport0 tx */ rti; rti; rti; rti; /* SPT1I sport1 tx */ nop; nop; nop; nop; /* Reserved */ nop; nop; nop; nop; /* Reserved */ rti; rti; rti; rti; /* EP0I ext port buffer0 */ rti; rti; rti; rti; /* EP1I ext port buffer1 */ nop; nop; nop; nop; /* Reserved */ nop; nop; nop; nop; /* Reserved */ nop; nop; nop; nop; /* Reserved */ rti; rti; rti; rti; /* CB7I circ buffer7 overflow */ rti; rti; rti; rti; /* CB15I circ buffer15 overflow */ rti; rti; rti; rti; /* TMZLI low timer */ rti; rti; rti; rti; /* FIXI fixed-pt overflow */ rti; rti; rti; rti; /* FLTOI floating-pt overflow */ rti; rti; rti; rti; /* FLTUI floating-pt underflow */ rti; rti; rti; rti; /* FLTII floating-pt invalid */ rti; rti; rti; rti; /* SFT0I user sw0 int */ rti; rti; rti; rti; /* SFT1I user sw1 int */ rti; rti; rti; rti; /* SFT2I user sw2 int */ rti; rti; rti; rti; /* SFT3I user sw3 int */ .endseg; /************************************************* * Main program *************************************************/ .segment/pm seg_pmco; start: call init_dsp; /* Set up Flags and IRQs */ call clear_sport_regs; /* Set all SPROT regs to 0 */ call init_codec_regs; /* Initialize AD1838 control regs */ call init_sport0_tdm_regs; /* Set up SPORT0 for TDM */ call init_sport0_dma_regs; /* Set up SPORT0 for DMA chaining */ IRPTL = 0x00000000; /* Clear pending interrupts */ bit set IMASK SPT0I|SPR0I; /* Enable SPORT0 interrupts */ USTAT2 = dm(SRCTL0); /* Allow multichannel */ bit set USTAT2 MCE; dm(SRCTL0) = USTAT2; main_loop: idle; /* Wait for interrupts */ jump main_loop; /************************************************* * Interrupt routine to process incoming audio data *************************************************/ process_audio_sample: r0 = dm(rx0_buf + Int_ADC_L1); /* Store ADC input data in memory */ dm(left_in1) = r0; r1 = dm(rx0_buf + Int_ADC_R1); dm(right_in1) = r1; // Put code to process the signals here call (pc, process_audio); r0 = dm(left_out1); /* Retrieve processed audio data from */ dm(tx0_buf + Int_DAC_L1) = r0; /* memory and write to tx buffer */ r1 = dm(left_out2); dm(tx0_buf + Int_DAC_L2) = r1; r2 = dm(left_out3); dm(tx0_buf + Int_DAC_L3) = r2; r0 = dm(right_out1); dm(tx0_buf + Int_DAC_R1) = r0; r1 = dm(right_out2); dm(tx0_buf + Int_DAC_R2) = r1; r2 = dm(right_out3); dm(tx0_buf + Int_DAC_R3) = r2; rti; /************************************************* * Subroutine to process incoming audio data *************************************************/ process_audio: r2 = dm(left_in1); /* Copy input to all outputs */ dm(left_out1) = r2; dm(left_out2) = r2; dm(left_out3) = r2; r2 = dm(right_in1); dm(right_out1) = r2; dm(right_out2) = r2; dm(right_out3) = r2; rts; /************************************************* * Subroutine to initialize the DSP *************************************************/ init_dsp: /* Set Flags 4-9 as outputs, Flags 10 & 11 as inputs */ USTAT2 = dm(IOCTL); bit set USTAT2 FLG9O|FLG8O|FLG7O|FLG6O|FLG5O|FLG4O; bit clr USTAT2 FLG11O|FLG10O; dm(IOCTL) = USTAT2; /* Set Flags 0-3 as pushbutton inputs */ bit clr MODE2 FLG3O|FLG2O|FLG1O|FLG0O; /* Enable IRQ 0-2 interrupts (pushbuttons) */ IMASK = 0x0; IRPTL = 0x00000000; bit set MODE2 IRQ2E|IRQ1E|IRQ0E; bit set MODE1 IRPTEN|NESTM; bit set IMASK IRQ2I|IRQ1I|IRQ0I; L0 = 0; L1 = 0; L2 = 0; L3 = 0; L4 = 0; L5 = 0; L6 = 0; L7 = 0; L8 = 0; L9 = 0; L10 = 0; L11 = 0; L12 = 0; L13 = 0; L14 = 0; L15 = 0; rts; /************************************************* * Subroutine to clear the SPORT registers *************************************************/ clear_sport_regs: /* Clear pending interrupts */ IRPTL = 0x00000000; bit clr IMASK SPT1I|SPT0I|SPR1I|SPR0I; /* Clear SPORT control and div registers */ r0 = 0x00000000; dm(STCTL0) = r0; dm(SRCTL0) = r0; dm(STCTL1) = r0; dm(SRCTL1) = r0; dm(TDIV0) = r0; dm(RDIV0) = r0; dm(TDIV1) = r0; dm(RDIV1) = r0; /* Clear SPORT multichannel registers */ r0 = 0x00000000; dm(MTCS0) = r0; dm(MRCS0) = r0; dm(MTCS1) = r0; dm(MTCS0) = r0; /* Clear SPORT multichannel companding-enable registers */ r0 = 0x00000000; dm(MTCCS0) = r0; dm(MRCCS0) = r0; dm(MTCCS1) = r0; dm(MRCCS1) = r0; rts; /************************************************* * Subroutine to initialize the codec registers *************************************************/ init_codec_regs: r0 = 0x00000000; dm(STCTL1) = r0; dm(SRCTL1) = r0; USTAT1 = dm(STCTL1); USTAT2 = dm(SRCTL1); /* Setup SPORT1 DMA registers */ r0 = powerdown_AD1838; /* SPORT1 DMA memory index */ dm(IIT1A) = r0; r0 = 1; /* SPORT1 DMA memory modifier */ dm(IMT1A) = r0; r0 = @powerdown_AD1838; /* Number of SPORT1 DMA transfers */ dm(CT1A) = r0; r0 = powerdown_rx_buf; /* Power down the codec twice to */ dm(IIR1A) = r0; /* counter an anomaly with the codec */ r0 = 1; dm(IMR1A) = r0; r0 = @powerdown_rx_buf; dm(CR1A) = r0; r0 = 0x0011003B; /* FS = 18 clocks, TCLK ~ 1 MHz */ dm(TDIV1) = r0; r0 = 0x00000000; dm(RDIV1) = r0; bit set USTAT1 SDEN_A|LAFS|LTFS|ITFS|TFSR|CKRE|ICLK|SLEN16|SPEN_A; dm(STCTL1) = USTAT1; bit set USTAT2 SDEN_A|LAFS|LRFS|RFSR|CKRE|SLEN16|SPEN_A; bit clr USTAT2 IRFS|ICLK; dm(SRCTL1) = USTAT2; bit set IMASK SPT1I|SPR1I; power_cycle_not_done: /* Wait for DMA completion idle; r1 = 0x00000008; r0 = dm(DMASTAT); r0 = r0 and r1; if NE jump power_cycle_not_done; bit clr IMASK SPT1I|SPR1I; wait_powerdown: LCNTR = 3000, do waitloop until lce; nop; nop; nop; waitloop: nop; bit clr USTAT1 0xFFFFFFFF; /* Clear SPORT1 CTRL regs */ dm(SRCTL1) = USTAT1; dm(STCTL1) = USTAT1; IRPTL = 0; SPORT_DMA_setup: USTAT1 = dm(STCTL1); USTAT2 = dm(SRCTL1); r0 = tx_ctrl_buf; /* Set up SPORT1 DMA */ dm(IIT1A) = r0; /* Initialize codec control regs */ r0 = 1; dm(IMT1A) = r0; r0 = @tx_ctrl_buf; dm(CT1A) = r0; r0 = rx_ctrl_buf; dm(IIR1A) = r0; r0 = 1; dm(IMR1A) = r0; r0 = @rx_ctrl_buf; dm(CR1A) = r0; r0 = 0x0011003B; dm(TDIV1) = r0; r0 = 0; dm(RDIV1) = r0; bit set USTAT1 SDEN_A|LAFS|LTFS|ITFS|TFSR|CKRE|ICLK|SLEN16|SPEN_A; dm(STCTL1) = USTAT1; bit set USTAT2 SDEN_A|LAFS|LTFS|RFSR|CKRE|SLEN16|SPEN_A; bit clr USTAT2 IRFS|ICLK; dm(SRCTL1) = USTAT2; bit set IMASK SPT1I|SPR1I; SPORT_DMA_not_done: idle; /* Wait for DMA completion */ r1 = 0x0000000A; r0 = dm(DMASTAT); r0 = r0 and r1; if NE jump SPORT_DMA_not_done; bit clr USTAT1 0xFFFFFFFF; dm(SRCTL1) = USTAT1; dm(STCTL1) = USTAT1; IRPTL = 0; bit clr IMASK SPT1I|SPR1I; rts; /************************************************* * Subroutine to initialize SPORT0 TDM registers *************************************************/ init_sport0_tdm_regs: r0 = 0x00000000; dm(TDIV0) = r0; dm(RDIV0) = r0; dm(STCTL0) = r0; dm(SRCTL0) = r0; nop; USTAT1 = dm(STCTL0); USTAT2 = dm(SRCTL0); /* Set MFD = 1, chaining enable, dma enable, word length = 32 bits */ bit set USTAT1 MFD1|SCHEN_A|SDEN_A|SLEN32; dm(STCTL0) = USTAT1; /* Set num. channels = 8, chaining enable, dma enable, word length = 32 */ /* Wait to set MCE bit */ bit set USTAT2 NCH7|SCHEN_A|SDEN_A|SLEN32; bit clr USTAT2 IRFS|ICLK; dm(SRCTL0) = USTAT2; /* Enable channels 0-7 */ r0 = 0x000000FF; dm(MTCS0) = r0; dm(MRCS0) = r0; /* No companding */ r0 = 0x00000000; dm(MTCCS0) = r0; dm(MRCCS0) = r0; rts; /************************************************* * Subroutine to initialize SPORT0 DMA registers *************************************************/ init_sport0_dma_regs: r1 = 0x0001FFFF; /* Set DMA chaining regs */ r0 = tx0_buf; /* index = tx0_buf */ dm(tx0_tcb + 7) = r0; r0 = 1; /* modifier = 1 */ dm(tx0_tcb + 6) = r0; r0 = 8; /* count = 8 */ dm(tx0_tcb + 5) = r0; r0 = tx0_tcb + 7; /* chain pointer = tx0_tcb + 7 */ r0 = r0 and r1; /* with CPI bit set */ r0 = bset r0 by 17; dm(tx0_tcb + 4) = r0; dm(CPT0A) = r0; r0 = rx0_buf; /* index = rx0_buf */ dm(rx0_tcb + 7) = r0; r0 = 1; /* modifier = 1 */ dm(rx0_tcb + 6) = r0; r0 = 8; /* count = 8 */ dm(rx0_tcb + 5) = r0; r0 = rx0_tcb + 7; /* chain pointer = rx0_buf + 7 */ r0 = r0 and r1; /* with CPI bit set */ r0 = bset r0 by 17; dm(rx0_tcb + 4) = r0; dm(CPR0A) = r0; rts; .endseg;
21065L SHARC SPORT in multichannel mode w/ DMA chaining
Started by ●December 10, 2003
Reply by ●December 10, 20032003-12-10
Alex Parkinson wrote: [schnipp]> The Problem: > The DSP DMA transfer begins one bit clock after the assertion of FSTDM > (MFD = 1), at which time it sends out the three left channels plus an empty > channel. Then, for some reason, the DSDATA line tri-states for the remainder > of the frame (four more channels).[schnipp] SHARCs tri-state the tx data line in the TDM mode when they think they're not supposed to tx data on a given slot. This is so you can gang multiple sharcs up on a single TDM interface. This sure makes it sound like the TDM tx is only set up to tx four slots, or possible that it somehow thinks it has 16-bit slots instead of 32. But looking at your code, I can't see where any of those mistakes could have crept in. I did notice that MRCS1 isn't cleared, but I don't think that's the problem.> /* Clear SPORT multichannel registers */ > r0 = 0x00000000; > dm(MTCS0) = r0; > dm(MRCS0) = r0; > dm(MTCS1) = r0; > dm(MTCS0) = r0;Once thing you might do to make the code a little easier to read is to assign values to the ustat registers outright instead of using the bit set/clr operations. For instance, "ustat2=NCH7|SCHEN_A|SDEN_A|SLEN32;" is a perfectly legal instruction, and it eliminates the need to sort through the preceeding lines of code to make sure that no other bits in ustat2 were set beforehand. For debugging serial port problems with an o'scope, I recommend that you continually transmit the word 0xb38f. I like this word because it's easy to spot on a scope (1 hi, 1 lo, 2 hi, 2 lo, etc...). I recommend that you ignore the rx until you get the tx worked out - and that means quit writing to the tx buffer in the isr so you can tx static data (i.e., 0xb38f) instead. Then look at the tx line. Do you see four slots or eight? are they 32-bits or 16? Good luck with this. Hope this helped a little at least. -- Jim Thomas Principal Applications Engineer Bittware, Inc jthomas@bittware.com http://www.bittware.com (703) 779-7770 There's a fine line between clever and stupid
Reply by ●December 10, 20032003-12-10
Jim Thomas wrote:> > This sure makes it sound like the TDM tx is only set up to tx four > slots, or possible that it somehow thinks it has 16-bit slots instead of32.> ... > For debugging serial port problems with an o'scope, I recommend that you > continually transmit the word 0xb38f. I like this word because it's > easy to spot on a scope (1 hi, 1 lo, 2 hi, 2 lo, etc...). > > I recommend that you ignore the rx until you get the tx worked out - and > that means quit writing to the tx buffer in the isr so you can tx static > data (i.e., 0xb38f) instead. Then look at the tx line. Do you see four > slots or eight? are they 32-bits or 16?I've taken your advice and sent static tx data to the codec (I also cleaned up my code a little bit). With this, I realized two things: 1) Some of the outputs on my codec were fried, and 2) the TDM is set up for four channels per frame. After replacing the codec, all three of the left outputs work as only DAC_L3 did previously. However, I still can't figure out why the DSP would only recognize four channels, since NCH is set to 7 (num. channels - 1) and MTCS0 and MRCS0 are set to 0x00FF (to enable DMA channels 0 - 7). Is it possible that I'm initializing certain registers in the wrong order? Alex Parkinson ahparky@ufl.edu
Reply by ●December 11, 20032003-12-11
Alex Parkinson wrote:> I've taken your advice and sent static tx data to the codec (I also cleaned > up my code a little bit). With this, I realized two things: 1) Some of the > outputs on my codec were fried, and 2) the TDM is set up for four channels > per frame. After replacing the codec, all three of the left outputs work as > only DAC_L3 did previously. However, I still can't figure out why the DSP > would only recognize four channels, since NCH is set to 7 (num. channels - > 1) and MTCS0 and MRCS0 are set to 0x00FF (to enable DMA channels 0 - 7). Is > it possible that I'm initializing certain registers in the wrong order?That's puzzling alright. You're initializing the reigsters in a different order than I do, but that doesn't mean your order is wrong. Here's an order I've used (which works): Set up TCB's clear tx and rx control registers setup divisor regs. setup rx ctrl setup rx ctrl clear companding registers setup MTCSx setup MRCSx write to the DMA chain point. Writing to the chain pointer starts the dma. I dunno if it'll have an effect, but you could also try setting the div registers so that the fs part is 0xff. I THINK that only has an effect if the sharc is generating the frame sync, but you never know. -- Jim Thomas Principal Applications Engineer Bittware, Inc jthomas@bittware.com http://www.bittware.com (703) 779-7770 Having a smoking section in a restaurant is like having a peeing section in a swimming pool.