Settings for the Arduino DAC

My settings and use of the Arduino DAC are detailed here. Most of the information in these notes is abstracted from the latest SAM3X8E datasheet. In the Atmel datsheet the DAC is described in the Section 44, Digital-to-Analog Converter Controller.

Many of the connections to the SAM3X8E are mulitplexed, and this is the case for the DAC inputs. However it is not necessary to program the PIO controller directly as enabling a DAC channel automatically connects the corresponding input pin to the DAC. The mapping of the Arduino pins to those of the SAM3X8E is given here; so, for example, Arduino DAC0 is connected to PB15.

The DACC uses the master clock frequency divided by two (i.e. 42 Mhz) to carry out the conversions. Once the conversin is started the analog output is available after 25 DACC clock periods.

The DACC has a number of registers that are used to control its operation. Some are read-only (RO), some are write-only (WO) and others are read-write (RW). I now detail how I setup these registers.

Control Register (WO, see section 44.7.1). This has just a single one bit field: SWRST which when set to one causes a software reset of the DAC and can be used to reset the DAC and put it into a known state. The status of the registers after a software reset is:

\displaystyle \begin{array}{llr} \mbox{Mode Register} & \rm{DACC\_MR} & 0\\ \mbox{Channel Status Register} & \rm{DACC\_CHSR} & 0\\ \mbox{Interrupt Mask Register} & \rm{DACC\_IMR} & 0\\ \mbox{Interrupt Status Register} & \rm{DACC\_ISR} & \rm{0}\\ \mbox{Analog Current Register} & \rm{DACC\_ACR} & \rm{0x1AA} \\ \mbox{Write Protect Mode Register} & \rm{DACC\_WPMR} & 0\\ \mbox{Write Protect Status Register} & \rm{DACC\_WPSR} & 0\\ \end{array}

Notes:

  1. The values shown here are obtained using a software reset directly after a system reset.
  2. The datasheet says that the Analog Control Register should have a value of 0. This is not what I see. Also I see that after using analogWrite() to write to DAC0 or DAC1 the Analog Current Register has the value 0x10A (for this register bits {4\ldots 7} are not used, so 0x1AA and 0x10A are equivalent).

Mode Register (RW, see section 44.7.2). I plan to just use the DAC0 output and to write the values to be converted ans words. With a single output in use I have no need for the TAG filed. For the SDR experiments I will run continuously, although not in free-run mode, and so the sleep mode will be turned off. This determines the following fields of the Mode Register:

\displaystyle \begin{array}{rcl} \rm{TRGEN} & = & 1 \mbox{\hspace{12pt}Use an external trigger (see below)} \\ \rm{WORD} & = & 0 \mbox{\hspace{12pt}Half-word transfers} \\ \rm{SLEEP} & = & 0 \mbox{\hspace{12pt}Sleep mode off} \\ \rm{FASTWKUP} & = & 0 \mbox{\hspace{12pt}Fast wake up - not relevant} \\ \rm{USER\_SEL} & = & 0 \mbox{\hspace{12pt}Select Channel 0 (i.e. DAC0)} \\ \rm{TAG} & = & 0 \mbox{\hspace{12pt}Do not use the tag mode, the channel is set by \rm{USER\_SEL}} \\ \rm{MAXS} & = & 0 \mbox{\hspace{12pt}Max speed mode disabled} \end{array}

As the sleep mode is not used, any startup delay only occurs at the beginning. The startup times for the different field values are given in the datasheet. In the absence of any information I am using the value set when using analogWrite() i.e. 512 DACC clock periods. This is represented by the macro {\rm{DACC\_MR\_STARTUP\_512}}. The DACC clock frequency is the system master clock divided by two, i.e. 42Mhz.

The TRGEN field is a one bit field which determines how the DACC is triggered. When set to zero the DACC is in free running mode. When set to one the DACC is triggered by hardware and the remaining field (TRGSEL) determines which hardware trigger is used. In my experiments I will be triggering the ADC and DAC separately and so using the TIOA output of channel 1 of timer module 0 (TC0) to trigger the DAC. This is represented by the {\rm{DACC\_MR\_TRGSEL (2)}} value for the TRGSEL field.

