Fastest Arduino DUE timer interrupts?

So I found some code on here for utilizing the DUE’s timers to create an interrupt. After messing around with it to see how fast I can get the DUE to flip the PORTD values, it is switching from high to low on the one pin at about 680.0 nanoseconds. I was wondering if there was a faster way to do this?

I have attached the code and pasted it below. I apologize in advance if I didn’t provide enough information and for the simple copy and paste of the code below. This is my first post.

void setup() {
// put your setup code here, to run once:
pinMode(14, OUTPUT);
pinMode(9, OUTPUT);
REG_PIOD_OWER = 0x0060;

startTimer(TC1,0,TC3_IRQn, 100000);

}

void TC3_Handler(){
TC_GetStatus(TC1, 0);

REG_PIOD_ODSR = REG_PIOD_ODSR ^ 0x00000010;

}

void loop() {
}

void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency){

//Enable or disable write protect of PMC registers.
pmc_set_writeprotect(false);
//Enable the specified peripheral clock.
pmc_enable_periph_clk((uint32_t)irq);

TC_Configure(tc, channel,TC_CMR_WAVE|TC_CMR_WAVSEL_UPDOWN_RC|TC_CMR_TCCLKS_TIMER_CLOCK1);//|TC_CMR_CPCSTOP);
uint32_t rc = 1;//VARIANT_MCK/128/frequency;

TC_SetRA(tc, channel, rc);
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);
}

sketch_jan17a.ino (983 Bytes)

That sounds entirely plausible, given the overhead of calling an interrupt routine.

What are you trying to do?

I'm working with Andross on this project, so I can answer what we are trying to do. However it should be stated that Andross is considerably better at programming than I am.

We are trying to drive a phase shifted H Bridge at about 20kHz. I've attached a picture of what we are trying to do below with 4 MOSFETs. We are driving a transformer instead of a motor, and the transformer has a bridge rectifier on the secondary side.

From the diagram you can see that each MOSFET has an individual duty cycle of 50%, and the Rectified duty cycle, D in the diagram, is changed by changing the delay between firing the sets (QA & QB, QC & QD). Hopefully that makes sense.

Our problem is that we don't want to use delays, we want this to run in the background so we can still use our peripherals and have feedback to adjust the timing. We can get it to work the way he posted above, however our resolution is terrible. As he stated our fastest time is about 680nS, however our typical time was 2-3uS. When you are dealing with 50uS periods, that is horribly slow.

Any other ideas besides interrupts are also welcome.
Thanks!

A quick browse of the SAM3X datasheet shows the timer-counters have a 'waveform mode' which will probably do what you want. It looks like it would only use one (of three) timer-counters to do it. Program the registers with the right values and then you never have to spend any processor cycles on it at all.

Thank you for the response MorganS. We do have the TC_CMR_WAVE bit set, so I do believe we are using the waveform mode. What do you mean when you say we won't have to spend any processor cycles on it all? What register values are you referring to there? Thanks again for the help.

If you set the values properly for the timers then you don't use any interrupts to change the values of he external pins. The timers do that for you. You may use an interrupt if you need to run some code synchronously with the PWM but that usually isn't necessary.

Just have your code set the timers up to do whatever you need (frequency, duty cycle) and then change those values as often as you need. You shouldn't be using interrupts to actually operate the pins.

Thank you once again for the fast response MorganS. I guess the part I'm having trouble with is when trying to monitor the TIOA output after

TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_ACPC_TOGGLE | TC_CMR_ASWTRG_TOGGLE | TC_CMR_CPCTRG | TC_CMR_TCCLKS_TIMER_CLOCK1)

and other variations of the above code, the pin that is supposed to be the TIOA pin for that timer stays at a solid 3.3V. I've made sure to set the pin as an output. Do you have any idea what I am doing wong or why it is not toggling?

Have you download and read data sheet? Section 39 PWM:

The PWM macrocell controls 8 channels independently. Each channel controls two complemen-
tary square output waveforms. Characteristics of the output waveforms such as period, duty-
cycle, polarity and dead-times (also called dead-bands or non-overlapping times) are configured
through the user interface.

Looks exactly like you time diagrams posted above. Though, same time overcomplicated. If its me, I'd dig a gogle upside down with pattern "sam3 PWM example code C".

For your question, here is example of setting pin:

void setup()
{
  Serial.begin (115200) ; 
  adc_setup ();         
  tmr_setup ();         
  pio_TIOA0 ();  // drive Arduino pin 2 at 48kHz to bring clock out
}

void pio_TIOA0 ()  // Configure Ard pin 2 as output from TC0 channel A (copy of trigger event)
{
  PIOB->PIO_PDR = PIO_PB25B_TIOA0 ;  // disable PIO control
  PIOB->PIO_IDR = PIO_PB25B_TIOA0 ;   // disable PIO interrupts
  PIOB->PIO_ABSR |= PIO_PB25B_TIOA0 ;  // switch to B peripheral
}
 
void tmr_setup ()
{
  pmc_enable_periph_clk (TC_INTERFACE_ID + 0 *3 + 0) ;  // clock the TC0 channel 0

  TcChannel * t = &(TC0->TC_CHANNEL)[0] ;    // pointer to TC0 registers for its channel 0
  t->TC_CCR = TC_CCR_CLKDIS ;  // disable internal clocking while setup regs
  t->TC_IDR = 0xFFFFFFFF ;     // 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, = 42MHz)
              TC_CMR_WAVE |                  // waveform mode
              TC_CMR_WAVSEL_UP_RC |          // count-up PWM using RC as threshold
              TC_CMR_EEVT_XC0 |     // Set external events from XC0 (this setup TIOB as output)
              TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
              TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR ;
  
  t->TC_RC = TMR_CNTR;// 875 ;     // counter resets on RC, so sets period in terms of 42MHz clock
  t->TC_RA = TMR_CNTR /2;// 440 ;     // roughly square wave
  t->TC_CMR = (t->TC_CMR & 0xFFF0FFFF) | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET ;  // set clear and set from RA and RC compares
  t->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ;  // re-enable local clocking and switch to hardware trigger source.  
}

Dispite AtMega, you DON"T set pin as output, it's periferial B should take care of driving, page 50? in data sheet tells which timer associated with corresponding pin.

Awesome. Thank you, Magician. I have looked through the data sheet but it still wasn't completely clear to me. This is my first experience with this chip so I'm kind of a newbie with this one. Your help is greatly appreciated.

Andross:
Awesome. Thank you, Magician. I have looked through the data sheet but it still wasn’t completely clear to me. This is my first experience with this chip so I’m kind of a newbie with this one. Your help is greatly appreciated.

I feel newbie myself, some parts of the SAM3 is still dark matter for me, including PWM.
Atmel has “asf” - their derivatives of the CMSIS, basicaly huge library to help to configure hardware.
http://asf.atmel.com/docs/latest/sam3s/html/sam_pwm_quickstart.html
I haven’t experimented with PWM on arduino yet, but there is a file inside /arduino~/hardware~/arduino~/sam~/system pwmc.h
and most likely arduino IDE would run “asf” example