sine wave generator doesn't work

I'm going to make a device which generates time shifting frequency sine wave with Arduino Due.

However it doesn't works when its code has "delay()", so I can't make the time shifting function.

I have no idea to fix it.

I'd appreciate it if you could give me some advice about my trouble.

double i=0.00;
void setup() {
analogWriteResolution(12);
}
void loop() {
analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.022;
/*
delay(500);

analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.023;
delay(500);

analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.024;
delay(500);

analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.025;
delay(500);
*/
}

it doesn't works when its code has "delay()", so I can't make the time shifting function.

I have no idea to fix it.

I'd appreciate it if you could give me some advice about my trouble.

delay() stops the program completely for the delay period. You need to use a different technique if you need to keep the loop() function running freely

Have a look at Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

An example sketch to output a sin wave on both DACs:

/***********************************************************************************/
/*   DAC0 and DAC1 output of a sin wave - Frequency of sin = 44.1 KHz / sinsize    */
/***********************************************************************************/

const uint32_t sinsize  = 256 ;   // Size of buffer must be a power of 2
uint32_t sinus[2][sinsize];
  
volatile uint32_t bufn;

void dac_setup () {

  PMC->PMC_PCER1 = PMC_PCER1_PID38;     // DACC power ON
  DACC->DACC_CR = DACC_CR_SWRST ;       // Reset DACC

  DACC->DACC_MR = DACC_MR_TRGEN_EN                   // Hardware trigger select
                  | DACC_MR_TRGSEL(0b011)            // Trigger by TIOA2
                  | DACC_MR_TAG_EN                   // enable TAG to set channel in CDR
                  | DACC_MR_WORD_WORD                // write to both channels
                  | DACC_MR_REFRESH (1)
                  | DACC_MR_STARTUP_8
                  | DACC_MR_MAXS;

  DACC->DACC_IER |= DACC_IER_TXBUFE;                 // Interrupt used by PDC DMA
                
  DACC->DACC_ACR = DACC_ACR_IBCTLCH0(0b10)
                   | DACC_ACR_IBCTLCH1(0b10)
                   | DACC_ACR_IBCTLDACCORE(0b01);

  NVIC_EnableIRQ(DACC_IRQn);                         // Enable DACC interrupt

  DACC->DACC_CHER = DACC_CHER_CH0                    // enable channel 0 = DAC0
                    | DACC_CHER_CH1;                 // enable channel 1 = DAC1

  /*************   configure PDC/DMA  for DAC *******************/

  DACC->DACC_TPR  = (uint32_t)sinus[0];         // DMA buffer
  DACC->DACC_TCR  = sinsize;
  DACC->DACC_TNPR = (uint32_t)sinus[1];         // next DMA buffer (circular buffer)
  DACC->DACC_TNCR = sinsize;
  bufn = 1;
  DACC->DACC_PTCR = DACC_PTCR_TXTEN;            // Enable PDC Transmit channel request

}

void DACC_Handler() {
  
  uint32_t status = DACC->DACC_ISR;   // Read and save DAC status register
  if (status & DACC_ISR_TXBUFE) {     // move DMA pointer to next buffer
    bufn = (bufn + 1) & 1;
    DACC->DACC_TNPR = (uint32_t)sinus[bufn];
    DACC->DACC_TNCR = sinsize;
  }
}

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_CLOCK2  // MCK/8, 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 = 238;  //<*********************  Frequency = (Mck/8)/TC_RC = 44.1 MHz
  TC0->TC_CHANNEL[2].TC_RA = 40;  //<********************   Any Duty cycle in between 1 and TC_RC

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

void setup() {

  for(int i = 0; i < sinsize; i++) 
    {
   uint32_t chsel = (0<<12) | (1<<28);                      // LSB on DAC0, MSB DAC1 !!
   sinus[0][i]  = 2047*sin(i * 2 * PI/sinsize) + 2047;      //  0 < sinus [i] < 4096
   sinus[1][i] = sinus[0][i] |= sinus[0][i] <<16 | chsel;   // two buffers formated
                                                            // MSB [31:16]on channel 1
                                                            // LSB [15:0] on chanel 0
    }
  tc_setup();
  dac_setup();
}