The remaining field to discuss is the refresh field. After {20\mu s} the analog voltage resulting from the conversion will start decreasing. To maintain the voltage it is necessary to refresh the channel on a regular basis. This field determines how long this refresh continues. The refresh time is given by

\displaystyle \rm{refresh~period}=\frac{1024~REFRESH}{DACC~clock}

Given the frequency with which samples are written to the DACC the necessary refresh period can be calculated and this used to calculate a REFRESH value. So with a sample frequency, {f_s} we have

\displaystyle \rm{REFRESH}=\left\lceil\frac{\rm{DACC~clock}}{1024 f_s}\right\rceil

For {f_s=24\times 10^3}, we get

\displaystyle \rm{REFRESH}=\left\lceil\frac{\rm{42\times 10^6}}{1024\times 24\times 10^3}\right\rceil=2

The REFRESH field has 8 bits, so {r} can be between 0 and 255. A value of 0 for this field disables the refresh.

Channel Enable Register (WO, section 44.7.3). The first two bits of this register are used to enable channels 0 and 1, writing a 1 in the corresponding bit enables that channel.

Channel Disable Register (WO, section 44.7.4). The first two bits of this register are used to disable channels 0 and 1, writing a 1 in the corresponding bit disables that channel.

Channel Status Register (RO, section 44.7.5). The first two bits of this register are used to disable channels 0 and 1, writing a 1 in the corresponding bit disables that channel. A zero in the corresponding bit position means that the channel is disabled, while a one means that the corresponding channel is enabled. Whether an channel is enabled, or disabled, depends on the latest update of the Channel Enable or Channel Disable Register. Setting an channel bit position in one of these registers overrides what went before.

Conversion Data Register (WO, section 44.7.6). I am using half word mode and so the first 16 bits of the value written is converted; the other 16 bits are ignored.

Interrupt Enable Register (WO, section 44.7.7). The first 4 bits of this register are used to enable the different interrupts. If at all, I will be only using the transmit ready (TXRDY) and end of conversion (EOC) interrupts. Setting the corresponding bit to one enables the interrupt. The other two bits of this register are used for other interrupts, but I am not planning to use these (at the moment).

The DAC has a 4 half-word FIFO. Data for conversion can be written to the FIFO when the TXRDT flag is set. When the FIFO is full the TXRDY flag is cleared.

Interrupt Disable Register (WO, section 44.7.8). Similarly the first 4 bits of this register are used to disable different interrupts. Setting the corresponding bit to one disables the interrupt.

Interrupt Mask Register (RO, section 44.7.9). The bits of this register are used to return the status of each of the interrupts. A zero in the corresponding bit position means that the interrupt is disabled, while a one means that the corresponding interrupt is enabled. Whether an interrupt is enabled, or disabled, depends on the latest update of the Interrupt Enable or Interrupt Disable Register. Setting an interrupt bit position in one of these registers overrides what went before.

Interrupt Status Register (RO, section 44.7.10). The bits in this register indicate whether the corresponding interrupt is active. For the transmit ready interrupt a zero indicates that the DACC is not ready to accept new requests, while a one indicates that the DACC is ready. For the end of conversion interrupt a zero indicates that no conversion has been completed since the previous read of this register. A one indicates that at least one conversion on this channel has been completed since the previous read of this register. Reading this register clears the EOC bit.

Analog Current Register (RW, section 44.7.11). The settings for this register are unclear. In test measurements in the electrical characteristics section (Section 45.9) the following values are used: {\rm{DACC\_ACR.IBCTLDACCORE}=01} and {\rm{DACC\_ACR.IBCTLCHx=10}}. In the absence of other information I will use these values (they give a value of 0x10A if both channels are included).

The remaining three registers can be used to write protect some of the DAC registers. I am not using this facility.

Note that the output range for the DAC is between {1/6} and {5/6} of the reference voltage (3.3V unless an external reference is supplied).

 

Advertisements
Posted in Arduino | Leave a comment

