Go Down

Topic: Timer Interrupts on Due (Read 88694 times) previous topic - next topic

jgmdavies

@WomensFashionArt

Yep, your understanding is correct.  The software delay I inserted (the 'for' loop) is irrelevant, as the 'digitalWrite' is causing the 2 us odd delay I wanted to get a reasonable pulse out.

I know how easy it is easy to miss something when you're head-scratching, like the toggle 'I = !I'  :D

The Due Timer code contributed by others in this thread will be very useful.

Re. your other query:
Quote
Also, we need to synchronise the start of these pulses with some other Due's so that they all output synchronised pulses. Can anyone help us with that? Do we simply re-start the timer and, if so, how?


I would output a pulse each cycle from a digital pin on the 'master' Due, and connect it to an unused digital input on each 'slave' Due. You then need to use a hardware interrupt, i.e. an ISR, on each slave Due to reset each slave timer.  I'm afraid I haven't got suitable code for the Due handy, but maybe someone else has?

Jim

@Jim; thanks so much for your pro-active engagement. No can do with the sync I'm afraid, there's 20m of cables between them and all sync is being done over this cable. I'm pretty sure that we'll end up using an interrupt of some sort so that all of them are able to reset at exactly the same time. This is our progress so far. It's reduced the PWM frequency to 2Khz for now (the Due can't handle the logic at the requisite 1,000,000 interrupts / second, but we'll work on that). This seems to work just fine and the comments should show the way.

It's late and we're off for the day, but hope that this is of use to somebody.

We'll update it as we go along so that others may benefit from the discussion.

Thanks again Jim, your help is very much appreciated.

Rgs,
WFA_Dev
Kind regards
Dev team

#32
Jan 05, 2013, 11:20 am Last Edit: Jan 06, 2013, 05:22 am by WomensFashionArt Reason: 1
@Jim; the code would be rather useful here, wouldn't it... 8)

[FOLLOW-UP EDIT - 6 JAN 2013] Updated the code to approximate our 10Khz signal with 0...100% duty cycle.
Note: the frequency generation algorithm (uint32_t rc = VARIANT_MCK/3000/frequency; ) does not provide an accurate frequency. We've tested between 5Khz and 10Khz, for 5Khz we get approx. 5.1Khz, and for 10Khz we get 9.26Khz - as close as we can get it to 10Khz. In between the 5Khz and 10Khz, results vary wildly... please check your own numbers before relying too much on this routine.

Quote

volatile char On;
volatile char Total;
volatile char Max;

int PWM_Percent;
int PWM_Freq;

//TC1 ch 0
void TC3_Handler()
{
  
  // reset interrupt 
  TC_GetStatus(TC1, 0);

  // process percentage-based PWM waveforms
  
  // If count is at leading edge, raise pulse
  if (Total == 0) {
    digitalWrite(13,1);
  }
  // If count is at trailing edge, drop pulse
  else if (Total == On) {
    digitalWrite(13,0);
  }
      
  Total += 1;
  
  // If count is at 100%, reset to zero and start all over again
  if (Total > Max) {
    Total = 0; 
  }
}

// End TC3_Handler()

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_CLOCK3);
  uint32_t rc = VARIANT_MCK/3000/frequency; 
  TC_SetRA(tc, channel, rc/2);
  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(){
  
  // Use the LED for now
  pinMode(13,OUTPUT);
  
  // Set the total to zero
  Total = 0;
  
  // Set pulse width to 50%
  PWM_Percent = 50;
  
  // Set interrupt frequency
  PWM_Freq = 10000; //

  // -------------------------------
  // calculate cycles
  On = PWM_Percent; //
  
  // set maximum percentage at full 100%
  Max = 100; //

  // -------------------------------
  
  // Start the timer
  startTimer(TC1, 0, TC3_IRQn, PWM_Freq); //TC1 channel 0, the IRQ for that channel and the desired frequency

}

void loop(){
}


Kind regards
Dev team

selfonlypath

I really don't understand why you guys are not fully using the the complete potential of timer possibilities, of course requires fine register initialization but you could get very precise high frequency PWM even beyond 500 KHz or 1 MHz.

