Arduino 16 bit PWM Revelation

Here is a piece of code I found – quite old now.  As most Arduino users will know, the PWM on the 328 chip is a bit… naff at only 8 bits. When attached to LEDS, at the low end, each step is painfully obvious – even value 1 is visible immediately – not then much use for smooth lighting!

However I discovered this..

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);                    /* no prescaling */
    ICR1 = 0xffff;                      /* TOP counter value */
/* 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;

That lovely piece of code lets you put 16-bit PWM on ports 9 and 10 at the expense of TIMER 1 – MARVELOUS unless you want to do RGB lighting – as there are only two.

So I kept on looking. The 1284P chip – compatible but more powerful than the 328, has an extra 16 bit timer (ignore the blogs that say it does not – the guys are reading out of date info).  It occurred to me that you should be able to use Timer 3 to get an extra 2 channels at 16 bits – wouldn’t that be marvellous.

Sadly there’s a problem – lack of info on Timer 3 meant that even after guessing the changes needed to that setup (ports 6 and 7 not 9 and 10) I managed to get the new PWM on port 7 – but not 6.  And worse – they’ve gone and stuck this in the middle of the pins for SCK, MOSI and MISO so you can’t do both at the same time. Ah well. I simply changed all references to timer 1 to timer 3 to get port 7 working but that didn’t seem to help port 6.

So I was wondering – the 2560 boards – they have even MORE timers. Has anyone taken this basic code and managed to get more 16-bit PWM timers on the the MEGA2560 boards?


18 thoughts on “Arduino 16 bit PWM Revelation

  1. Hi guys,

    I’m Jet, I try this code and it works on my arduino atmega 2560, at pin 11 , 16 bit resolution of PWM.. it was really great.

    1. Thanks for that Patrik – however the I2c Adafruit board is virtually identical to the Chinese version – same chip even – and taking postage into account I can buy several of the Chinese ones for the price of one Adafruit.

      Indeed, as I’ve recently come to the realisation that you can use the timers in an Arduino MEGA to get seven 16-bit PWM timers – and as these are now around $6 from China… need I say more 🙂 I just wish they didn’t have to make it looks like an Arduino – a Mega based board at that price but super slim would be a wonderful thing.

      1. You are right. But maybe you can just integrate one of these chips together with an esp as it has i2c and spi, as you already know 🙂

        1. Indeed you could.. Well, I’m hoping to have a little test board with a 328 and an ESP shortly when my friend who excels at board layouts gets a testing board for me – to be honest we could have put a 2560 on the board but for manual assembly the chips are beyond my abilities to solder 🙂 I only just found out today that the Chinese are selling MEGA2560s for under a fiver and that is worth pondering.

  2. So up to now – on the MEGA boards (2560) which are currently running at a stunningly low £4.60 from AliExpress… link below… you can it would seem get SEVEN 16-bit PWM channels thanks to the extra timers.. that is starting to look like one hell of a universal I2c peripheral to plug into my ESPs…. pwms, serial ports, port extension…. shame it wasn’t a tad smaller.

  3. Hi Peter,

    Why not have a look at a cheapish chip that is dedicated to the task, such as the TLC59711?

    1. already done that but I want more than just PWM. If you look at the blog I have a 16 channel PWM chip already accounted for. A processor appeals as I can have A/D in and a bidirectional port thrown in. Waiting for a SAM32 board to turn up from China. I have 2 16-bit PWM channels running on the 328 and that chip is ideal as they are pennies – but I need 3 channels for RGB. Why not do that on the ESP you say – because the constant interrupts screw up other stuff like I2c and RGB serial lighting.

  4. Interestingly looking on the Arduino site – the 32u4 Leonardo has 7 PWM ports – but as elswhere – they only support 8-bit PWM – how DAFT is that when the hardware is able to do 16-bit – I’ve a board sitting here managing 16 bit PWM on 2 channels no problem.

    1. Hell yes. Right – the first link comforms my worst fears – we CAN only have two 16 bit channels on the 328 – but 11 channels of 16 bit on the Mega – wow! I’m keeping that bookmark. Indeed all three of these links are winners – well done.

    1. Hi there – thanks for that – and the PWM possibilities are great – the chip pinout looks like around the same physical size as the surface mount 1284 which is do-able on home kit – unlike the 2560 which is a pain…. will investigate. Strangely – they are £3.50 from Ebay but MORE expensive from Aliexpress at £4 + never seen that before.

  5. The arduino leonardo has a atmega32u4. Those chips also have two 16 bit timers and they are cheaper than the 2560…

Comments are closed.