Hello:
Introduction:
I am having a difficult problem with the DMA engine in the LPC54114. I am trying to use the DMA in a continuously linked transfer described on page 160 of User Manual 1.4 UM10914. Instead of a ping pong, I am setting up 4 descriptors where the last one links back to the 1st. I am transferring data from the ADC into some memory buffers. To test, I am feeding the ADC with a known frequency sine wave.
Observed Issue:
The 1st four transfers always work OK. If I terminate the transfer at the 4th descriptor, I can looked at the data and it is correct. If I link the 4th descriptor back to the 1st, data in my memory buffer is incorrect after the 1st four transfers. It looks like it is ADC data BUT it is out of order. I cannot find a pattern to the out of order data but it only appears to occur after the 1st set of 4 descriptors are executed.
Also note, that the DMA is continually operating. It is doing the correct number if transfers, it just is not moving to the correct destination addresses. It does appear the DMA is moving data into the correct region, but the actual ordering is messed up. I am monitoring via a pin on an o-scope when I get a DMA IRQ as well as when the ADC is triggered via the SCT. I get ADC & DMA pulses at the correct rate, etc.
Background:
Here is a description of of the DMA setup.
I am using the setup to get a set of 4 buffers such that I can have 4 at any time to process
Here is the Setup routine:
#define NUM_BUFFERS 4
#define DMA_TRANSFER_SIZE 8
__BSS(RAM2) ALIGN(512) DMA_CHDESC_T ADC_TransferDescriptors[4];
uint16_t CapturedData[NUM_BUFFERS * DMA_TRANSFER_SIZE];
void InitADC()
{
DMA_CHDESC_T Initial_DMA_Descriptor;
Chip_SCTPWM_Init(LPC_SCT);
Chip_SCTPWM_Stop(LPC_SCT);
LPC_SCT->REGMODE_L = 0;
LPC_SCT->REGMODE_H = 0;
Chip_SCT_SetMatchCount(LPC_SCT, SCT_MATCH_0, 0);
Chip_SCT_SetMatchReload(LPC_SCT, SCT_MATCH_0, 960);
LPC_SCT->EVENT[0].CTRL = 1 << 12;
LPC_SCT->EVENT[0].STATE = 1;
Chip_SCT_Config(LPC_SCT, SCT_CONFIG_32BIT_COUNTER | SCT_CONFIG_AUTOLIMIT_L);
Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 14, IOCON_FUNC3 | IOCON_MODE_INACT | IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
Chip_SCTPWM_SetOutPin(LPC_SCT, SCT_PWM_OUT, SCT_PWM_PIN_OUT);
Chip_SCTPWM_SetDutyCycle(LPC_SCT, SCT_PWM_OUT, 1);
Chip_SCTPWM_Start(LPC_SCT);
ADC_TransferDescriptors[0].source = (uint32_t)&LPC_ADC->DAT[1];
ADC_TransferDescriptors[1].source = (uint32_t)&LPC_ADC->DAT[1];
ADC_TransferDescriptors[2].source = (uint32_t)&LPC_ADC->DAT[1];
ADC_TransferDescriptors[3].source = (uint32_t)&LPC_ADC->DAT[1];
ADC_TransferDescriptors[0].dest = (uint32_t)&CapturedData[(0+1)*DMA_TRANSFER_SIZE-1];
ADC_TransferDescriptors[1].dest = (uint32_t)&CapturedData[(1+1)*DMA_TRANSFER_SIZE-1];
ADC_TransferDescriptors[2].dest = (uint32_t)&CapturedData[(2+1)*DMA_TRANSFER_SIZE-1];
ADC_TransferDescriptors[3].dest = (uint32_t)&CapturedData[(3+1)*DMA_TRANSFER_SIZE-1];
ADC_TransferDescriptors[0].next = (uint32_t)&ADC_TransferDescriptors[1];
ADC_TransferDescriptors[1].next = (uint32_t)&ADC_TransferDescriptors[2];
ADC_TransferDescriptors[2].next = (uint32_t)&ADC_TransferDescriptors[3];
ADC_TransferDescriptors[3].next = (uint32_t)&ADC_TransferDescriptors[0];
ADC_TransferDescriptors[0].xfercfg = (DMA_XFERCFG_CFGVALID |
DMA_XFERCFG_RELOAD |
DMA_XFERCFG_SETINTA |
DMA_XFERCFG_WIDTH_16 |
DMA_XFERCFG_SRCINC_0 |
DMA_XFERCFG_DSTINC_1 |
DMA_XFERCFG_XFERCOUNT(DMA_TRANSFER_SIZE));
ADC_TransferDescriptors[1].xfercfg = ADC_TransferDescriptors[0].xfercfg;
ADC_TransferDescriptors[2].xfercfg = ADC_TransferDescriptors[0].xfercfg;
ADC_TransferDescriptors[3].xfercfg = (DMA_XFERCFG_CFGVALID |
DMA_XFERCFG_RELOAD |
DMA_XFERCFG_SETINTA |
DMA_XFERCFG_WIDTH_16 |
DMA_XFERCFG_SRCINC_0 |
DMA_XFERCFG_DSTINC_1 |
DMA_XFERCFG_XFERCOUNT(DMA_TRANSFER_SIZE));
Initial_DMA_Descriptor.source = ADC_TransferDescriptors[0].source;
Initial_DMA_Descriptor.dest = ADC_TransferDescriptors[0].dest;
Initial_DMA_Descriptor.next = (uint32_t)&ADC_TransferDescriptors[1];
Initial_DMA_Descriptor.xfercfg = ADC_TransferDescriptors[0].xfercfg;
Chip_DMA_Init(LPC_DMA);
Chip_DMA_Enable(LPC_DMA);
Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
Chip_DMA_EnableChannel(LPC_DMA, DMA_CH0);
Chip_DMA_EnableIntChannel(LPC_DMA, DMA_CH0);
Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_CH0,
(DMA_CFG_HWTRIGEN |
DMA_CFG_TRIGBURST_BURST |
DMA_CFG_TRIGTYPE_EDGE |
DMA_CFG_TRIGPOL_HIGH |
DMA_CFG_BURSTPOWER_1 |
DMA_CFG_CHPRIORITY(0)
)
);
LPC_INMUX->DMA_ITRIG_INMUX[0] = 0;
NVIC_EnableIRQ(DMA_IRQn);
Chip_DMA_SetupTranChannel(LPC_DMA, DMA_CH0, &Initial_DMA_Descriptor);
Chip_DMA_SetupChannelTransfer(LPC_DMA, DMA_CH0,
ADC_TransferDescriptors[0].xfercfg
);
Chip_DMA_SetValidChannel(LPC_DMA, DMA_CH0);
ADC_BufferState = 0;
Chip_ADC_Init(LPC_ADC, ADC_CR_RESOL(3) | ADC_CR_CLKDIV(0));
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 30, IOCON_FUNC0 | IOCON_ANALOG_EN| IOCON_INPFILT_OFF);
LPC_ADC->INSEL = 0x01;
Chip_ADC_SetupSequencer(LPC_ADC,
ADC_SEQA_IDX,
ADC_SEQ_CTRL_SEQ_ENA |
ADC_SEQ_CTRL_CHANNEL_EN(ADC_INPUT_CHANNEL) |
ADC_SEQ_CTRL_TRIGGER(2) |
ADC_SEQ_CTRL_HWTRIG_POLPOS |
ADC_SEQ_CTRL_MODE_EOS);
Chip_ADC_EnableInt(LPC_ADC, ADC_INTEN_SEQA_ENABLE);
if(Chip_ADC_Calibration(LPC_ADC) == LPC_OK)
{
}
else {
DEBUGSTR("ADC Calibration Failed \r\n");
Board_LED_Set(0, true);
return 0;
}
}
The DMA handler:
void DMA_IRQHandler(void)
{
Chip_GPIO_SetPinState(LPC_GPIO,TEST_PORT,true);
if ((Chip_DMA_GetIntStatus(LPC_DMA) & DMA_INTSTAT_ACTIVEERRINT) != 0)
{
Chip_DMA_DisableChannel(LPC_DMA, DMA_CH0);
while ((Chip_DMA_GetBusyChannels(LPC_DMA) & (1 << DMA_CH0)) != 0) {}
Chip_DMA_AbortChannel(LPC_DMA, DMA_CH0);
Chip_DMA_ClearErrorIntChannel(LPC_DMA, DMA_CH0);
Chip_DMA_EnableChannel(LPC_DMA, DMA_CH0);
Board_LED_Set(0, true);
}
ADC_BufferState++;
ADC_BufferState &= 0x03;
LPC_DMA->DMACOMMON[0].INTA = 1;
}
I can upload my entire source code if needed. The only other pieces I have not shown is the main routine which calls the InitADC() function.
I will certainly post the results if I solve the issue. Hopefully someone else has seen this behavior.