void loop() {

}

Thank you UKHeliBob.

I have built a code like the below, however it doesn't work.
Would you give me an advice?

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 500;
double i=0.00;

void setup() {
  Serial.begin(115200);
  pinMode(DAC1,OUTPUT);
  analogWriteResolution(12);
  startMillis = millis();
}

void loop() {
  currentMillis = millis();
  if (currentMillis - startMillis >= period)
  {
    analogWrite(DAC1, 2048 + 2048 * sin(i));
    i+=0.022;
    startMillis = currentMillis;
  }

  if (currentMillis - startMillis >= period*2)
  {
analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.023;
startMillis = currentMillis;
  }

  if (currentMillis - startMillis >= period*3)
  {
analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.024;
startMillis = currentMillis;
  }

  if (currentMillis - startMillis >= period*4)
  {
analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.025;
startMillis = currentMillis;
  }
}

You don’t say what you mean by “doesn’t work” but looking at this portion of your code

  currentMillis = millis();
  if (currentMillis - startMillis >= period)
  {
    analogWrite(DAC1, 2048 + 2048 * sin(i));
    i += 0.022;
    startMillis = currentMillis;
  }
  if (currentMillis - startMillis >= period * 2)
  {

currentMillis - startMillis >= period will always be true before currentMillis - startMillis >= period * 2 so will the second statement ever be true ?

sorry for my poor reply…

I’ve remade the code, but it still doesn’t act the time shifting.

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 1000;
double i=0.00;

void setup() {
  Serial.begin(115200);
  pinMode(DAC1,OUTPUT);
  analogWriteResolution(12);
  startMillis = millis();
}

void loop() {
  currentMillis = millis();
  if (currentMillis - startMillis <= period)
  {
    analogWrite(DAC1, 2048 + 2048 * sin(i));
    i+=0.022;
    startMillis = currentMillis;
  }

  else if (currentMillis - startMillis <= period*2)
  {
analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.023;
startMillis = currentMillis;
  }

  else if (currentMillis - startMillis <= period*3)
  {
analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.024;
startMillis = currentMillis;
  }

  else if (currentMillis - startMillis <= period*4)
  {
analogWrite(DAC1, 2048 + 2048 * sin(i));
i+=0.025;
startMillis = currentMillis;
  }
}
  if (currentMillis - startMillis <= period)

This is going to be true most of the time so the else clauses will never be executed.

What exactly is it that you are trying to do ?

It became clear to act the time shifting when I had changed the frequency from infra sound to audible range.
I'm sorry for my confused reply.

Thank you for your advice.
I managed to make a one of loop shifting version.
However its performance is unstable.
So I’ll improve it later.

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 1000;
double i=0.00;

void setup() 
{
  Serial.begin(115200);
  pinMode(DAC1,OUTPUT);
  analogWriteResolution(12);
  startMillis = millis();
}

void loop() 
{
  currentMillis = millis();
  if (currentMillis - startMillis <= period)
  {
    analogWrite(DAC1, 2048 + 2048 * sin(i));
    i+=0.2;
  }

  else if (currentMillis - startMillis <= period*2)
  {
    analogWrite(DAC1, 2048 + 2048 * sin(i));
    i+=0.4;
  }

  else if (currentMillis - startMillis <= period*3)
  {
    analogWrite(DAC1, 2048 + 2048 * sin(i));
    i+=0.8;
  }

  else if (currentMillis - startMillis <= period*4)
  {
    analogWrite(DAC1, 2048 + 2048 * sin(i));
    i+=1.6;
  }
  else
  {
    startMillis = currentMillis;
  }
}

I made a improved version which perform is stable.

below links are movies of the device before and after.

https://youtu.be/nzPz1L32ggA

https://youtu.be/LENNIoOxBLs

And it’s a improved source code.

#include "Waveforms.h"

#define oneHzSample 1000000/maxSamplesNum  // sample for the 1Hz signal expressed in microseconds 
unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 1000;

volatile int wave1 = 0;

int i = 0;
int sample=55;


void setup() 
{
  analogWriteResolution(12);  // set the analog output resolution to 12 bit (4096 levels)
}

void loop() 
{
  currentMillis = millis();
  if (currentMillis - startMillis <= period)
  {
    sample = map(9, 0, 4095, 0, oneHzSample);
    sample = constrain(sample, 0, oneHzSample);

    analogWrite(DAC1, waveformsTable[wave1][i]);  // write the selected waveform on DAC1

    i++;
    if(i == maxSamplesNum)  // Reset the counter to repeat the wave
    i = 0;

    delayMicroseconds(sample);  // Hold the sample value for the sample time
  }
  
  else if (currentMillis - startMillis <= period*2)
  {
    sample = map(8, 0, 4095, 0, oneHzSample);
    sample = constrain(sample, 0, oneHzSample);

    analogWrite(DAC1, waveformsTable[wave1][i]);  // write the selected waveform on DAC1

    i++;
    if(i == maxSamplesNum)  // Reset the counter to repeat the wave
    i = 0;

    delayMicroseconds(sample);  // Hold the sample value for the sample time
  }

  else if (currentMillis - startMillis <= period*3)
  {
    sample = map(7, 0, 4095, 0, oneHzSample);
    sample = constrain(sample, 0, oneHzSample);

    analogWrite(DAC1, waveformsTable[wave1][i]);  // write the selected waveform on DAC1

    i++;
    if(i == maxSamplesNum)  // Reset the counter to repeat the wave
    i = 0;

    delayMicroseconds(sample);  // Hold the sample value for the sample time
  }

  else if (currentMillis - startMillis <= period*4)
  {
    sample = map(6, 0, 4095, 0, oneHzSample);
    sample = constrain(sample, 0, oneHzSample);

    analogWrite(DAC1, waveformsTable[wave1][i]);  // write the selected waveform on DAC1

    i++;
    if(i == maxSamplesNum)  // Reset the counter to repeat the wave
    i = 0;

    delayMicroseconds(sample);  // Hold the sample value for the sample time
  }

  else
  {
    startMillis = currentMillis;
  }
}

Waveforms.h

#ifndef _Waveforms_h_
#define _Waveforms_h_

#define maxWaveform 4
#define maxSamplesNum 120

static int waveformsTable[maxWaveform][maxSamplesNum] = {
  // Sin wave
  {
    0x7ff, 0x86a, 0x8d5, 0x93f, 0x9a9, 0xa11, 0xa78, 0xadd, 0xb40, 0xba1,
    0xbff, 0xc5a, 0xcb2, 0xd08, 0xd59, 0xda7, 0xdf1, 0xe36, 0xe77, 0xeb4,
    0xeec, 0xf1f, 0xf4d, 0xf77, 0xf9a, 0xfb9, 0xfd2, 0xfe5, 0xff3, 0xffc,
    0xfff, 0xffc, 0xff3, 0xfe5, 0xfd2, 0xfb9, 0xf9a, 0xf77, 0xf4d, 0xf1f,
    0xeec, 0xeb4, 0xe77, 0xe36, 0xdf1, 0xda7, 0xd59, 0xd08, 0xcb2, 0xc5a,
    0xbff, 0xba1, 0xb40, 0xadd, 0xa78, 0xa11, 0x9a9, 0x93f, 0x8d5, 0x86a,
    0x7ff, 0x794, 0x729, 0x6bf, 0x655, 0x5ed, 0x586, 0x521, 0x4be, 0x45d,
    0x3ff, 0x3a4, 0x34c, 0x2f6, 0x2a5, 0x257, 0x20d, 0x1c8, 0x187, 0x14a,
    0x112, 0xdf, 0xb1, 0x87, 0x64, 0x45, 0x2c, 0x19, 0xb, 0x2,
    0x0, 0x2, 0xb, 0x19, 0x2c, 0x45, 0x64, 0x87, 0xb1, 0xdf,
    0x112, 0x14a, 0x187, 0x1c8, 0x20d, 0x257, 0x2a5, 0x2f6, 0x34c, 0x3a4,
    0x3ff, 0x45d, 0x4be, 0x521, 0x586, 0x5ed, 0x655, 0x6bf, 0x729, 0x794
  }
  ,

};

#endif m