Testing the Arduino ADC

The ADC is setup as described in the previous document. The code to do this is

void adc_setup(void)
{
  pmc_enable_periph_clk(ID_ADC);  // start clocking the ADC - not really necessary
                // as tests show that after reset the ADC clock is already enabled

  ADC->ADC_CR = ADC_CR_SWRST;  // reset ADC

  // ADC_MR set to zero on software reset
  ADC->ADC_MR = ADC_MR_TRANSFER(1) | ADC_MR_PRESCAL(1) |
                   ADC_MR_STARTUP_SUT24 | ADC_MR_TRGSEL_ADC_TRIG1;
  // TRANSFER=1, as recommended in the datasheet
  // PRESCAL=1, ADC clock is 21MHz (fine as the source impedance is very low)
  // STARTUP=24 ADC clock periods
  // TRGSEL=1, Timer COunter 0, Channel 0
  ADC->ADC_CHDR = 0xFFFF;      // disable all channels
  ADC->ADC_CHER = 0x80;        // enable just A0
  ADC->ADC_CGR = 0x0;           // All gains set to x1 for single ended inputs
  ADC->ADC_COR = 0x0;           // All offsets off
  ADC->ADC_ACR = ADC_ACR_IBCTL(0);  // Sample frequency less than 500kHz

  ADC->ADC_IDR = 0x1F00FFFF;   // disable all interrupts
  ADC->ADC_IER = 0x80;         // enable AD7 End-Of-Conv interrupt
							   // (Arduino pin A0)
  NVIC_EnableIRQ(ADC_IRQn);    // enable ADC interrupt vector
}

void disableADCTrigger(void)
{
	ADC->ADC_MR &= (~ADC_MR_TRGEN);	// Clear the trigger enable bit
}

void enableADCTrigger(void)
{
	ADC->ADC_MR |= (ADC_MR_TRGEN);	// Set the trigger enable bit
}

The ADC is tested by digitising a signal using the ADC and writing the results to the serial port. A Matlab program is used to read these results and plot the data and its FFT. The plot below shows the results for a 440Hz signal sampled at 48kHz.
ADCTestPlot

Similar results are obtained for other frequencies, a clean digitised signal is obtained.

The Arduino code to do this is

/**********************************************************************
* Sketch:      ADCTest.ino
* Description: Read ADC and send a set of values to the serial port
*
* Author:      Chris Newton
*
* (C) Copyright 2015, Chris Newton.
*
**********************************************************************/

// Define the circular buffers used in these tests
#include "circularBuffer.h"

#include "ADC_routines.h"
#include "timer_routines.h"

void setup()
{
	Serial.begin(115200);

	adc_setup();         // setup ADC

	timer_setup();        // setup timer
}

#ifdef __cplusplus
extern "C"
{
#endif

void ADC_Handler(void)  // Read the ADC 
{
    int16_t val;
	if (ADC->ADC_ISR & ADC_ISR_EOC7)
	{  // ensure there was an End-of-Conversion and we read the ISR reg
		val = *(ADC->ADC_CDR + 7);  // get conversion result
		inputBuffer[ibFront] = val; // put in the input buffer
		ibFront = (ibFront + 1)&BUFMASK;     // move pointer
		ibCount++;
	}
}

#ifdef __cplusplus
}
#endif


#define   SEND_BUFF  BUFSIZE/2
int16_t sendBuffer[SEND_BUFF] = { 0 };
uint16_t sbIndex = 0;
bool collectingData = false;

void stopDataCollection(void)
{
	disableADCTrigger();
	collectingData = false;
}

void resetDataCollection(void)
{
	disableADCTrigger();
	collectingData = false;
	ibFront = 0;    // Reset the circular buffer
	ibBack = 0;
	ibCount = 0;

	sbIndex = 0;
}

void loop()
{
	while (Serial.available())
	{
		// get the next byte:
		char inChar = char(Serial.read());
		// ignore if it is white space
		if (isspace(inChar))
			continue;
		switch (inChar)
		{
		case 'v':
			Serial.print("ADCT 0.0\n");
			break;
		case 's':
			stopDataCollection();
			Serial.print("OK\n");
			break;
		case 'r':
			resetDataCollection();
			Serial.print("OK\n");
			break;
		case 'g':
			enableADCTrigger();
			collectingData = true;
		        break;
		case 'd':
			Serial.print("\n");
			printADCRegisters();
			Serial.print("\n");
		        break;
		case 't':
			Serial.print("\n");
			printTC0Registers();
			Serial.print("\n");
			break;
		default:
			Serial.print("?\n");
		}
	}

    while (collectingData && sbIndexADC_IMR;
			ADC->ADC_IDR == 0x1F00FFFF;   // disable all interrupts
			val  = inputBuffer[ibBack];
			ibBack = (ibBack + 1)&BUFMASK;
			ibCount--;
			ADC->ADC_IER = imr; // Re-enable interrupts
			sendBuffer[sbIndex++] = val;
		}
	}
	if (sbIndex == SEND_BUFF)
	{
		stopDataCollection();
		Serial.write((uint8_t*)sendBuffer, 2 * SEND_BUFF);
		sbIndex = 0;
	}
}

The timer setup used is similar to that given previously.

Advertisements
This entry was posted in Arduino. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s