I post here the code for a 8 channel (A0-A7) simple oscilloscope.
Thanks to the arduino due forum community, and especially to stimmer, PakARD (prescaler suggestion) and more.
It streams the data via native serial.
EDIT: Tested with 8 inputs activated: works fine!
150000 interrupts /sec
/
512
*
8192 bytes = 2392064 bytes per/sec = 2.39 MB/sec
Arduino Due Rocks!
Regards,
John
#define NUM_OF_SCOPES 8
static const uint16_t serial_buffer_size = NUM_OF_SCOPES * 1024;
static char my_num_char[serial_buffer_size]="";
static int32_t my_counter = 0;
static uint16_t my_val[12] = {0};
static const uint8_t my_ports_hex[8] = { 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
static bool start_transmission = false;
char ch;
void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
pmc_set_writeprotect(false);
pmc_enable_periph_clk( (uint32_t) irq );
TC_Configure( tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4 );
uint32_t rc = VARIANT_MCK / 128 / frequency;
TC_SetRA(tc, channel, rc / 2 );
TC_SetRC(tc, channel, rc );
TC_Start(tc, channel);
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPCS;
tc->TC_CHANNEL[channel].TC_IDR = ~TC_IER_CPCS;
NVIC_EnableIRQ(irq);
}
void TC3_Handler(){
TC_GetStatus(TC1, 0);
if(start_transmission) {
my_counter++;
while( ( ADC->ADC_ISR & my_ports_hex[ NUM_OF_SCOPES - 1 ] ) != my_ports_hex[ NUM_OF_SCOPES - 1 ] );
for (uint8_t i = 0; i < NUM_OF_SCOPES; i++){
my_val[i] = ADC->ADC_CDR[ 7 - i ];
my_num_char[ ( my_counter + i * 512 ) << 1 ] = my_val[ i ] & 0xFF;
my_num_char[ ( ( my_counter + i * 512 ) << 1 ) + 1 ] = ( my_val[ i ] >> 8 ) & 0x0F; }
if(my_counter >= 511) { SerialUSB.write( my_num_char, NUM_OF_SCOPES * 1024 ); my_counter = 0; }
}
}
void setup() {
pinMode(13, OUTPUT);
analogReadResolution(12);
pmc_enable_periph_clk(ID_ADC);
ADC->ADC_MR |= 0x1280;
ADC->ADC_CR = 2;
ADC->ADC_CHER = my_ports_hex[ NUM_OF_SCOPES - 1 ];
SerialUSB.begin(9600);
while(!SerialUSB);
delay(100);
startTimer(TC1, 0, TC3_IRQn, 150000); //16000 //48000//100000
}
void loop(){
if ( ( SerialUSB.available() > 0) ) {
ch = SerialUSB.read();
if( ch == 'F') start_transmission = true;
if( ch == 'G') { start_transmission = false; my_counter = 0; }
} //Read serial
}
To unpack the data and fill the arrays do something like this in your serial/drawing app:
#define NUMBER_OF_SCOPES 8
#define SERIAL_BUFFER_SIZE 8192
static char szBuffer[SERIAL_BUFFER_SIZE] = {""};
LONG lLastError = ERROR_SUCCESS;
static DWORD dwBytesRead = 0;
static unsigned int index[NUMBER_OF_SCOPES] = {0};
static long my_wave_scope[NUMBER_OF_SCOPES][2048] = {0};
static float height_divisor = ( 100.0f / ( NUMBER_OF_SCOPES * 2.0f ) );
static bool zero_cross = false;
static int sel_cha = 0;
case CSerialWnd::EEventRecv: {
lLastError = serial.Read( szBuffer, SERIAL_BUFFER_SIZE, &dwBytesRead );
if( dwBytesRead == SERIAL_BUFFER_SIZE ){
for ( unsigned int i = 0; i < dwBytesRead; i+=2 ){
sel_cha = i / 1024;
audio_temp[sel_cha][ (i-sel_cha*1024) >> 1 ] = ( ( szBuffer[ i ] & 0xFF ) | ( ( szBuffer[ i+1 ] & 0x0F ) << 8 ) ) - 2048;}
for ( unsigned int i = 0; i < 512; i++ ){
if( i == 511 ) { zero_cross = false; index[0] = 0; } else
if( ( audio_temp[0][ i ] >= 0 && audio_temp[0][ i + 1 ] < 0 ) && !zero_cross ) zero_cross = true; else
if( zero_cross ) {
my_wave_scope[0][ index[0]++ ] = audio_temp[0][i];
my_wave_scope[1][ index[0] ] = audio_temp[1][i];
my_wave_scope[2][ index[0] ] = audio_temp[2][i];
my_wave_scope[3][ index[0] ] = audio_temp[3][i];}
}
} //expand as necessary
break; }
Connect each signal with a voltage divider -> 2 100k resistors.
Due Analog input o ------------VV------------o Uno Digital Pin
| (100k)
Z (100k)
|
o
Ground (Uno Ground)