weird problem with 10bit PWM output on Leonardo (255 is taboo)

I am outputting a uint16_t var using analogWrite to pin 10
once the 16 bit variable reaches 255 , all hell breakes loose, the PWM controls a high current stage, and currents up to 80A is measured, this causes PWM to drop fast, and it may as well hit the magic number on it's way up again.

  • A simple workaround is to check for, and do not send 255 , going to 256 works correctly, and duty cucle of 256 is bigger than 254 (no rollover).

I also have some code to speed up the PWM, maybe there is something wrong there, but I don't see it.

 TCCR1B = 0b00001000 | 0x01;   //bit4 WGM13 bit 3 WGM12
  ICR1 = 0xFFFF;
  TCCR1A = 0b10101011;  //bit1 WGM11 bit0 WGM10

The allowable range for analogWrite() is 0 to 255 (8 bits). No wonder that you have problems with values above that. See http://www.arduino.cc/en/Reference/AnalogWrite

If you want to do PWM at more than 8 bits you can’t use the Arduino core. Fortunately that problem came up a while back and I wrote some functions to handle it:

// Set 'TOP' for PWM resolution.  Assumes 16 MHz clock.
// un-comment one of the choices
// const unsigned int TOP = 0xFFFF; // 16-bit resolution.   244 Hz PWM
// const unsigned int TOP = 0x7FFF; // 15-bit resolution.   488 Hz PWM
// const unsigned int TOP = 0x3FFF; // 14-bit resolution.   976 Hz PWM
// const unsigned int TOP = 0x1FFF; // 13-bit resolution.  1953 Hz PWM
// const unsigned int TOP = 0x0FFF; // 12-bit resolution.  3906 Hz PWM
// const unsigned int TOP = 0x07FF; // 11-bit resolution.  7812 Hz PWM
   const unsigned int TOP = 0x03FF; // 10-bit resolution. 15624 Hz PWM


void PWM16Begin() {
  // Stop Timer/Counter1
  TCCR1A = 0;  // Timer/Counter1 Control Register A
  TCCR1B = 0;  // Timer/Counter1 Control Register B
  TIMSK1 = 0;   // Timer/Counter1 Interrupt Mask Register
  TIFR1 = 0;   // Timer/Counter1 Interrupt Flag Register
  ICR1 = TOP;
  OCR1A = 0;  // Default to 0% PWM
  OCR1B = 0;  // Default to 0% PWM

  // Set clock prescale to 1 for maximum PWM frequency
  TCCR1B |= (1 << CS10);

  // Set to Timer/Counter1 to Waveform Generation Mode 14: Fast PWM with TOP set by ICR1
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12) ;
}

void PWM16EnableA() {
  // Enable Fast PWM on Pin 9: Set OC1A at BOTTOM and clear OC1A on OCR1A compare
  TCCR1A |= (1 << COM1A1);
  pinMode(9, OUTPUT);
}

void PWM16EnableB() {
  // Enable Fast PWM on Pin 10: Set OC1B at BOTTOM and clear OC1B on OCR1B compare
  TCCR1A |= (1 << COM1B1);
  pinMode(10, OUTPUT);
}

inline void PWM16A(unsigned int PWMValue) {
  OCR1A = constrain(PWMValue, 0, TOP);
}

inline void PWM16B(unsigned int PWMValue) {
  OCR1B = constrain(PWMValue, 0, TOP);
}


void setup() {
  Serial.begin(9600);
  PWM16Begin();
  
  // On the Arduino UNO T1A is Pin 9 and T1B is Pin 10
  
//  PWM16A(0);  // Set initial PWM value for Pin 9
//  PWM16EnableA();  // Turn PWM on for Pin 9

  PWM16B(0);  // Set initial PWM value for Pin 10
  PWM16EnableB();  // Turn PWM on for Pin 10
}

void loop() {
}

Thanks - the Ardunio source .. I don't see point of setting it high when 255

	// We need to make sure the PWM output is enabled for those pins
	// that support it, as we turn it off when digitally reading or
	// writing with them.  Also, make sure the pin is in output mode
	// for consistenty with Wiring, which doesn't require a pinMode
	// call for the analog output pins.
	pinMode(pin, OUTPUT);
	if (val == 0)
	{
		digitalWrite(pin, LOW);
	}
	else if (val == 255)
	{
		digitalWrite(pin, HIGH);
	}
	else
	{

@johnwasser - thanks - I already solved it directly, like you did.

I don't see point of setting it high when 255

Why not ? It guarantees full voltage on the pin and requires no further computation.