aboutsummaryrefslogtreecommitdiff
path: root/pwm.c
blob: eaaa5afc2b6c5b26d8979c3ba973b4978708439a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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;
}