A short blip when enabling a hardware PWM on ATtiny, why?

Last post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm trying to use an ATtiny85 to charleplex some LEDs, and using a hardware timer to generate PWM for a 'fade up / fade down' effect. Code attached.

Randomly, there's an initial "blip" pulse of random length before the correct pulse train starts when enabling PWM. The blip measures from 0 to 2.040 ms in length. This is causing a quick strobe (flash) before the LED is 'fading' up.

What's causing this blip?

Attachment(s): 

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

First thing that jumps out at me is

#define F_CPU 8000000UL  // 1 MHz

Are you running at 8MHz or 1MHz? I'm not sure if this would cause your problem but would at minimum screw up your delay() calls. Maybe something isn't timing like you think.

Hope I can help,
Mike
My Robotics/AVR Blog

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

Sorry, I'm running at 8Mhz, I just forgot to change the comment from the cut&paste.

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

In fadeInOut, why do you call setDuty twice?

Maybe not related, but shouldn't have things there without a reason.

Hope I can help,
Mike
My Robotics/AVR Blog

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

Err, I originally tried this in an Arduino enviroment using both pwm channels and was observing the same problem. I (roughly) brought they code out of Arduino to eliminate it as the cause. But I was sloppy and missed removing the second call to what would be the second pin.

Just tried removing it now, still same problem.

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

madsci1016 wrote:
Err, I originally tried this in an Arduino enviroment using both pwm channels and was observing the same problem. I (roughly) brought they code out of Arduino to eliminate it as the cause. But I was sloppy and missed removing the second call to what would be the second pin.

Just tried removing it now, still same problem.


Yeah I thought it looked odd.

If I was debugging it in front of me I'd have to bring the code a little simpler and then start pulling pieces off until it went away, then poke around that spot a bit.

Unfortunately I can't really see the reason by just skimming your code.

Best of luck. I'm sure someone will chime in soon.

Hope I can help,
Mike
My Robotics/AVR Blog

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

Why are you not including ?

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

Why are you not including ?

Presumably because:

C:\WinAVR-20100110\avr\include\avr>grep "#include " interrupt.h
#include 

 

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

12 downloads and no other thoughts?

Sorry it's messy. When I get back from traveling for work I'll clean it up and simplify it. I was hoping it was something easy like "you forgot poking register ABC"

The best way to summarize what I see is that it's like when I enable the PWM, the IO pin goes HIGH (or LOW) until the timer overflows, then starts correctly running PWM. The manual mentioned something like this in the section on resetting the pre-scaler, and I followed the suggestion (I think) to correct for this, but no change.

I had a temp fix, where I enabled the PWM when the DDR register was set for input, delayed 10ms, then enabled the IO as output. This 'skips' the PWM blip, but i'd really like to figure out why it's doing it in the first place.

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

Well, according to this guy:

http://www.societyofrobots.com/robotforum/index.php?topic=12603.msg94580#msg94580

It seems this is just a thing with ATtiny PWM.

I think I'm just going to do software PWM, since I won't be doing anything else.

Thanks guys for taking the time to look.

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

Looking at your code, you do not start any PWM until you call setDuty() after the first delay(1000).

When you disable COM0A1 bit, the o/p pin reverts to GPIO.

You could achieve your effects in a simpler manner.

David.

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

I'm not intimately familiar with LED PWMs, or PWM on that particular model.

Without digging into the code and experimenting, the symptom descriptions would appar to me as if the "start" isn't from a set of known conditions. For example, at "start" the compare flag might already be set and there is one cycle of PWM where the output is in an undesirable state.

So, I'd examine the "start" sequence. I guess since there are problems, I'd stop the timer, clear the TCNT, clear all pertinent IF flags, set the OCR register(s), set the TOP register(s) if pertinent, configure the node as an output, set the output to the desired initial state, connect the pin to the timer with COM bits, set the mode WGM bits, then start the timer with CS bits.

Regardless of AVR model, I cannot think of why there might be an blip, much less of significant duration (up to several milliseconds), using the above sequence.

In practice, I combine most of the steps above. When the timer is stopped, I disconnect the output and set it to the desired "idle" state. When ready to 'start", I go through roughly the sequence above.

Lee

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

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

@david.prentice, I am charlie-plexing LEDs, so I need the pin to go into High-Z mode in-between PWM cycles. Care to fill me in on the simpler method?

@Lee, I'll give it a try, just seems like a lot of resetting stuff every time I want to start PWM again during the same program.

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

Quote:

@Lee, I'll give it a try, just seems like a lot of resetting stuff every time I want to start PWM again during the same program.

Like, three lines of code, to address a situation that seems to be vexing you?

Yes, indeed, if you start PWM in an arbitrary state, especially (as it appears to be here) in a state where a bogus compare match can fire immediately--you can get a "blip". Note that the AVR is just doing what you tell it to.

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

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

theusch wrote:

Like, three lines of code, to address a situation that seems to be vexing you?

Three?

