From ddc8f4be4d90e7e709832b5135b2e7e4631b1554 Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Mon, 10 Sep 2012 21:52:00 +0200 Subject: [PATCH] pwm: channel D is inverted This is to avoid power spikes when all three channels switch on. We make channel D to switch on on OCR1D match, while other two channels (A and B) switch off on OCR1A and OCR1B match, respectively. --- firmware/pwm.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/firmware/pwm.c b/firmware/pwm.c index 0c4f3d0..2df2e6b 100644 --- a/firmware/pwm.c +++ b/firmware/pwm.c @@ -4,6 +4,8 @@ #include "lights.h" +#define PWM_MAX 0x1FF + void init_pwm() { /* Async clock */ @@ -15,16 +17,20 @@ void init_pwm() ; PLLCSR |= _BV(PCKE); - TCCR1C = _BV(COM1D0) | _BV(COM1D1) | _BV(PWM1D); - TCCR1A = _BV(COM1A0) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(PWM1A) | _BV(PWM1B); - TCCR1B = _BV(7) // PWM1X: PWM inversion mode - | _BV(CS10) // no clock prescaling - ; - TC1H = 0x01; - OCR1C = 0xFF; // TOP value + // PWM channel D is inverted, ... + TCCR1C = _BV(COM1D1) | _BV(COM1D0) | _BV(PWM1D); + // PWM channels A and B are not + TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(PWM1A) | _BV(PWM1B); + TCCR1D = 0; + TCCR1B = _BV(CS10); // no clock prescaling + TC1H = PWM_MAX >> 8; + OCR1C = PWM_MAX & 0xFF; // TOP value + + TC1H = PWM_MAX >> 8; + OCR1D = PWM_MAX & 0xFF; TC1H = 0x00; - OCR1D = OCR1B = OCR1A = 0; // initial stride is 0 + OCR1B = OCR1A = 0; // initial stride is 0 DDRB &= ~(_BV( PB1 ) | _BV( PB3 ) | _BV( PB5 )); // tristate it PORTB &= ~(_BV( PB1 ) | _BV( PB3 ) | _BV( PB5 )); // set to zero @@ -54,7 +60,15 @@ void pwm_set(unsigned char n, unsigned char stride) switch (n) { case 0: OCR1A = stride; break; case 1: OCR1B = stride; break; - case 2: OCR1D = stride; break; + case 2: { + uint16_t s16 = PWM_MAX - (uint16_t)stride; + volatile unsigned char hi, lo; + hi = s16 >> 8; + lo = s16 & 0xFF; + TC1H = hi; + OCR1D = lo; + } + break; } } -- 2.39.3