# Producing waveforms on Due through DAC

I'm currently trying to produce AC waveforms on the Due and have run into some issues with lower frequencies. The Due has been producing the waveforms correctly at 12.4 hz but when I have tried lower ratios of it, say 6.2Hz, the peak amplitude of the signal drops. I have been writing the output amplitudes to Serial and I am seeing the correct peak amplitude, it is only when I measure them through an oscilloscope that I see a drop in amplitude.

I also cannot produce a DC signal through the DACs, once again in Serial I am seeing the correct value for the DC voltage but if I measure on the oscilloscope I get 0v. Any idea why the amplitude of the wave is dropping at lower/DC voltages?

Did you set the scope to DC or AC.
If set to AC, then the scope blocks DC (and very low frequencies).
Leo..

Scope was set to AC or DC depending on which signal I was looking for. I could still see the AC waveform, the amplitude was about 80% that of what it should be, so the signal being blocked wasn't an issue.

The question was if you did set the scope to DC when you measured that very low frequency.

Maybe you didn't understand.
When measuring a very low frequency with the scope set to AC, the buildin highpass flter will gradually reduce peak/peak voltage below the corner frequency of the scope's input filter.
Leo..

I set the scope to AC to measure all AC frequencies and had it set to DC when I tired to measure the DC signal.

At these very low frequencies, I guess it could be an issue with the refresh period (see DACC_MR_REFRESH).

Post your code (between code tags).

Here is my code:

``````/* Arduino generate the PE voltage for Lambda Zup. */

/* Signal behaviours.*/
unsigned int peakAmplitude = 150; // Amplitude of the signal in [0, 4095].
float frequency = 6.2*2;  // Frequency of the signal in Hz. PE signal.
float period = 1 / frequency;  // Period of the signal.

/* Transient signal behaviours.*/
int signal1Amplitude = 0;
int signal2Amplitude = 0;

/* Behaviour of signal 1 (starting and stopping signal)*/
bool signalOn = true;
long onTime = 1000000000 * period;
long offTime = 0 * period;

/* Timing variables and termination conditions.*/
unsigned long startTime = 0;
unsigned long cycleStartTime = 0;
unsigned long currentTime = 0;
unsigned long previousTime = 0;
long remainingOnTime = onTime;
long remainingOffTime = offTime;
int cycle = 1;  /* The current cycle we are on*/
int cycles = 10;  /* The number of cycles that will happen.*/
unsigned long cyclePause = 0 * period / 8.0 ;  /* The amount
of time to pause at the end of each cycle. This gives the phase change.
If we do not want phase change we just put it to zero*/

/* Trigger and hardware.*/
int trigger = 1;
int pin = 53;   /* Connected to digital pin 53*/

void setup() {
Serial.begin(115200);  /* Boundrate for transfering data*/
Serial.println("[Setup] Test BZ ");  /* This just print*/
analogReadResolution(12);  /* It is defining the 12 bits D2A*/
analogWriteResolution(12);  /* It is defining the 12 bits D2A*/
pinMode(pin, INPUT);  /* sets the digital pin as input*/
Serial.println("[Setup] Setup complete.");
}

