ATtiny85 PWM glitch

Go To Last Post
27 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello fellow freaks!

 I’m having a little problem in one of my projects… I’m trying to generate a series of (clean) PWM trains. It generally works, except at the beginning, when I get an (undesirable) glitch of 2 clocks periods. I’ve developed and simulated the project with Atmel Studio 7 (ver. 7.0.1645). Hoping there is a (another) bug in the simulator (it reports, for example, TC1 as 16 bit), I’ve tried to debug it on real hardware with an JTAGICE mkII, but having identical results. So, it’s not Atmel/Microchip… it’s me!
 The PWM outputs are not blinking a LED, or get filtered (DAC), but drive kind of sensitive hardware, so I would like to have this nasty glitch go away! Of course I’ve reduced the code to a minimum, to demonstrate the problem… here it is:

#define F_CPU	8000000
#define _NOP() do { __asm__ __volatile__ ("nop"); } while (0)

#include <avr/io.h>
	
FUSES =
{
	.low = (FUSE_SUT0 & FUSE_CKSEL3 & FUSE_CKSEL2 & FUSE_CKSEL0),				// Internal RC osc, 8MHz; StartUp Time 14CK + 64 ms
	.high = (FUSE_SPIEN & FUSE_BODLEVEL0 & FUSE_BODLEVEL1),
	.extended = EFUSE_DEFAULT,
};

int main(void)
{

/* Ports:
PB0 - pin 5 - \OC1A = Out
PB1 - pin 6 -  OC1A = Out
PB2 - PB5 = In , not used
*/
PORTB = 0b111100;	// pull-ups on PB2 - PB5
DDRB  = 0b000011;	// PB0 = \OC1A, PB1 = OC1A

OCR1C = 35;		// Just for test. In my app they're variable (var. freq., duty cycle of 50%).
OCR1A = 17;
// TCNT1 = 0; // it makes no difference, TCNT1 = 0 after reset
TCCR1 = (1 << PWM1A) | (1 << COM1A0) | (1 << CS11) | (1 << CS10);
 /* PWM mode, prescaler = 4 (TMR1_clk = 2MHz)
	COM1A1|COM1A0 = 01. According to DS:
	OC1A  cleared on compare match. Set when TCNT1 = $00
	\OC1A set on compare match. Cleared when TCNT1 = $00
 */
_NOP();	// PB0 = 0, PB1 = 0
_NOP();	// PB0 = 0, PB1 = 0
//	...but at this point PB0 = 1, PB1 = 0 !!...
_NOP();
_NOP();
// up to here - for 2 CK cycles;
// then it comes to its senses and reverses to PB0 = 0, PB1 = 1 until the compare match (TCNT1 = OCR1A)..
// From now on it works as expected.
_NOP();
_NOP();
_NOP();
_NOP();
_NOP();
_NOP();

while(1);

}

 The explanations/block diagrams/etc. from the datasheet have not helped much... obviously I'm missing something! Can anybody see it?

In case someone wants to take the time to test/prove this project, I attached it entirely. Thanks in advance for any input and have a great weekend!

Luch

 

Attachment(s): 

This topic has a solution.

Last Edited: Sat. Jun 16, 2018 - 10:23 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

how about a scope photo?

 

 

The timer will start once the clocks are selected (from having no clock)....perhaps make setting the clocks a 100% separate statement (rather than combining with other bits)....check the compiled code to ensure the compiler is doing this as well.

 

 

 but drive kind of sensitive hardware, so I would like to have this nasty glitch go away

That's a recipe for trouble! You should consider changing things a bit, if a small pulse causes disaster.

When in the dark remember-the future looks brighter than ever.

Last Edited: Sat. Jun 9, 2018 - 01:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, avrcandies!

 I have tried just about everything... including what you suggested: sat up individual bits in TCCR1 (although it doesn’t make much sense and is also not advised anywhere in the documentation) – PWM1A, COM1A0/1, CSxx. The only difference is in timing; the glitch happens at different times / delays, but it happens nonetheless!
I attach a diagram taken with a logic analyzer. I changed the parameters a bit, to focus more on that period with the glitch. As you can see, after the reset, both PB0 and PB1 are zero, because of setting it to output a 0. The front of the glitch appears after TC1 is setup in PWM mode… and the period measured by the LA (0.25us) corresponds with what I noticed in simulation: 2 CK periods.

new parameters: OCR1C = 67; OCR1A = 33; Prescaler = 8.

 

