Overview
Ping-pong is a special case of a linked transfer which typically used more frequently than more complicated versions of linked transfers.
A ping-pong transfer usually uses at least two buffers. At any one time, one buffer is being loaded or unloaded by DMA operations. The other buffers have the opposite operation being handled by software, readying the buffer for use when the buffer currently being used by the DMA controller is full or empty. The Fig 1 illustrates an example of descriptors for ping-pong from a peripheral to two buffers in memory.

Fig 1
Implementation detail
To continuous transfer the converted result of the ADC to RAM, I’m going to use four 4 DMA descriptors to work in Ping-Pong mode to
achieve this goal as the Fig 2 shows.

Fig 2 Data flow via Ping-Pong mode
Hardware introduction

Fig 3 LPCXpressor54114 Board
Example code
The code is based on the periph_adc demo, using the SCTimer output as the hardware trigger of ADC, meanwhile, the ADC converted value is transferred to the appointed area of RAM automatically.
#include "board.h"
#define SCT_PWM LPC_SCT
#define NUM_BUFFERS 4
#define DMA_TRANSFER_SIZE 8
#define ADC_INPUT_CHANNEL 1
#define SCT_PWM_RATE 10000
#define SCT_PWM_PIN_OUT 7
#define SCT_PWM_OUT 1
uint16_t adcOut;
ALIGN(512) DMA_CHDESC_T ADC_TransferDescriptors[NUM_BUFFERS];
uint16_t CapturedData[32];
uint16_t DMA_Sum=0;
void ADC_SEQA_IRQHandler(void)
{
Chip_GPIO_SetPinState(LPC_GPIO, 0, 6, true);
Chip_GPIO_SetPinState(LPC_GPIO, 0, 6, false);
Chip_ADC_ClearFlags(LPC_ADC,0xFFFFFFFF);
}
void DMA_IRQHandler(void)
{
static uint16_t DMA_Sum=0;
DMA_Sum++;
if(DMA_Sum ==8)
{
DMA_Sum=4;
}
Chip_GPIO_SetPinState(LPC_GPIO, 0, 7,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);
}
Chip_GPIO_SetPinState(LPC_GPIO, 0,7,false);
LPC_DMA->DMACOMMON[0].INTA = 1;
}
void DMA_Steup(void)
{
DMA_CHDESC_T Initial_DMA_Descriptor;
ADC_TransferDescriptors[0].source = (uint32_t)&LPC_ADC->SEQ_GDAT[0];
ADC_TransferDescriptors[1].source = (uint32_t)&LPC_ADC->SEQ_GDAT[0];
ADC_TransferDescriptors[2].source = (uint32_t)&LPC_ADC->SEQ_GDAT[0];
ADC_TransferDescriptors[3].source = (uint32_t)&LPC_ADC->SEQ_GDAT[0];
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_LOW |
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);
}
void SCT_PWM_Generate(void)
{
Chip_SCTPWM_Init(SCT_PWM);
Chip_SCTPWM_SetRate(SCT_PWM, SCT_PWM_RATE);
Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 14, IOCON_FUNC3 | IOCON_MODE_INACT | IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
Chip_SCTPWM_SetOutPin(SCT_PWM, SCT_PWM_OUT, SCT_PWM_PIN_OUT);
Chip_SCTPWM_SetDutyCycle(SCT_PWM, SCT_PWM_OUT, Chip_SCTPWM_PercentageToTicks(SCT_PWM, 10));
Chip_SCTPWM_Start(SCT_PWM);
}
void ADC_Steup(void)
{
LPC_SYSCON->ADCCLKSEL = 0;
LPC_SYSCON->ADCCLKDIV = 0;
Chip_ADC_Init(LPC_ADC, ADC_CR_RESOL(3) | ADC_CR_CLKDIV(0)| ADC_CR_ASYNC_MODE);
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_HWTRIG_SYNCBYPASS |
ADC_SEQ_CTRL_MODE_EOS |
ADC_SEQ_CTRL_SEQ_ENA);
Chip_ADC_EnableInt(LPC_ADC, ADC_INTEN_SEQA_ENABLE);
if(Chip_ADC_Calibration(LPC_ADC) == LPC_OK) {
NVIC_EnableIRQ(ADC_SEQA_IRQn);
}
else {
DEBUGSTR("ADC Calibration Failed \r\n");
return ;
}
}
int main(void)
{
SystemCoreClockUpdate();
Board_Init();
DMA_Steup();
ADC_Steup();
SCT_PWM_Generate();
while(1)
{}
}
Verification
- Building the project, then click the
to debug; - Generate the sine wave: 1 KHz, 幅度:0~2 V,feed the wave the ADC via the J9_1(P0_30-ADC1);
- Setting the breakpoint (Fig 4) to observe the ADC converted value CapturedData[32];

Fig 4
4. To verifying the result, I collect several group of data and use the Excel to make these data graphical for checking. Fig 6 is an example.

Fig 5

Fig 6

Fig 7

Fig 8