void loop() {
/* Waiting for the trigger.*/
Serial.println(frequency, 5);
Serial.println("[Loop] Waiting for trigger.");
wait_for_trigger();
Serial.println("[Loop] Trigger block passed.");

/* Now we start generating signals!*/
startTime = micros();
previousTime = startTime;
cycleStartTime = startTime;

Serial.println("[Loop] Start time recorded as:");
Serial.println(startTime);
Serial.println("[Loop] Signal dump follows:");
Serial.println("time (microseconds), signal1, signal2");
while (cycle <= cycles){
currentTime = micros();

/* Signal 1 is on.*/
if (signalOn == true){

// Process timings.
remainingOnTime = remainingOnTime - currentTime + previousTime;
if (remainingOnTime <= 0){
/* Serial.println("[Loop] On-time ended at time:");*/
/* Serial.println(currentTime);*/
/* Serial.println("[Loop] On-time ended at cycle:");*/
/* Serial.println(cycle);*/
signal1Amplitude = 0;
signalOn = false;
remainingOffTime = offTime + cyclePause - currentTime + previousTime;
}
else{
/* Calculate signal amplitude.*/
signal1Amplitude = peakAmplitude * cos(1 * TWO_PI * frequency * (currentTime - cycleStartTime) * 0.000001);
}
}

// Signal 1 is off.
else{
signal1Amplitude = 0;

/* Process timings.*/
remainingOffTime = remainingOffTime - currentTime + previousTime;
if (remainingOffTime <= 0){
/* Serial.println("[Loop] Off-time ended at time:");*/
/* Serial.println(currentTime);*/
/* Serial.println("[Loop] Off-time ended at cycle:");*/
/* Serial.println(cycle);*/
signalOn = true;
remainingOnTime = onTime;
cycle = cycle + 1;
cycleStartTime = currentTime;
}
}

/* Generate signal 2 relative to the start time, not the cycle start time. This means that the phase will not change with the cycle.*/
signal2Amplitude = peakAmplitude * cos(0.5 * TWO_PI * frequency * (currentTime - startTime) * 0.000001);

/* Send the signals to output at the same time.*/
analogWrite(DAC1, signal2Amplitude + 2047);  /* The white one.*/
analogWrite(DAC0, signal1Amplitude + 2047);  /* I want to look at the PE signal in osciloscope so I changed it           red one*/

/* Log stuff */
// Serial.println("[Loop] Current time:");
Serial.println(currentTime - startTime);
// Serial.println("[Loop] Signal 1 (stop-start signal) amplitude:");
Serial.print("[Loop] Signal 1: ");
Serial.println(signal1Amplitude);
// Serial.println("[Loop] Signal 2 (always-on signal) amplitude:");
Serial.print("[Loop] Signal 2: ");
Serial.println(signal2Amplitude);

/* Prepare for next iteration.*/
previousTime = currentTime;
}

/* Exit safely. Yay!*/
Serial.println("[Loop] Loop complete.");
exit(0);
}

void wait_for_trigger() {
/* This function holds execution until five seconds after BZ releases the trigger. */
while (trigger == 0){
}
delay(5000);
}
``````

The trigger function is not currently being used.

I just tried outputting a DC signal and measuring it with a multimeter but I recieved a reading of 0v. Tried also outputting a frequency of 12.4 hz but this time could see the alternating voltage on the multimeter.

From the point of view of a 50,000,000Hz scope, 6.4Hz is so close to DC that you should be using the DC range to measure it.

Try this code for a precise DACC conversion frequency of 6 Hz triggered by a Timer Counter output (TIOA2).

(I didn't test it though):

``````/***********************************************************************************/
/***                          DACC conversions  at a 6 Hz frequency                   ***/
/**********************************************************************************/
void setup() {

tc_setup();
dacc_setup ();

}

void loop() {

}

void dacc_setup ()
{

PMC->PMC_PCER1 |= PMC_PCER1_PID38 ;       // DACC power on
DACC->DACC_CR = DACC_CR_SWRST ;           // DAC reset

DACC->DACC_MR = DACC_MR_REFRESH (1)      // Warning  : Minimum at 1 !!!!!
| DACC_MR_TRGEN_EN       // External trigger mode enable
| DACC_MR_TRGSEL(0b011); // DACC Conversion triggered by TIOA2

/* This might not be necessary
DACC->DACC_ACR = DACC_ACR_IBCTLCH0(0b10)
| DACC_ACR_IBCTLCH1(0b10)
| DACC_ACR_IBCTLDACCORE(0b01);
*/
DACC->DACC_CHER = DACC_CHER_CH0;       // enable channel 0 = DAC0

}

/*************  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_CLOCK4  // MCK/128, 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 = 109375;  //<*********************  Frequency = (Mck/128)/TC_RC  Hz = 6 Hz
TC0->TC_CHANNEL[2].TC_RA = 1000;  //<********************   Any Duty cycle in between 1 and 109375

TC0->TC_CHANNEL[2].TC_IER = TC_IER_CPAS;                // Interruption on RA compare match
NVIC_EnableIRQ( TC2_IRQn );                             // Enable TC2 interruptions

TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable

}

/****************   Update DACC output inside the TC handler     ******/
void TC2_Handler() {

TC0->TC_CHANNEL[2].TC_SR;   // Clear status register

// Adjust the output value here in the range  0< DACC_CDR < 4095
// Note that DACC output is in the range 1/6 * 3.3 V and 5/6 * 3.3 V
DACC->DACC_CDR = 1000;     // Update the value to convert

}
``````