Hello,
I am trying to use the su1 ADC and am getting really confused. The example code (sc_periph) does not even remotely match that in the Audio example (app_usb_aud_su1). I found two short paragraphs in section 3.7 of the XC Programming Guide calling the method a "service", but that does not tell me much.
Anyone know what is going on?
Thank You,
-Erik
XMOS "service"
-
- Member
- Posts: 12
- Joined: Thu Aug 18, 2011 9:51 pm
-
- XCore Expert
- Posts: 589
- Joined: Wed Feb 29, 2012 10:03 am
The example in the sc_periph use service for interfacing with functions pre-programmed into the non-volatile memory of an xCORE. The service declaration is available in the XN file of the su1 device.
Code: Select all
<Service Proto="xs1_su_adc_service(chanend c_adc)">
<Chanend Identifier="c_adc" end="2" remote="5"/>
-
- Member
- Posts: 12
- Joined: Thu Aug 18, 2011 9:51 pm
That still doesn't explain the service. I will assume that it somehow fills in the channel passed.
Questions:
1. I see that the only other part of that is the stub in audio.xc which takes that channel output and stuffs it into a global variable. How is it initialized?
2. How do I probe the multiple ADC channels? The code appears to only work with one ADC pin.
3. Related to #1, how do I initialize it before the service starts?
4. Where the #$!! is the documentation? All I can find is 3.19.3 in the USB Audio Design Guide and 3.7 in the XC Programming Guide.
Thank you for any responses,
-Erik
Questions:
1. I see that the only other part of that is the stub in audio.xc which takes that channel output and stuffs it into a global variable. How is it initialized?
2. How do I probe the multiple ADC channels? The code appears to only work with one ADC pin.
3. Related to #1, how do I initialize it before the service starts?
4. Where the #$!! is the documentation? All I can find is 3.19.3 in the USB Audio Design Guide and 3.7 in the XC Programming Guide.
Thank you for any responses,
-Erik
-
- XCore Addict
- Posts: 230
- Joined: Wed Mar 10, 2010 12:46 pm
Apologies for the lack of documentation. 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:
In this case only ADC 0 is enabled:
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.
The ADC will deliver blocks of samples (packets). The data delivered is always a sequence with one sample per active ADC.
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.
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.
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:
And then the rest of the application is handling the data from that trigger and periodically printing the current ADC value:
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.
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:
Code: Select all
adc_config_t adc_config = { { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 0, 0 };
Code: Select all
adc_config.input_enable[0] = 1;
Code: Select all
adc_config.bits_per_sample = ADC_32_BPS;
Code: Select all
adc_config.samples_per_packet = 1;
The ADC has a calibration mode where the ADC is connected to a 0.8V reference voltage.
Code: Select all
adc_config.calibration_mode = 0;
Code: Select all
adc_enable(xs1_su, c, trigger_port, adc_config);
- 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:
Code: Select all
adc_trigger_packet(trigger_port, adc_config);
Code: Select all
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;
}
}
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.
-
- Member
- Posts: 12
- Joined: Thu Aug 18, 2011 9:51 pm
Thank you, I got it working.