For the moment, i've doing so for years with arduino mega on my power electronics project (plasma drivers, full H-bridge, MWO inverters...) many of them, see old post then specific update code even though now is even more refined http://arduino.cc/forum/index.php/topic,8162.msg65115.html#msg65115 )

I do have an arduino DUE but as explained on other threads recently, I cannot download my actual MEGA projects using advanced arduino mega timer management because USB link of DUE is full of bugs.

Again I insist, just program the proper WAVESEL value and other registers, there is NO need to make interrupts slowing down and skewing the PWM jitter precision if using a timer, in particular with DUE being much more sophisticated timer possibilities than MEGA !

Just my 2 cents

@Selfonlypath:

Thanks for your contribution. I don't necessarily disagree with your position, but the documentation (even the complete data sheet) isn't entirely clear on what / how these registers are programmed. Further, there is a serious shortage of programming examples in Atmel's documentation for these chips (well, in our opinion anyway).

All references to the Sam3A4C registers include stuff like setting timers as peripherals, using nested interrupts, programming the timers and cascades; all without examples and/or any guiding principles.

Consequently it is difficult (if not near-on impossible) for those of us without experience with this chip to even begin to explore its potential. Even using the Arduino IDE - which is still in Beta stage - we are still experiencing issues - it's early days yet.

For now, we are getting a relatively clean 9Khz signal over which we have full control - because it is software generated. We can modify the waveform - if and as we please. We can change its duty cycle - even by fractions of a percent if needed, and - because the waveform is generated in software - we are able to synchronise it accurately across multiple Arduino Due's.

So, in conclusion, yes - all things being equal your point is entirely valid.

However, until there is more clarity for us on how to accurately program the registers, and until we are able to identify some examples out there that we can piggy-back on, this does the job for us.

It's not an ideal world out there; we simply get the job done for now.

J.

Kind regards
Dev team

selfonlypath

#35
Jan 06, 2013, 07:22 am Last Edit: Jan 06, 2013, 07:36 am by selfonlypath Reason: 1
I do agree that the Sam... datasheet register are not very detailed, maybe a mix of Atmel releasing too early beta datasheet or whatever.

You might want see this video where I'm using the four 16-bits MEGA timers, each being specifically delayed 90°, 180°, 270° with less than 62.5 ns

http://www.youtube.com/watch?v=sTSF23NCw8E

P.S. In fact, there really SIX 16-bit timers, two of them are being emulated by my specific protoshield using some 74HCxy chips

Just hoping the arduino team will soon fix the USB serial issue via a new IDE release, at least on my side I cannot afford to migrate my actual project MEGA software using very advanced timer register tricks since i'm shuttling more than 5000 VAR's with my igbt's drivers, blue smoking and $$$ gone !

Once DUE serial USB will be OK, I'll look deeper on the DUE timers which i feel from datasheet are very very interesting with fascinating new features.

@ SelfOnlyPath:

We're out on the yoga bit...  :smiley-mr-green: - informative video.
There is broad agreement that chip-generated PWM / waveforms will end up being superior to our (temporary) solution.

However, let's not forget that this is software; not hardware. We work with what we know and can realistically deliver at the highest possible quality in an acceptable timeframe. Once we understand the timers a bit better, we'll simply replace that bit of code.

Eliminates wasteful research, achieves the objective, and saves standing still altogether waiting for the right solution to arrive - :)

Kind regards
Dev team

selfonlypath

#37
Jan 06, 2013, 07:45 am Last Edit: Aug 26, 2014, 08:38 pm by selfonlypath Reason: 1
I really hope to have access to a new IDE so I can start using DUE on ALL my projects, more particularly its timers and interrupt routines.

You'll notice some of my boards hosting the MEGA as piggy board are in fact fully space compatible with DUE, the board were designed more than 1 year ago betting DUE will come up.

In fact, my special loose-coupled ferro-resonant project is bit stuck due to lack of more advanced timer low level inside MEGA.

As you said, world is not perfect but keeps moving.



