1 | /*** INCLUDE ******************************************************************/
|
2 | #include <avr/io.h>
|
3 | #include <avr/interrupt.h>
|
4 | #include <avr/pgmspace.h>
|
5 | #include <util/delay.h>
|
6 | #include <inttypes.h>
|
7 | #include "leds.h"
|
8 | #include "speaker.h"
|
9 |
|
10 | /*** DEFINE *******************************************************************/
|
11 | #define F_CPU 20000000L
|
12 | #define F_PWM 100L
|
13 | #define PWM_PRESCALER 1
|
14 | #define PWM_CHANNELS 8
|
15 | #define PWM_STEPS 256
|
16 | #define T_PWM (F_CPU / (PWM_PRESCALER * F_PWM * PWM_STEPS))
|
17 |
|
18 | /** VARS/CONSTS ***************************************************************/
|
19 | volatile uint8_t sync;
|
20 | uint8_t cur = 0;
|
21 | uint8_t pwm_count[2];
|
22 | uint16_t pwm_timing[PWM_CHANNELS + 1][2];
|
23 | uint8_t pwm_mask[PWM_CHANNELS + 1][2];
|
24 |
|
25 | uint16_t pwm_table[32] PROGMEM = {0, 1, 2, 2, 2, 3, 3, 4,
|
26 | 5, 6, 7, 8, 10, 11, 13, 16,
|
27 | 19, 23, 27, 32, 38, 45, 54, 64,
|
28 | 76, 91, 108, 128, 152, 181, 215, 255};
|
29 |
|
30 |
|
31 |
|
32 | /** FUNCTIONS *****************************************************************/
|
33 | ISR(TIMER1_COMPA_vect) {
|
34 | static uint8_t pwm = 0;
|
35 | OCR1A += pwm_timing[pwm][cur ^ 1];
|
36 | if (pwm == 0)
|
37 | leds_set(pwm_mask[pwm][cur ^ 1]);
|
38 | else
|
39 | leds_off(pwm_mask[pwm][cur ^ 1]);
|
40 | pwm++;
|
41 | if (pwm == pwm_count[cur ^ 1] + 1) {
|
42 | sync = 1;
|
43 | pwm = 0;
|
44 | }
|
45 | }
|
46 |
|
47 | void leds_pwm_set(uint8_t pwm_setting_unsorted[]) {
|
48 | uint8_t i, j, k;
|
49 | uint8_t pwm_setting[PWM_CHANNELS];
|
50 |
|
51 | // mask
|
52 | pwm_mask[0][cur] = 0;
|
53 | for (i = 0; i < PWM_CHANNELS; i++) {
|
54 | pwm_setting[i] = pgm_read_word(pwm_table + pwm_setting_unsorted[i]);
|
55 | if (pwm_setting[i] != 0)
|
56 | pwm_mask[0][cur] |= (1 << i);
|
57 | pwm_mask[i + 1][cur] = (1 << i);
|
58 | }
|
59 |
|
60 | // sort pwm_settings (bubblesort)
|
61 | for (i = PWM_CHANNELS - 1; i > 0; i--) {
|
62 | for (j = 0; j < i; j++) {
|
63 | // swap
|
64 | if (pwm_setting[j] > pwm_setting[j + 1]) {
|
65 | // swap pwm_settings
|
66 | uint8_t tmp_pwm_setting = pwm_setting[j];
|
67 | pwm_setting[j] = pwm_setting[j + 1];
|
68 | pwm_setting[j + 1] = tmp_pwm_setting;
|
69 | // swap masks
|
70 | uint8_t tmp_mask = pwm_mask[j + 1][cur];
|
71 | pwm_mask[j + 1][cur] = pwm_mask[j + 2][cur];
|
72 | pwm_mask[j + 2][cur] = tmp_mask;
|
73 | }
|
74 | }
|
75 | }
|
76 |
|
77 | // join same values, remove zero values
|
78 | pwm_count[cur] = PWM_CHANNELS;
|
79 | i = 0;
|
80 | while (pwm_count[cur] > i) {
|
81 | while (pwm_count[cur] > i && (pwm_setting[i] == pwm_setting[i + 1] || pwm_setting[i] == 0)) {
|
82 | if (pwm_setting[i] != 0)
|
83 | pwm_mask[i + 2][cur] |= pwm_mask[i + 1][cur];
|
84 | for (k = i; k < pwm_count[cur] + 1; k++) {
|
85 | pwm_setting[k] = pwm_setting[k + 1];
|
86 | pwm_mask[k + 1][cur] = pwm_mask[k + 2][cur];
|
87 | }
|
88 | pwm_count[cur]--;
|
89 | }
|
90 | i++;
|
91 | }
|
92 | if (pwm_setting[i] == 0)
|
93 | pwm_count[cur]--;
|
94 |
|
95 | // calc timings
|
96 | pwm_timing[0][cur] = T_PWM * pwm_setting[0];
|
97 | for (i = 1; i < pwm_count[cur]; i++) {
|
98 | pwm_timing[i][cur] = T_PWM * (pwm_setting[i] - pwm_setting[i - 1]);
|
99 | }
|
100 | pwm_timing[cur][pwm_count[cur]] = T_PWM * (PWM_STEPS - 1 - pwm_timing[cur][pwm_count[cur] - 1]);
|
101 |
|
102 | // swap
|
103 | sync = 0;
|
104 | while (sync == 0);
|
105 |
|
106 | cli();
|
107 | cur ^= 1;
|
108 | sei();
|
109 | }
|
110 |
|
111 |
|
112 | int main(void) {
|
113 | leds_init();
|
114 |
|
115 | // set timer prescaler to F_CPU/8
|
116 | TCCR1B |= (1 << CS00);
|
117 | // enable output compare interrupt
|
118 | TIMSK1 |= (1 << OCIE1A);
|
119 | // enable global interrupts
|
120 | sei();
|
121 |
|
122 | uint8_t vals[] = {31, 31, 0, 0, 0, 0, 0, 0};
|
123 | uint8_t i = 0;
|
124 | while (1) {
|
125 | vals[i]--;
|
126 | vals[(i + 2) % 4]++;
|
127 |
|
128 | if (vals[i] == 0)
|
129 | i = (i + 1) % 4;
|
130 |
|
131 | leds_pwm_set(vals);
|
132 | _delay_ms(20);
|
133 | }
|
134 | }
|