lpcware

ADC and DMA

Discussion created by lpcware Employee on Jun 15, 2016
Latest reply on Jun 17, 2016 by Martin Lorenz
Content originally posted in LPCWare by lg_inetyx on Thu Jan 29 09:04:12 MST 2015
Hi everybody !

I need to acquire buffers of 512 sample to monitor a waveform using the LPC1549 ADC.

I am trying to have it working using the ADC1 in burst mode, triggering the DMA.

The ADC driver should work fine, as the sequence interrupt is properly fired and the value is correct.
(when I enable NVIS, which I should not do using dma).

Does anybody sees what I'm doing wrong while setting up dma ?

The DMA driver code :
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/

/* Size of the source and destination buffers in 32-bit words.
   Allowable values  = 128, 256, 512, or 1024 */
#define SIZE_BUFFER            (512)

/* Source and destination buffers */
uint32_t adc_buf[SIZE_BUFFER];

/* DMA completion flag */
static volatile bool dmaDone;


/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/

/*****************************************************************************
* Private functions
****************************************************************************/

/*****************************************************************************
* Public functions
****************************************************************************/

/**
* @briefDMA Interrupt Handler
* @returnNone
*/
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);
Board_LED_Set(0, true);
}

/* Clear DMA interrupt for the channel */
Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_CH0);

dmaDone = true;
}


void DMA_init( void ) {

DMA_CHDESC_T dmaDesc;

/* 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
   - trigger on ACD1 seq A completion
   - burst size is 1 */
Chip_DMA_EnableChannel(LPC_DMA, DMA_CH0);
Chip_DMA_EnableIntChannel(LPC_DMA, DMA_CH0);
Chip_INMUX_SetDMATrigger(DMA_CH0, DMATRIG_ADC1_SEQA_IRQ);
Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_CH0,
(DMA_CFG_PERIPHREQEN | DMA_CFG_HWTRIGEN | DMA_CFG_TRIGTYPE_EDGE |
DMA_CFG_TRIGPOL_HIGH | DMA_CFG_BURSTPOWER_1 | DMA_CFG_CHPRIORITY(0)));

/* DMA descriptor for peripheral to memory operation - note that addresses must
   be the END address for src and destination, not the starting address.
     DMA operations moves from end to start. */
dmaDesc.source = DMA_ADDR(&(LPC_ADC1->DR[ADC1_IBUS_CH]));
dmaDesc.dest = DMA_ADDR(&adc_buf[SIZE_BUFFER - 1]) + 3;
dmaDesc.next = DMA_ADDR(0);

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


NVIC_EnableIRQ(DMA_IRQn);// Enable DMA interrupt

/* 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_0 | DMA_XFERCFG_DSTINC_1 |
   DMA_XFERCFG_XFERCOUNT(SIZE_BUFFER)));

dmaDone = false;

}



The ADC driver code :

/**
* Init ADC1 to perform periodical reads on channels 0 and 1, whith threshold detection
*/
void ADC1_init( void )
{

/* --- ADC Init --- */

/* Setup ADC for 12-bit mode and normal power */
Chip_ADC_Init(ADC, 0);

/* Setup for maximum ADC clock rate */
Chip_ADC_SetClockRate(ADC, ADC_MAX_SAMPLE_RATE);

/* For ADC1, sequencer A will be used with threshold events.
   It will run continuously in burst mode and will monitor the CH0 & CH1 input. */
Chip_ADC_SetupSequencer(ADC, ADC_SEQA_IDX,(ADC_SEQ_CTRL_CHANSEL(ADC1_VBUS_CH) |
ADC_SEQ_CTRL_CHANSEL(ADC1_IBUS_CH) |
ADC_SEQ_CTRL_BURST   |
ADC_SEQ_CTRL_MODE_EOS));
/* Need to do a calibration after initialization and trim */
Chip_ADC_StartCalibration(ADC);
while (!(Chip_ADC_IsCalibrationDone(ADC))) {}

/* ACD clock must be set after calibration !! (bug in lib) */
Chip_ADC_SetClockRate(ADC, ADC_MAX_SAMPLE_RATE);

/* setup thresholds so that they are never crossed.
* They will be set by application, through ADC1_set_thr(...)
*/
// ch 0
Chip_ADC_SelectTH0Channels(ADC, ADC_SEQ_CTRL_CHANSEL(ADC1_VBUS_CH));
Chip_ADC_SetThrLowValue(ADC, 0,  0x000);
Chip_ADC_SetThrHighValue(ADC, 0, 0xFFF);

// ch 1
Chip_ADC_SelectTH1Channels(ADC, ADC_SEQ_CTRL_CHANSEL(ADC1_IBUS_CH));
Chip_ADC_SetThrLowValue(ADC, 1,  0x000);
Chip_ADC_SetThrHighValue(ADC, 1, 0xFFF);

/* Clear all pending interrupts */
Chip_ADC_ClearFlags(ADC, Chip_ADC_GetFlags(ADC));

/* Enable sequence A completion and threshold crossing interrupts for ADC1_0 and ADC 1_1 */
Chip_ADC_EnableInt(ADC, ADC_INTEN_CMP_ENABLE(ADC_INTEN_CMP_CROSSTH, ADC1_VBUS_CH) |
ADC_INTEN_CMP_ENABLE(ADC_INTEN_CMP_CROSSTH, ADC1_IBUS_CH) |
ADC_INTEN_SEQA_ENABLE);
Chip_ADC_SetThresholdInt(ADC, ADC1_VBUS_CH, ADC_INTEN_THCMP_CROSSING);
Chip_ADC_SetThresholdInt(ADC, ADC1_IBUS_CH, ADC_INTEN_THCMP_CROSSING);

// DO NOT ACTIVATE NVIC (for dma operation)
//_NVIC_ClearEnableIRQ(ADC1_SEQA_IRQn);

/* Enable sequencers */
Chip_ADC_EnableSequencer(ADC, ADC_SEQA_IDX);

}

/**
* ADC Mux PIN enable
*/
void ADC1_init_PinMux( void )
{
/* Disables pullups/pulldowns and disable digital mode */
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 9, (IOCON_MODE_INACT | IOCON_ADMODE_EN));
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 32+1, (IOCON_MODE_INACT | IOCON_ADMODE_EN));

/* Assign ADC1_1 to PIO0_9 via SWM (fixed pin) */
Chip_SWM_EnableFixedPin(SWM_FIXED_ADC1_0);/*!< ADC0_0 fixed pin enable/disable on pin P1_1 */
Chip_SWM_EnableFixedPin(SWM_FIXED_ADC1_1);/*!< ADC0_1 fixed pin enable/disable on pin P0_9 */

}

Outcomes