selfonlypath

P.S. You might notice from time 7min 0s in the video that actually I live update by ISR (Interrupt Software Routines) all the FOUR internal 16-bit timers register so you'll se a global frequency sweeping up. Due to the special topology of my circuit, this is equivalent to have arduino MEGA-generate phase locked 8 independent PWM rails aka 8 channel frequency generator.

http://www.youtube.com/watch?v=sTSF23NCw8E

Once DUE will become more mature and guess as you said, the Atmel datasheet, such project will be easier with more timers and software possibilities with incredible few ns precision jitter.

jgmdavies

@selfonlypath:  Very impressive - well done!

@WomensFashionArt:

No can do with the sync I'm afraid, there's 20m of cables between them and all sync is being done over this cable. I'm pretty sure that we'll end up using an interrupt of some sort so that all of them are able to reset at exactly the same time.

... the Due can't handle the logic at the requisite 1,000,000 interrupts / second


Couple of queries:


  • How well synchronized do the different Dues have to be?   10 us, 1 ms, 1s ?

  • And how did you get the 1 MHz figure?  Is it from the precision you want for each part of the PWM cycle?



Best,
Jim

Hi Jim,

Thanks for the questions.

1) "How well synchronised do the different Dues have to be" 

We'd like to get it below 20us. However, there are some obstacles to this. Firstly, total capacitance, line driver & logic gate delays will add some delays. We have not yet calculated those, but they are - presently - thought to be within our limits. Our second problem is that - for a new design - we'd like to go radio (probably some variant of 802.11 for its broad availability). That puts the cat among the pigeons because now that very fast response time is becoming increasingly difficult to achieve. Again, we haven't done the maths, but we are pretty sure that there are going to be complications. Our middle name... LOL.


2) "How did you get the 1 Mhz figure"? 

Well, 1,000,000 interrupts for 10 Khz leaves 100 interrupts for each cycle. In other words, 10 Khz @ between 0% and 100% duty cycle in 1% increments.

However, as these units will - initially - only see service inside our studios, we are fine with 5 Khz (which corresponds to exactly 5 pulses of light for a 1/1000 shutter speed on our cameras) - something which, thanks to the Due's fast clock - we have already achieved.

==============================

Unfortunately we only have a small hobby scope at our disposal and its resolution is inadequate for testing the Sync. However, there is a solution (we think) in that we are considering using an 8 input AND gate which will allow us to test the synchronicity of up to 8 Due's by the following methodologies:

* Assume pulses are initially out-of-phase by - say - 50%. That gives a net duty cycle of 25% on a 50% PWM (the AND gate is shut for the rest of the time because not all inputs are high).
* Issue a SYNC pulse to the Due's
* Verify that the AND gate output pulses now show a 50% duty cycle.

Whilst the above is inadequate to verify whether or not we were able to keep our response time sub 20 us, it will show us that our SYNC system is working, and that all the PWM signals are now lining up nicely.

The reason "jitter" isn't that much of an issue for us is, that at lower shutter speeds (and @ 10 Khz), each exposure is likely to be subjected to - say - 80 light pulses (1/125 sec). Even if we missed an entire pulse (not overly desirable, but not catastrophic either), we'd only experience a variance of just over one percent; not distinguishable by the naked eye.