Output from audioTest program

The plot below shows a recording of the output from the audioTest program. The recording was made using Matlab and the audio data and its FFT plotted. The signal was a single tone of 2640Hz.

audioOutputThe data is clean and noise free. Changing the frequency makes little difference to the results; at 10kHz the plot is no longer smooth, but the FFT is clean.

audioOutput10k

 

Posted in Arduino | Leave a comment

Settings for the Arduino Timers

The SAM3X8e processor has three timer counter modules and each of these has three channels giving nine timer counter channels in all. These channels can be independently programmed to carry out a wide range of different functions. For these experiments I will only be using timer channels to generate triggers at regular intervals for the ADC and the DACs. These notes will concentrate on the programming necessary to do this.

In the examples given so far one timer channel is used to trigger the ADC and DAC conversions. Once the ADC conversion is complete an interrupt is generated and the ADC interrupt handler reads the value and, if available, also writes an item of data to the DAC. While satisfactory for the initial tests in general it will be better to use different timer channels for triggering the ADC and the DACs as this will allow multi-rate processing to be used.

Both the ADC and the DACs need their triggers to be generated by timer counter module 0 (TC0). This module has three channels available and fields in the ADC and DAC mode registers specify which of these channels will be used as a trigger. I will use channel 0 to trigger the ADC and channel 1 to trigger the DACs. Each channel in the timer counter module has its own set of registers. There are some common registers, but these will not be used here.

I will now describe how I setup the channel registers; noting that after a system reset all of the registers are zero. Some registers are read-only (RO), some are write-only (WO) and others are read-write (RW).

Control Register (WO, see section 36.7.1). Only three bits of this register are used. CLKEN, CLKDIS and SWTRG. CLKEN, enables the clock if CLKDIS is not equal to 1. CLKDIS disables the clock. SWTRG resets the counter and the clock is started.

Mode Register (RW, see section 36.7.3). The WAVE bit in this register determines how the remaining bits are used. I will be using the WAVE mode, selected when the WAVE bit is set to 1. There are a number of different options in this mode, but I will just be using it to generate a series of regular pulses (on TIOA) and this is done by setting the WAVSEL field to 10 (see section 36.11.2 and figure 36-9). In this case the counter is incremented and when it reaches the value set in the Register C (RC) the counter is reset and we start again. The TIOA output is set when the counter reaches the RC value and cleared when the value set in a second register, Register A, (RA) is reached. Register A, is set to one half of the RC value, therefore generating a trigger with an equal mark space ratio. The clock frequency used to drive the counter is selected by the TCCLKS field, we will use an internal clock and the relevant options are:

\displaystyle \begin{array}{rcl} \rm{TIMER\_CLOCK1}& = & \rm{MCK}/2 \\ \rm{TIMER\_CLOCK2}& = & \rm{MCK}/8 \\ \rm{TIMER\_CLOCK3}& = & \rm{MCK}/32 \\ \rm{TIMER\_CLOCK4}& = & \rm{MCK}/128 \\ \end{array}

{\rm{MCK}=84}MHz and so the corresponding clock frequencies are: 42,000, 10,500, 2,625 and 656.25 kHz. To get, for example, a sampling rate of 44.1kHz, we would need counts of: 952.38, 238.09, 59.52 and 14.88. Counts are integers, so taking the nearest integer values we would have effective sample rates of: 44.1176, 44.1176, 43.75 and 43.75 kHz. In this case we would take {\rm{RC}=952} using the larger value for RC and we can then take {\rm{RA}=476}.

