Clock Signal using Arduino Due

Hi guys,

I want to generate 7 clock signals in parallel between 100-1000Hz. Moreover they all should be differen and adjustable.
Means I will send via serial monitor a clock frequenz and a certain pin will generate the clock signal.

First idea was to use delay and simple digital.write HIGH /LOW with delay which can be adjust by changing the delay time.
But of course the speed of the whole program slows down......
By the way I want to use serveral other functions on the same arduino which should not be slowed down.

Second Idea was to use timers as clock generator. On Arduino Uno I did this allready once .... but the Ardino due is a real pain in the ass.... sorry :wink: , also iam not sure if the timer can be changed so easily while the program is running.

is there another easier option or does anybody is a littble familiar with the due timers ?
Is it possible to use the delay idea without slowing the whole program down ?

kind regards
kohlmeise :wink:

Found Something ...

// Black magic
void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
  pmc_set_writeprotect(false);
  pmc_enable_periph_clk((uint32_t)irq);
  TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
  uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
  TC_SetRA(tc, channel, rc/2); //50% high, 50% low
  TC_SetRC(tc, channel, rc);
  TC_Start(tc, channel);
  tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
  tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
  NVIC_EnableIRQ(irq);
}

void setup(){
  pinMode(13,OUTPUT);

  // Start timer. Parameters are:

  // TC1 : timer counter. Can be TC0, TC1 or TC2
  // 0   : channel. Can be 0, 1 or 2
  // TC3_IRQn: irq number. See table.
  // 40  : frequency (in Hz)
  // The interrupt service routine is TC3_Handler. See table.

  startTimer(TC1, 0, TC3_IRQn, 1000);

  // Paramters table:
  // TC0, 0, TC0_IRQn  =>  TC0_Handler()
  // TC0, 1, TC1_IRQn  =>  TC1_Handler()
  // TC0, 2, TC2_IRQn  =>  TC2_Handler()
  // TC1, 0, TC3_IRQn  =>  TC3_Handler()
  // TC1, 1, TC4_IRQn  =>  TC4_Handler()
  // TC1, 2, TC5_IRQn  =>  TC5_Handler()
  // TC2, 0, TC6_IRQn  =>  TC6_Handler()
  // TC2, 1, TC7_IRQn  =>  TC7_Handler()
  // TC2, 2, TC8_IRQn  =>  TC8_Handler()
}

void loop(){
}

volatile boolean l;

// This function is called every 1/40 sec.
void TC3_Handler()
{
  // You must do TC_GetStatus to "accept" interrupt
  // As parameters use the first two parameters used in startTimer (TC1, 0 in this case)
  TC_GetStatus(TC1, 0);

  digitalWrite(13, l = !l);
}

But how can I use a second Timer ? tried this like this :

// Black magic
void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
  pmc_set_writeprotect(false);
  pmc_enable_periph_clk((uint32_t)irq);
  TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
  uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
  TC_SetRA(tc, channel, rc/2); //50% high, 50% low
  TC_SetRC(tc, channel, rc);
  TC_Start(tc, channel);
  tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
  tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
  NVIC_EnableIRQ(irq);
}

void setup(){
  pinMode(13,OUTPUT);
  pinMode(12,OUTPUT);
  // Start timer. Parameters are:

  // TC1 : timer counter. Can be TC0, TC1 or TC2
  // 0   : channel. Can be 0, 1 or 2
  // TC3_IRQn: irq number. See table.
  // 40  : frequency (in Hz)
  // The interrupt service routine is TC3_Handler. See table.

  startTimer(TC1, 0, TC3_IRQn, 1000);
  startTimer(TC1, 1, TC4_IRQn, 500);
  // Paramters table:
  // TC0, 0, TC0_IRQn  =>  TC0_Handler()
  // TC0, 1, TC1_IRQn  =>  TC1_Handler()
  // TC0, 2, TC2_IRQn  =>  TC2_Handler()
  // TC1, 0, TC3_IRQn  =>  TC3_Handler()
  // TC1, 1, TC4_IRQn  =>  TC4_Handler()
  // TC1, 2, TC5_IRQn  =>  TC5_Handler()
  // TC2, 0, TC6_IRQn  =>  TC6_Handler()
  // TC2, 1, TC7_IRQn  =>  TC7_Handler()
  // TC2, 2, TC8_IRQn  =>  TC8_Handler()
}

void loop(){
}

volatile boolean l;

// This function is called every 1/40 sec.
void TC3_Handler()
{
  // You must do TC_GetStatus to "accept" interrupt
  // As parameters use the first two parameters used in startTimer (TC1, 0 in this case)
  TC_GetStatus(TC1, 0);

  digitalWrite(13, l = !l);
}
void TC4_Handler()
{
  // You must do TC_GetStatus to "accept" interrupt
  // As parameters use the first two parameters used in startTimer (TC1, 0 in this case)
  TC_GetStatus(TC1, 1);

  digitalWrite(12, l = !l);
}

Doesen´t work ... both channels generate a frequency but around 22 Hz ... instead of 1kHz

any idea ?

How accurate should the frequencies be and how much jitter can you tolerate?

The frequencies don´t need to be that precise... I would like to use them to run some pumps ... the frequencies should increase or decrease the pumpspeed.... as iam controlling the pumped volume via pressure sensors... i can tolerate some deviations in frequencies and jitter... as i want to drive 7 timers in parallel i expected some of these problems.

You have a frequency-controlled motor? I'd like to see that. Datasheet please? And the motor-driver,

You know, perhaps the Due is the right Arduino for this. If you're using delay then it yields control to other threads. You just need to put each process onto its own thread. See: http://www.arduino.cc/en/Tutorial/MultipleBlinks

First of all thank you!!!
Here comes the datasheet to the pump and motor-driver (OEM).

The pump which Iam using is called mp6.

Well that is a specialised piece of equipment.

I think you would be best looking at how others have driven large numbers of stepper motors with Arduinos, since they're basically frequency controlled too. 3D printers have 4-6 steppers and I know firmware exists to do this with a Due. I don't know the name of the firmware. Marlin is what I use in my printer, which has the same processor as an Arduino Mega.

If you don't mind some jitter you can use DDS from a regular timer interrupt at 10 to 20kHz
sort of rate.

For each output you need a phase and frequency variable, and add the frequency to the
phase on each interrupt - the top bit of the phase variable is copied to the relevant pin.

So to derive 300Hz using a 10kHz interrupt you would need a frequency value of
2^32 * 0.03 (about 128850000). From the main code you just adjust
the frequency values appropriately.

You modify the same volatile in 2 interrupts. Are you sure, that this is correct? I would use two static bools.

The multiple blink fits pretty good to my problem.
Another point ... is it possible to exchange the delay by a variable, so i could write a number to serial monitor and change the delay time ?