As they title may explain, I've got a ADC and a DAC both on one McBSP, the ADC has to be 32bit stereo, similar to I2S but without the leading 0. The DAC is 16bit stereo, right hand justifed with no padding bits. The clocks for the DAC are derived from the ADC clock via the SRG. Both sides have a sample rate of 96kHz, both DMA controllers are set to use double indexing, the RX one set to 32 bits, the TX one set to 16 bit. The TX DMA routine is triggered by a flag that is set in the RX DMA ISR
What is happening is a speed mismatch problem, which as far as I can see shouldn't happen, there is nothing in the documentation that says the McBSPs RX and TX need to run at the same speed.
When I configure the RX side to be 16 bit single indexed and ignore the rest of the data from the ADC everything runs as expected. If I set the RX side to 32 bits it still runs fine. As soon as I change it to double indexing which as to be 32 bit the TX side decides it needs to send twice as many frames and I get dead patches in the DAC output.
I can set the TX part of the McBSP to 32 bits, as the DAC is RH justifed it copes with the leading zeros, but this does not help the timing.
From the test I have run it seems that this only happens when the RX DMA has to handle more data then the TX DMA.
I've attached some of the code.
SOME SETUP CODE
// set up the MCBSP
portRegSet(0x4000, 0x2C04); // SPCR1
portRegSet(0x0000, 0x2C05); // SPCR2
portRegSet(0x0A8F, 0x2C12); // PCR
portRegSet(0x01A0, 0x2C06); // RCR1
portRegSet(0x00A0, 0x2C07); // RCR2
portRegSet(0x01A0, 0x2C08); // XCR1 16 = 0x0140, 32 = 0x01A0
portRegSet(0x00A0, 0x2C09); // XCR2 16 = 0x0040, 32 = 0x00A0
portRegSet(0x1F00, 0x2C0A); // SRGR1 16 = 0x0F01, 32 = 0x1F00
portRegSet(0x103F, 0x2C0B); // SRGR2 16 = 0x101F, 32 = 0x103F
portRegSet(0x0000, 0x2C03); // DXR2
THIS IS THE MAIN LOOP
while(1) {
// main loop, check to see if some data is ready, if it is, then send it back out
while(!dataReady); // wait for data
// we should have already loaded the next output DMA register set
// so all we need to do is start the transfer
DMA_FSETH(hDmaTx, DMACCR, ENDPROG, 1); // starts the next transfer
dataReady = 0;
if(dmaTxBufferNum == 1)
dmaTxBufferNum = 0;
else
dmaTxBufferNum++;
// check to see if we can update the register values
while(DMA_FGETH(hDmaTx, DMACCR, ENDPROG));
// program the registers for the next transfer
srcAddrHi = (Uint16)(((Uint32)dmaTxBufferPtr[dmaTxBufferNum]) >> 15) & 0xFFFFu;
srcAddrLo = (Uint16)(((Uint32)dmaTxBufferPtr[dmaTxBufferNum]) << 1) & 0xFFFFu;
DMA_RSETH(hDmaTx, DMACSSAU, srcAddrHi);
DMA_RSETH(hDmaTx, DMACSSAL, srcAddrLo);
}
}
RX DMA ISR
interrupt void dmaRxISR(void) {
// we have filled up a buffer
// swap to the next buffer
Uint16 dstAddrHi, dstAddrLo;
Uint16 reg;
if(dmaRxBufferNum == 1)
dmaRxBufferNum = 0;
else
dmaRxBufferNum++;
// signal that data is ready
dataReady = 1;
dstAddrHi = (Uint16)(((Uint32)dmaRxBufferPtr[dmaRxBufferNum]) >> 15) & 0xFFFFu;
dstAddrLo = (Uint16)(((Uint32)dmaRxBufferPtr[dmaRxBufferNum]) << 1) & 0xFFFFu;
// make sure we can program the next transfer by checking the ENDPROG bit
while(DMA_FGETH(hDmaRx,DMACCR,ENDPROG));
// program the next destination address
DMA_RSETH(hDmaRx, DMACDSAU, dstAddrHi);
DMA_RSETH(hDmaRx, DMACDSAL, dstAddrLo);
// Set programmation bit to 1, ENDPROG = 1
DMA_FSETH(hDmaRx, DMACCR, ENDPROG, 1);
}