aboutsummaryrefslogtreecommitdiff
path: root/pwm.c
diff options
context:
space:
mode:
Diffstat (limited to 'pwm.c')
-rw-r--r--pwm.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/pwm.c b/pwm.c
new file mode 100644
index 0000000..eaaa5af
--- /dev/null
+++ b/pwm.c
@@ -0,0 +1,81 @@
+/* LED pwm, uses timer0
+ * XXX: this works, but we should use non-linear steps
+ */
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <stdbool.h>
+
+#include "speaker.h"
+
+#define PWM_STEPS 16
+
+/* inverse brightness; 0 is max brightness, PWM_STEPS off */
+static uint8_t invbrightness[6];
+static uint8_t count = 0;
+
+ISR(TIMER0_COMPA_vect) {
+ if (count == 0) {
+ /* switch off all LEDs */
+ PORTB = PORTB & ~((1 << PB6) | (1 << PB7));
+ PORTD = PORTD & ~((1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5));
+ } else {
+ uint8_t pb = 0, pd = 0;
+ if (count > invbrightness[0]) {
+ pb |= (1 << PB6);
+ }
+ if (count > invbrightness[1]) {
+ pb |= (1 << PB7);
+ }
+ if (count > invbrightness[2]) {
+ pd |= (1 << PD2);
+ }
+ if (count > invbrightness[3]) {
+ pd |= (1 << PD3);
+ }
+ if (count > invbrightness[4]) {
+ pd |= (1 << PD4);
+ }
+ if (count > invbrightness[5]) {
+ pd |= (1 << PD5);
+ }
+ /* actually set them */
+ PORTB |= pb;
+ PORTD |= pd;
+ }
+ ++count;
+ if (count >= PWM_STEPS) {
+ count = 0;
+ }
+}
+
+void pwmInit () {
+ /* set led1,led2 to output */
+ DDRB |= (1 << PB6) | (1 << PB7);
+ /* set led3,led4,led5,led6 to output */
+ DDRD |= (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5);
+}
+
+void pwmStart () {
+ /* reset timer value */
+ TCNT0 = 0;
+ /* set ctc timer0 (part 1) */
+ TCCR0A = 0;
+ /* enable compare match interrupt */
+ TIMSK0 = (1 << OCIE0A);
+ /* compare value; interrupt on every tick */
+ OCR0A = 0;
+ /* io clock with 8 prescaler (>8 is too slow and starts flickering); ctc
+ * (part 2) */
+ TCCR0B = (1 << CS01) | (1 << WGM02);
+}
+
+void pwmStop () {
+ /* zero clock source */
+ TCCR0B = 0;
+}
+
+void pwmSetBrightness (const uint8_t i, const uint8_t b) {
+ invbrightness[i] = b;
+}
+