PWM Duty Cycle Resolution Arduino Uno from 8-bit to 10-bit

Hello,

I am writing a programme that communicates over I2C with a raspberry pi. The raspberry pi sends values for the Arduino to set the PWM duty cycles on pins 3, 9, 10 and 11. I have alread changed the PWM frequency on these pins to ~ 30 Hz to match it with the system which I am controlling. This is done using:
Code:

TCCR1B = TCCR1B & 0b11111000 | 0x05;
TCCR2B = TCCR2B & 0b11111000 | 0x07;

Currently I can set PWM duty cycles between 0 - 255 (8-bit). I have been reading that it is possible (hardware is sufficient) to set atleast some of these pins to have a better duty cycle resolution (10-bit; 0 - 1024). Is this possible with the Uno? If so could you give me some pointers to how I should go about it. I am concerned that since I have changed the PWM frequency that this will intefere with my ability to adjust the duty cycle resolution since they’re intricately related?

Cheers,
Andy

Here is my code:

Code:

#include <Wire.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/wdt.h>

#define SLAVE_ADDRESS 0x03 // I2C Address of the Arduino
int howMany = 0, debug = 0;
int state = 0,x,y,z;
char buffer100[7];
int position=0,A,B;
char str,values[100],warr[20];
String receivedMessage,X,Y,Z;

int startStringPosition,startStringPosition1,startStringPosition2;
int endStringPosition,endStringPosition1,endStringPosition2;



void setup() {
    pinMode(13, OUTPUT);
    Serial.begin(115200);         // start serial for output
    Wire.begin(SLAVE_ADDRESS);    // initialize i2c as slave
    
TCCR1B = TCCR1B & 0b11111000 | 0x05;  // Reduce PWM Frequency to 30 Hz.
TCCR2B = TCCR2B & 0b11111000 | 0x07;  // Reduce PWM Frequency to 30 Hz.

    // define callbacks for i2c communication
    Wire.onReceive(receiveEvent);
    Serial.println("Listening on Serial Port");
    wdt_enable(WDTO_8S); // Setting watchdog timer for 8s. If no reset of timer within 8s, Arduino will reset.
}

void loop() {
    delay(100);
}

// callback for received data
void receiveEvent(int howMany)
{
position = 0;
digitalWrite(13,HIGH); // When data recieved, set LED on PIN13 high.
  while(Wire.available())  //Reading data over I2C.
  {

    str = Wire.read();
values[position] = str; 

position++;

    }
values[position] ='\n';


// -------------- Extracting values for PWM Duty Cycles from String.
// -------------- String format: A%dB%dC%dZ.


receivedMessage = String(values);
 startStringPosition= receivedMessage.indexOf('A')+1; 
 endStringPosition= receivedMessage.lastIndexOf('B');
 X=receivedMessage.substring(startStringPosition,endStringPosition);
if(debug > 0){ // Show X if in Debug mode. This slows program down.
 Serial.print(X);
}
 char Xchar[X.length() +1];
  X.toCharArray(Xchar,sizeof(Xchar));
 x=atoi(Xchar);
 
 
 startStringPosition1= receivedMessage.indexOf('B')+1; 
 endStringPosition1= receivedMessage.lastIndexOf('C');
 Y=receivedMessage.substring(startStringPosition1,endStringPosition1);
 if(debug > 0){ 
 Serial.print(Y);
 }
  char Ychar[Y.length() +1];
  Y.toCharArray(Ychar,sizeof(Ychar));
 
 y=atoi(Ychar);
 
 
 startStringPosition2= receivedMessage.indexOf('C')+1; 
 endStringPosition2= receivedMessage.lastIndexOf('Z');
 Z=receivedMessage.substring(startStringPosition2,endStringPosition2);
  if(debug > 0){ 
 Serial.print(Z);
  }
  char Zchar[Z.length() +1];
  Z.toCharArray(Zchar,sizeof(Zchar));
 
 z=atoi(Zchar); 
 
 
// --- Using values to set PWM Values (0 - 255) 
 

//   analogWrite(3,y); // Not used Currently

   analogWrite(9,x);

   analogWrite(10,y);

   analogWrite(11,z);

digitalWrite(13,LOW); // Resetting the LED on PIN13

wdt_reset(); // Reseting watchdog timer. 

}
  1. No, as far as PWM outputs are concerned, 255 is the max. Analog inputs, however are 0-1023 range.
    2)There is absolutely no need to be concerned. You can use a normal analogWrite(pin,value), only thing is, it might happen too fast or too slow, so you may need to compensate for that.

Hope that helped!

I would have thought that would be the case but there seems to be some people claiming that it is possible by 'brute force':

http://code.google.com/p/arduino-v-neusci/wiki/ControlPWM

I am not sure exactly how to go about it or what others think of this. This site also eludes to the fact that it's possible:

http://sphinx.mythic-beasts.com/~markt/ATmega-timers.html

Cheers,
Andy

Andy, I think your aim is only partly achievable. According to this:

PWM pins 5 & 6 use timer0. timer0 is an 8-bit timer, so 10-bit resolution not possible
PWM pins 9 & 10 use timer1. timer1 is a 16-bit timer, so 10-bit resolution should be possible
PWM pins 3 & 11 use timer2. timer2 is an 8-bit timer, so 10-bit resolution not possible

You could consider upgrading to a Arduino Mega, which has a 16-bit timer3 I believe.

Paul