Other fields of interest in the mode register are:

  • CLKI – when this bit is 0 the counter is clocked on the rising edge, when it is 1 the counter is clocked on the falling edge. I will use the risng edge, so set a value of 0.
  • BURST – this field controls whether the clock is gated by an external signal. I do not want to use this facility and so this field’s value will be zero.
  • CPCSTOP – this bit determines whether the clock is stopped when the counter reaches RC. I will not use this option, so the field’s value will be zero.
  • CPCDIS – this bit determines whether the clock is disabled when the counter reaches RC. I will not use this option, so the value will be zero.
  • EEVTEDG, EEVT and EEVETRG – these control the handling of external events and will not be used here. These fields will all be set to 0. Setting EEVT to 0 also sets TIOB as an input rather than an output, this is not a problem as the TIOB output is not required.
  • ACPA – this field controls what happens to TIOA when the counter reaches RA. This field is used to clear TIOA ready for the next trigger.
  • ACPC – this field controls what happens to TIOA when the counter reaches RC. This field is set to 1 and this has the effect of setting TIOA to 1 when the counter reaches the value set in RC.

The remaining fields control the effect of external events and control output to TIOB, these are not used and all fields set to zero

Stepper Motor Mode Register (RW, see section 36.7.4). This register is not used here.

Counter Value Register (RO, see section 36.7.5). This register contains the counter value. I will not be using this value directly.

Register A (RW, when WAVE=1, see section 36.7.6) and Register C(RW, when WAVE=1, see section 36.7.8). These are set as outlined above.

Register B (RW, when WAVE=1, see section 36.7.7). I will not be using this register.

Status Register (RO, see section 36.7.9). This register contains status information, but I will not be using it here.

Interrupt Enable Register (WO, see section 36.7.10), Interrupt Disable Register (WO, see section 36.7.11) and Interrupt Mask Register (RO, see section 36.7.12). These register control the generation of timer interrupts. I will not be using interrupts at the moment.

Other registers, which are common to all of the channels in a timer module, are not used here.

The revised code used to setup the TC0 timers is

double setup_TC0Timer(
uint32_t channelNumber,
uint32_t freq
)
{
        if (channelNumber<0 || channelNumber>2)
          return -1;
	uint32_t rcCount = VARIANT_MCK / (2 * freq);
	double actualFreq = double(VARIANT_MCK) / (2 * rcCount);

	TcChannel * t = TC0->TC_CHANNEL+channelNumber;	// pointer to TC0 registers
							// for the given channel
	t->TC_CCR = TC_CCR_CLKDIS;  // disable internal clocking while setup regs
	t->TC_IDR = 0xFF;			// disable interrupts
	t->TC_SR;                   // read int status reg to clear pending
	t->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 |   // use TCLK1 (prescale by 2)
		TC_CMR_WAVE |			// waveform mode
		TC_CMR_WAVSEL_UP_RC |	// count-up PWM using RC as threshold
		TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET;
				// set and clear flags for RA and RC compares
	t->TC_RC = rcCount;	// counter resets on RC, so sets period in terms of master clock frequency/2
	t->TC_RA = rcCount / 2;	// roughly square wave

	return actualFreq;
}

void TC0ClockDisable(
uint32_t channelNumber
)
{
    if (channelNumber<0 || channelNumber>2)
	return;

    TcChannel * t = TC0->TC_CHANNEL + channelNumber; // pointer to TC0 registers
	                                             // for the given channel
    t->TC_CCR = TC_CCR_CLKDIS;  // disable internal clocking 
}

void TC0ClockEnable(
uint32_t channelNumber
)
{
    if (channelNumber < 0 || channelNumber>2)
	return;

    TcChannel * t = TC0->TC_CHANNEL + channelNumber;  // pointer to TC0 registers
	                                              // for the given channel
    t->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;  // re-enable local clocking and 
	                                      // switch to hardware trigger source.
}

double timer_setup(uint32_t freq) // Frequency in Hz
{
 pmc_enable_periph_clk (ID_TC0) ; // clock the TC0 channel 0

 double actualFreq = setupTC0Timer(0, freq);

 return actualFreq;
}
Posted in Arduino | Leave a comment

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.

Posted in Arduino | Leave a comment

Settings for the Arduino ADC

My settings and use of the Arduino ADC are detailed here. Most of the information in these notes is abstracted from the latest SAM3X8E datasheet.

