Timing problems with short 2...12 us pulses generation with PWM out

Hello Forum users,

I have used an UNO Rev. 3 (Atmega 328) to create 2...12 us pulses at a repetition rate (freq.) of 10Hz ... 2kHz. These pulses are made with TIMER 2 (8 bits / pin 3.) with no division, so it runs on 31250Hz. With a variable OCR2A (read in via a potmeter) I have sufficient control over de pulse width (resolution ~62ns/bit). So now I have the pulses I want, however at a repetition rate of 31250Hz instead of 10Hz ... 2kHz.

The latter is solved with a extra digital output; that acts as an ENABLE. It skips (eliminates) the excess of pulses by using an and hardware AND function. This works fine with an ISR on TIMER2 overflow.

In a next configuration I have introduced OCR2B to create a second pulse on pin 11. And now I have serious timing problems. The delay between the ENABLE (pin 7) and the PWM outputs (pin 3. and pin 11.) is to large to eliminate the pulses sufficiently. I see now much shorter pulses.

Anyone suggustions how to solve this problem? All solutions are welcome ...

Regards. Rtrab

I am confused by a few things - you are clocking at 16MHz by the sound of it, which implies a PWM frequency of 62.5kHz if using fast mode (you probably don't want to touch phase-correct mode for this sort of thing, it's there for smoother motor control).

You claim OCR2B is relevant to pin 11, but channel A is pin 11, channel B is pin 3...

You seem to be wanting to run the counter long enough to generate one pulse and then stop it?

And you haven't posted your code...

Hello MarkT, Thanks for answer.

The TIMER2 is running free and continuously generates short pulses (2...12us) properly. With a TIMER2 interupt I remove externally the excess of pulses by using an external hardwired AND function. Controlling this AND port is done with a digitalWrite(). The latter function creates my timing problems, because it takes approx. 4us to execute this function.

What about the wrong pinning suggest that there is a crossing somewhere on the two PCBs that are controlled by the UNO. This may explain (some of) my problems. I will check this a.s.a.p.

Thanks again and regards, Rtrab

p.s.: The code is not posted because I'm not at home at the moment.

I would not use PWM to define a pulse width, as you need interrupt subroutine anyway, and it takes 3 -6 usec to get in and back, it makes sense simply organize one main ISR 10 - 2 kHz , using TimerOne library for example, than inside ISR you setting a pin and waiting required amount of time doing while(--time). Of course to set and reset a pin (or few pins) you have to use direct port manipulation. Interesting part of this approach, is to set or reset pins simultaneously, if they belongs to different ports

I would do it slightly differently. First of all, use timer 1 not timer 2. Timer 1 is a 16-bit timer, therefore with a prescaler of 1 (to give your 62ns pulse width resolution), you can generate pulse frequencies down to 244Hz directly. Second, for lower pulse frequencies, there is no need to use external gating, because this gating is already included on the chip. You just need to enable generation of an interrupt at the end of the pulse, and in the ISR, set the COM1Ax bits to 0 to suppress the next pulse at the OCR1A output pin. Similarly for the OCR2A output pin.

[EDIT: corrected timer numbers]

you want a 2-12us pulse at 31250hz

31250hz=32us period.

to get 2us pulse, you just need to count to 32 using 0.0625us per count

modify the code I posted here

at 16mhz, each count is 0.0625us
to get 31250hz freq or 32us period, you need to count to 512, but since this is symmetrical, you need to count to 256.

if you try 8 bit pwm resolution, top is 255
set your OCR to 16 to get 2us pulse @31250hz (since phase correct pwm is symmetrical, you divide 32/2 to get 16)

set your OCR to 96 to get your 12us pulse @31250hz

void setup() {
DDRB |= _BV(PB5);
TCCR1A=0;
TCCR1B=0;
TCCR1A |= _BV(WGM10); //8bit phase correct PWM
TCCR1B |= _BV(CS10);
OCR1A = 96;//96=12us, 16=2us
TCCR1A |= _BV(COM1A1);
}

void loop() {

}

waveform, exactly what you want, no need to complicate things :slight_smile:

I think I misread what you need. I think you need a frequency of 2khz? or 10hz? which is it? nonetheless, the principle is the same to change the frequency

use my code in the other thread. you need the max count of 4000 (for ICR1 register) to get 2khz you will need to divide the clock further to get 10hz, as 16bits is not enough to get a count of 16000000 to get 10hz at div 1.

read up on mode 11 of waveform generation. that is what you need.

Second, for lower pulse frequencies, there is no need to use external gating, because this gating is already included on the chip.

My understanding, it’s software PWM, we are counting numbers of overflows for freq.< 244 Hz, than setting ISR register with remaining part ( the mode 8/10/12/14 only available, as both OCR’s busy) . Potentially a jitter issue, if remaining part may be low, so time to get out from last time interrupt happened (full cycle) and new interrupt to be served. I don’t know if TimerOne free of this complication.

Update: oops. one more message:

read up on mode 11 of waveform generation. that is what you need.

No, OCR is busy

this code

