AnsweredAssumed Answered

DMA keep getting "Empty FIFO empty" 0x8000 from HSADC

Question asked by CP Chen on Apr 13, 2018
Latest reply on Apr 23, 2018 by jeremyzhou

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, 

Outcomes