Many of the connections to the SAM3X8E are mulitplexed, and this is the case for the ADC inputs. However it is not necessary to program the PIO controller directly as enabling an ADC channel automatically connects the corresponding input pin to the ADC. On reset the ADC input pins are allocated as digital inputs with their pull-up resistors enabled, any circuit connected to these pins must allow for this so that no damage is incurred before the ADC channels are initialised. The pins can source up to 6mA and sink up to 3mA. The mapping of the Arduino pins to those of the SAM3X8E is given here; so, for example, Arduino pin A0 is connected to PA16, the SAM3X8E I/O pin for AD7.

The ADC has a number of registers that are used to control its operation. Some are read-only (RO), some are write-only (WO) and others are read-write (RW). I now detail how I setup these registers.

Control Register (WO, see section 43.7.1). This has just two one bit fields: SWRST which when set to one causes a software reset of the ADC and START which when set to one triggers a conversion. I will be using a timer to trigger the ADC at regular intervals and so the only relevant field will be SWRST which I can use to reset the ADC and put it in a known state. The status of the registers after a software reset is:

\displaystyle \begin{array}{llr} \mbox{Mode Register} & \rm{ADC\_MR} & 0\\ \mbox{Channel Sequence Register 1} & \rm{ADC\_SEQR1} & 0\\ \mbox{Channel Sequence Register 2} & \rm{ADC\_SEQR2} & 0\\ \mbox{Channel Status Register} & \rm{ADC\_CHSR} & 0\\ \mbox{Last Converted Data Register} & \rm{ADC\_LCDR} & 0 \\ \mbox{Interrupt Mask Register} & \rm{ADC\_IMR} & 0\\ \mbox{Interrupt Status Register} & \rm{ADC\_ISR} & \rm{0x18000000}\\ \mbox{Overrun Status Register} & \rm{ADC\_OVER} & 0\\ \mbox{Extended Mode Register} & \rm{ADC\_EMR} & 0\\ \mbox{Compare Window Register} & \rm{ADC\_CWR} & 0\\ \mbox{Channel Gain Register } & \rm{ADC\_CGR} & 0\\ \mbox{Channel Offset Register} & \rm{ADC\_COR} & 0\\ \mbox{Channel Data Register 6} & \rm{ADC\_CDR[6]}\mbox{ (Arduino A1)} & 0 \\ \mbox{Channel Data Register 7} & \rm{ADC\_CDR[7]}\mbox{ (Arduino A0)} & 0 \\ \mbox{Analog Control Register} & \rm{ADC\_ACR} & \rm{0x101} \\ \mbox{Write Protect Mode Register} & \rm{ADC\_WPMR} & 0\\ \mbox{Write Protect Status Register} & \rm{ADC\_WPSR} & 0\\ \end{array}

Notes:

  1. The values shown here are obtained using a software reset directly after a system reset.
  2. Testing the software reset after using analogRead() to read A0 or A1 (or both) shows that a software reset does not change the last converted data register, the interrupt status register or the channel data registers.
  3. The value shown for the Interrupt Status Register is not the same as given in the data sheet, the bits that are set refer to DMA settings and are not relevant here.
  4. The datasheet says that the Analog Control Register should have a value of 0x100, however the first bit is un-used, so the discrepancy seems irrelevant.

Mode Register (RW, see section 43.7.2). I plan to use one, or two, single ended inputs with the same gain and offset values and to use the 12-bit resolution setting. Also for the SDR experiments I will run continuously, although not in free-run mode, and so the sleep mode will be turned off. This determines the following fields of the Mode Register:

\displaystyle \begin{array}{rcl} \rm{LOWRES} & = & 0 \mbox{\hspace{12pt}12-bit resolution} \\ \rm{SLEEP} & = & 0 \mbox{\hspace{12pt}Sleep mode off} \\ \rm{FWUP} & = & 0 \mbox{\hspace{12pt}Fast wake up - not relevant} \\ \rm{FREERUN} & = & 0 \mbox{\hspace{12pt}Triggered mode} \\ \rm{SETTLING} & = & 0 \mbox{\hspace{12pt}Settling time - not relevant} \\ \rm{ANACH} & = & 0 \mbox{\hspace{12pt}All channels use the same gain and offset} \\ \rm{TRACKTIM} & = & 0 \mbox{\hspace{12pt}Tracking time (see below)} \\ \rm{TRANSFER} & = & 1 \mbox{\hspace{12pt}Transfer time (see below)} \\ \rm{USEQ} & = & 0 \mbox{\hspace{12pt}Convert channels in numerical order} \end{array}

