Part Number: TM4C1294NCPDT
Hi,
I am trying to transfer data from an external ADC into the TM4C using SPI. The ADC is the slave device and after each conversion sends 24 bytes. I have configured the SSI0 dma TX and RX. I transmit a set of 24 dummy bytes to receive the actual sample from the ADC. However, for some reason my interrupt function for the end of RX dma is invoked continuously. Also, I get a lot of FIFO overrun error and rx time out errors. Anyway, it looks like the dma transfer is behaving very erratically. So, in order to find the problem, I simplified my code. I have enabled the loopback mode and just send one set of 24 dummy bytes. In my main function, I just call
ssi0_Init();
ssi0_DmaTransferSetup();
ssi0_DmaTransferStart();
However, I observe the same behavior and no data is written in my receive buffer. So far, I have not found what is wrong with the code. I would appreciate your help (copied below).
Thanks,
Sina
extern uint32_t g_systemClockFrequency; //120Mhz
#define SAMPLE_BUFFER_SIZE 24
uint8_t g_dummyByte = 8;
uint8_t g_rxSampleBuffer[SAMPLE_BUFFER_SIZE];
uint32_t g_rxBufCount = 0;
uint32_t g_nbOverrun = 0;
uint32_t g_nbTimeout = 0;
void ssi0_HwSetup(void);
void ssi0_Init(void)
{
memset(g_rxSampleBuffer,0,SAMPLE_BUFFER_SIZE);
g_rxBufCount = 0;
g_nbOverrun = 0;
g_nbTimeout = 0;
ssi0_HwSetup();
GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_4,0);
GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5,0);
}
void ssi0_HwSetup(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_2 | GPIO_PIN_5);
GPIOPinConfigure(GPIO_PA2_SSI0CLK);
GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
//wait for the peripheral to be ready
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_SSI0)){}
SSIClockSourceSet(SSI0_BASE,SSI_CLOCK_SYSTEM);
//ADC_SPI_CLOCK_FREQUENCY = 4Mhz
//ADC_DATA_FORMAT_BITS = 8
SSIConfigSetExpClk(SSI0_BASE, g_systemClockFrequency, SSI_FRF_MOTO_MODE_2, SSI_MODE_MASTER, ADC_SPI_CLOCK_FREQUENCY, ADC_DATA_FORMAT_BITS);
SSIEnable(SSI0_BASE);
g_dummyByte = 0;
uint32_t dummy = 0;
while(SSIDataGetNonBlocking(SSI0_BASE, &dummy)){}
}
void ssi0_DmaTransferSetup(void)
{
// Enable the uDMA interface for both TX and RX channels.
SSIDMAEnable(SSI0_BASE, SSI_DMA_TX|SSI_DMA_RX);
//DMA TX setup
//Put the attributes in a known state for the uDMA SSI0TX channel.
uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
//no increment on source since we are sending the same dummy byte
//no increment on destination since we are copying to the same register location
uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE |
UDMA_ARB_8);
//DMA RX setup
// Put the attributes in a known state for the uDMA SSI0RX channel. These
// should already be disabled by default.
uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0RX,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
//no increment on source since we are reading the same register
//increment destination address one byte on each dma transfer since we are writing to reception buffer
uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
UDMA_ARB_8);
//enable loopback for debugging
HWREG(SSI0_BASE + SSI_O_CR1) |= SSI_CR1_LBM;
//clear any pending interrupt
SSIIntClear(SSI0_BASE, 0xFF);
SSIIntEnable(SSI0_BASE, SSI_DMARX|SSI_RXOR|SSI_RXTO);
//enable the interrupt in the NVIC
IntEnable(INT_SSI0);
}
void ssi0_DmaTransferStart(void)
{
uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
UDMA_MODE_BASIC,
&g_dummyByte,
(void *)(SSI0_BASE + SSI_O_DR),
SAMPLE_BUFFER_SIZE);
//final code: get new buffer here
uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
UDMA_MODE_BASIC,
(void *)(SSI0_BASE + SSI_O_DR),
g_rxSampleBuffer, SAMPLE_BUFFER_SIZE);
uDMAChannelEnable(UDMA_CHANNEL_SSI0TX|UDMA_CHANNEL_SSI0RX);
}
void ssi0_IntHandler(void)
{
uint32_t ui32Status;
// Read the interrupt status
ui32Status = SSIIntStatus(SSI0_BASE, 1);
if(ui32Status & SSI_RXOR)
{
++g_nbOverrun;
}
if(ui32Status & SSI_RXTO)
{
++g_nbTimeout;
}
// Clear any pending status, even though there should be none since no SSI
// interrupts were enabled.
SSIIntClear(SSI0_BASE, ui32Status);
// If the dma channel is disabled, that means the transfer is complete
if(!uDMAChannelIsEnabled(UDMA_CHANNEL_SSI0RX))
{
g_rxBufCount++;
}
}