PWM value for 100% ON

Status
Not open for further replies.

Raptor

Active member
I've been laboring under the notion that a PWM value of 255 was the maximum value and with the minimum being 0 from 0 to 255 is 256 values in total. So, I was just checking things with my oscilloscope and low-and-behold PWM=255 is NOT 100% ON. In order to get 100% ON you need to specify a PWM value of 256. What's the deal?


Brian
 
Isn't 256 the same as 0 for 8bit PWM?
What is the output at 255?

on the adafruit pca9685 for example, specifying 4096 (12bit pwm) will be always on, constant high, but PWM ranges are between 0-4095
perhaps teensy does the same?

I would imagine specifying that value would wrap around to 0, essentially calling 0 instead of 256 ? Could depend on the function operation.., it would need to accept something bigger since it can accept higher resolutions :)
 
Well I just discovered something else here...

I've been using a PWM frequency of 75Hz and at 75Hz PWM=255 does not give full ON whereas PWM=256 does. However, if I use the default PWM frequency of about 488Hz it's different. At the default PWM frequency of 488Hz PWM=255 is 100% ON.

So, there's a difference in the way the Teensy 3.6 outputs a PWM of 255 when using the default freq of 488Hz versus 75Hz. I'm guessing it's a register binning issue, but it just goes to show you that you need to look at it with a scope to be sure what you're getting.

I'm running the Teensy 3.6 from a Win10 laptop running Arduino IDE version 1.83.


Brian
 
I would think its a timing issue, the default PWM frequency is 488.28Hz. Considering where it divides into the clock that is probably an ideal value. 75Hz is 6.51 times smaller then 488.28 so there is some left over that does not divide out correctly. Take a look at the PWM & Tone page.
 
here is what analogWrite() does in hardware/teensy/avr/cores/teensy3/pins_teensy.c
Code:
    max = 1 << analog_write_res;
    if (val <= 0) {
        digitalWrite(pin, LOW);
        pinMode(pin, OUTPUT);   // TODO: implement OUTPUT_LOW
        return;
    } else if (val >= max) {
        digitalWrite(pin, HIGH);
        pinMode(pin, OUTPUT);   // TODO: implement OUTPUT_HIGH
        return;
    }
So if you use value of 256 or more (for 8-bit resolution), the teensy core will set the pin HIGH with digtalWrite(); For 255, as Donziboy2 notes, it will depend on how math works for the frequency divisors.

default frequency (488.28125 hz, FTM1_MOD is 49151, F_BUS 48mhz), 255 timer value is
cval = ((uint32_t)val * (uint32_t)(FTM1_MOD + 1)) >> analog_write_res;

For 255 with a scope or logic analyzer, i think you will see that at 75 Hz signal is low for 52 us, and at 488 Hz signal is low for 8 us

For the Arduino/AVR core, analogWrite(pin, 255) uses digitalWrite() to set pin HIGH,
see hardware/arduino/avr/cores/arduino/wiring_analog.c
https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/
 
Last edited:
here is what analogWrite() does in hardware/teensy/avr/cores/teensy3/pins_teensy.c
Code:
    max = 1 << analog_write_res;
    if (val <= 0) {
        digitalWrite(pin, LOW);
        pinMode(pin, OUTPUT);   // TODO: implement OUTPUT_LOW
        return;
    } else if (val >= max) {
        digitalWrite(pin, HIGH);
        pinMode(pin, OUTPUT);   // TODO: implement OUTPUT_HIGH
        return;
    }
So if you use value of 256 or more (for 8-bit resolution), the teensy core will set the pin HIGH with digtalWrite(); For 255, as Donziboy2 notes, it will depend on how math works for the frequency divisors.

default frequency (488.28125 hz, FTM1_MOD is 49151, F_BUS 48mhz), 255 timer value is
cval = ((uint32_t)val * (uint32_t)(FTM1_MOD + 1)) >> analog_write_res;

For 255 with a scope or logic analyzer, i think you will see that at 75 Hz signal is low for 52 us, and at 488 Hz signal is low for 8 us

For the Arduino/AVR core, analogWrite(pin, 255) uses digitalWrite() to set pin HIGH,
see hardware/arduino/avr/cores/arduino/wiring_analog.c
https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/


I looked at the Arduino site and didn't see anything about 256 equaling a digitalWrite versus an analogWrite but I guess I could have missed it. I can understand how variation is PWM frequency and PWM value could result in a mismatch that results in a remainder of some sort that expresses itself as a PWM=255 that isn't quite 100% duty cycle.


Brian
 
I do not have anything to back it, but suspect this was a historical accident where simple PWM hardware counter logic produces true 0 for analogeWrite(0) but leaves single cycle gaps in 255 out of a 256 single byte counter. Changing 255 to by 100% high potentially breaks things so some logic gets added to accept 256 in what is nominally a byte input so people do not have to hack their own code.

Another of those things that might be done differently if starting from scratch.
 
And that just highlights the value of an oscilloscope -- you can think you know what's suppose to happen but seeing is believing. A DVM, even a good bench meter is never going to see this so an o'scope is pretty much necessary.


Brian
 
Status
Not open for further replies.
Back
Top