The 8 Bit Conspiracy

Hi Guys,

I posted a question a while ago, I wanted to know was there a way to create a better LED fade, because the current method of decreasing analogWrite(255) by 1 created noticeable steps in brightness, especially as the LED got dim.

I was told that it couldn’t be done, the Arduino was an 8bit microcontroller and that the only way to achieve it was with a higher resolution board/microcontroller.

The other night I couldnt sleep, so went outside for a smoke, and while I was out there, started thinking of the problem again, I ran lots of things through my head, and decided I would do a Google search in the morning to look at software PWM, to see if I could get a better resolution that way.

Anyway, to cut a long story short, during my search the next day, there on the first page of results was this site - Arduino Slovakia - 16-bit PWM resolution for Arduino
I nearly fell off my chair, the Arduino CAN have 16bit PWM channels. I couldnt believe it, all those people on the Arduino forum lied to me!!!

I know there are forces on the Arduino Forum, who want this secret to remain hidden, they are strong and powerful and will do anything to stop this getting out, but I will not be stopped… FREEDOM.

Now that the truth is out there!! my question is, now that Pin 9 has been changed to 16bit, will I still be able to convert this to Fade Without delay() or will the change to 16bit have undesired consequences.

void setup() {
  Serial.begin(9600);
  setupPWM16();
}

uint16_t icr = 0xffff;

void loop() {
  Serial.println("*");
  //for (uint16_t i = 0; i < 8000; i++)
  for (uint16_t i = 65535; i > 0; i=i-1)
  {
    analogWrite16(9, i);
    //delay(1);
    delayMicroseconds(300);
  }
}

void setupPWM16() {
  DDRB  |= _BV(PB1) | _BV(PB2);       /* set pins as outputs */
  TCCR1A = _BV(COM1A1) | _BV(COM1B1)  /* non-inverting PWM */
        | _BV(WGM11);                 /* mode 14: fast PWM, TOP=ICR1 */
  TCCR1B = _BV(WGM13) | _BV(WGM12)
        | _BV(CS10);                  /* prescaler 1 */
  ICR1 = icr;                         /* TOP counter value (freeing OCR1A*/
}

/* 16-bit version of analogWrite(). Works only on pins 9 and 10. */
void analogWrite16(uint8_t pin, uint16_t val)
{
  switch (pin) {
    case  9: OCR1A = val; break;
    case 10: OCR1B = val; break;
  }
}

Karma+

I, for one, welcome our new 16-bit overlords and would remind them that I may be helpful rounding up others to devise code to be used for hi-res PWM!

I was told that it couldn't be done, the Arduino was an 8bit microcontroller and that the only way to achieve it was with a higher resolution board/microcontroller.

Bullshit.

I nearly fell off my chair, the Arduino CAN have 16bit PWM channels. I couldnt believe it, all those people on the Arduino forum lied to me!!!

The ATmega328p has one timer with 16 bit resolution and two timers with 8 bit resolution. So you can have the 16 bit resolution on two PWM pins, the other 4 PWM pins have only 8 bit resolution.

The ATmega2560 has 4 16 bit timers and 2 8 bit timers.

Every single JPEG picture you have ever seen, every beautiful sunset or adorable cat, is 8 bits.

Of course you can use fade-without-delay with 16 bit timers. Why would it not work? Just don't mess with timer0, the millis() timer.

@ MorganS

The reason I asked would it have undesirable results, was because when I changed Delay(1) to a fraction eg 0.9, or removed the delay completely, the LED changed from fading out over several seconds to blinking rapidly. Delay(1) is only one millisecond, so removing Delay(1) shouldnt of produced the results i got, hence why I asked if it has undesirable consequences.

Delay takes an integer. 0.9 will be truncated to 0.

You can use microseconds in without-delay.

Every single JPEG picture you have ever seen, every beautiful sunset or adorable cat, is 8 bits.

Yes, but a PWM faded LED doesn't have a linear brightness curve. A JPEG picture expects the brightness values to be linear.

The reason I asked would it have undesirable results, was because when I changed Delay(1) to a fraction eg 0.9, or removed the delay completely, the LED changed from fading out over several seconds to blinking rapidly.

The parameter to delay() is an integer, you should not provide a floating point value to it. BTW, there is no Delay() call in the Arduino IDE.

pylon:
BTW, there is no Delay() call in the Arduino IDE.

Pedantic springs to mind, but thank you anyway :slight_smile:

Which conspiracy? As I remember, you had a post where you asked whether or not the PWM frequency had anything to do with the granularity of the PWM signal, but that had nothing to do with the resolution..

The standard analogWrite() PWM is 8-bits and the Arduino has an 8-bit core but it can handle ints (16-bits), longs (32-bits), doubles, (64-bits) floats (32-bits,), etc. by processing one byte at a time. The C/C++ compiler takes care of the details. But, there is no 16-bit PWM instruction in the standard compiler/language. (Of course processing is slower, requiring more processor instructions and moving the bytes around, etc.)

@Danois90

In this thread Using a Flux Capacitor to Fade an LED

I received the following reply -

septillion:
The most straightforward way would be to use PWM with more resolution. For example use the PCA9685, that's 12-bit instead of 8-bit a standard Arduino uses. That makes that a step is 1/16th of the size now.

Arduino is based on ATmega328P and Arduino uses 8bit PWM as standard. Even if the ATmega328P supports 16bit PWM, it has nothing to do with Arduino (knitpicking alarm). Conspiracy hereby defused! :stuck_out_tongue:

The most straightforward way would be to use PWM with more resolution. For example use the PCA9685, that's 12-bit instead of 8-bit a standard Arduino uses.

The fact that you can do it using an AVR does not mean that it is straightforward