preliminary support for 16 bit pwm. The 16 bit counter ist still used for
authorsimimeie <simimeie>
Sun, 25 Jul 2010 20:40:44 +0000 (20:40 +0000)
committersimimeie <simimeie>
Sun, 25 Jul 2010 20:40:44 +0000 (20:40 +0000)
precise timing info as well (e.g. for ir decoding). pwm support still is
a little buggy - e.g. when values are too close together.

console.c
ledpwm.c
ledpwm.h
main.c
timers.c

index 8dff9f4b72ecef5c2d034fd52f6e9bd6657f5a0e..d884017f3822f284e33fd775bdf089e55a7bc637 100644 (file)
--- a/console.c
+++ b/console.c
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.4 2010/07/24 20:55:48 simimeie Exp $
+/* $Id: console.c,v 1.5 2010/07/25 20:40:44 simimeie Exp $
  * Functions for a serial console.
  */
 
@@ -349,6 +349,7 @@ ISR(USART_RX_vect) {
                        saveeepromsettings();
                        console_printpgm_noirq_P(PSTR("Settings written to EEPROM."));*/
                } else if (strcmp_P(inputbuf, PSTR("status")) == 0) {
+                       uint8_t v;
                        console_printpgm_noirq_P(PSTR("Current status:\r\n"));
                        console_printpgm_noirq_P(PSTR("red = "));
                        console_printhex8_noirq(ledpwm_re);
@@ -358,34 +359,38 @@ ISR(USART_RX_vect) {
                        console_printhex8_noirq(ledpwm_bl);
                        console_printpgm_noirq_P(PSTR(", brightness = "));
                        console_printhex8_noirq(ledpwm_bri);
+                       console_printpgm_noirq_P(PSTR("\r\nvalues "));
+                       for (v = 0; v < 3; v++) {
+                               console_printhex8_noirq(ledpwm_val[v] >> 8);
+                               console_printhex8_noirq(ledpwm_val[v] & 0xff);
+                               console_printpgm_noirq_P(PSTR(" "));
+                       }
                } else if (strncmp_P(inputbuf, PSTR("r "), 2) == 0) {
                        uint8_t v;
                        v = strtoul(&inputbuf[2], NULL, 0);
                        ledpwm_re = v;
-                       ledpwm_setled(LEDPWM_REDLED, (((uint16_t)ledpwm_re * ledpwm_bri) / 255));
+                       ledpwm_setled(LEDPWM_REDLED, ((uint16_t)ledpwm_re * ledpwm_bri));
                        console_printpgm_noirq_P(PSTR("RED value set to 0x"));
                        console_printhex8_noirq(v);
                } else if (strncmp_P(inputbuf, PSTR("g "), 2) == 0) {
                        uint8_t v;
                        v = strtoul(&inputbuf[2], NULL, 0);
                        ledpwm_gr = v;
-                       ledpwm_setled(LEDPWM_GREENLED, (((uint16_t)ledpwm_gr * ledpwm_bri) / 255));
+                       ledpwm_setled(LEDPWM_GREENLED, ((uint16_t)ledpwm_gr * ledpwm_bri));
                        console_printpgm_noirq_P(PSTR("GREEN value set to 0x"));
                        console_printhex8_noirq(v);
                } else if (strncmp_P(inputbuf, PSTR("b "), 2) == 0) {
                        uint8_t v;
                        v = strtoul(&inputbuf[2], NULL, 0);
                        ledpwm_bl = v;
-                       ledpwm_setled(LEDPWM_BLUELED, (((uint16_t)ledpwm_bl * ledpwm_bri) / 255));
+                       ledpwm_setled(LEDPWM_BLUELED, ((uint16_t)ledpwm_bl * ledpwm_bri));
                        console_printpgm_noirq_P(PSTR("BLUE value set to 0x"));
                        console_printhex8_noirq(v);
                } else if (strncmp_P(inputbuf, PSTR("bri "), 2) == 0) {
                        uint8_t v;
                        v = strtoul(&inputbuf[4], NULL, 0);
                        ledpwm_bri = v;
-                       ledpwm_setled(LEDPWM_REDLED, (((uint16_t)ledpwm_re * ledpwm_bri) / 255));
-                       ledpwm_setled(LEDPWM_GREENLED, (((uint16_t)ledpwm_gr * ledpwm_bri) / 255));
-                       ledpwm_setled(LEDPWM_BLUELED, (((uint16_t)ledpwm_bl * ledpwm_bri) / 255));
+                       ledpwm_set(ledpwm_re, ledpwm_gr, ledpwm_bl, ledpwm_bri);
                        console_printpgm_noirq_P(PSTR("brightness set to 0x"));
                        console_printhex8_noirq(v);
                } else if (strcmp_P(inputbuf, PSTR("rfstatus")) == 0) {
index b9ef73cb8dcc15e83c03ad71da83034a2d703ba6..d4aa5e298c46edb4c2752ff74aad95f53e0e267d 100644 (file)
--- a/ledpwm.c
+++ b/ledpwm.c
-/* $Id: ledpwm.c,v 1.3 2010/07/10 07:34:51 simimeie Exp $
+/* $Id: ledpwm.c,v 1.4 2010/07/25 20:40:44 simimeie Exp $
  * Functions for led brightness control via PWM (pulse width modulation).
  */
 
 #include <avr/io.h>
+#include <avr/interrupt.h>
 #include "ledpwm.h"
 
-/* Select between Phase correct PWM and Fast PWM mode.
- * setting this to 1 selects phase correct mode, everything else is Fast PWM. */
-#define PHASECORRECTPWM 1
-
 /*
- * Our hardware connections are as follows:
- *  Red -> PD6 / OC0A
- *  Green -> PD5 / OC0B
- *  Blue -> PD3 / OC2B
+ * Our hardware connections on the first prototype are as follows:
+ *  Red ->   PD6 (OC0A)
+ *  Green -> PD5 (OC0B)
+ *  Blue ->  PD3 (OC2B)  CHANGED umgeloetet durch Julian jetzt PD7
+ * In the next hardware revision this will be:
+ *  Red ->   PC3
+ *  Green -> PC2
+ *  Blue ->  PC1
  */
 
+#define LEDPORT PORTD
+#define LEDDDR DDRD
+#define LEDPINR 6
+#define LEDPING 5
+#define LEDPINB 7
+
 uint8_t ledpwm_re = 0xff, ledpwm_gr = 0xff, ledpwm_bl = 0xff;
 uint8_t ledpwm_bri = 128;
+/* Internal */
+volatile uint16_t ledpwm_val[3] = { 0x8000, 0x8000, 0x8000 };
+volatile uint16_t ledpwm_curoreg = 0;
 
-void ledpwm_init(void)
-{
-  /* Set OC2B, OC0A and OC0B to output */
-  DDRD |= _BV(3) | _BV(5) | _BV(6);
-  /* Set compare output mode for OC2B in timer counter control register: */
-#if (PHASECORRECTPWM == 1)
-  /* select phase correct PWM mode (1). WGM2 bit is 0 so we don't need to touch TCCR2B. */
-  TCCR2A |= _BV(COM2B1) | _BV(WGM20);
-#else  /* not PHASECORRECTPWM */
-  /* set output at BOTTOM (=0), clear it on compare match.
-   * select fast PWM mode 3. WGM2 bit is 0 so we don't need to touch TCCR2B. */
-  TCCR2A |= _BV(COM2B1) | _BV(WGM20) /*| _BV(WGM21)*/;
-#endif /* PHASECORRECTPWM */
-  /* select clock source: cpu clock without prescaler. */
-  TCCR2B |= _BV(CS20);
-  /* Default brightness: PWM 0 */
-  OCR2B = 0;
-  /* Set compare output mode for OC0A and OC0B in timer counter control register: */
-#if (PHASECORRECTPWM == 1)
-  /* select phase correct PWM mode (1). WGM2 bit is 0 so we don't need to touch TCCR0B. */
-  TCCR0A |= _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00);
-#else  /* not PHASECORRECTPWM */
-  /* set output at BOTTOM (=0), clear it on compare match.
-   * select fast PWM mode 3. WGM2 bit is 0 so we don't need to touch TCCR0B. */
-  TCCR0A |= _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00) | _BV(WGM01);
-#endif /* PHASECORRECTPWM */
-  /* select clock source: i/o clock without prescaler. */
-  TCCR0B |= _BV(CS20);
-  /* Default brightness: PWM 0 */
-  OCR0A = 0;
-  OCR0B = 0;
+/* To do a 16-bit write, the high byte must be written before the low byte.
+ * For a 16-bit read, the low byte must be read before the high byte */
+static void ledpwm_programnextstep(void) {
+  uint16_t nextval = 0xffff;
+  uint8_t i;
+  for (i = 0; i < 3; i++) {
+    if ((ledpwm_val[i] > ledpwm_curoreg) && (ledpwm_val[i] <= nextval)) {
+      nextval = ledpwm_val[i];
+    }
+  }
+  OCR1AH = nextval >> 8;
+  OCR1AL = nextval & 0xff;
+  ledpwm_curoreg = nextval;
 }
 
-/* In none-phase-correct PWM mode, This function does some mapping of
- * the values:
- * 0 really turns the LED off.
- * 1 is an PWM value of 0, which still lets the LED glimmer.
- * 2 to 254 are mapped to PWM 3 to 253 (always one less!)
- * 255 is mapped to PWM 255.
- * So there is no way to set PWM 254, but you cannot visually see the
- * difference to 253 or 255 anyways...
- * In phase-correct PWM mode there does not need to be a mapping, 0 means off.
- */
-void ledpwm_setled(uint8_t led, uint8_t val)
+/* This gets called from timers.c which holds the 'main' (interrupt)
+ * handler for the timer1 overflow. */
+void ledpwm_TIMER1OVF_hook(void) {
+  /* Turn on all LEDs */
+  if (ledpwm_val[LEDPWM_REDLED] > 0) {
+    LEDPORT |= _BV(LEDPINR);
+  }
+  if (ledpwm_val[LEDPWM_GREENLED] > 0) {
+    LEDPORT |= _BV(LEDPING);
+  }
+  if (ledpwm_val[LEDPWM_BLUELED] > 0) {
+    LEDPORT |= _BV(LEDPINB);
+  }
+  ledpwm_curoreg = 0;
+  ledpwm_programnextstep();
+}
+
+/* Called on compare match */
+ISR(TIMER1_COMPA_vect)
 {
-#if (PHASECORRECTPWM == 1)
-  switch (led) {
-  case LEDPWM_REDLED:   OCR0A = val; break;
-  case LEDPWM_GREENLED: OCR0B = val; break;
-  case LEDPWM_BLUELED:  OCR2B = val; break;
-  };
-#else /* not PHASECORRECTPWM */
-  if (val == 0) {
-    switch (led) {
-    case LEDPWM_REDLED:   DDRD &= (uint8_t)~_BV(6);
-                          break;
-    case LEDPWM_GREENLED: DDRD &= (uint8_t)~_BV(5);
-                          break;
-    case LEDPWM_BLUELED:  DDRD &= (uint8_t)~_BV(3);
-                          break;
-    };
-  } else {
-    val -= 1;
-    if (val == 254) {
-      val = 255;
-    }
-    switch (led) {
-    case LEDPWM_REDLED:   DDRD |= _BV(6);
-                          OCR0A = val;
-                          break;
-    case LEDPWM_GREENLED: DDRD |= _BV(5);
-                          OCR0B = val;
-                          break;
-    case LEDPWM_BLUELED:  DDRD |= _BV(3);
-                          OCR2B = val;
-                          break;
-    };
+  if (ledpwm_val[LEDPWM_REDLED] <= ledpwm_curoreg) {
+    LEDPORT &= (uint8_t)~_BV(LEDPINR);
+  }
+  if (ledpwm_val[LEDPWM_GREENLED] <= ledpwm_curoreg) {
+    LEDPORT &= (uint8_t)~_BV(LEDPING);
+  }
+  if (ledpwm_val[LEDPWM_BLUELED] <= ledpwm_curoreg) {
+    LEDPORT &= (uint8_t)~_BV(LEDPINB);
   }
-#endif /* PHASECORRECTPWM */
+  ledpwm_programnextstep();
+}
+
+void ledpwm_init(void) {
+  /* Set our Port Pins to output */
+  LEDDDR |= _BV(LEDPINR) | _BV(LEDPING) | _BV(LEDPINB);
+  /* DO NOT initialize TIMER1 frequency and overflow interrupt.
+   * timers.c already does that. */
+  /* Enable TIMER1 output compare interrupt A */
+  TIMSK1 |= _BV(OCIE1A);
+  ledpwm_programnextstep();
+}
+
+void ledpwm_setled(uint8_t led, uint16_t val) {
+  if (led > 2) { return; /* ignore invalid values */ }
+  ledpwm_val[led] = val;
+  ledpwm_programnextstep();
 }
 
 void ledpwm_set(uint8_t red, uint8_t green, uint8_t blue, uint8_t br) {
-  ledpwm_setled(LEDPWM_REDLED,  (((uint16_t)red   * br) / 255));
-  ledpwm_setled(LEDPWM_GREENLED,(((uint16_t)green * br) / 255));
-  ledpwm_setled(LEDPWM_BLUELED, (((uint16_t)blue  * br) / 255));
+  ledpwm_val[LEDPWM_REDLED]   = red * br;
+  ledpwm_val[LEDPWM_GREENLED] = green * br;
+  ledpwm_val[LEDPWM_BLUELED]  = blue * br;
+  ledpwm_programnextstep();
 }
index 6d813193a8086a8a470db3617302bd1dfdbca90a..b7065fd5ad3dea419ce06bb96c658d6d1f9e75a2 100644 (file)
--- a/ledpwm.h
+++ b/ledpwm.h
@@ -1,24 +1,28 @@
-/* $Id: ledpwm.h,v 1.3 2010/07/10 07:34:51 simimeie Exp $
+/* $Id: ledpwm.h,v 1.4 2010/07/25 20:40:44 simimeie Exp $
  * Functions for led brightness control via PWM (pulse width modulation).
  */
 
 #ifndef _LEDPWM_H_
 #define _LEDPWM_H_
 
-#define LEDPWM_REDLED    1
-#define LEDPWM_GREENLED  2
-#define LEDPWM_BLUELED   3
+#define LEDPWM_REDLED    0
+#define LEDPWM_GREENLED  1
+#define LEDPWM_BLUELED   2
 
 extern uint8_t ledpwm_re;
 extern uint8_t ledpwm_gr;
 extern uint8_t ledpwm_bl;
 extern uint8_t ledpwm_bri;
 
+/* Temporary for debugging - these should be internal */
+extern volatile uint16_t ledpwm_val[3];
+extern volatile uint16_t ledpwm_curoreg;
+
 /* Init PWM (pins and timers) */
 void ledpwm_init(void);
 
 /* Set brightness for a certain LED */
-void ledpwm_setled(uint8_t led, uint8_t val);
+void ledpwm_setled(uint8_t led, uint16_t val);
 
 /* Set brightness for all LEDs */
 void ledpwm_set(uint8_t red, uint8_t green, uint8_t blue, uint8_t br);
diff --git a/main.c b/main.c
index 3e66f1a5c5532373de52eb35575138d6d2b907e5..05d4b6b8259968c631c1274fb8dd357d55515bdf 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.7 2010/07/24 20:55:48 simimeie Exp $
+/* $Id: main.c,v 1.8 2010/07/25 20:40:44 simimeie Exp $
  * Main file for the HaWo moodlight.
  * This is the main file that glues it all together. It also contains all
  * functionality that is too small to require an extra file.
@@ -166,9 +166,7 @@ int main(void)
                  irstate = 0;
                  break;
       };
-      ledpwm_setled(LEDPWM_REDLED,   (((uint16_t)ledpwm_re * ledpwm_bri) / 255));
-      ledpwm_setled(LEDPWM_GREENLED, (((uint16_t)ledpwm_gr * ledpwm_bri) / 255));
-      ledpwm_setled(LEDPWM_BLUELED,  (((uint16_t)ledpwm_bl * ledpwm_bri) / 255));
+      ledpwm_set(ledpwm_re, ledpwm_gr, ledpwm_bl, ledpwm_bri);
     }
     /* i++;
     console_printhex8(i);
index 754db0605cb48d5facf94771aa78f6bee11bf4fa..eb2f2fe46600c8eda98ebb5d7544b0aa5399ee38 100644 (file)
--- a/timers.c
+++ b/timers.c
@@ -1,4 +1,4 @@
-/* $Id: timers.c,v 1.1 2010/06/27 22:18:26 simimeie Exp $
+/* $Id: timers.c,v 1.2 2010/07/25 20:40:44 simimeie Exp $
  * Functions for timing.
  * This mainly allows you to get a timestamp value
  */
 /* Internal ticks */
 static volatile uint16_t ticks = 0;
 
-/* FIXME TCNT1H TCNT1L */
+void ledpwm_TIMER1OVF_hook(void);
 
 /* Executes every 65536 cpu cycles when the timer overflows */
 ISR(TIMER1_OVF_vect)
 {
   ticks++;
+  ledpwm_TIMER1OVF_hook();
 }
 
 uint16_t getticks(void)
This page took 0.065934 seconds and 4 git commands to generate.