The TRACKTIM and TRANSFER fields are set to the values given in the electrical characteristics section (45.7.2). The actual tracking time will be 15 ADC clock cycles and the frequency of the ADC clock will need to be adjusted to allow for the source impedance. The frequency of this clock is set by the PRESCAL field, with

\displaystyle f_{ADC}=\frac{\rm{MCK}}{2(\rm{PRESCAL}+1)}

where MCK is the master clock frequency (84MHz in this case). In the electrical characteristics section the limits for the ADC clock frequency are minimum 1MHz and maximum 22MHz and so the PRESCAL field must have values between 1 and 41.

As the sleep mode is not used, the startup delay only occurs at the beginning. The startup field, needs to be set to ensure that the tracking time for the first conversion is long enough. The startup times for the different field values are given in the datasheet. In fact, for my configuration this turns out to be largely irrelevant as, in this case, to allow for an error in the system, the datasheet says that the first 16 conversions after startup should be discarded (see section 49.1.4).

The TRGEN field is a one bit field which determines how the ADC is triggered. When set to zero the ADC can only be triggered by software (by setting the START bit in the control register). When set to one the ADC is triggered by hardware and the remaining field (TRGSEL) determines which hardware trigger is used. In this case the TRGEN bit can be used to start and stop the ADC without affecting the other settings.

In my experiments I will be using the TIOA output of timer channel 0 and this is represented by the {\rm{ADC\_TRIG1}} value for the TRGSEL field.

Channel Sequence 1 Register and Channel Sequence 2 Register. These are used to enable the user to define the order in which channels are converted. I am not using this facility.

Channel Enable Register (WO, section 43.7.5). The first 16 bits of this register are used to select which channels are to be converted. Setting the corresponding bit to one enables the channel for conversion.

Channel Disable Register (WO, section 43.7.6). The first 16 bits of this register are used to disable channel conversions. Setting the corresponding bit to one disables the channel for conversion.

Channel Status Register (RO, section 43.7.7). The first 16 bits of this register are used to return the status of each of the channels. A zero in the corresponding bit position means that the channel is disabled, while a one means that the corresponding channel is enabled. The status of a channel depends on the latest update of the Channel Disable Register or the Channel Enable Register. Setting a channel bit position in one of these registers overrides what went before.

Last Converted Data Register (RO, section 43.7.8). This contains the last converted data value and its channel number (if the TAG option is set). I am not using this register.

Interrupt Enable Register (WO, section 43.7.9). The first 16 bits of this register are used to enable end of conversion interrupts on the corresponding channels. Setting the corresponding bit to one enables the interrupt. Other bits of this register are used for other interrupts, but I am not using these (at the moment).

Interrupt Disable Register (WO, section 43.7.10). Similarly the first 16 bits of this register are used to disable end of conversion interrupt from the corresponding channel. Setting the corresponding bit to one disables the interrupt. Other bits of this register are used for other interrupts, but I am not using these.

Interrupt Mask Register (RO, section 43.7.11). The bits of this register are used to return the status of each of the interrupts. A zero in the corresponding bit position means that the interrupt is disabled, while a one means that the corresponding interrupt is enabled. Whether an interrupt is enabled, or disabled, depends on the latest update of the Interrupt Enable or Interrupt Disable Register. Setting an interrupt bit position in one of these registers overrides what went before.

Interrupt Status Register (RO, section 43.7.12). The bits in this register indicate whether the corresponding interrupt is active. For end of conversion interrupts a zero indicates that the channel is disabled, or that a conversion on this channel is incomplete. A one indicates that a conversion on this channel is complete, reading the corresponding Channel Data Register clears this interrupt.

Overrun Status Register (RO, section 43.7.13). The first 16 bits in this register indicate whether there has been an overrun on the corresponding channel since the status register was last read.

