Skip to main content
The code comment described the use of no prescaler, but a prescaler 8 was being used.
Source Link

I would like to increase the PWM bit resolution of the Arduino Uno. At this moment it is 8-bit which I consider too low. Is this possible without losing the ability of interrupts and delays?

Koen

EDIT This setup delivers a 16-bit resultion

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(CS11);                    /* prescaler: 1clock / 8 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> (16000000/8)/(65535+1)=244,14Hz=30.5175Hz
*/

/* 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;
    }
}

I would like to increase the PWM bit resolution of the Arduino Uno. At this moment it is 8-bit which I consider too low. Is this possible without losing the ability of interrupts and delays?

Koen

EDIT This setup delivers a 16-bit resultion

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(CS11);                    /* prescaler 1 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> 16000000/(65535+1)=244,14Hz
*/

/* 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;
    }
}

I would like to increase the PWM bit resolution of the Arduino Uno. At this moment it is 8-bit which I consider too low. Is this possible without losing the ability of interrupts and delays?

Koen

EDIT This setup delivers a 16-bit resultion

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(CS11);                    /* prescaler: clock / 8 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> (16000000/8)/(65535+1)=30.5175Hz
*/

/* 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;
    }
}
Question Protected by VE7JRO
Tweeted twitter.com/StackArduino/status/772708856086560768
added 257 characters in body
Source Link
KoenR
  • 177
  • 1
  • 3
  • 11

I would like to increase the PWM bit resolution of the Arduino Uno. At this moment it is 8-bit which I consider too low. Is this possible without losing the ability of interrupts and delays?

Koen

EDIT This setup delivers a 16-bit resultion

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(CS11);                    /* prescaler 1 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> 16000000/(65535+1)=244,14Hz
*/ 

/* 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;
    }
}

I would like to increase the PWM bit resolution of the Arduino Uno. At this moment it is 8-bit which I consider too low. Is this possible without losing the ability of interrupts and delays?

Koen

EDIT This setup delivers a 16-bit resultion

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(CS11);                    /* prescaler 1 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> 16000000/(65535+1)=244,14Hz
*/

I would like to increase the PWM bit resolution of the Arduino Uno. At this moment it is 8-bit which I consider too low. Is this possible without losing the ability of interrupts and delays?

Koen

EDIT This setup delivers a 16-bit resultion

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(CS11);                    /* prescaler 1 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> 16000000/(65535+1)=244,14Hz
*/ 

/* 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;
    }
}
added 350 characters in body
Source Link
KoenR
  • 177
  • 1
  • 3
  • 11

EDIT Changed the Setup, which Edgar Bonet delivered, to what I think isThis setup delivers a 1316-bit resolutionresultion

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(CS11);                    /* prescaler 81 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}

At this moment I am using oversampling to increase my analogread resolution. This in combination with increasing the frequency of the ADC. Is someone able to take a look at(although it is out of topic)?

    #define FASTADC 1
    // defines for setting and clearing register bits
    #ifndef cbi
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
    #endif
    #ifndef sbi
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    #endif
    
    int value[100];   // variable to store the value* comingComments fromabout the sensor
    int i=0;
    
    void setup() 
 Changing ICR1 will {
effect the amount of bits of Serialresolution.begin(9600) ;
     int start ;
     int i ;
     
    #if FASTADC
     // set prescale to 16
     sbi(ADCSRA,ADPS2) ;
     cbi(ADCSRA,ADPS1) ;
     cbi(ADCSRA,ADPS0) ;
    #endif
    }
    
    void loop() 
      { 
    ICR1 = for0xffff; (i=0;i<100;i++65535)
     16-bit {resolution
    ICR1 = 0x7FFF; value[i]=Read12bit(032767);
      }15-bit resolution
    ICR1 = for0x3FFF; (i=0;i<100;i++16383)
      {
     14-bit resolution Serialetc.println(value[i]);
      } 
      Serial.println();//Some blanks between values
      Serial.println();
      delay(5000);.
     
  Changing the }
prescaler will effect the 
 frequency of the PWM signal.
    int Read12bitFrequency[Hz}=CPU/(uint8_t pinICR1+1){
     where in

t Result = 0;
  analogRead(pin);                    this case //SwitchCPU=16 ADCMHz
  for(int i = 0;i < 16; i++) {          //Read 16 times
    Result = Result + analogRead(pin);  //Sum results 
  }
  Result = (int)Result/4;           -bit PWM will be>>> /16000000/Divide by 4 for 12 bit value
  return(Result65535+1);=244,14Hz
}*/

At this moment the resolution of this oversampled analogread is 12-bits. With a little calculation the time to read will take 0,208milliseconds. As I see no way to change the PWM to 12 bit mode, I have to increase the analogread to 13 bits. This will take the measurement 0,832 milliseconds. This seems rather big, so my question is can I do this in another way?

EDIT Changed the Setup, which Edgar Bonet delivered, to what I think is a 13-bit resolution

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(CS11);                    /* prescaler 8 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}

At this moment I am using oversampling to increase my analogread resolution. This in combination with increasing the frequency of the ADC. Is someone able to take a look at(although it is out of topic)?

    #define FASTADC 1
    // defines for setting and clearing register bits
    #ifndef cbi
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
    #endif
    #ifndef sbi
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    #endif
    
    int value[100];   // variable to store the value coming from the sensor
    int i=0;
    
    void setup() 
    {
      Serial.begin(9600) ;
     int start ;
     int i ;
     
    #if FASTADC
     // set prescale to 16
     sbi(ADCSRA,ADPS2) ;
     cbi(ADCSRA,ADPS1) ;
     cbi(ADCSRA,ADPS0) ;
    #endif
    }
    
    void loop() 
      { 
      for (i=0;i<100;i++)
      {
       value[i]=Read12bit(0);
      } 
      for (i=0;i<100;i++)
      {
       Serial.println(value[i]);
      } 
      Serial.println();//Some blanks between values
      Serial.println();
      delay(5000);
     
    }
    
     
    int Read12bit(uint8_t pin){
      in

t Result = 0;
  analogRead(pin);                      //Switch ADC
  for(int i = 0;i < 16; i++) {          //Read 16 times
    Result = Result + analogRead(pin);  //Sum results 
  }
  Result = (int)Result/4;               //Divide by 4 for 12 bit value
  return(Result);
}

At this moment the resolution of this oversampled analogread is 12-bits. With a little calculation the time to read will take 0,208milliseconds. As I see no way to change the PWM to 12 bit mode, I have to increase the analogread to 13 bits. This will take the measurement 0,832 milliseconds. This seems rather big, so my question is can I do this in another way?

EDIT This setup delivers a 16-bit resultion

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(CS11);                    /* prescaler 1 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> 16000000/(65535+1)=244,14Hz
*/
added 2557 characters in body
Source Link
KoenR
  • 177
  • 1
  • 3
  • 11
Loading
Source Link
KoenR
  • 177
  • 1
  • 3
  • 11
Loading