void setup() {
DDRB |= _BV(PB5);
TCCR1A=0;
TCCR1B=0;
TCCR1A |= _BV(WGM11);
TCCR1B |= _BV(WGM13)|_BV(CS10);
OCR1A = 16;
ICR1=4000;
TCCR1A |= _BV(COM1A1);
}

void loop() {

}

generates this waveform. 2us pulse at 2khz.

Magician:

Second, for lower pulse frequencies, there is no need to use external gating, because this gating is already included on the chip.

My understanding, it’s software PWM, we are counting numbers of overflows for freq.< 244 Hz, than setting ISR register with remaining part ( the mode 8/10/12/14 only available, as both OCR’s busy) . Potentially a jitter issue, if remaining part may be low, so time to get out from last time interrupt happened (full cycle) and new interrupt to be served. I don’t know if TimerOne free of this complication.

Update: oops. one more message:

read up on mode 11 of waveform generation. that is what you need.

No, OCR is busy

not sure what you mean. no interrupts are needed to get the waveform, just follow instructions for setting up waveform using mode 11. see my sample code.

not sure what you mean. no interrupts are needed to get the waveform, just follow instructions for setting up waveform using mode 11. see my sample code

Code looks o'k, MODE = 10 ? OP , AFAIU needs 10 Hz - 2 kHz range. Arduino is lacking "binding timers " feature, which implemented in cortex-3. Otherway, I can't see any "elegant" solution except limiting frequency resolution down to 1/244 or use external hardware

ah yes, its mode 10 not mode 11.

in order to change frequency, just change ICR register value. But in order to get the 10hz - 2000hz range, use div 16, which gives 1us per count to get 10 hz, you need to count to 50,000 (fits 16 bit) (set ICR1 to 50000) to get 2000 hz, count to 250 (set ICR1 to 250)

it can be done. all you need to do to modify freq is change ICR1 value, and to change the duty cycle, change the OCR1A value.

I just realized there is no div 16. so don't follow the numbers I gave in the previous post.

you will need to use div 64 to get 10hz using ICR1 of 12500, 2000hz using 62 (62.5 is the exact value, so there will be some error)., but since each count is 4us, the smallest pulse you can get is 8us.

So you will need to switch both clock divider and ICR1 and OCR1A values to change from 10hz to 2000hz at various pulse width from 2us to 12us.

doughboy: not sure what you mean. no interrupts are needed to get the waveform, just follow instructions for setting up waveform using mode 11. see my sample code.

Read the original post and my post again, then you will realise why your sample code doesn't meet the OP's requirements.

Right, I realized that hence I said I misread the original post. Anyway, the OP posted in another thread and only knew to use analogWrite. I replied with instructions to use timer registers. Instead of following up in the same thread, he started this new thread and made it appear he knows how to use timer rrlegisters. Anyways, the answer was given in the other thread and one just need to apply a little creativity to get the right waveform.

dc42: I would do it slightly differently. First of all, use timer 1 not timer 2. Timer 1 is a 16-bit timer, therefore with a prescaler of 1 (to give your 62ns pulse width resolution), you can generate pulse frequencies down to 244Hz directly. Second, for lower pulse frequencies, there is no need to use external gating, because this gating is already included on the chip. You just need to enable generation of an interrupt at the end of the pulse, and in the ISR, set the COM1Ax bits to 0 to suppress the next pulse at the OCR1A output pin. Similarly for the OCR2A output pin.

[EDIT: corrected timer numbers]

Dear dc42, thank you for answering. The use of timer 2 does decrease the pulse repetition frequency, but doesn't increase the resolution in pulse width adjustment. The use of the COM1Ax bits is new to me, and hopefully faster than the external gating I'm using now. Thanks again. Regards, Rtrab

doughboy: I think I misread what you need. I think you need a frequency of 2khz? or 10hz? which is it?

First of all, tanks for your help! I need all frequency values in between and preferably adjustable from outside, however that is one of the next steps. Regards, Rtrab

doughboy: use my code in the other thread. you need the max count of 4000 (for ICR1 register) to get 2khz you will need to divide the clock further to get 10hz, as 16bits is not enough to get a count of 16000000 to get 10hz at div 1.

read up on mode 11 of waveform generation. that is what you need.

Doughboym thanks for your help. 1) If you devide the clock further than the resolution is to small to make 2us and no longer 62ns/bit. I agree that the repetition rate will decrease of course. 2) Mode 11 is a Timer1 mode, now I'm using Timer2 in mode 5. Regards, Rtrab

I think for what you need, the simplest solution is to just use mode 0 (normal mode) and just control the pin output high low in the compare match ISR. You have total control of pulse width and frequency.. I don't think the suggestion to use the wave generation mode and setting com1a1 to 0 is not quite right, hence. might as well use normal mode.

if you div clock by 8, one count is 0.5us. to get a 2us pulse at 10hz, set pin high at count=0 set pin low at count=4 (4*0.5=2us) set pin high at count =200,000 (since this is higher than 8 or 16 bit, you have to count the overflows) for 2000hz pulse set pin high at count = 1000 (again if you are using 8bit timer, you need to count the overflows)