Regarding the "recipe for trouble": I'm not controlling a nuclear reactor plant with this thing, just some lousy piezo elements. While the elements won't care about this glitch, the drivers won't be happy, especially that it will happen over and over again. They won't die, although not designed to handle 0.25 us pulses. Trying to change something? Yeah, that's why I'm here!

So,

1 - it is more of an annoyance and

2 - I would like to know what is going on, WHY is it doing it? And how can it be avoided?

Last Edited: Sat. Jun 9, 2018 - 06:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another picture at a different scale - the following pulses are visible.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well regardless of what you do, there will be initially some brief time when they are both low---is that of any concern?

 

 

Note that in PWM mode, writing to the Output Compare Registers OCR1A or OCR1B, the data value is first transferred

to a temporary location. The value is latched into OCR1A or OCR1B when the Timer/Counter reaches

OCR1C. This prevents the occurrence of odd-length PWM pulses (glitches) in the event of an unsynchronized

OCR1A or OCR1B

 

...perhaps modifying the value in OCR1C would do the trick?

When in the dark remember-the future looks brighter than ever.

Last Edited: Sat. Jun 9, 2018 - 08:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

luch wrote:
and the period measured by the LA (0.25us) corresponds with what I noticed in simulation: 2 CK periods.

Something isn't quite making sense.  (that is, besides your glitch)  I'll have to compare your code to the datasheet.  The comment says /4 prescaler, and the comments say 8MHz main clock. Then how can 2 timer clocks be 0.25us -- when the period should be 36 timer clocks with an OCR1C of  35.  And the trace shows a period of ~36us.  So either /8 or 4MHz (!) main clock.

 

There are no interrupts involved, but does the output switch when the compare flag is set?  That is beyond my detail knowledge in timer work over the years.  But perhaps worth a shot -- set OCR1C; set OCR1A; clear timer flags; set TCCR1.

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks guys!

@avrcandies: The outputs are driving differential (full bridge), so when they are both high or low, the load voltage is zero. I am aware of the synchronization delays - they are also clearly visible in the simulator - but the only difference they make is the moment the glitch appears and the duration of it (2CK is the result of these propagation delays). More important is the order these 3 registers are loaded: TCCR1, OCR1A, OCR1C. If we change their order weird things may happen - but nothing good/useful.

 

@theusch: Yes, 'main clock' is 8MHz and prescaler is 4 => as I mentioned, TMR1_clk = 2MHz, that's "timer clock". When I said "2 CK", I meant 2 system/main clock periods (2 x 125 ns), which is actually two NOPs worth (that's why the code is filled with NOPs - so I can observe the delays and duration of these pulses). And the duration of this glitch is always 2 CK periods wide, regardless of OCR1A or OCR1C.

The flags are acting normally and have no bearing on the issue at hand. They are reflecting what TMR1 does and not the other way around.

 

Anyways, after I wasted most of my Saturday and part of today, I discovered that this 'glitch' appears ONLY ONCE, after a reset (regardless of what triggered the reset)! Until the next reset, the timer behaves  normally, no mater if active or stopped, or even turned off (by way of PRR). I've been chasing a storm in a teacup... I do not know why it happens (probably I never will, at least because of insufficient information), but if it only happens once, I can live with that! And so can my electronics!

 

Thanks again for your input and for being there for those in need of assistance! Love you!

Luch

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