Quote:
I'd stop the timer, clear the TCNT, clear all pertinent IF flags, set the OCR register(s), set the TOP register(s) if pertinent, configure the node as an output, set the output to the desired initial state, connect the pin to the timer with COM bits, set the mode WGM bits, then start the timer with CS bits.

You can do all that in three instructions?

Best I could do was :

TCNT0 = 0;
TIFR = 0b00011010;
OCR0A = val;
sbi(DDRB, 0);
sbi(PORTB, 0);
TCCR0A = 0b10000011;
TCCR0B = 0b00000011;

and when I'm done with PWM:

cbi(DDRB, 0);
cbi(PORTB, 0);
TCCR0B = 0b00000000;
TCCR0A = 0b00000000;
OCR0A = 0;

And still, i'm getting blips. Any other thoughts?

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

If you are connecting 4 LEDs to 3 AVR pins, you clearly want to have them lit simultaneously.

I ran this on a mega168 @ 16MHz.
I did not see any glitches. However, you will need to limit the minimum level to 1. The Charlieplexing interrupt occurs every 1024us. The ISR() takes 4us in CodeVision. Obviously you will need an IRQ latency of less than 1000us to ensure that OCR0A gets updated fast enough.

You should be able to recompile for a Tiny25 @ 8MHz. Your minimum latency will be 2000us. I can see no particular reason for using PWM modes. You need to multiplex at 1ms to 10ms period anyway to avoid flicker. You would only be doing one complete PWM period anyway before you change the duty cycle. (and then OCR0A does not change immediately)

// Charlieplex an array of LEDs,  all with independent brightness.
// Turn all LEDs off by OC0A.dir = 0

#include "/src/scripts/portab_kbv.h"

#define REDPWM 6                // OCR0A o/p pin
#define ONETWO 4                // charlieplex 1,2
#define THREEFOUR 7             // charlieplex 3,4
#define PWMPORT PORTD
#define PWMDDR  DDRD

uint8_t level[4] = { 1, 1, 1, 1 }; // levels must be > 0

ISR(TIM0_OVF)                   // 1.024ms @ 16MHz
{
    static uint8_t n = 3;       // start as #3
    if (++n > 3)
        n = 0;
    OCR0A = level[n];                             //ONE,TWO,THR,FOU
    PWMPORT ^= (1<<ONETWO)|(1<<THREEFOUR);        // 11, 00, 11, 00
    if ((n & 1) == 0)
        PWMDDR ^= (1<<ONETWO)|(1<<THREEFOUR);     // 10, 10, 01, 01
}

void main()
{
    uint8_t i, j;
    TCCR0A = (1<<COM0A0);             // toggle OC0A on compare
    TCCR0B = (1<<CS01)|(1<<CS00);     // div64
    TIMSK0 = (1<<TOIE0);              // GPIO mode, interrupt on OVF
    PWMPORT &= ~((1<<REDPWM)|(1<<ONETWO)|(1<<THREEFOUR));     // RST default anyway.
    PWMDDR = (1<<REDPWM)|(0<<ONETWO)|(1<<THREEFOUR);  // start as #3
    SEI();

    for (;;) {
        for (i = 0; i < 4; i++) {
            for (j = 1; j < 255; j++) {
                level[i] = j;
                DELAY_MS(10);
            }
        }
        for (i = 4; i-- > 0; ) {
            for (j = 255; j > 1; j--) {
                level[i] = j;
                DELAY_MS(10);
            }
        }
    }
}

David.

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

Quote:
If you are connecting 4 LEDs to 3 AVR pins, you clearly want to have them lit simultaneously.

Actually, the end result will be 8 LEDs on 4 pins, with only two lit simultaneously at different PWM levels. I haven't finish scaling up to that level till I figured this out. The reason I went with Charlie-plexing was to avoid using any external components like decoders or shift registers.

But thanks for the code David, I'm going to try to dissect it to see what you did.

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

You just double up your level[] array.
You could use the OCR0B pin for the other 4 LEDs.

I take your point that you only want to view two LEDs at any one time. However 8 simultaneous LEDs with different intensities is pretty simple.

You only have two pins left on a Tiny25 (one if you keep RST). What else will your Tiny do?

David.

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

Quote:
You could use the OCR0B pin for the other 4 LEDs.

That's what I planed on.

Quote:
You only have two pins left on a Tiny25 (one if you keep RST). What else will your Tiny do?

Nothing, So I could have easily done this in software, but I wanted to solve the hardware issue for my own sake of learning & understanding.

Another project I am working on is using a ATtiny85 to measure voltage, current and phase angle (to calculate pf, real, reactive power, etc) off my Apartment's mains. So I wanted to gain more experience with ATtiny timers through this.

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

I would reckon that it is easiest to develop your programs on a mega328 or mega324. Or perhaps use a tiny2313 when playing with the USI.

The Tiny25 has some special facilities with PLL and dead time, but most things, most of the time are similar with all AVRs.

Simply re-compile for the reduced-pin target, and check that everything works ok.

David.