Dear Sir,
I am using DMA to collect HSADC output FIFO and store into a local buffer, while the FIFO output seems to be collected correctly, there is always several 0X8000 in between the actual converted sample values. . Below are the local buffer content and code for your reference.
I have done various check, but could find out where was the probelm. hope you can advise how can I get rmake DMA access only valid samples.
Here is what I have done to check the problem,
1. Check the FIFO output by using HSADC interrupt, confirm FIFO contain only correct sample values.
2. I have test it with differenct HSADC speeds, all have this "0x8000" in between samples. howevr, they seems to be reducing with higher HSADC speed.
******* Printout of local buffer, filled by DMA *********************
************** Code used with above output ****************************
#define HSADC_DMA_READ 8
#define DMA_TRANSFER_SIZE 4095 // max. 4095
#define DMA_CH 7
#define NUM_SAMPLE DMA_TRANSFER_SIZE
uint32_t sample[NUM_SAMPLE];
long sample_value;
void Setup_ADCHS_J(void)
{
Chip_HSADC_Init(LPC_ADCHS);/* Initialize HSADC */
// Disable the HSADC interrupt
LPC_ADCHS->INTS[0].CLR_EN = 0x7F; // disable interrupt 0
LPC_ADCHS->INTS[0].CLR_STAT = 0x7F; // clear interrupt status
while(LPC_ADCHS->INTS[0].STATUS & 0x7D); // wait for status to clear, have to exclude FIFO_EMPTY
LPC_ADCHS->INTS[1].CLR_EN = 0x3FFFFFFF;
LPC_ADCHS->INTS[1].CLR_STAT = 0x3FFFFFFF;
while(LPC_ADCHS->INTS[1].STATUS);
/********** Setup FIFO trip points for interrupt/DMA to 8 samples, no packing */
Chip_HSADC_SetupFIFO(LPC_ADCHS, 8, false);
/* Software trigger only, 0x90 recovery clocks, add channel IF to FIFO entry */
Chip_HSADC_ConfigureTrigger(LPC_ADCHS, HSADC_CONFIG_TRIGGER_SW,
HSADC_CONFIG_TRIGGER_RISEEXT, HSADC_CONFIG_TRIGGER_NOEXTSYNC,
HSADC_CHANNEL_ID_EN_NONE, 0x90);
/* Select both positive and negative DC biasing for input 3 */
Chip_HSADC_SetACDCBias(LPC_ADCHS, 1, HSADC_CHANNEL_DCBIAS, HSADC_CHANNEL_NODCBIAS);
/* Setup data format for 2's complement and update clock settings. This function
should be called whenever a clock change is made to the HSADC */
Chip_HSADC_SetPowerSpeed(LPC_ADCHS, false);
/* Enable HSADC power */
Chip_HSADC_EnablePower(LPC_ADCHS);
LPC_ADCHS->POWER_DOWN = 0;
LPC_ADCHS->FLUSH = 1;
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 0);
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 1);
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 2);
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 3);
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 4);
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 5);
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 6);
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 7);
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 0, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_SWAP | HSADC_DESC_MATCH(0x90) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 0, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 1, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 2, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 3, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 4, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 5, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 6, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 7, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_FIRST | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_UpdateDescTable(LPC_ADCHS, 1);
}
void Setup_DMA_J(void)
{
Chip_GPDMA_Init(LPC_GPDMA);
/* Clear all DMA interrupt and error flag */
LPC_GPDMA->CONFIG = 0x00;
LPC_GPDMA->INTTCCLEAR = 0xFF; //clears channel terminal count interrupt
LPC_GPDMA->INTERRCLR = 0xFF; //clears channel error interrupt.
LPC_GPDMA->CONFIG = 0x01;
while( !(LPC_GPDMA->CONFIG & 0x01) );
LPC_GPDMA->CH[DMA_CH].SRCADDR = (uint32_t) &LPC_ADCHS->FIFO_OUTPUT[0];
LPC_GPDMA->CH[DMA_CH].DESTADDR = ((uint32_t) &sample);
LPC_GPDMA->CH[DMA_CH].CONTROL = (DMA_TRANSFER_SIZE << 0)// transfer size
| (0x2 << 12) // src burst size
| (0x2 << 15) // dst burst size
| (0x2 << 18) // src transfer width
| (0x2 << 21) // dst transfer width
| (0x1 << 24) // src AHB master select
| (0x0 << 25) // dst AHB master select
| (0x0 << 26) // src increment: 0, src address not increment after each trans
| (0x1 << 27) // dst increment: 1, dst address increment after each trans
| (0x1 << 31); // terminal count interrupt enable bit: 1, enabled, (0x0UL << 31); // Terminal count interrupt disabled
LPC_GPDMA->CH[DMA_CH].CONFIG = (0x1 << 0) // enable bit: 1 enable, 0 disable
| (HSADC_DMA_READ << 1) // src peripheral: set to 8 - HSADC
| (0x0 << 6) // dst peripheral: no setting - memory
| (0x2 << 11) // flow control: peripheral to memory - DMA control
| (0x1 << 14) // IE - interrupt error mask
| (0x1 << 15) // ITC - terminal count interrupt mask
| (0x0 << 16) // lock: when set, this bit enables locked transfer
| (0x1 << 18); // Halt: 1, enable DMA requests; 0, ignore further src DMA req
LPC_GPDMA->CH[DMA_CH].LLI = 0;
}
uint32_t freqHSADC = 0;
uint32_t freqM4 = 0;
int main(void)
{
int i, j;
int sts;
SystemCoreClockUpdate();
Board_Init();
//************** Setup_ADCHS_Clock *****************//
Chip_USB0_Init(); /* Initialize the USB0 PLL to 480 MHz */
Chip_Clock_SetDivider(CLK_IDIV_A, CLKIN_USBPLL, 2); /* Source DIV_A from USB0PLL, and set divider to 2 (Max div value supported is 4) [IN 480 MHz; OUT 240 MHz */
Chip_Clock_SetDivider(CLK_IDIV_B, CLKIN_IDIVA, 4); /* Source DIV_B from DIV_A, [IN 240 MHz; OUT 80 MHz */
Chip_Clock_SetBaseClock(CLK_BASE_ADCHS, CLKIN_IDIVB, true, false); /* Source ADHCS base clock from DIV_B */
Chip_Clock_EnableOpts(CLK_ADCHS, true, true, 1); /* Enable the Clock */
/* ************* Show the HSADC clock rate */
freqHSADC = Chip_HSADC_GetBaseClockRate(LPC_ADCHS);
DEBUGOUT("HSADC sampling rate = %dKHz\r\n", freqHSADC / 1000);
/******************* Show the M4 clock rate */
freqM4 = Chip_Clock_GetBaseClocktHz(CLK_BASE_MX);
DEBUGOUT("M4 Clock rate = %dKHz\r\n", freqM4 / 1000);
//************** Setup_DMA *******************//
Setup_DMA_J();
//************** Setup_ADCHS *****************//
Setup_ADCHS_J();
//************** Start ADCHS *****************//
Chip_HSADC_SWTrigger(LPC_ADCHS);
//************** Start DMA *******************//
LPC_GPDMA->CH[DMA_CH].CONFIG = (0x1 << 0); // enable bit, 1 enable, 0 disable
//need to add wait for DMA complete
for(i=0; i<4094; i++)
{
//Issues with DMA interrupt, wait for end of sampling
}
// *****Printout Mem_buffer
for(j=0; j<4095; j++)
{
sample_value = sample[j];
DEBUGOUT("Mem_Buff content = %d\r\n", sample_value);
}
//******************** Shutdown ADCHS & DMA ***********
Chip_HSADC_FlushFIFO(LPC_ADCHS);
sts = Chip_HSADC_GetFIFOLevel(LPC_ADCHS);
/* Shutdown HSADC when done */
Chip_GPDMA_DeInit(LPC_GPDMA);
Chip_HSADC_DeInit(LPC_ADCHS);
}
Best Regards,
I don't know if this is the reason for your problem, but you seem to be starting from the last vector (1,7), since this is the last call to Chip_HSADC_SetActiveDescriptor(), so you are never waiting for the HSADC recovery time before taking measurements. This really only needs to be called once with the descriptor that you want to start the measurements with. Also you never save the Table 0 descriptor 0.
Try the following changes.
// REMOVE Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 0);
// REMOVE Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 1);
// REMOVE Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 2);
// REMOVE Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 3);
// REMOVE Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 4);
// REMOVE Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 5);
// REMOVE Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 6);
// REMOVE Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 1, 7);
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 0, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_SWAP | HSADC_DESC_MATCH(0x90) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_UpdateDescTable(LPC_ADCHS, 0); // ADD -- SAVE TABLE 0
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 0, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 1, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 2, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 3, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 4, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 5, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 6, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_SetupDescEntry(LPC_ADCHS, 1, 7, (HSADC_DESC_CH(1) | HSADC_DESC_BRANCH_FIRST | HSADC_DESC_MATCH(1) | HSADC_DESC_RESET_TIMER));
Chip_HSADC_UpdateDescTable(LPC_ADCHS, 1);
Chip_HSADC_SetActiveDescriptor(LPC_ADCHS, 0, 0);// ADD -- SET TABLE 0, VECTOR 0 ACTIVE