I found this example:
https://community.nxp.com/t5/LPC-Microcontrollers-Knowledge/DMA-Ping-Pong-application/ta-p/1120977
for the LPCXpressor54114 Board and changed it to match the LPC1549 LPCXpresso™ board.
There are some ADC results in the buffer. But there are zeros and not compleately processed data there too.
I'm using the SCT2_Out3 to ADC0_SEQA to DMA. I'm not sure if the ADC_SEQA is setup correctly.
What could be wrong?
The code is shown below:
//-------------------------------------------------------------
#if defined (__USE_LPCOPEN)
#if defined(NO_BOARD_LIB)
#include "chip.h"
#else
#include "board.h"
#endif
#endif
#include <cr_section_macros.h>
#define NUM_BUFFERS 4
#define DMA_TRANSFER_SIZE 8
#define ADC_INPUT_CHANNEL 0
#define SCT_PWM_RATE 10000 /* PWM frequency 10 KHz */
#define SCT_PWM_PIN_OUT 3 /* COUT3 Generate square wave */
#define SCT_PWM_OUT 3 /* Index of OUT PWM */
uint16_t adcOut;
DMA_CHDESC_T ADC_TransferDescriptors[NUM_BUFFERS] __attribute__ ((aligned(512)));
uint16_t CapturedData[32];
uint16_t DMA_Sum=0;
/**
*
* ADC IRQ not Used right now... Only for testing
*/
void ADC_SEQA_IRQHandler(void)
{
/* If SeqA flags is set i.e. data in global register is valid then read it */
Chip_ADC_ClearFlags(LPC_ADC0,0xFFFFFFFF);
}
void DMA_IRQHandler(void)
{
static uint16_t DMA_Sum=0;
DMA_Sum++;
if(DMA_Sum ==8)
{
DMA_Sum=4;
}
/* Rrror interrupt on channel 0? */
if ((Chip_DMA_GetIntStatus(LPC_DMA) & DMA_INTSTAT_ACTIVEERRINT) != 0)
{
/* This shouldn't happen for this simple DMA example, so set the LED
to indicate an error occurred. This is the correct method to clear
an abort. */
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);
}
/* Clear DMA interrupt for the channel */
Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_CH0);
}
/***
* ____ __ __ _
* | _ \| \/ | / \
* | | | | |\/| | / _ \
* | |_| | | | |/ ___ \
* |____/|_| |_/_/ \_\
* / ___| ___| |_ _ _ _ __
* \___ \ / _ \ __| | | | '_ \
* ___) | __/ |_| |_| | |_) |
* |____/ \___|\__|\__,_| .__/
* |_|
*/
void DMA_Setup(void)
{
DMA_CHDESC_T Initial_DMA_Descriptor;
ADC_TransferDescriptors[0].source = (uint32_t)&LPC_ADC0->SEQ_GDAT[0];
ADC_TransferDescriptors[1].source = (uint32_t)&LPC_ADC0->SEQ_GDAT[0];
ADC_TransferDescriptors[2].source = (uint32_t)&LPC_ADC0->SEQ_GDAT[0];
ADC_TransferDescriptors[3].source = (uint32_t)&LPC_ADC0->SEQ_GDAT[0];
ADC_TransferDescriptors[0].dest = DMA_ADDR(&CapturedData[(0+1)*DMA_TRANSFER_SIZE-1]);
ADC_TransferDescriptors[1].dest = DMA_ADDR(&CapturedData[(1+1)*DMA_TRANSFER_SIZE-1]);
ADC_TransferDescriptors[2].dest = DMA_ADDR(&CapturedData[(2+1)*DMA_TRANSFER_SIZE-1]);
ADC_TransferDescriptors[3].dest = DMA_ADDR(&CapturedData[(3+1)*DMA_TRANSFER_SIZE-1]);
//The initial DMA desciptor is the same as the 1st transfer descriptor. It
//Will link into the 2nd of the main descriptors.
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];
//Link back to the 1st descriptor
ADC_TransferDescriptors[3].next = (uint32_t)&ADC_TransferDescriptors[0];
//For a test, stop the transfers here. The sine wave will look fine.
//ADC_TransferDescriptors[3].next = 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;
/* DMA initialization - enable DMA clocking and reset DMA if needed */
Chip_DMA_Init(LPC_DMA);
/* Enable DMA controller and use driver provided DMA table for current descriptors */
Chip_DMA_Enable(LPC_DMA);
Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
/* Setup channel 0 for the following configuration:
- High channel priority
- Interrupt A fires on descriptor completion */
Chip_DMA_EnableChannel(LPC_DMA, DMA_CH0);
Chip_DMA_EnableIntChannel(LPC_DMA, DMA_CH0);
Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_CH0, //(DMA_CFG_PERIPHREQEN |
(DMA_CFG_HWTRIGEN |
DMA_CFG_TRIGBURST_BURST |
DMA_CFG_TRIGTYPE_EDGE |
DMA_CFG_TRIGPOL_HIGH | //DMA_CFG_TRIGPOL_HIGH
DMA_CFG_BURSTPOWER_1 |
DMA_CFG_CHPRIORITY(0)
)
);
//make sure ADC Sequence A interrupts is selected for for a DMA trigger
Chip_INMUX_SetDMATrigger(DMA_CH0, DMATRIG_ADC0_SEQA_IRQ);
/* Enable DMA interrupt */
NVIC_EnableIRQ(DMA_IRQn);
// The 1st descriptor is set up through the registers.
/* Setup transfer descriptor and validate it */
Chip_DMA_SetupTranChannel(LPC_DMA, DMA_CH0, &Initial_DMA_Descriptor);
//Use the transfer configuration for our 4 main descriptors
Chip_DMA_SetupChannelTransfer(LPC_DMA, DMA_CH0, ADC_TransferDescriptors[0].xfercfg);
Chip_DMA_SetValidChannel(LPC_DMA, DMA_CH0);
}
void SCT_PWM_Generate(void)
{
/* Initialize the SCT2 as PWM and set frequency */
Chip_SCTPWM_Init(LPC_SCT2);
Chip_SCTPWM_SetRate(LPC_SCT2, SCT_PWM_RATE);
/* Use SCT2_OUT3 pin */
Chip_SCTPWM_SetOutPin(LPC_SCT2, SCT_PWM_OUT, SCT_PWM_PIN_OUT);
/* Start with 50% duty cycle */
Chip_SCTPWM_SetDutyCycle(LPC_SCT2, SCT_PWM_OUT, Chip_SCTPWM_PercentageToTicks(LPC_SCT2, 50));
Chip_SCTPWM_Start(LPC_SCT2);
}
/***
* _ ____ ____
* / \ | _ \ / ___|
* / _ \ | | | | |
* / ___ \| |_| | |___
* /_/__ \_\____/ \____|
* / ___| ___| |_ _ _ _ __
* \___ \ / _ \ __| | | | '_ \
* ___) | __/ |_| |_| | |_) |
* |____/ \___|\__|\__,_| .__/
* |_|
*/
void ADC_Setup(void)
{
/*Set Asynch Clock to the Main clock*/
// LPC_SYSCON->ADCCLKSEL = 0;
// Chip_Clock_SetADCASYNCSource(SYSCTL_ADCASYNCCLKSRC_IRC);
//Set the divider to 1 and enable. note, the HALT bit (30) and RESET (29) are not in the manual
// LPC_SYSCON->ADCCLKDIV = 0;
/* Initialization ADC to 12 bit and set clock divide to 1 to operate synchronously at System clock */
Chip_ADC_Init(LPC_ADC0, ADC_CR_BITACC(0) | ADC_CR_CLKDIV(0)| ADC_CR_ASYNMODE);
Chip_ADC_SetClockRate(LPC_ADC0, ADC_MAX_SAMPLE_RATE);
//select ADC Channel 0 as input
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 8, IOCON_FUNC0 | IOCON_MODE_INACT | IOCON_ADMODE_EN);
Chip_SWM_Init();
Chip_SWM_EnableFixedPin(SWM_FIXED_ADC0_0); //P0_8
Chip_ADC_SetADC0Input(LPC_ADC0, ADC_INSEL_ADC0);
//Setup ADC0_SEQA_IRQ
Chip_ADC_SetupSequencer(LPC_ADC0,ADC_SEQA_IDX,
ADC_SEQ_CTRL_SEQ_ENA |
ADC_SEQ_CTRL_CHANSEL(ADC_INPUT_CHANNEL) |
ADC0_SEQ_CTRL_HWTRIG_SCT2_OUT3 |
// ADC_SEQ_CTRL_HWTRIG_POLPOS |
// ADC_SEQ_CTRL_HWTRIG_SYNCBYPASS |
ADC_SEQ_CTRL_MODE_EOS);
/* Enable Sequence A interrupt */
Chip_ADC_EnableInt(LPC_ADC0, ADC_INTEN_SEQA_ENABLE);
/* Calibrate ADC */
Chip_ADC_StartCalibration(LPC_ADC0);
while (!(Chip_ADC_IsCalibrationDone(LPC_ADC0))) {}
Chip_ADC_ClearFlags(LPC_ADC0, Chip_ADC_GetFlags(LPC_ADC0));
// Chip_ADC_EnableInt(LPC_ADC0, ADC_INTEN_SEQA_ENABLE);
// NVIC_EnableIRQ(ADC0_SEQA_IRQn);
Chip_ADC_EnableSequencer(LPC_ADC0, ADC_SEQA_IDX);
}
int main(void)
{
/* Setup SystemCoreClock and any needed board code */
SystemCoreClockUpdate();
Board_Init();
DMA_Setup();
ADC_Setup();
SCT_PWM_Generate();
while(1)
{}
}
Solved! Go to Solution.
Hello Jesper,
“There are some ADC results in the buffer. But there are zeros and not completely processed data there too.”
-> Dose the data all right when only use ADC,without DMA?
BR
Alice
Hello Jesper,
“There are some ADC results in the buffer. But there are zeros and not completely processed data there too.”
-> Dose the data all right when only use ADC,without DMA?
BR
Alice
Hello Alice.
Now the values comes into the buffer.. Thanks.
I removed the boardlib and made some small changes:
#include "chip.h"
#include <cr_section_macros.h>
#define NUM_BUFFERS 4
#define DMA_TRANSFER_SIZE 8
#define ADC_INPUT_CHANNEL 0
#define SCT_PWM_RATE 10000 /* PWM frequency 10 KHz */
#define SCT_PWM_PIN_OUT 3 /* COUT3 Generate square wave */
#define SCT_PWM_OUT 3 /* Index of OUT PWM */
uint16_t adcOut;
DMA_CHDESC_T ADC_TransferDescriptors[NUM_BUFFERS] __attribute__ ((aligned(512)));
uint16_t CapturedData[32];
uint16_t DMA_Sum=0;
/**
*
* ADC IRQ not Used right now... Only for testing
*/
void ADC_SEQA_IRQHandler(void)
{
/* If SeqA flags is set i.e. data in global register is valid then read it */
Chip_ADC_ClearFlags(LPC_ADC0,0xFFFFFFFF);
}
void DMA_IRQHandler(void)
{
static uint16_t DMA_Sum=0;
DMA_Sum++;
if(DMA_Sum ==8)
{
DMA_Sum=4;
}
/* Error interrupt on channel 0? */
if ((Chip_DMA_GetIntStatus(LPC_DMA) & DMA_INTSTAT_ACTIVEERRINT) != 0)
{
/* This shouldn't happen for this simple DMA example, so set the LED
to indicate an error occurred. This is the correct method to clear
an abort. */
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);
}
/* Clear DMA interrupt for the channel */
Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_CH0);
}
/***
* ____ __ __ _
* | _ \| \/ | / \
* | | | | |\/| | / _ \
* | |_| | | | |/ ___ \
* |____/|_| |_/_/ \_\
* / ___| ___| |_ _ _ _ __
* \___ \ / _ \ __| | | | '_ \
* ___) | __/ |_| |_| | |_) |
* |____/ \___|\__|\__,_| .__/
* |_|
*/
void DMA_Setup(void)
{
DMA_CHDESC_T Initial_DMA_Descriptor;
ADC_TransferDescriptors[0].source = (uint32_t)&LPC_ADC0->SEQ_GDAT[0];
ADC_TransferDescriptors[1].source = (uint32_t)&LPC_ADC0->SEQ_GDAT[0];
ADC_TransferDescriptors[2].source = (uint32_t)&LPC_ADC0->SEQ_GDAT[0];
ADC_TransferDescriptors[3].source = (uint32_t)&LPC_ADC0->SEQ_GDAT[0];
ADC_TransferDescriptors[0].dest = DMA_ADDR(&CapturedData[(0+1)*DMA_TRANSFER_SIZE-1]);
ADC_TransferDescriptors[1].dest = DMA_ADDR(&CapturedData[(1+1)*DMA_TRANSFER_SIZE-1]);
ADC_TransferDescriptors[2].dest = DMA_ADDR(&CapturedData[(2+1)*DMA_TRANSFER_SIZE-1]);
ADC_TransferDescriptors[3].dest = DMA_ADDR(&CapturedData[(3+1)*DMA_TRANSFER_SIZE-1]);
//The initial DMA desciptor is the same as the 1st transfer descriptor. It
//Will link into the 2nd of the main descriptors.
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];
//Link back to the 1st descriptor
ADC_TransferDescriptors[3].next = (uint32_t)&ADC_TransferDescriptors[0];
//For a test, stop the transfers here. The sine wave will look fine.
//ADC_TransferDescriptors[3].next = 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;
/* DMA initialization - enable DMA clocking and reset DMA if needed */
Chip_DMA_Init(LPC_DMA);
/* Enable DMA controller and use driver provided DMA table for current descriptors */
Chip_DMA_Enable(LPC_DMA);
Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
/* Setup channel 0 for the following configuration:
- High channel priority
- Interrupt A fires on descriptor completion */
Chip_DMA_EnableChannel(LPC_DMA, DMA_CH0);
Chip_DMA_EnableIntChannel(LPC_DMA, DMA_CH0);
Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_CH0, //(DMA_CFG_PERIPHREQEN |
(DMA_CFG_HWTRIGEN |
DMA_CFG_TRIGBURST_BURST |
DMA_CFG_TRIGTYPE_EDGE |
DMA_CFG_TRIGPOL_HIGH | //DMA_CFG_TRIGPOL_HIGH
DMA_CFG_BURSTPOWER_1 |
DMA_CFG_CHPRIORITY(0)
)
);
//make sure ADC Sequence A interrupts is selected for for a DMA trigger
Chip_INMUX_SetDMATrigger(DMA_CH0, DMATRIG_ADC0_SEQA_IRQ);
/* Enable DMA interrupt */
NVIC_EnableIRQ(DMA_IRQn);
// The 1st descriptor is set up through the registers.
/* Setup transfer descriptor and validate it */
Chip_DMA_SetupTranChannel(LPC_DMA, DMA_CH0, &Initial_DMA_Descriptor);
//Use the transfer configuration for our 4 main descriptors
Chip_DMA_SetupChannelTransfer(LPC_DMA, DMA_CH0, ADC_TransferDescriptors[0].xfercfg);
Chip_DMA_SetValidChannel(LPC_DMA, DMA_CH0);
}
void SCT_PWM_Generate(void)
{
/* Initialize the SCT2 as PWM and set frequency */
Chip_SCTPWM_Init(LPC_SCT2);
Chip_SCTPWM_SetRate(LPC_SCT2, SCT_PWM_RATE);
/* Use SCT2_OUT3 pin */
Chip_SCTPWM_SetOutPin(LPC_SCT2, SCT_PWM_OUT, SCT_PWM_PIN_OUT);
/* Start with 50% duty cycle */
Chip_SCTPWM_SetDutyCycle(LPC_SCT2, SCT_PWM_OUT, Chip_SCTPWM_PercentageToTicks(LPC_SCT2, 50));
Chip_SCTPWM_Start(LPC_SCT2);
}
/***
* _ ____ ____
* / \ | _ \ / ___|
* / _ \ | | | | |
* / ___ \| |_| | |___
* /_/__ \_\____/ \____|
* / ___| ___| |_ _ _ _ __
* \___ \ / _ \ __| | | | '_ \
* ___) | __/ |_| |_| | |_) |
* |____/ \___|\__|\__,_| .__/
* |_|
*/
void ADC_Setup(void)
{
/* Initialization ADC to 12 bit and set clock divide to 1 to operate synchronously at System clock */
Chip_ADC_Init(LPC_ADC0, ADC_CR_BITACC(0) | ADC_CR_CLKDIV(0)| ADC_CR_ASYNMODE);
Chip_ADC_SetClockRate(LPC_ADC0, ADC_MAX_SAMPLE_RATE);
//select ADC Channel 0 as input
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 8, IOCON_FUNC0 | IOCON_MODE_INACT | IOCON_ADMODE_EN);
Chip_SWM_Init();
Chip_SWM_EnableFixedPin(SWM_FIXED_ADC0_0); //P0_8
Chip_ADC_SetADC0Input(LPC_ADC0, ADC_INSEL_ADC0);
//Setup ADC0_SEQA_IRQ
Chip_ADC_SetupSequencer(LPC_ADC0,ADC_SEQA_IDX,
ADC_SEQ_CTRL_SEQ_ENA |
ADC_SEQ_CTRL_CHANSEL(ADC_INPUT_CHANNEL) |
ADC0_SEQ_CTRL_HWTRIG_SCT2_OUT3 |
// ADC_SEQ_CTRL_HWTRIG_POLPOS |
// ADC_SEQ_CTRL_HWTRIG_SYNCBYPASS |
ADC_SEQ_CTRL_MODE_EOS);
/* Enable Sequence A interrupt */
Chip_ADC_EnableInt(LPC_ADC0, ADC_INTEN_SEQA_ENABLE);
/* Calibrate ADC */
Chip_ADC_SetTrim(LPC_ADC0, ADC_TRIM_VRANGE_HIGHV);
Chip_ADC_StartCalibration(LPC_ADC0);
while (!(Chip_ADC_IsCalibrationDone(LPC_ADC0))) {}
Chip_ADC_ClearFlags(LPC_ADC0, Chip_ADC_GetFlags(LPC_ADC0));
// NVIC_EnableIRQ(ADC0_SEQA_IRQn);
Chip_ADC_EnableSequencer(LPC_ADC0, ADC_SEQA_IDX);
}
int main(void) {
// Read clock settings and update SystemCoreClock variable
SystemCoreClockUpdate();
Chip_GPIO_Init(LPC_GPIO);
Chip_GPIO_SetPinDIROutput(LPC_GPIO, 0, 0);
DMA_Setup();
ADC_Setup();
SCT_PWM_Generate();
while(1)
{}
return 0 ;
}
Hello Alice
If I keep a breakpoint in the loop and break it every time the interrupt fires, the value is not updated.
But if the MCU runs free for a while, and then I stop it, the value is correct.
Maybe the ADC interrupt is not correctly setup?
Best regards
Jesper
Hello,
"Maybe the ADC interrupt is not correctly setup?"
-> No, when you use breakpoint, there is some delay by software.
I recommend you set block to lock problem, for example without DMA, just check whether ADC
, then add DMA...
There are still some problems in the program.
I tried to set it up with
DMA_TRANSFER_SIZE 64
SCT_PWM_RATE 5000
And a 70 Hz triangle signal on the ADC-input.
The samples with DMA are chopped as you see in the pictures
The samples without DMA has only one jump.
How can this be?
PS: The curves in the figurs are not in fase.
ADC-input:
Samples without DMA:
Samples with DMA: