Hi Guys,
I'm quite new to Arduino and this forum. Though I've read many topics surrounding my subject, it's still not possible for me to get what I want.
For a project, I want to measure 12 Analoge voltages simultaneoulsy at waves of 75Hz each.
The minimum desired samplerate is 1kHz per channel. So I went for the Arduino Due which has 12 Analoge inputs, and following the datasheet a ADC with sample rate up to 1MSPS.
The values of the readings, I want to transfer to a Raspberry Pi 3B+, to store and to compute later. I tried Serial communication with a baudrate of 115200.
The problem for me lies with getting the samplerate at 1kHz. At this moment, the maximum sample rate is 196 Hz.
Can anyone help me to get a higher frequency?
Regards,
Laxmen
unsigned long timeStart;
unsigned long timeEnd;
unsigned long testTimer;
int freq = 0;
int countLoop = 0;
int value[11];
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
REG_ADC_MR = (REG_ADC_MR & 0xFFF0FFFF) | 0x00020000; //ADC STARTUP to 2/ 21mHz
REG_ADC_MR = (REG_ADC_MR & 0xFFFFFFEF); // LOWRES = 0, dus 12-BIT resolutie
REG_ADC_MR = (REG_ADC_MR & 0x7FFFFFFF); // USEQ = 0, dus normal mode
REG_ADC_MR = (REG_ADC_MR & 0xFF7FFFFF); // ANARCH = 0, dus DIFF0, GAIN0 en OFFSET0
REG_ADC_COR = (REG_ADC_COR & 0x0); // DIFFx = 0 on all channels -> Single ended mode. No offset
ADC->ADC_MR |= 0x80; //set free running mode on ADC
ADC->ADC_CHER = 0x3CFF; // Enable A0 tm A11
delay(2000);
}
void loop() {
// put your main code here, to run repeatedly:
timeStart = micros();
testTimer = millis();
delayMicroseconds(50);
while((ADC->ADC_ISR & 0x3CFF)==0); // wait for conversion on EOC7
value[0]=ADC->ADC_CDR[7]; //get values in [0-4095]
// delayMicroseconds(50);
value[1]=ADC->ADC_CDR[6]; //get values in [0-4095]
// delayMicroseconds(50);
value[2]=ADC->ADC_CDR[5]; //get values in [0-4095]
// delayMicroseconds(50);
value[3]=ADC->ADC_CDR[4]; //get values in [0-4095]
// delayMicroseconds(50);
value[4]=ADC->ADC_CDR[3]; //get values in [0-4095]
// delayMicroseconds(50);
value[5]=ADC->ADC_CDR[2]; //get values in [0-4095]
// delayMicroseconds(50);
value[6]=ADC->ADC_CDR[1]; //get values in [0-4095]
// delayMicroseconds(50);
value[7]=ADC->ADC_CDR[0]; //get values in [0-4095]
// delayMicroseconds(50);
value[8]=ADC->ADC_CDR[10]; //get values in [0-4095]
// delayMicroseconds(50);
value[9]=ADC->ADC_CDR[11]; //get values in [0-4095]
// delayMicroseconds(50);
value[10]=ADC->ADC_CDR[12]; //get values in [0-4095]
// delayMicroseconds(50);
value[11]=ADC->ADC_CDR[13]; //get values in [0-4095]
// delayMicroseconds(50);
for (int i = 0; i < 12; i++)
{
Serial.print(value[i]);
Serial.print("\t");
}
timeEnd = micros()-timeStart;
freq = 1000000/timeEnd;
Serial.print("\t");
Serial.print(" | ");
Serial.print("\t");
Serial.print(timeEnd);
Serial.print("\t");
Serial.print(freq);
Serial.print("\t");
Serial.print(countLoop);
Serial.println("\t");
countLoop++;
}
Due_Reading12Analog.ino (2.43 KB)
Whenever you read n ADC channels, keep in mind that (n * samplerate) <= 1 MHz with PRESCAL = 1.
The ADC peripheral automatically multiplies the input conversion frequency for 1 channel with the number of enabled channels.
Every Serial.print (or printf()) takes a few hundreds of us, so use it with moderation only during debugging stage.
Here is an example sketch to read n channels, each at 10 Hz.
/*******************************************************************************/
/* 10 Hz ADC conversions for nchannels */
/*******************************************************************************/
#define SampleRate (10)
uint8_t channels[] = {7,6,5};
#define nchannels (sizeof(channels))
uint16_t Buf[nchannels];
volatile boolean FlagConversion;
void setup()
{
Serial.begin(250000);
pinMode(LED_BUILTIN, OUTPUT);
adc_setup();
tc_setup();
}
void loop()
{
if (FlagConversion == true)
{
FlagConversion = false;
for (int i = 0; i < nchannels; i++)
{
printf(" ADC[%d] = %d\n", channels[i], Buf[i]);
}
}
}
/************* Configure ADC function *******************/
void adc_setup() {
PMC->PMC_PCER1 |= PMC_PCER1_PID37; // ADC power on
ADC->ADC_CR = ADC_CR_SWRST; // Reset ADC
ADC->ADC_MR |= ADC_MR_TRGEN_EN | // Hardware trigger select
ADC_MR_PRESCAL(1) |
ADC_MR_TRGSEL_ADC_TRIG3; // Trigger by TIOA2 Rising edge
ADC->ADC_IDR = ~(0ul);
ADC->ADC_CHDR = ~(0ul);
for (int i = 0; i < nchannels; i++)
{
ADC->ADC_CHER |= ADC_CHER_CH0 << channels[i];
}
ADC->ADC_IER |= ADC_IER_EOC0 << channels[nchannels - 1];
//ADC->ADC_ACR = ADC_ACR_IBCTL(0b01); // For frequencies > 500 KHz
ADC->ADC_PTCR |= ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS; // Disable PDC DMA
NVIC_EnableIRQ(ADC_IRQn); // Enable ADC interrupt
}
/************* Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2 ************/
void tc_setup() {
PMC->PMC_PCER0 |= PMC_PCER0_PID29; // TC2 power ON : Timer Counter 0 channel 2 IS TC2
TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2 // MCK/8, clk on rising edge
| TC_CMR_WAVE // Waveform mode
| TC_CMR_WAVSEL_UP_RC // UP mode with automatic trigger on RC Compare
| TC_CMR_ACPA_CLEAR // Clear TIOA2 on RA compare match
| TC_CMR_ACPC_SET; // Set TIOA2 on RC compare match
TC0->TC_CHANNEL[2].TC_RC = F_CPU / 8 / SampleRate; //<********************* Frequency = (Mck/8)/TC_RC Hz = 10 Hz
TC0->TC_CHANNEL[2].TC_RA = 50; //<******************** Any Duty cycle in between 1 and (TC_RC - 1)
TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable
}
void ADC_Handler() {
static uint32_t LedBlink;
for (int i = 0; i < nchannels; i++)
{
Buf[i] = (uint16_t) * (ADC->ADC_CDR + channels[i]);
}
FlagConversion = true;
// For debugging only : Blink every 1 Hz
if (LedBlink++ == SampleRate)
{
LedBlink = 0;
PIOB->PIO_ODSR ^= PIO_ODSR_P27;
}
}
Thanks Ard for your fast reply!
ard_newbie:
Whenever you read n ADC channels, keep in mind that (n * samplerate) <= 1 MHz with PRESCAL = 1.
The ADC peripheral automatically multiplies the input conversion frequency for 1 channel with the number of enabled channels.
What do you mean by this? I have to use all 12 channels, does this mean that de ADC Peripheral multiplies the input conversion frequency with 12 for each channel?
Though I still don't understand what this means to be honest.
ard_newbie:
Every Serial.print (or printf()) takes a few hundreds of us, so use it with moderation only during debugging stage.
What would be a better way to send data to another device (Rasp Pi). I was trying to do this with the USB connection, but sounds like that is not the proper way.
Is it even possible to read 12 channels at 1kHz each 'simultaneously' and send the data over with the Arduino Due?
This is straightforward:
1/ ADC channels are multiplexed. You choose how many channels you want the uc multiplexes when you enable channels.
2/ You set the conversion frequency. Each channel is sampled at the same frequency than the other enabled channels. The total: number of channels times the conversion frequency for a single channel can't be greater than 1 MHz.
Of course you can use Serial.print , or Serial.Write which is faster.
Thanks again! I'm understanding it a bit better now. I'll try your code for my project 