I'm new to RTOS concepts and I'm playing around with ChibiOS on and off as I have free time hoping to get acquainted enough with it to use it for projects soon enough.
I've hit a bit of a problem that I would like some advice on.
I want to sample 6 ADC channels at 100kHz each, but for the time being I am starting out slower. My problem is that I do not know how to get the data out fast enough or how to synchronize data capture and output properly. Currently, I have tried a few different approaches (using a GPT timer, using a thread that sends out data) and I've been the most successful with the approach below (stripped to a minimum code example and outputting a single ADC channel data):
Code: Select all
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ch.h"
#include "hal.h"
#include "chprintf.h"
#include "usbcfg.h"
/* ADC conversion group settings */
#define ADC_GRP_NUM_CHANNELS 6
#define ADC_GRP_BUF_DEPTH 1
/* Buffer for ADC samples */
static adcsample_t samples[ADC_GRP_NUM_CHANNELS * ADC_GRP_BUF_DEPTH];
/* Virtual serial port over USB.*/
SerialUSBDriver SDU1;
/*
* ADC conversion group.
* Mode: Circular buffer, 1 samples of 6 channels, SW triggered.
* Channels: IN10, IN11, IN14, IN15, IN8, IN9
*/
static const ADCConversionGroup adcgrpcfg = {
TRUE,
ADC_GRP_NUM_CHANNELS,
NULL,
NULL,
0, /* CR1 */
ADC_CR2_SWSTART, /* CR2 */
ADC_SMPR1_SMP_AN10(ADC_SAMPLE_15) | ADC_SMPR1_SMP_AN11(ADC_SAMPLE_15) |
ADC_SMPR1_SMP_AN14(ADC_SAMPLE_15) | ADC_SMPR1_SMP_AN15(ADC_SAMPLE_15),
ADC_SMPR2_SMP_AN8(ADC_SAMPLE_15) | ADC_SMPR2_SMP_AN9(ADC_SAMPLE_15),
ADC_SQR1_NUM_CH(ADC_GRP_NUM_CHANNELS),
0, /* SQR2 */
ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11) |
ADC_SQR3_SQ3_N(ADC_CHANNEL_IN14) | ADC_SQR3_SQ4_N(ADC_CHANNEL_IN15) |
ADC_SQR3_SQ5_N(ADC_CHANNEL_IN8) | ADC_SQR3_SQ6_N(ADC_CHANNEL_IN9),
};
/*===========================================================================*/
/* Initialization and main thread. */
/*===========================================================================*/
/*
* Application entry point.
*/
int main(void) {
halInit();
chSysInit();
/*
* Initializes a serial-over-USB CDC driver.
*/
sduObjectInit(&SDU1);
sduStart(&SDU1, &serusbcfg);
/*
* Activates the USB driver and then the USB bus pull-up on D+.
* Note, a delay is inserted in order to not have to disconnect the cable
* after a reset.
*/
usbDisconnectBus(serusbcfg.usbp);
chThdSleepMilliseconds(1000);
usbStart(serusbcfg.usbp, &usbcfg);
usbConnectBus(serusbcfg.usbp);
/* Setup pins for ADC */
palSetGroupMode(GPIOC, PAL_PORT_BIT(0) | PAL_PORT_BIT(1) |
PAL_PORT_BIT(4) | PAL_PORT_BIT(5),
0, PAL_MODE_INPUT_ANALOG);
palSetGroupMode(GPIOB, PAL_PORT_BIT(0) | PAL_PORT_BIT(1),
0, PAL_MODE_INPUT_ANALOG);
adcStart(&ADCD1, NULL);
adcStartConversion(&ADCD1, &adcgrpcfg, samples, ADC_GRP_BUF_DEPTH);
while (TRUE) {
chprintf(((BaseSequentialStream *)&SDU1), "%d\r\n", samples[0]);
}
}
As you can see I am using the USB CDC driver to send out the data (I figured this is faster than a standard UART?). The data I am feeding is a 100Hz sinewave, and the sampled data is attached. As you can see, the first two periods of the sinewave are output nicely, at a much higher rate than needed, but then something happens and I start losing samples.
My questions are as follows:
1) What do you think happens that I start losing samples?
2) What advice can you give me on getting ADC data out of the device fast enough? What interface would you recommend? I realise what I am currently doing is quite rubbish.
3) Is it possible to stream 6 channels at 100kHz each (600 000 data points, each a adcsample_t (16 bits) = 9.6Mbit) out of the device somehow to a host computer?
4) Any examples or resources you can point me to in regards to synchronous sampling and streaming out the data? Not necessarily ChibiOS specific, just general strategies.
Thank you very much for any help,
Cheers,
-Igor