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;