Forums

Setting up codec on ADSP 21489

Started by Joel_H 2 years ago4 replieslatest reply 2 years ago160 views

Hi all, 

I'm trying to program the Sharc ADSP 21489 EZ kit to send out an array of values through one of the RCA connectors and to sample another signal on another. I am therefore looking to setup the CODEC to send and receive at user defined rates. I have so far condensed the example POST code in CCES so I can see how they have connected to the AD1939 CODEC etc..but now I have hit a brick wall. They use compiler scratch registers and a look up table to output a sinusoidal signal, and this has confused me. Could anyone here explain what they are doing? 

So far I know that I need to configure the control registers of the AD1939 via SPI. I then need to set up a link between the processor pins and the AD1939, this can be done using I2S via the SPORT interface. I can then setup a link between the DAC output to one of the J4 OUT channels. My question is now that with all the communications setup how do you send and receive signal values? Is the input into the DAC memory mapped and the output of the ADC? Do you need to send a signal to the CODEC to begin a conversion? Or do you write directly to the processor pins? Any help would be greatly appreciated. 

Kind regards,

Joel. 

[ - ]
Reply by djmaguireOctober 22, 2019
This codec and many others are time division multiplexed.  ...meaning that the configuration registers are sent every sample with the outgoing data.  Then, any useful status data is returned every sample with the incoming data.  If you dig into the examples, you'll see the setup.  The rest will be in the I/O handler.You can write it from scratch, but pack a lunch.  ...because it's going to take a while.  That's not me insulting your skills.  Codec drivers are just not the simplest thing.  Your best bet is to grab the source of the demo program most like what you want and edit it for what you need.



[ - ]
Reply by bholzmayerOctober 23, 2019

Years ago, I faced the same challenge.

As djmaguire stated, digging into the details requires a lot of patience and devotedness... but it's worth the effort.

The most challenging approach is using a "chained DMA" setup.
If you happened to come across such an example it might really be looking very strange. But to my opinion it's the best approach, because the DMA machine does all the work and the DSP core is only alerted if new data are waiting on the input and the output being ready for the next sample.
The DSP can use almost all of its time to process the samples.

In the end codec driver and DMA setup was completely done during configuration phase and, after that initial phase, did nothing in the main programme.
Although it still copied every sample from microphone input to loudspeaker output.
From then on, this was my favorite starting point for different audio projects.

You'll like it. So I'd propose that besides the examples, read the documentation until you understand the details. 

Good luck ...

[ - ]
Reply by Joel_HOctober 23, 2019

Thanks for the replies, it is comforting to know that other people have found it as labouring as I have...

Thank you for letting me know about the DMA chaining, the code made more sense having gone away and read the documentation. I think it's going to take a while to truely grasp the details! 

On a final note could either of you explain some of the syntax, what do they mean by (this|that) in the C code? It is not something that I've come across and the documentation doesn't really explain it. For instance:

I2S_xmit2b_tcb[4]=*pCPSP2B = ((int) (I2S_xmit2b_tcb + 7) & 0x7FFFF) | (1<<19)

I2S_xmit2b_tcb is defined earlier in the code as an integer array of length 8, it is then being masked with a hexadecimal value and truncated. What is the (1<<19) doing? Shifting the bits left? In the documentation it sounds like this is a choice? I understand that the purpose is to setup the chain pointer register for sport 2B. 

There are further uses of this throughout including

*pSPCTL1 = (OPMODE | SLEN32 | SPEN_A | SCHEN_A | SDEN_A | SPEN_B | SCHEN_B | SDEN_B);

With the variables defined in a header file, for example:

#define SCHEN_A (BIT_19)  /* SPORT TXnA/RXnA DMA chaining enable primary A channel */

In this definition are they sending BIT_19 high? 

Any reply would be massively appreciated, this forum's been a huge help. 

Thanks, 

Joel. 

[ - ]
Reply by kozcetinOctober 23, 2019

DMA TCB Chain on 214xx SHARC processor family has the following structure:

CPSPx - chain pointer register

ICSPx - Internal Count  

IMSPx - Internal Modifier

IISPx - Internal/External Index

For example if you are utilizing a SPORT DMA to receive your ADC I2S data as frame of N I2S samples you can chain them in the following way by using two buffers (2 buffers are just for demonstration):

int rxbuffer1[2*N]; /* L and R */

int rxbuffer2[2*N];

int adctcb1[4];

int adctcb2[4];


....

/* Set the next tcb to adctcb2 */

adctcb1[0] = ((int) (adctcb2 + 3) & 0x7FFFF) | (1<<19); /*CPSPx*/

adctcb1[1] = N; /* ICSPx count of samples until the transaction is done */ 

adctcb1[2] = 1; /* increase the buffer index by one as one I2S pair received */

adctcb1[3] = (int)rxbuffer1; /* offset to internal buffer that I2S samples copied */ 


/* Second DMA TCB now points to first one so that ADC data continuously received */

adctcb2[0] = ((int) (adctcb1 + 3) & 0x7FFFF) | (1<<19); /*CPSPx*/

adctcb1[1] = N; /* ICSPx count of samples until the transaction is done */  

adctcb1[2] = 1; /* increase the buffer index by one as one I2S pair received */

adctcb1[3] = (int)rxbuffer2; /* offset to internal buffer that I2S samples copied */  


...

Some details:

Setting of ((int) (adctcb1 + 3) & 0x7FFFF) | (1<<19); /*CPSPx*/

does the address translation as well as interrupt setting for the SPORT DMA transactions. The (1<<19) sets the PCI bit for this SPORT DMA transaction so that whenever you receive N L/R I2S samples an interrupt service is requested and you can process the received samples in the interrupt handler. If you want to have an interrupt at the end of two complete transaction (at the end of the tcb2) then set this:

adctcb1[0] = ((int) (adctcb2 + 3) & 0x7FFFF);

adctcb2[0] = ((int) (adctcb1 + 3) & 0x7FFFF) | (1<<19);

Then the completion of tcb1 chain will not generate an interrupt but tcb2.

To start your SPORT DMA transactions simply set your parameters (yes SCHEN_A bit enables the port A) and then

*pCPSPxA = (unsigned int)adctcb1+3;

That is set the chain pointer register of SPORTx buffer A to the first tcb chain pointer index.

This is rather processor specific application. I would suggest that you should seek some help on Analog Device online forums.