AnsweredAssumed Answered

How to achieve 80MHz using DMA from LPC4370's HSADC?

Question asked by Benjamin Artes on Jul 1, 2016
Latest reply on Apr 5, 2018 by Raymundo Velarde

I am currently trying to help a colleague get use the LPC4370's HSADC for a sensor project and am unable to get the advertised 80M samples from a single ADC channel (ADC0).  We are using LPCXpresso and 2 LPClink2's.  We have based the project off the example code in "periph_hsadc".  We're using some ~2MHz test signals to verify performance (# of samples per cycle).

 

I've thoroughly read through the relevant sections of the Datasheet and User Manual (CGU, HSADC, DMA etc).  I understand the operation of the ADC and it's associated FIFO and also have a good understanding of the DMA settings.  I've reviewed many posts found through google (including every relevant post on here).

Issues:

  • Unable to achieve 80MHz from HSADC.  Using a 2 MHz sine wave and reading for 4095 samples we see ~20 samples per cycle showing that ADC and DMA are, combined, storing 40MHz bandwidth of data.  I assumed this was due to DMA configuration and that ADC was dropping samples due to a full FIFO.  Tried using burst reads from DMA and ending up reading an empty FIFO ~every other sample.  I believe HSADC is currently running at 40MHz even though it reports that it's clock is set to 80MHz.  Code is included below: What could possibly be limiting the sample-rate?
  • As discussed in previous issue we have tried using burst DMA to no avail.  User Manual is pretty clear that you have to use a FIFO LEVEL smaller than 15 so that src burst size and FIFO LEVEL will be the same, but no combination of FIFO LEVEL and src burst has yielded increased performance.  What are the circumstances / settings that DMA bursts will succeed?
  • We have also tried using Packed mode and run into issues.  Packed mode works fine for ~15 samples after which the packed sample is ALWAYS 0.  What are the limitations on using Packed mode?

 

Configuration:

Using Cortex M4 processor clocked at 204MHz.

AHB is set for 204MHz.

HSADC:

80Mhz.

Uses two descriptor entires: Table 0 entry 0 is first run with long match time to allow ADC to stabilize, then swap to Table 1 entry 0 with shortest match time and branch to self.

Uses no interrupts and has a FIFO Level of 15 (thought we have tried many other FIFO Levels, other settings depending).

Uses fastest CRS setting and has DGEC configured for 80MHz operation.

DMA:

Configured for transfer of 4095 samples from FIFO_OUTPUT[0].

Uses src and dst burst size of 1 (whenever we have tried to change burst size DMA ends up reading empty FIFO ~50% of samples).

Doesn't use Linked List.

Tried using DMA as Flow Controller AND HSADC, performance doesn't change.

 

Thanks,

Ben

 

(And sorry for the code below, tried quoting with syntax highlighting and it hid a large number of the lines)

 

#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];

 

int main(void)

{

       SystemCoreClockUpdate();

       Board_Init();

 

 

       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, 3); /* 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 */

 

 

       /////////////////////////////////////////// HSADC settings ////////////////////////////////////////////////////////////////

       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   = 0x7F;

       LPC_ADCHS->INTS[1].CLR_STAT = 0x7F;

       while(LPC_ADCHS->INTS[1].STATUS & 0x7D);

 

 

       /* Initialize HSADC */

       LPC_ADCHS->POWER_DOWN = 0;

       LPC_ADCHS->FLUSH = 1;

       Chip_HSADC_Init(LPC_ADCHS);

       LPC_ADCHS->FIFO_CFG      = (15 << 1) /* FIFO_LEVEL*/ | (1) /* PACKED_READ*/;

       LPC_ADCHS->DSCR_STS = 1;

       LPC_ADCHS->DESCRIPTOR[0][0] = (1 << 31) /* UPDATE TABLE*/ | (1 << 24) /* RESET_TIMER*/ | (0 << 22) /* THRESH*/ | (0xA00 << 8) /* MATCH*/ | (0x10 << 6) /* BRANCH*/;

       LPC_ADCHS->DESCRIPTOR[1][0] = (1 << 31) /* UPDATE TABLE*/ | (1 << 24) /* RESET_TIMER*/ | (0 << 22) /* THRESH*/ | (0x01 << 8) /* MATCH*/ | (0x01 << 6) /* BRANCH*/;

 

 

 

 

       LPC_ADCHS->CONFIG        = (0x90 << 6) /* RECOVERY_TIME*/

                                                         | (0 << 5) /* CHANNEL_ID_EN*/

                                                         | (0x01) /* TRIGGER_MASK*/;

       uint8_t DGEC = 0xE;

       LPC_ADCHS->ADC_SPEED     = (DGEC << 16) | (DGEC << 12) | (DGEC << 8) | (DGEC << 4) | (DGEC);

       //Didn't set threshold registers as they aren't used

       LPC_ADCHS->POWER_CONTROL = (1 << 18) /* BGAP*/

                                                                      | (1 << 17) /* POWER*/

                                                                      | (1 << 10) /* DC in ADC0*/

                                                                      | (1 << 4) | (0x4) /* CRS*/;

 

 

       ////////////////////////////////////////////////////// DMA settings ///////////////////////////////////////////////////////////////////

       Chip_GPDMA_Init(LPC_GPDMA);

       LPC_GPDMA->CONFIG =   0x01;

       while( !(LPC_GPDMA->CONFIG & 0x01) );

       /* Clear all DMA interrupt and error flag */

       LPC_GPDMA->INTTCCLEAR = 0xFF; //clears channel terminal count interrupt

       LPC_GPDMA->INTERRCLR = 0xFF; //clears channel error interrupt.

 

 

       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)   // transfer size

 

 

                                                   | (0x0                << 12)  // src burst size

                                                   | (0x0                << 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

 

 

       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

                                                   | (0x6                << 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;

 

 

       ///////////////////////////////////////// start HSADC and GPDMA //////////////////////////////////////////////////////

       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(int i =0; i<4094; i++)

       {

             ;//Issues with DMA interrupt, wait for end of sampling

       }

 

       Chip_HSADC_FlushFIFO(LPC_ADCHS);

       sts = Chip_HSADC_GetFIFOLevel(LPC_ADCHS);

       Chip_HSADC_DeInit(LPC_ADCHS);

       Chip_GPDMA_DeInit(LPC_GPDMA);

 

 

}

*/

Outcomes