Hope that answers some of your questions (as well as some you haven't asked, but are directly related).

Rgds, J.
Kind regards
Dev team

Hi all,
We were wondering, with so much confusion about timers, PWM etc. whether one of our standard code blocks might come in handy.
This one trades resolution for frequency (as you do). Hope it is useful to somebody; nothing lost if it's not.

Quote


// Software PWM for the Arduino Atmel 328p @ 16MHz
//
// Women's Fashion Art Dev team
// 7 January 2013
// 
// Default settings: 
// volatile byte Maximum_Resolution_In_Percent = 50;
// byte Duty_Cycle_In_Percent = 50;
//
// Measured performance
// Freq: 3.27kHz
// Duty: 49.9%
// Vrms: 2.44V
// Vpp: 5.02V
// Vmin: 80.0 mV
// Vmax: 5.12V
// Vavg: 2.60V
// Target: Arduino Duemilanove - genuine
//
// Version 1.0 - 18 December 2012
//

#include <io.h>

// Variables
volatile byte Count;

// User variables - change these to suit
// volatiles
//
volatile byte Pin = 9;
volatile byte HighCount = 0;
volatile byte Maximum_Resolution_In_Percent = 50; // do not exceed 100% here...

// non volatiles
//
byte Duty_Cycle_In_Percent = 50; // do not exceed 100% here either...

// Setup routine
//
void setup(){

  // Set user's preferred pin to output
  //
  pinMode(Pin, OUTPUT);

  // Set up the high count
  HighCount = DoCalcs(Maximum_Resolution_In_Percent, Duty_Cycle_In_Percent);
  
  // Clear interrupts
  //
  cli();

  // Configure timer registers
  //
  TCCR2A = 0;//
  TCCR2B = 0;//
  TCNT2  = 0;//
  
  // set compare match register
  // OCR2A = 99; // 200 Hz at 100% or 400 Hz at 50%
  // OCR2A = 49; // 400 Hz at 100% or 800 Hz at 50%
  // OCR2A = 24; // 800 Hz at 100% or 1.6 Khz at 50%
   OCR2A = 11; // 1.6 kHz at 100% or 3.2 kHz at 50%   

  // CTC mode
  //
  TCCR2A |= (1 << WGM21);
  //CS11 bit for 8 prescaler
  //
  TCCR2B |= (1 << CS11);   
  // timer compare interrupt
  //
  TIMSK2 |= (1 << OCIE2A);

  // Re-enable interrupts
  //
  sei();
  
  // Create a dependable PWM sequence
  //
  digitalWrite(Pin, HIGH); // Start off with a high pulse
}

// Interrupt Service Vector (IDE preset)
//
ISR(TIMER2_COMPA_vect){

  // PWM High / Low Routine
  // Pull pin low once HighCount is achieved
  //
  if (Count == HighCount) {
    digitalWrite(Pin, LOW);
  }
  // Pull pin high once at the end of our resolution count
  //
  else if (Count == Maximum_Resolution_In_Percent) {
    digitalWrite(Pin, HIGH);
    Count = 0;
  }
    // Bump count by 1
    //
    Count += 1;
}

// Subroutines
//
int DoCalcs (byte Resolution, byte DutyCycle)
{
    // Set up the high count
  return (Duty_Cycle_In_Percent / (100 / Maximum_Resolution_In_Percent));
}

// Main loop
// This does nothing at present, but can add other stuff to this
// depending on how hard the timer is being driven....
//
void loop()
{
  while (1);
  {
    // do other stuff here
  }
}




Kind regards
Dev team

@SelfOnlyPath:
Yes we know. However, sometimes it is desirable - for example for PCB layout purposes - to be able to use a user-assigned pin. In some cases that will allow you to use a single-sided board instead of double, or a double-sided board in place of 4 layers. We take a rather holistic approach to such things and this is only one of several libraries - each with a specific purpose. We chose to list this one because it is the most flexible for users not familiar with the timers on these chips.
Kind regards
Dev team

@SelfOnlyPath:
Points taken. Frankly, if we needed jitter-free PWM we'd either use a dedicated chip (i.e. the uM-PWM) or drive an interrupt with a high precision crystal at the MCU's highest priority level. Personally I'd never rely on a software timer inside an MCU for highly time-critical PWM - no matter what anyone suggests. A nice 10Mhz crystal running through a /10 would give you a nice clean and (if temperature controlled) highly predictable reference signal that is ns accurate with a small correction lookup table (if needed).

If you want high precision, jitter free, you have to - in my humble view - look outside the MCU software counters at any rate. As noted hereinbefore, jitter is the least of our problems; we have up to 1.5% tolerance - well within the MCU's software capabilities for our timeframes (down to 1/125th of a second).
Kind regards
Dev team

@SelfOnlyPath:
Thanks for your expert help. All the best.
Kind regards
Dev team

Go Up