I am trying to build an oscilloscope using an Arduino Due and an LCD. I have the LCD running perfectly and started working on using the ADC peripheral to sample signals. Here's what I have so far:
#define SAMPLE_BUFFER_SIZE 800
volatile int sample_buffer[SAMPLE_BUFFER_SIZE];
volatile bool sample_buffer_full = 0;
volatile int sample_buffer_idx = 0;
void adcm_init() {
pmc_enable_periph_clk(ID_ADC); // To use peripheral, we must enable clock distributon to it
adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST); // initialize, set maximum posibble speed
adc_disable_interrupt(ADC, 0xFFFFFFFF);
adc_set_resolution(ADC, ADC_12_BITS);
adc_configure_power_save(ADC, 0, 0); // Disable sleep
adc_configure_timing(ADC, 0, ADC_SETTLING_TIME_3, 1); // Set timings - standard values
adc_set_bias_current(ADC, 1); // Bias current - maximum performance over current consumption
adc_stop_sequencer(ADC); // not using it
adc_disable_tag(ADC); // it has to do with sequencer, not using it
adc_disable_ts(ADC); // deisable temperature sensor
adc_disable_channel_differential_input(ADC, ADC_CHANNEL_7);
adc_configure_trigger(ADC, ADC_TRIG_SW, 1); // triggering from software, freerunning mode
adc_disable_all_channel(ADC);
adc_enable_channel(ADC, ADC_CHANNEL_7); // just one channel enabled
adc_enable_interrupt(ADC, ADC_IER_DRDY); // Data Ready Interrupt Enable
NVIC_EnableIRQ(ADC_IRQn);
adc_start(ADC);
}
void ADC_Handler(void) {
if (!sample_buffer_full) {
if ((adc_get_status(ADC) & ADC_ISR_DRDY) == ADC_ISR_DRDY) {
sample_buffer[sample_buffer_idx] = adc_get_latest_value(ADC);
sample_buffer_idx++;
if (sample_buffer_idx == SAMPLE_BUFFER_SIZE) {
sample_buffer_full = 1;
sample_buffer_idx = 0;
}
}
}
}
void setup()
{
adcm_init();
Serial.begin(115200);
}
void loop() {
Serial.print("Loop\n");
if (sample_buffer_full) {
for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++) {
Serial.print(sample_buffer[i]);
Serial.print(" ");
}
Serial.print("\n");
sample_buffer_full = 0;
}
}
This was copied and slightly modified from somewhere on the internet (can't remember where, though). I have also studied the docs and this code seems to make perfect sense and it should work.
The idea is for the sampling to be interrupt-based. However, if I set the ADC to freerunning mode and enable interrupts, it just gives up and stops working.
What I mean by that is: on my serial monitor, after pressing reset, all I see are 2 lines saying "Loop" and it just stops there. Normally it should print "Loop" indefinitely, and also print ADC values from time to time.
If I disable interrupts, "Loop" is printed indefinitely, but of course no values are shown. If I disable free-running mode, "Loop" is printed and no values are shown unless the buffer size is 1, in which case the same value is printed over and over (as expected, in that case the interrupt runs only once, right at the beginning).
The CPU clock freq. is 84Mhz, I'm going for the fastest I can get out of the ADC, so a sample is taken (and an interrupt is fired) every 1Mhz. That means 84 clock cycles per interrupt. Don't know for sure if that is enough for the rest of the program to work, but my gut tells me that's not a problem. Besides, I tried with a lower ADC clock value and it still didn't work.
Any ideas? I'm really at a loss here...
extern "C"
declarations.void ADC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));