How to configure ADCs on U and A Devices? Topic is solved

If you have a simple question and just want an answer.
User avatar
sethu_jangala
XCore Expert
Posts: 589
Joined: Wed Feb 29, 2012 10:03 am

How to configure ADCs on U and A Devices?

Post by sethu_jangala »



View Solution
User avatar
sethu_jangala
XCore Expert
Posts: 589
Joined: Wed Feb 29, 2012 10:03 am

Post by sethu_jangala »

The ADC itself is documented in the xCORE-USB data sheet of each part (https://www.xmos.com/support/documentat ... =datasheet). However, that documentation does not necessarily provide enough information to use it.
 
The sc_periph library provides an abstraction layer to make it easy to use the ADCs. The best place to look for how this works is the app_adc_demo_u example application in http://github.com/xcore/sc_periph
 
Hopefully looking at how that works will answer your questions. Firstly it configures and enables the ADC:
 adc_config_t adc_config = { { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 0, 0 };
 
In this case only ADC 0 is enabled:
 adc_config.input_enable[0] = 1;
 
The accuracy of the ADCs is set to 32 bits per sample. It can be configured to 8, 16 or 32 bits per sample. Note that the accuracy of the ADC is only 12-bit anyway, so the values returned will have no increased accuracy if using 32-bit instead of 16-bit samples.             adc_config.bits_per_sample = ADC_32_BPS;
 
The ADC will deliver blocks of samples (packets). The data delivered is always a sequence with one sample per active ADC.
    adc_config.samples_per_packet = 1;
 
If you were to enable ADC 0 and ADC 1 and keep the samples_per_packet then each packet will alternate returning data for ADC 0, then ADC 1, then ADC 0, and so on. If you configure samples_per_packet to 2, then each packet will contain a sample from ADC 0 and one from ADC 1. We'll see how this is read in a minute.
 
The ADC has a calibration mode where the ADC is connected to a 0.8V reference voltage.
    adc_config.calibration_mode = 0;
 
And finally, one call to enable the ADCs. This call takes care of the fact that there the ADC requires a number of calibration samples before it is ready for use.
    adc_enable(xs1_su, c, trigger_port, adc_config);
 
After that the library provides two ways of using the ADC:
 - adc_trigger / adc_read
 - adc_trigger_packet / adc_read_packet
 
The example app uses the second of these. It starts the process by triggering a packet of data to be read:
   adc_trigger_packet(trigger_port, adc_config);
 
And then the rest of the application is handling the data from that trigger and periodically printing the current ADC value:
 

    while (1)
    {
        unsigned data[1];
        select
        {
            case print_timer when timerafter(print_time) :> void:
                if (new_value != current_value)
                {
                    debug_printf("ADC value: 0x%x\n", new_value);
                    current_value = new_value;
                }
                print_time += PRINT_PERIOD;
                break;
 
            case adc_read_packet(c, adc_config, data):
                new_value = data[0];
                adc_trigger_packet(trigger_port, adc_config);
                break;
        }
    }

 
Each time a packet is received the next packet is triggered.
 
There is only one ADC trigger pin and it will cause the next active ADC to read a sample. They work in a round-robin manner.