From 64a3d3a699cd60b7a6b4b06c5c38689975a3d460 Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Thu, 29 Nov 2012 14:36:45 +0100 Subject: [PATCH] firmware: emulate higher resolution of PWM Emulate the sub-1 LSB resolution of PWM by updating the PWM values in the timer interrupt routine --- firmware/lights.h | 4 ++++ firmware/pwm.c | 44 ++++++++++++++++++++++++++++++++++++++++---- firmware/tmr.c | 2 ++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/firmware/lights.h b/firmware/lights.h index b159ae8..434f051 100644 --- a/firmware/lights.h +++ b/firmware/lights.h @@ -29,11 +29,15 @@ void timer_start_adcs(); /* pwm.c */ #define PWM_MAX 0x1E4 /* This should be different than ADC frequency 125 kHz */ +#define PWM_STEP_SHIFT 2 /* second parameter of pwm_set is shifted by + * PWM_STEP_SHIFT bits to the right before setting + * into HW */ void init_pwm(); void susp_pwm(); void pwm_off(unsigned char n); void pwm_set(unsigned char n, uint16_t stride); +void pwm_timer(); /* tmr.c */ extern volatile uint16_t jiffies; diff --git a/firmware/pwm.c b/firmware/pwm.c index 201770f..da9fe3d 100644 --- a/firmware/pwm.c +++ b/firmware/pwm.c @@ -4,8 +4,18 @@ #include "lights.h" +static uint16_t pwm[N_PWMLEDS]; +static volatile unsigned char step; + void init_pwm() { + int i; + + step = 0; + + for (i = 0; i < N_PWMLEDS; i++) + pwm[n] = 0; + /* Async clock */ PLLCSR = _BV(PLLE); @@ -37,6 +47,11 @@ void init_pwm() void susp_pwm() { + unsigned char i; + + for (i = 0; i < N_PWMLEDS; i++) + pwm[i] = 0; + DDRB &= ~(_BV( PB1 ) | _BV( PB3 ) | _BV( PB5 )); TCCR1D = TCCR1C = TCCR1B = TCCR1A = 0; TIMSK = 0; @@ -45,6 +60,8 @@ void susp_pwm() void pwm_off(unsigned char n) { + pwm[n] = 0; + switch (n) { case 0: DDRB &= ~_BV(PB1); break; case 1: DDRB &= ~_BV(PB3); break; @@ -52,12 +69,10 @@ void pwm_off(unsigned char n) } } -void pwm_set(unsigned char n, uint16_t stride) +static void pwm_update_hw(unsigned char n) { unsigned char hi, lo; - - if (stride > PWM_MAX) - stride = PWM_MAX; + uint16_t stride = (pwm[n] + step) >> PWM_STEP_SHIFT; if (n == 2) stride = PWM_MAX - stride; @@ -84,6 +99,27 @@ void pwm_set(unsigned char n, uint16_t stride) } } +void pwm_set(unsigned char n, uint16_t stride) +{ + if (((stride + (1 << PWM_STEP_SHIFT)) >> PWM_STEP_SHIFT) >= PWM_MAX) + stride = PWM_MAX << PWM_STEP_SHIFT; + + pwm[n] = stride; + pwm_update_hw(n); +} + +void pwm_timer() +{ + unsigned char i; + + if (++step >= (1 << PWM_STEP_SHIFT)) + step = 0; + + for (i = 0; i < N_PWMLEDS; i++) + if (pwm[n]) + pwm_update_hw(n); +} + #if 0 static void inline pwm_handler() { diff --git a/firmware/tmr.c b/firmware/tmr.c index 5a94f9a..9a0a38b 100644 --- a/firmware/tmr.c +++ b/firmware/tmr.c @@ -29,6 +29,8 @@ ISR(TIMER0_COMPA_vect) { ++jiffies; + pwm_timer(); + if (--pattern_div == 0) { timer_check_buttons(); patterns_next_tick(); -- 2.39.3