Hi,
I've read all of the forum threads on how the ADC operates on the Kinetis and also spent some time trying to understand the examples from ADC_Timers.h. For all the value that uTasker provides, I think a slightly more comprehensive document covering ADC operation and individual examples on various types of setups would greatly improve the experience and alleviate the learning curve.
With that in mind, let me jump straight in. Our product requires several ADC channels to be running, sampling and converting at the same time, on both AD0 and AD1. I wrote a simple driver to wrap uTasker's ADC functionality with another layer to provide the same interface as the old Processor Expert drivers. I just want to make sure I got the basics right, if someone more familiar doesn't mind taking a look:
1. First of all, this is the routine for calibrating the ADC. It's only done once for both AD0 and AD1 at startup.
adc_setup.int_adc_controller = ad;
adc_setup.int_adc_mode = (ADC_CALIBRATE | ADC_SELECT_INPUTS_A | ADC_CLOCK_BUS_DIV_2 | ADC_CLOCK_DIVIDE_4 | ADC_SAMPLE_ACTIVATE_LONG | ADC_CONFIGURE_ADC | ADC_REFERENCE_VREF | ADC_CONFIGURE_CHANNEL | ADC_SINGLE_ENDED | ADC_SINGLE_SHOT_MODE | ADC_16_BIT_MODE | ADC_SW_TRIGGERED);
adc_setup.int_adc_sample = (ADC_SAMPLE_LONG_PLUS_12 | ADC_SAMPLE_AVERAGING_32); // additional sampling clocks
fnConfigureInterrupt((void *)&adc_setup);
As I'm setting everything up with the interrupts disabled, at this stage I should poll for the result and perform the calibration as described in the Kinetis reference manual? Is there any example on how to do this in uTasker?
2. After performing the ADC calibration, I initialize both AD modules in this manner, for continuous sampling and conversion:
adc_setup.int_adc_controller = ad;
adc_setup.int_adc_result = (ad == ADC_MODULE_0) ? (&ad0_results) : (&ad1_results);
adc_setup.int_type = ADC_INTERRUPT; // identifier when configuring
adc_setup.int_adc_bit = chan_msk;
adc_setup.int_adc_mode = (ADC_CONFIGURE_ADC | ADC_CONFIGURE_CHANNEL | ADC_SEQUENTIAL_MODE | ADC_SINGLE_ENDED
| ADC_LOOP_MODE | ADC_ALL_RESULTS | ADC_START_OPERATION); // single ended configuration in loop mode
adc_setup.int_adc_speed = (ADC_SAMPLING_SPEED(5000000)); // 5MHz sampling (must be between 100kHz and 5MHz)
adc_setup.int_adc_int_type = 0; // no interrupt
fnConfigureInterrupt((void *) &adc_setup); // configure and start operation
Then, approximately each 2ms, I read the result values and statuses from the corresponding variables (ad0_results or ad1_results)
ADC_RESULTS res;
switch (module) {
case ADC_MODULE_0:
res.ucADC_status = ad0_results.ucADC_status[chan_idx];
res.sADC_value = ad0_results.sADC_value[chan_idx];
break;
case ADC_MODULE_1:
res.ucADC_status = ad1_results.ucADC_status[chan_idx];
res.sADC_value = ad1_results.sADC_value[chan_idx];
break;
Thanks!
Alex