Extended Mode Register and Compare Window Register. These are used when testing the converted values against given lower and upper thresholds. I am not using this facility.

Channel Gain Register (RW, section 43.7.16). This allows the gain for each channel to be adjusted. I am using the default value (0) which for single ended inputs gives a gain of 1.

Channel Offset Register (RW, section 43.7.17). This allows channel offsets to be set. For the moment I am using the default 0 values, no offset.

Channel Data Register[{\textrm{x}=0\ldots 15}] When the conversion of a channel is completed the value is put into the corresponding CDR. It remains there until the next conversion of that channel.

Analog Control Register (RW, section 43.7.19). There are 2 fields in this register. One, TSON turns the temperature sensor on when it is set. The other, 2-bit field, IBCTL is the bias current control. In the electrical characteristics it says to set this to 00 if the sampling frequency is less than 500kHz and to set it to 01 when the sampling frequency is between 500kHz and 1MHz. In my programs the sampling frequency will always be less than 500kHz.

The remaining three registers can be used to write protect some of the ADC registers. I am not using this facility.

Posted in Arduino | Leave a comment

Arduino ADC timing again

Continuing on  . . .

I spoke to Atmel support and they told me that there is a problem with the TRACKTIM field and its implementation (“there is an issue with how tracking is implemented in the current SAM3X module. It is documented, that the TRACTIM time is extended to the next start of conversion. But the field TRACTIM turn to be useless, the track time will be always 15 or 16 cycles”).

They confirmed that values for this field between 0 and 14 always give a tracking time of 15 ADC clock cycles. While a TRACKTIM value of 15 gives a tracking time of 16 ADC clock cycles. These are the only values that can be obtained.

So, I plan to use TRACKTIM=0 and TRANSFER=1 and to change the ADC clock frequency to make sure that the tracking time is long enough (see the previous plot).

Posted in Arduino | Leave a comment

More on Arduino ADC timing

Continuing on the previous thread …

Looking at the timing diagrams in the Atmel SAM3X8e datasheet (Figures 40-2 and 40-3) together with the notes `Analog-to-Digital Converter in the SAM3S4′ for a simlar microntroller, it seems that part of my confusion is due to the way that the terms are described. So

  • In one part of the datasheet the conversion time is given as {20 t_{CP\_ADC}}, elsewhere it talks about a conversion time of {15 t_{CP\_ADC}}. The explanation is that the total conversion time is {20 t_{CP\_ADC}} and this is made up of {5 t_{CP\_ADC}} to transfer the analog iinput from the sample and hold and {15 t_{CP\_ADC}} to do the actual conversion and digitise the data.
  • The TRANSFER field in the Mode Register does not control the time to transfer the analog input from the sample and hold to the digitiser, this is always {5 t_{CP\_ADC}}. The TRANSFER field in the Mode Register controls the time from the start of the conversion (an ADC\_Start pulse) to the time when the input channel is changed. {\rm{TRANSFER=1}} makes this time equal to the actual transfer time ({5 t_{CP\_ADC}}) and this is the recommended value. Other values can be used, but they affect other timings and are not recommended.

In Section 45.7.2.1 of the datasheet, titled “Track and Hold Time versus Source Output Impedance”, it says to set {\rm{TRANSFER=1}} and {\rm{TRACKTIM=0}} whatever the tracking time, calculated from the source impedance, works out to be so these fields aren’t significant and are probably only there for backwards compatibility.

If the tracking time is less that {15 t_{CP\_ADC}} the tracking of a selected channel can be carried out while the previous channel is being converted and the total time between ADC_Start pulses is {20 t_{CP\_ADC}}. In this case we can calculate the maximum ADC clock frequency as a function of the source impedance. A plot of this is shown below

fzPlot

If the tracking time is greater than {15 t_{CP\_ADC}} the time between ADC_Start pulses must be increased to allow for this.

In either case, to ensure correct tracking for the first channel to be converted the startup time must be greater than or equal to the tracking time.

Posted in Arduino | Leave a comment