luch wrote:
When I said "2 CK", I meant 2 system/main clock periods (2 x 125 ns), which is actually two NOPs worth (that's why the code is filled with NOPs - so I can observe the delays and duration of these pulses). And the duration of this glitch is always 2 CK periods wide, regardless of OCR1A or OCR1C.

Now, back up a minute and consider what I am questioning...

 

If the timer is really running at /4, then each timer tick is 500ns.  Yet you say you are observing timer events less than the period of one timer tick.  That makes no sense to me.

 

In addition

theusch wrote:
when the period should be 36 timer clocks with an OCR1C of 35. And the trace shows a period of ~36us.

...which doesn't seem to be explained with your clock numbers.

 

luch wrote:
The flags are acting normally and have no bearing on the issue at hand. They are reflecting what TMR1 does and not the other way around.

I don't think you can make that statement.  Isn't it when the flag gets set that the event happens?

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
Well regardless of what you do, there will be initially some brief time when they are both low---is that of any concern?

Upon reflection, that may well be the situation, it seems to me.  [full disclosure:  I've never done detailed work with complementary outputs on an AVR8]  (and might also be why there is the mysterious pulse with a width less than a timer tick? ...)

 

If indeed you are starting with both signal legs low -- how does your driver like that?  Anyway, do you get a glitch isf you put the two signal legs into proper orientation before setting up starting the timer?  It appears to me that at some point the timer "catches up" to get the outputs complementary.

 

Fllowing up on that, if you are starting out with both outputs at the same value, what waveform do you >>expect<< when you start the timer to produce complementary outputs?

 

 

 

 

 

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Sun. Jun 10, 2018 - 01:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fllowing up on that, if you are starting out with both outputs at the same value, what waveform do you >>expect<< when you start the timer to produce complementary outputs? 

I suppose it would be nice (really, only appearance-wise) to transition at the beginning of a full cycle, rather than creating a partial runt.

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

Starting up is logically problematic...It's sort of like saying,  I must begin with my outputs set to 0x101101....well, bad idea....how do you get there from power up? ....and what if you get 0x100101 for 50 ns before getting to 0x101101?  

 

 

catches up" to get the outputs complementary

Yep, seems so...some of the avr sheets mention one output is set when blahblah....  and the other output is cleared when blahblah  happens.....so they are not inherently complementary at all times (at least with this interpretation), until blahblah happens

 

When in the dark remember-the future looks brighter than ever.

Last Edited: Sun. Jun 10, 2018 - 08:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so they are not inherently complementary at all times (at least with this interpretation), until blahblah happens

Often you want a "deadtime" where none of your outputs are on.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks everybody!

Let me explain a bit the purpose of this little timer thing: I'm using the 2 outputs (PB0 and PB1) to drive a couple of amplifiers. The (mostly capacitive) load is connected between their outputs. The load voltage is therefore: Vout=A * (VPB0 - VPB1). So, as long PB0==PB1, the output is zero. I have 2 situations:

1 - PWM off : TC1 stopped, PB0=PB1=Output = 0.

2 - PWM runs: TC1 in PWMA mode, output OC1A=>PB1, \OC1A=>PB0.

I've already tried just about every imaginable combination of setup... One solution that I found would be something like this (a workaround): 

int main(void)
{

/* Ports:
PB0 - pin 5 - \OC1A = Out
PB1 - pin 6 -  OC1A = Out
PB2 - PB5 = In , not used for this test
*/
PORTB = 0b111100;	// pull-ups on PB2 - PB5

OCR1C = 35;
OCR1A = 17;
TCCR1 = (1 << PWM1A) | (1 << COM1A0) | (1 << CS11) | (1 << CS10);
_NOP();
_NOP();             // the glitch is masked by leaving PB0,PB1 as inputs
DDRB  = 0b000011;	
_NOP();             // outputs active, but the glitch is gone
_NOP();

// more code/delay here

TCCR1 = 0;  // stop PWM
TCNT1 = 0;

// ETC.
}

The DDRB is simply delayed 2 CK cycles after setting up TCCR1 and the glitch is masked. But, like I said, I could live with this small imperfection al long as it only happens once!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

luch wrote:
But, like I said, I could live with this small imperfection al long as it only happens once!

???  It appeared to be only once in the traces you posted.

 

As I asked, what waveform would you >>expect<<?  Or, I guess, prefer to happen?  As you mentioned your Case 1 has both outputs in the same state.  Exactly when do you expect them to go complementary?

 

luch wrote:
I've already tried just about every imaginable combination of setup.

I haven't seen many of those combinations, nor the result.  In particular, setting /OC output pin high (complementary to OC pin) in the instruction before the timer setup.  I'm guessing that the first period may then be stretched by a bit but no "glitches".

 

(and I'm still confused about the period of 36us, with the stated clock and timer parameters)

 

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Mon. Jun 11, 2018 - 05:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tell the fuse bits, especially CKSEL.  Tiny15 mode?

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
Often you want a "deadtime" where none of your outputs are on.

And OP's model has timer support for that, right?

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

luch (#7):

I discovered that this 'glitch' appears ONLY ONCE, after a reset (regardless of what triggered the reset)! Until the next reset, the timer behaves normally, no matter if active or stopped, or even turned off (by way of PRR)

 #12: I could live with this small imperfection al long as it only happens once

I should have said: I CAN live with that because it only happens once. Sorry about the wrong wording!

teusch (#13): what waveform would you >>expect<<?

That's easy: what I've already shown, without the glitch! Like I've explained in #12, in 'idle' state timer is stopped (eventually turned off) and the outputs PB0/1 are both '0'. They could be also both '1', but I prefer '0' because I have the input of the amp. acting as a pull-down resistor, so even during reset, a '0' is applied on PB0/1. When I turn TMR1 on in PWM mode I expect PB1=OCR1A to go to '1' first, as it should (before the first compare match) and not to '0' and 2 CK later to '1', while \OC1A does exactly the opposite (which is normal).

In 'idle' or 'stopped' state both PB0 and PB1 are '0' and disconnected form the (stopped) timer  for a looong period of time (say minutes). That is not 'dead time'! There are no pulses whatsoever, no overlapping, no dead time between them!

I haven't seen many of those combinations, nor the result. In particular, setting /OC output pin high (complementary to OC pin) in the instruction before the timer setup.

That 'setting up in advance the outputs the way I want them to be in the first period' is one of those many combinations: the glitch is still there, only a bit delayed. It would take me two days to explain everything I've tried. As a matter of fact, yesterday I've spent a couple of hours answering to your last (4) posts... After I filled an entire screen with text, my lovely chrome browser decided, out of the blue, to refresh the page and provided me a new, clean one! I almost had a nervous breakdown! I forced myself to sketch post #12, had a couple of beers and went to bed.

I'm still confused about the period of 36us. Tell the fuse bits, especially CKSEL.  Tiny15 mode?

 The fuse settings are part of the code in the first post. No Tiny15 mode.

 About the 36us: In #3, under the picture I mentioned "new parameters: OCR1C = 67; OCR1A = 33; Prescaler = 8". I've changed those values to focus on the region with the glitch. Then, realizing that the pwm pulses are not visible at all, I've changed the prescaler back to 4 and took a new picture, where both the glitch and the pwm pulses are visible. The period in this last picture is 68/2 = 34us. Sorry about the confusion.

 

Thanks again!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

luch wrote:
When I turn TMR1 on in PWM mode I expect PB1=OCR1A to go to '1' first, as it should (before the first compare match) and not to '0' and 2 CK later to '1', while \OC1A does exactly the opposite (which is normal).

That is my point, I guess.  From an "illegal" complementary state (both lines low),  I can't see why you "expect" a timer to act as you described.  A magic change of state on the A line? 

 

luch wrote:
As a matter of fact, yesterday I've spent a couple of hours answering to your last (4) posts...

So I guess I'm out so I don't cause any pain. 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

luch wrote:
or even turned off (by way of PRR)

Well, I'd say PRR more or less suspends timer operation.  Does it turn it off?  Semantics, I guess.  The point is that using PRR IMO/IME doesn't confirm a one-time setup situation.  To make the "one-time" experiment, I'd really stop the timer and disconnect the pins (in this case that would be TCCR1 of 0, right?)  Then set both signals to the low state.  Than again call the timer init. 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

    theusch: 

From an "illegal" complementary state (both lines low),  I can't see why you "expect" a timer to act as you described.  A magic change of state on the A line? 

Those two lines are born 'illegal'. They are just two bits of port B. Whatever their state (input/output/0/1), they have nothing to do with T/C1 until they are connected to it by way of setting T/C1 in PWM mode AND setting COM1Ax to something other than 00. Only from that moment on can we speak of "illegal state". And at that moment, according to DS, PB1 (OC1A) should eventually (after a synchronization delay) turn to '1' and then, after a compare match, turns to '0' and later, after reaching OCR1C (overflow) turns to '1' again, and so on forever, or until we change something... Well, it turns out, after a reset and the first setup, it has a moment of confusion: instead of turning to '1' (and there shouldn't be anything 'magical' in that - it is the normal/expected/promised operation of the timer), it turns to '0' (actually, in my setup, it remains '0', while PB0 turns '1'). Two CK (propagation delay?) later recovers and turns to what should have been from the beginning: a '1'. And this 'confusion' only happens once, after a reset. No matter what we do with the timer later on, it does not happen again (and I stop and even turn T/C1 off and back to PWM repeatedly in my app.). Like I said, not a biggie for me. I've posted this because I thought it happens all the time, systematically and is caused by me doing something wrong. Maybe I do; I just couldn't find a more 'natural' solution to this than the one I've posted in #12.

So I guess I'm out so I don't cause any pain.

 When I said "answering your last posts" I meant you, avrcandies and sparrow2. Answering to someone's post - someone who has invested some brain activity and time, trying to help me, the OP - is, if not an obligation, at least politeness and acknowledgement of his/her work. So, I was not trying to blame (!) anyone but myself for being sloppy enough not to edit my post in a separate text editor, as I usually do.

Well, I'd say PRR more or less suspends timer operation.  Does it turn it off?  Semantics, I guess.

I would say it should be actually even more than "turn it off" (whatever that means): it should actually be something like turning off (removing) its power supply! That's the whole point of doing it, by way of Power Reduction Register: to save power.

I agree with you about not having a 'one time' setup. Every time we setup the timer, after having TCCR1=0, even more so after having it turned off, we are doing a NEW setup, just like the first time. Except the glitch is not there anymore! The 'magic' that you were talking about happens this time, although starting from the same situation (illegal state & all).

 Thanks again!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you explored FOC1A/FOC1B?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
Have you explored FOC1A/FOC1B?

I thought of that too.  But it would need to be part of a different magic incantation sequence, as the datasheet says they are n/a in PWM mode.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I thought of that too.  But it would need to be part of a different magic incantation sequence, as the datasheet says they are n/a in PWM mode.

But that's the case on any AVR with FOC.  The question is whether they will elicit the desired behaviour with a complementary output.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried that too. I didn't expected it to work (theusch already explained why), but tried it anyway. It has no effect.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch already explained why

He explained that FOC doesn't work in PWM modes.  Except that's not relevant.  It's the case on all AVR, not just the t85.  One uses FOC to preset the states of the output compare units >>before<< switching into a PWM mode.

 

The general method:

  • keep timer in a non-PWM mode (default normal mode is fine)
  • keep timer stopped
  • set COMnx bits to mode 2 or 3 (mode 2 will clear an output, mode 3 will set it)
  • write FOCnx bits
  • only now do you configure your timer as desired (and change DDRxn).

 

The question was whether this would have any effect on the complementary output.  >>If<< you've followed the above procedure, and get the same glitchy results, then you can say:

It has no effect.

 

Another option might be simply to wait for the 'glitch' to pass before configuring the compare output pins as outputs.  The timer's underlying logic should still clock through the glitch, but you won't see it on pins because they aren't yet outputs.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Fri. Jun 15, 2018 - 02:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The timer's underlying logic should still clock through the glitch

Note the tiny85 does have some errata mentioned regarding timers, maybe there is a little more hidden away waiting for us to reveal it.  Most PWM apps would not notice a single short runt pulse (by the time you look at the scope , it would be long gone!).

 

When in the dark remember-the future looks brighter than ever.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Note the tiny85 does have some errata mentioned regarding timers, maybe there is a little more hidden away waiting for us to reveal it. 

Indeed.  Multiple threads kicking around concerning the well-known errata concerning Timer Counter1 PWM output OC1B-XOC1B.  Datasheet claims it only affects some revisions of t25 and t45, but it's clear that it also affects at least some revisions of t85.

 

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@joeymorin (#24): it is a bit of a convoluted way, isn't it? And it shouldn't be like this. This the resulting code from your recommendation:

int main(void)
{
PORTB = 0b111100;	// pull-ups on PB2 - PB5
TCCR1 = (1 << COM1A1) | (1 << COM1A0);  // Normal Mode, Set the OC1A output line
GTCCR = (1 << FOC1A);	// Force OC1A = 1
OCR1C = 35;	// Regular setting of TMR1:
OCR1A = 17;
TCCR1 = (1 << PWM1A) | (1 << COM1A0) | (1 << CS11) | (1 << CS10);  // PWM mode, CK/4, OC1A cleared on compare match
DDRB  = 0b000011;	// PB0,1 -> outputs

while(1);
}

It works and it doesn't take a lot of extra code to achieve our goal (to convince TMR1 to behave). By the way, I've found something interesting (and revealing) in the DS (pag. 70), but in the chapter describing TMR0 operation. Not repeated in the chapter for TMR1, that's why I missed it:

The setup of the OC0x should be performed before setting the Data Direction Register for the port pin to output.
The easiest way of setting the OC0x value is to use the Force Output Compare (FOC0x) strobe bits in Normal
mode. The OC0x Registers keep their values even when changing between Waveform Generation modes.

I wouldn't call that quite "the easiest way" as long as this would work as well:

PORTB = 0b111100;	// pull-ups on PB2 - PB5

OCR1C = 35;
OCR1A = 17;
TCCR1 = (1 << PWM1A) | (1 << COM1A0) | (1 << CS11) | (1 << CS10);
_NOP();             // here any (eventually useful) instructions to
_NOP();             // create a 2 CK delay
                    // the glitch is masked by leaving PB0,PB1 as inputs
DDRB  = 0b000011;	

It is, however, a cleaner solution and in accordance with the DS instructions. That's why I'm going to mark your advice as the solution.

There should, probably a mention of this behavior of TMR1 in PWM mode in the DS (for people who might use it in a more critical/sensitive application), but  I don't know if it can be considered a 'bug'...

Anyways, thanks again everybody, you've been, as always, great!