LPC1549: Problem with SCT triggering ADC triggering DMA at a certain frequency

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC1549: Problem with SCT triggering ADC triggering DMA at a certain frequency

788 Views
jespermadsen
Contributor III

I'm using the Xpresso-LPC1549 board with MCUXpresso IDE v11 and LPCOpen v2_20.

I made the SCT trigger the ADC at 100 KHz.

And then the DMA should to write the result to memory (eventually with the Ping - Pong mode).

The DMA interrupt is only fired one time, when the ADC is enabled.

Can someone help?


void DMA_IRQHandler(void)
{
/* 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);
Chip_ADC_ClearFlags(LPC_ADC0, Chip_ADC_GetFlags(LPC_ADC0));

dmaDone = true;
}

int main(void) {

#if defined (__USE_LPCOPEN)
// Read clock settings and update SystemCoreClock variable
SystemCoreClockUpdate();
#if !defined(NO_BOARD_LIB)
// Set up and initialize all required blocks and
// functions related to the board hardware
Board_Init();
// Set the LED to the state of "On"
Board_LED_Set(0, true);
#endif
#endif
/* Initialize GPIO */
Chip_GPIO_Init(LPC_GPIO);
Chip_GPIO_SetPinDIROutput(LPC_GPIO, 0, 0); //Use PIO_0_0 for test toggle

//Setup DMA
Chip_DMA_Init(LPC_DMA);
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_HWTRIGEN | DMA_CFG_TRIGTYPE_EDGE | DMA_CFG_TRIGPOL_HIGH
| DMA_CFG_TRIGBURST_BURST | DMA_CFG_BURSTPOWER_1
| DMA_CFG_CHPRIORITY(0)));

Chip_INMUX_SetDMATrigger(DMA_CH0, DMATRIG_ADC0_SEQA_IRQ);

DMA_CHDESC_T dmaDesc0, dmaDesc1;
dmaDesc0.source = DMA_ADDR(&(LPC_ADC0->SEQ_GDAT[ADC_SEQA_IDX]));
dmaDesc0.dest = DMA_ADDR(&src[SIZE_BUFFERS - 1]) + 3;
dmaDesc0.next = DMA_ADDR(0);

dmaDesc1.source = DMA_ADDR(&(LPC_ADC0->SEQ_GDAT[ADC_SEQA_IDX]));
dmaDesc1.dest = DMA_ADDR(&dst[SIZE_BUFFERS - 1]) + 3;
dmaDesc1.next = DMA_ADDR(0);

/* Setup transfer descriptor and validate it */
Chip_DMA_SetupTranChannel(LPC_DMA, DMA_CH0, &dmaDesc0);

Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_CH0);

/* Enable DMA interrupt */
NVIC_EnableIRQ(DMA_IRQn);

/* Setup data transfer and software trigger in same call */
Chip_DMA_SetupChannelTransfer(LPC_DMA, DMA_CH0,
// (DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTA |
// DMA_XFERCFG_WIDTH_32 | DMA_XFERCFG_SRCINC_1 | DMA_XFERCFG_DSTINC_1 |
// DMA_XFERCFG_XFERCOUNT(SIZE_BUFFERS)));
(DMA_XFERCFG_CFGVALID | DMA_XFERCFG_RELOAD | DMA_XFERCFG_SETINTA |
DMA_XFERCFG_WIDTH_32 |
DMA_XFERCFG_SRCINC_0 | DMA_XFERCFG_DSTINC_1 |
DMA_XFERCFG_XFERCOUNT(SIZE_BUFFERS)));
Chip_DMA_SetValidChannel(LPC_DMA, DMA_CH0);

/* Setup ADC for 12-bit mode and normal power */
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 8, (IOCON_MODE_INACT));
Chip_SWM_Init();
Chip_SWM_EnableFixedPin(SWM_FIXED_ADC0_0); //P0_8

Chip_ADC_Init(LPC_ADC0, 0);
Chip_ADC_SetClockRate(LPC_ADC0, ADC_MAX_SAMPLE_RATE);
Chip_ADC_SetupSequencer(LPC_ADC0, ADC_SEQA_IDX, (ADC_SEQ_CTRL_CHANSEL(0) | ADC0_SEQ_CTRL_HWTRIG_SCT2_OUT3 | ADC_SEQ_CTRL_MODE_EOS));
Chip_ADC_SetTrim(LPC_ADC0, ADC_TRIM_VRANGE_HIGHV);
Chip_ADC_StartCalibration(LPC_ADC0);
while (!(Chip_ADC_IsCalibrationDone(LPC_ADC1))) {}

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);

//Setup SCT 2
Chip_SCT_Init(LPC_SCT2);
Chip_SCT_Config(LPC_SCT2, (SCT_CONFIG_32BIT_COUNTER | SCT_CONFIG_AUTOLIMIT_L));
Chip_SCT_SetMatchReload(LPC_SCT2, SCT_MATCH_0, Chip_Clock_GetSystemClockRate() / 100000);

LPC_SCT2->EVENT[0].STATE = 0xFFFFFFFF; // event 0 happens in all states
LPC_SCT2->EVENT[0].CTRL = (1 << 12); // match 0 condition only

Chip_SCTPWM_SetOutPin(LPC_SCT2, 3, 3);

Chip_SCT_ClearControl(LPC_SCT2, SCT_CTRL_HALT_L | SCT_CTRL_HALT_H);

while(1) {
__NOP();
}
return 0 ;
}

Labels (1)
0 Kudos
2 Replies

779 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Jesper,

I think you have to reinitialize the Transfer Configuration registers in the void DMA_IRQHandler(void), especially XFERCOUNT bits so that the DMA can  work repeatedly.

For simplicity, you can have a test without using ping-pong mode, and check if you can enter void DMA_IRQHandler(void) continuously.

BR

XiangJun Rong

744 Views
jespermadsen
Contributor III

Thank you xiangjun_rong.

You where right. The interrupt entered continuously.

But I could not get the ADC data out.

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.

Now I get 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.

Can you help again? 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)
{}
}

 

0 Kudos