We will be using potentiometer and temperature sensor for this project. First we have to enable the clock for ADC hardware.
pmc_enable_periph_clk(ID_ADC);
Initialization of ADC requires some formula.
adc_init(ADC, sysclk_get_cpu_hz(), 6400000, ADC_STARTUP_TIME_4);
The second parameter is the main clock, third is ADC clock and the last is start up time which is 64 periods of ADCClock.
To configure the timing for ADC, we need
adc_configure_timing(ADC, TRACKING_TIME, ADC_SETTLING_TIME_3, TRANSFER_PERIOD);
Enable TAG option so that the number of the last converted channel can be indicated. p_adc is a pointer to an ADC instance.
adc_enable_tag(ADC);
Set user defined channel sequence using
adc_configure_sequence(ADC, ch_list, 2);
Now we have to start the sequencer.
adc_start_sequencer(ADC);
Enable the specified ADC channel.
adc_enable_channel(ADC, (enum adc_channel_num_t)i);
Now we have to update the channel numbers.
g_adc_sample_data.uc_ch_num[0] = ch_list[0];
g_adc_sample_data.uc_ch_num[1] = ch_list[1];
Now to enable the temperature sensor.
adc_enable_ts(ADC);
Now we have to set the gain and offset value.
adc_disable_anch(ADC);
adc_enable_anch(ADC);
adc_set_channel_input_gain(ADC, ADC_CHANNEL_POTENTIOMETER, ADC_GAINVALUE_2);
adc_enable_anch(ADC);
adc_enable_channel_input_offset(ADC, ADC_CHANNEL_POTENTIOMETER);
We can also set auto calibration mode.
adc_set_calibmode(ADC);
while (1) {
if ((adc_get_status(ADC) & ADC_ISR_EOCAL) ==
ADC_ISR_EOCAL)
break;
}
To set power save mode.
adc_configure_power_save(ADC, 1, 0);
To transfer data with PDC
adc_read_buffer(ADC, g_adc_sample_data.us_value, BUFFER_SIZE);
adc_enable_interrupt(ADC, ADC_IER_RXBUFF);
and without PDC
adc_enable_interrupt(ADC, ADC_IER_DRDY);
Now we have to enable ADC interrupt.
NVIC_EnableIRQ(ADC_IRQn);
Now to configure trigger mode
case TRIGGER_MODE_SOFTWARE:
adc_configure_trigger(ADC, ADC_TRIG_SW, 0); /* Disable hardware trigger. */
break;
case TRIGGER_MODE_ADTRG:
gpio_configure_pin(PINS_ADC_TRIG, PINS_ADC_TRIG_FLAG);
adc_configure_trigger(ADC, ADC_TRIG_EXT, 0);
break;
case TRIGGER_MODE_TIMER:
configure_time_trigger();
break;
case TRIGGER_MODE_PWM:
configure_pwm_trigger();
break;
case TRIGGER_MODE_FREERUN:
adc_configure_trigger(ADC, ADC_TRIG_SW, 1);
break;
The interrupt handler for the ADC is
if (g_adc_test_mode.uc_pdc_en) {
if ((adc_get_status(ADC) & ADC_ISR_RXBUFF) ==
ADC_ISR_RXBUFF) {
g_adc_sample_data.us_done = ADC_DONE_MASK;
adc_read_buffer(ADC, g_adc_sample_data.us_value, BUFFER_SIZE);
/* Only keep sample value, and discard channel number. */
for (i = 0; i < NUM_CHANNELS; i++) {
g_adc_sample_data.us_value[i] &= ADC_LCDR_LDATA_Msk;
}
}
} else { /* Without PDC transfer */
if ((adc_get_status(ADC) & ADC_ISR_DRDY) ==
ADC_ISR_DRDY) {
ul_temp = adc_get_latest_value(ADC);
for (i = 0; i < NUM_CHANNELS; i++) {
uc_ch_num = (ul_temp & ADC_LCDR_CHNB_Msk) >>
ADC_LCDR_CHNB_Pos;
if (g_adc_sample_data.uc_ch_num[i] == uc_ch_num) {
g_adc_sample_data.us_value[i] =
ul_temp &
ADC_LCDR_LDATA_Msk;
g_adc_sample_data.us_done |= 1 << i;
}
}
}
}