0
\$\begingroup\$

I have searched the AtTiny data sheet and not found anything about this. I'm experiencing a weird PWM bug. When I expect 100% on I'm getting less. I'm using an inverted PWM scheme, so setting it equal to 0 should be full on, but my scope shows a ~95% on duty pulse.

Below I posted applicable setup code, then the function I call occasionally in my main() to change the PWM rate... When I set the OCR0B=0, I do not get a full on PWM.

I'll also note all other PWM settings appear to work correctly, the duty cycle matches what is expected.

Anyone want to take a look to check I'm sane before I complain to Microchip/Atmel?

//Setup Pins:
DDRB =  DDRB |  0b00000010;     //set B1 output and B2 to input.
PUEB = PUEB |   0b00000100;     //Pullup on B2

//Setup Timer:
//output pin is OC0B (PB1)
//Set PWM Fast Mode 8 Bit, enable output on all PWM pins (only 1 on tiny5).
TCCR0A = 1<<COM0A1 | 1<<COM0B1 | 1<<COM0A0 | 1<<COM0B0 | 1<<WGM01;  //COM0A0 COM0B0 set to 1 for inverting PWM.
//Set PWM top [ICR0] to 5bit (this allows effective 31khz pwm)
ICR0 = TOP_PWM; //Set TOP...
//Set PWM Mode Fast 8 bit & No pre-scaler.
TCCR0B =  1<<CS00 | 1<<WGM02 | 1<<WGM03;
OCR0B = TOP_PWM; //Start with 0 output.

//Setup INO0 (External Interrupt):
EICRA = 1<<ISC00 | 1<<ISC01;    //Enable rising edge interrupt
EIMSK = 1<<INT0;                //Enable INT0

 ----------------------------------------------------------------

/******************************************
* Function to decide what speed to set.
* NOTE: All alterations to motor speed should
*       be done in this function!
* Also note that inverse PWM is used,
* so 0 is full speed, and TOP_PWM is stopped.
******************************************/
void speedLogic()
{
    //Speed logic
    if      (speed_state == 0)
        speed = TOP_PWM;//Off
    else if (speed_state == 1)
        speed = 24;     //Slow
    else if (speed_state == 2)
        speed = 16;     //Med
    else if (speed_state == 3)
        speed = 0;      //Fast (3=91% Otherwise 0=100%)
    else
        speed = TOP_PWM;

    //Set PWM Reg
    OCR0B = speed;

    //Increment State Variable
    speed_state++;
    if (speed_state > 3)
        speed_state = 0;
}
\$\endgroup\$
2
\$\begingroup\$

I believe, it is a feature not a bug. Citing from the datasheet (page 94):

The extreme values for the OCR0x registers represents special cases when generating a PWM waveform output in the Fast PWM mode. If the OCR0x is set equal to BOTTOM (0x0000) the output will be a narrow spike for each TOP+1 timer clock cycle. Setting the OCR0x equal to TOP will result in a constant high or low output (depending on the polarity of the output which is controlled by COM0x[1:0]).

This describes your observation pretty well. With 5 bit PWM (32 steps, right?) the duty cycle should be 97 % (not 95 %), but it is probably good enough for approximately.

\$\endgroup\$
  • \$\begingroup\$ This makes sense, but seems odd? So then to get a 0 PWM output, I would need to flip the COM0x0 bit? I have never seen a PWM setup quite like that. \$\endgroup\$ – MadHatter Feb 28 '18 at 2:45
  • \$\begingroup\$ This or stop the timer or change the WG mode or something else (there is probably a few other possibilities). It is not completely clear to me from the datasheet, but I guess the waveform generator uses the same logic as a OCF0x flag, that is action happens at the start of next tick after the match. Maybe strange or impractical, but probably allows more simple HW implementation. (I suspect that for full 0 to 100 %, the HW would have to implement one of edge value as a special case.) \$\endgroup\$ – Martin Feb 28 '18 at 3:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.