Greetings.
I am developing an application using the MSP430F5510 mcU that will acquire monophonic (one channel) output data from the TLV320AIC3256 (recording mode) using SPI and DMA and store them on an SD card.
I have properly setup TLV320 to output 16bit data in LJF mode. I have also used TI's FatFS interface for the SD card (from development board examples) and can successfully write sectors on the SD (512 bytes/sector) . I am not using DMA for the SPI SD interface. I have also configured SPI with DMA to acuire the I2S data and that implementation works as well (based on the corresponding application note).
The problem arises when I put everything together and try to acquire I2S data and write to the SD. The DMA interrupt stops being triggered after a while or sometimes it may not trigger at all.
I want to be able to minimize data loss as much as possible, so I am using two buffers to store the DMA data. Once a buffer is filled (DMA interrupt triggered) I set up the DMA to store data in the other buffer and write the acquired data on the SD (raw write). From the extensive debugging I did, it seems that the DMA interrupt is not triggered while SD writing is ongoing ( I am acquiring 1024 bytes from I2S and store 512 on the as only 16 bits of the 32 of each sample are useful). MCLK is configured for 25 MHz operation, while the SD SPI interface operates with a clock of 12.5 MHz. The I2S data have a bit clock of 3 MHz.. Finally, I have mapped the USCI_B0 pins to P4 using MSP430 port mapping capability.
Any help or insight to my problem is greatly appreciated.
Here is the I2S SPI DMA setup code I am using and the main loop of the application :
void I2S_TLV320_init(void)
{
// Configure SPI pins
I2S_SEL |= I2S_SIMO + I2S_CLK + I2S_CS; // CLK, SIMO, STE
I2S_DIR |= I2S_SIMO + I2S_CLK + I2S_CS;
//Initialize USCI_B0 for SPI Slave operation
UCB0CTL1 |= UCSWRST; //Put state machine in reset
UCB0CTL0 |= UCMSB + UCMODE_2 + UCSYNC; //4-pin, 8-bit SPI slave
UCB0CTL1 &= ~UCSWRST; //Release USCI state machine
//Wait for slave to initialize
__delay_cycles(100);
}
void I2S_readFrame ()
{
UCB0IFG &= ~(UCRXIFG + UCTXIFG); /* clear flags */
/* Get the block */
/* DMA trigger is UCB0 receive for DMA0 */
DMACTL0 |= (DMA0TSEL__USCIB0RX);
/* Source DMA address: receive register. */
DMA0SAL = UCB0RXBUF_;
/* Destination DMA address: the user data buffer. */
if(!act_buf)
DMA0DAL = (unsigned short)i2s_buffer1;
else
DMA0DAL = (unsigned short)i2s_buffer2;
/* The size of the block to be transferred */
DMA0SZ = 1024;
/* Configure the DMA transfer*/
DMA0CTL =
DMAIE | /* Enable interrupt */
DMADT_0 | /* Single transfer mode */
DMASBDB | /* Byte mode */
DMAEN | /* Enable DMA */
DMADSTINCR1 | DMADSTINCR0; /* Increment the destination address */
}
void I2S_contRead()
{
UCB0IFG &= ~UCRXIFG;
if(!act_buf)
DMA0DAL = (unsigned short)i2s_buffer1;
else
DMA0DAL = (unsigned short)i2s_buffer2;
DMA0CTL |= DMAEN;
}
#pragma vector = DMA_VECTOR
__interrupt void DMA0_ISR(void)
{
DMA0CTL &= ~(DMAIFG);
I2S_Data_Ready = 1;
}
// Main
WDTCTL = WDTPW + WDTHOLD; //Stop the watchdog
Port_Mapping();
SetVCore(3);
Init_Clock(); //Init clocks
Init_Ports(); //Init ports
__enable_interrupt();
Delay(50000);
disk_initialize(0);
if(!detectCard())
exit(0);
I2S_TLV320_init();
repeats = 0;
act_buf = 0;
I2S_Data_Ready = 0;
P1OUT &= ~BIT4;
I2S_readFrame();
while (1)
{
while(!I2S_Data_Ready);
repeats++;
act_buf = !act_buf;
I2S_Data_Ready = 0;
I2S_contRead();
if(act_buf)
i2s_buffer = i2s_buffer1;
else
i2s_buffer = i2s_buffer2;
disk_write2(0,i2s_buffer,repeats-1,1);
}