ADC exact sampling rate (near maximal possible rate) - using timer or not?

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

ADC exact sampling rate (near maximal possible rate) - using timer or not?

2,584 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ano on Tue Sep 02 17:14:37 MST 2014
Quick question:
I would like to use the 10bit ADC of the LPC11C24 to sample at an exact rate (which will be adjustable by the user).
The maximal sample rate is 400kHz. I think this is just the case in burst mode?!

I want to sample one value and write it into an array, then sample the next. So no big code between the sample events.
I just thought to initialize the ADC with an adjustable rate and sample -> save -> sample -> save and so on.
But I think, this would not lead to the exact sample rate, would it?
Is it better to implement a timer for the samples? But, could I achieve a sampling rate near 400kHz with this method?

Thanks guys!


(I know that there are tons of threads about the ADC, but I couldn't find a solution (some thread titles really are choosen badly)
0 Kudos
Reply
5 Replies

2,248 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ano on Thu Oct 23 08:53:01 MST 2014
Hey,
I still have the same problem.
void ADC_ReadBurst(uint16_t *data, uint16_t number)
{
Chip_ADC_SetBurstCmd(LPC_ADC, ENABLE);

uint16_t i;

for(i = 0; i < number; i++)
{
data = ADC_ReadValue();
Chip_GPIO_SetPinToggle(LPC_GPIO, 2, 4);
}
}


With
uint16_t ADC_ReadValue(void)
{
uint16_t dataADC;

while (Chip_ADC_ReadStatus(LPC_ADC, UltrasonicChannel, ADC_DR_DONE_STAT) != SET) {}
Chip_ADC_ReadValue(LPC_ADC, UltrasonicChannel, &dataADC);

return dataADC;
}


Still outputs a Frequency on Pin2.4 that is neither consistent (means time between two cycles is alway different), nor near the sample frequency I want to achieve. With setting the ADC_Samplefrequency to 400kHz, i can barely sample with real 100kHz, but even then, the sample time is inconsistent.

(Still, only 1 channel active the whole time)
0 Kudos
Reply

2,248 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ano on Wed Sep 03 06:32:53 MST 2014
Big thanks for your answers so far!

In fact, I'm using the code from the examples, just changed some little things to have a better overall structure of the files.
My ReadValue is actually waiting for the sampe process to be finished (don't need to change that, nothing else must happen while sampling).
uint16_t ADC_ReadValue(void)
{
uint16_t dataADC;

// Start A/D conversion, wait for conversion complete, read value and print value
Chip_ADC_SetStartMode(LPC_ADC, ADC_START_NOW, ADC_TRIGGERMODE_RISING);
while (Chip_ADC_ReadStatus(LPC_ADC, ADC_CH0, ADC_DR_DONE_STAT) != SET) {}
Chip_ADC_ReadValue(LPC_ADC, ADC_CH0, &dataADC);

return dataADC;
}


So now I'm going to change my code to use the burst mode, to ensure the right sampling frequency

However with the description of the the CLK-Section in the register:
Table 364. A/D Control Register (AD0CR - address 0x4001 C000) bit description
15:8 CLKDIV 
The APB clock (PCLK) is divided by CLKDIV +1 to produce the clock for the ADC, which
should be less than or equal to 4.5 MHz. Typically, software should program the smallest
value in this field that yields a clock of 4.5 MHz or slightly less, but in certain cases (such
as a high-impedance analog source) a slower clock may be desirable.

I would think, that the sampling frequency has indeed an impact even if not in burst mode.
0 Kudos
Reply

2,248 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by OldManVimes on Wed Sep 03 06:08:38 MST 2014
Possibly.

I don't have the resources here to check any LPC11xx code, nor do I have experience with LPCOpen. Not a big fan yet. I do have source code for the LPC17xx LPCopen so I've been looking at that.

If burstMode is set in your ADCSetup variable then you are on your way to success. If not, you probably have to call Chip_ADC_SetStartMode() each time before calling ADC_ReadValue(). Reason: burst mode triggers automatic A/D conversion. Non-burst mode leaves that up to you. I think the call to Chip_ADC_SetSampleRate only relates to burst mode.

If ADC_ReadValue() internally waits for a new A/D conversion to have completed, then your loop will probably be ok. In the LPC17xx ADC_ReadValue() returns ERROR in case the A/D conversion is (still) active. So you would have to loop until the call returns OK.

If you do not have burst mode, then you are still responsible for limiting the rate of your calls to ADC_ReadValue() within your 'for' loop. So you'd still need a timer.

Top tip: Have a look at the sample code that comes with LPCOpen. Those are actually pretty good to understand the API. The LPC17xx sample code for the ADC comes close to what you want. I think it is just missing a sample-rate implementation for manual A/D conversion that you need.

From the LPC17xx example code:

/* Start A/D conversion if not using burst mode */
if (!Burst_Mode_Flag) {
Chip_ADC_SetStartMode(_LPC_ADC_ID, ADC_START_NOW, ADC_TRIGGERMODE_RISING);
}
/* Waiting for A/D conversion complete */
while (Chip_ADC_ReadStatus(_LPC_ADC_ID, _ADC_CHANNLE, ADC_DR_DONE_STAT) != SET) {}
/* Read ADC value */
Chip_ADC_ReadValue(_LPC_ADC_ID, _ADC_CHANNLE, &dataADC);
/* Print ADC value */
App_print_ADC_value(dataADC);

0 Kudos
Reply

2,248 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ano on Wed Sep 03 04:58:03 MST 2014
I think I missed to write: I just need one ADC-Channel.
If I understand correctly, with just one channel, I would just need to set the sampling time to my desired frequency (via adjusting the prescaler). As my max sampling frequency the time added for saving the data (just writing the sample into an existing array) is negligible small, so that it shouldn't matter for the sampling frequency. Do I need the burst mode for just one channel?
So, if I'm right, it should be dead simple:

Setting the sampling rate with the LCPopen function:
void ADC_Init(void)
{
Chip_IOCON_PinMuxSet(LPC_IOCON, ADCpin, FUNC2);
Chip_ADC_Init(LPC_ADC, &ADCSetup);//Default Setup 400kHz/10bit
Chip_ADC_SetSampleRate(LPC_ADC, &ADCSetup, 200000);//Set Rate to 200kHz
Chip_ADC_EnableChannel(LPC_ADC, ADC_CH0, ENABLE);
}


and then just sample a number of times:
void ADC_ReadNumberOfSamples(uint16_t *data, uint16_t number)
{
uint16_t i;

for(i = 0; i /*<*/ number; i++)
data = ADC_ReadValue();
}


("/*<*/" should be just "<" but forum-code-field doesn't allow that)

Am I right?
0 Kudos
Reply

2,248 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by OldManVimes on Wed Sep 03 04:29:03 MST 2014
I'm doing something like what you want, but on a LPC12xx, so any comments I make may or may not apply to the LPC11xx.

I sample every used ADC channel in burst mode at one specific sample frequency. I can control the frequency by changing ADC prescaler. The rest is explained in detail in the user manual. It explains how many clock cycles one ADC sample takes and you extrapolate for the number of ADC channels in use combined with the peripheral clock rate. You then apply a formula that takes these variables as input and that calculates the ADC prescaler value such that the sampling frequency of the ADC channel(s) is what you want. (Sorry, I do not have any code handy, so I'm a bit sketchy on details).

Then I make the ADC I'm interested in trigger an interrupt. Inside the ISR I queue the sample (the A/D conversion has already taken place). This means the amount of jitter on the sampling is as low as can be. The downside is that only a limited number of frequencies are possible, but given a high enough peripheral clock it is pretty good. I've added code to my solution that can measure the ADC interrupt interval to verify that I'm getting the expected sampling frequency. That helps to check the correctness of the calculations.

Then again a timer may do the trick as well, but this way my CPU load is exceedingly low which I find important. Handling the queue contents is then handled by regular code outside of interrupt context. Burst mode ADC is a pretty cool feature.

Hope this helps,
Vimes
0 Kudos
Reply