Removed an unnecessary sleep from r0ketbeam. Added support for 7 segment
[cerebrum.git] / cerebrum_firmware.c
blobb9ac1a8a75020b3572e01805f938752895c473aa
1 /*
2 Copyright (C) 2012 jaseg <s@jaseg.de>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 version 3 as published by the Free Software Foundation.
7 */
9 #include <avr/io.h>
10 #include <util/delay.h>
11 #include <avr/pgmspace.h>
12 #include <avr/interrupt.h>
13 #include "uart.h"
14 #include "r0ketbeam.h"
16 void setup(void);
17 void loop(void);
19 int main(void){
20 setup();
21 for(;;) loop();
24 void setup(){
25 uart_init(UART_BAUD_SELECT_DOUBLE_SPEED(115200, F_CPU));
26 //s/w "BCM"(<== "Binary Code Modulation") timer setup
28 TCCR0A |= _BV(WGM00)|_BV(WGM01);
29 TCCR0B |= _BV(CS02);
30 TIMSK0 |= _BV(TOIE0);
32 //FIXME set PWM output DDRs
33 //The DDRs of the led matrix outputs are set in the mux loop.
34 r0ketbeam_setup();
35 sei();
38 //this scary construct is in place to make the compiler happy. if you know a better way, feel free to improve.
39 uint8_t _frameBuffer[] = {0,0,0,0};
40 uint8_t _secondFrameBuffer[] = {0,0,0,0};
41 uint8_t* frameBuffer = _frameBuffer;
42 uint8_t* secondFrameBuffer = _secondFrameBuffer;
43 char nbuf;
44 int state = 0;
45 uint8_t switch_last_state = 0;
46 int switch_debounce_timeout = 0;
47 uint8_t mcnt = 0;
48 uint8_t ccnt = 0;
50 #define PWM_COUNT 5
51 uint8_t pwm_cycle = 0;
52 uint8_t pwm_val[PWM_COUNT];
53 #define INPUT_COUNT 0
54 uint8_t debounce_timeouts[INPUT_COUNT];
55 uint8_t switch_states[INPUT_COUNT];
57 void swapBuffers(void){
58 uint8_t* tmp = frameBuffer;
59 frameBuffer = secondFrameBuffer;
60 secondFrameBuffer = tmp;
63 void setLED(int num, int val){
64 if(num<32){
65 frameBuffer[num>>3] &= ~(1<<(num&7));
66 if(val)
67 frameBuffer[num>>3] |= 1<<(num&7);
71 int parseHex(char* buf){
72 int result = 0;
73 int len = 2;
74 for(int i=0; i<len; i++){
75 char c = buf[len-i];
76 int v = 0;
77 if(c>='0' && c<='9'){
78 v=(c-'0');
79 }else if(c>='a' && c<= 'f'){
80 v=(c-'a'+10);
81 }else if(c>='A' && c<= 'F'){
82 v=(c-'A'+10);
84 result |= v<<(4*i);
86 return result;
89 inline char hex_nibble(uint8_t data){
90 if(data<0xA)
91 return data+'0';
92 else
93 return data+'A'-0xA;
96 void put_hex(uint8_t data){
97 uart_putc(hex_nibble(data&15));
98 uart_putc(hex_nibble(data>>4));
101 void loop(){ //one frame
102 static uint8_t escape_state = 0;
103 uint16_t receive_state = 1;
104 //primitive somewhat messy state machine of the uart interface
105 do{ //Always empty the receive buffer since there are _delay_xxs in the following code and thus this might not run all that often.
106 receive_state = uart_getc();
107 char c = receive_state&0xFF;
108 receive_state &= 0xFF00;
109 //escape code format:
110 // \\ - backslash
111 // \n - newline
112 // \[x] - x
113 //eats three commands: 's' (0x73) led value sets led number [led] to [value]
114 // 'b' (0x62) buffer buffer buffer buffer sets the whole frame buffer
115 // 'a' (0x61) meter value sets analog meter number [meter] to [value]
116 // 'r' (0x72) read the frame buffer
117 //this device will utter a "'c' (0x63) num state" when switch [num] changes state to [state]
118 //commands are terminated by \n
119 if(!receive_state){
120 if(!escape_state){
121 if(c == '\\'){
122 receive_state |= 0x02;
123 escape_state = 1;
124 }else if(c == '\n'){
125 receive_state |= 0x02;
126 state = 0;
128 }else{
129 receive_state = 0;
130 escape_state = 0;
131 switch(c){
132 case '\\':
133 break;
134 case 'n':
135 c = '\n';
136 break;
140 if(!receive_state){
141 switch(state){
142 case 0: //Do not assume anything about the variables used
143 //command char
144 switch(c){
145 case 's':
146 state = 2;
147 break;
148 case 'b':
149 nbuf = 0;
150 state = 4;
151 break;
152 case 'a':
153 state = 5;
154 nbuf = 0;
155 break;
156 case 'r':
157 uart_putc('r');
158 for(uint8_t i=0; i<sizeof(frameBuffer); i++){
159 put_hex(frameBuffer[i]);
161 uart_putc('\n');
162 break;
164 break;
165 case 2:
166 nbuf=c;
167 state = 3;
168 break;
169 case 3:
170 setLED(nbuf, c);
171 state = 0;
172 break;
173 case 4:
174 secondFrameBuffer[(uint8_t) nbuf] = c;
175 nbuf++;
176 if(nbuf == 4){
177 swapBuffers();
178 state = 0;
180 break;
181 case 5:
182 if(c > PWM_COUNT)
183 c = 0;
184 nbuf = c;
185 state = 6;
186 break;
187 case 6:
188 pwm_val[(uint8_t) nbuf] = c;
189 state = 0;
192 }while(!receive_state);
193 for(int i=0; i<8; i++){
194 uint8_t Q = 0x80>>i; //select the currently active "row" of the matrix. On the protoboards I make, this actually corresponds to physical traces.
195 //uint8_t DDRQ = 0xFF>>i; //This is supposed to be an optimization. It is untested and will probably not work.
196 uint8_t DDRQ = 0xFF; //Just for testing: reactivating the old behavioor
197 //unpacking of frame data: data is packed like this: [11111117][22222266][33333555][4444----]
198 if(!(i&4))
199 Q |= frameBuffer[i&3] >> i;
200 else
201 Q |= frameBuffer[i&3] & (0xFF << (i&3));
202 //FIXME this whole mapping shit should be done in h/w!!1!
203 //FIXME this whole mapping is not even correct!!1!
204 //FIXME IT DOES NOT WORK!!1!
205 // Q&0x01 ==> PG5
206 // 02 ==> PE3
207 // 04 ==> PH3
208 // 08 ==> PH4
209 // 10 ==> PH5
210 // 20 ==> PH6
211 // 40 ==> PB4
212 // 80 ==> PB5
213 DDRG&=~(1<<5);
214 DDRG|=(DDRQ&1)<<5;
215 PORTG&=~(1<<5);
216 PORTG|=(Q&1)<<5;
217 DDRE&=~(1<<3);
218 DDRE|=(DDRQ&2)<<2;
219 PORTE&=~(1<<3);
220 PORTE|=(Q&2)<<2;
221 DDRH&=0xC3;
222 DDRH|=(DDRQ&0x3C);
223 PORTH&=0xC3;
224 PORTH|=(Q&0x3C);
225 DDRB&=0xCF;
226 DDRB|=(DDRQ&0xC0)>>2;
227 PORTB&=0xCF;
228 PORTB|=(Q&0xC0)>>2;
229 /* second channel skeleton
230 Q = 0x80>>i;
231 if(!(i&4))
232 Q |= frameBuffer[4+(i&3)] >> i;
233 else
234 Q |= frameBuffer[4+(i&3)] & (0xFF << (i&3));
235 DDRA = DDRQ;
236 PORTA = Q;
237 //PORTD &= 0x0F;
238 //PORTD |= Q&0xF0;
239 //PORTB &= 0xF0;
240 //PORTB |= Q&0x0F;
242 _delay_ms(1);
244 r0ketbeam_loop();
245 /* no switches (yet)
246 switch_states[0] |= !!(PINH&0x02);
247 for(int i=0; i<INPUT_COUNT; i++){
248 debounce_timeouts[i]--;
249 //A #define for the debounce time would be great
250 if(debounce_timeouts[i] == 0){
251 uint8_t new_switch_state = switch_states[i]<<1;
252 if(!(switch_states[i]^new_switch_state)){
253 uart_putc('c');
254 uart_putc(i);
255 uart_putc(switch_states[i]&1);
256 debounce_timeouts[i] = 0xFF;
257 switch_states[i] = new_switch_state&3;
264 //Software PWM stuff
265 //Called every 256 cpu clks (i.e should not get overly long)
266 ISR(TIMER0_OVF_vect){
267 uint8_t Q = 0;
268 Q |= (pwm_val[0] & pwm_cycle);
269 Q |= (pwm_val[1] & pwm_cycle)?2:0;
270 Q |= (pwm_val[2] & pwm_cycle)?4:0;
271 Q |= (pwm_val[3] & pwm_cycle)?8:0;
272 Q |= (pwm_val[4] & pwm_cycle)?16:0;
273 PORTC = Q;
274 OCR0A = pwm_cycle;
275 pwm_cycle<<=1;
276 if(!pwm_cycle)
277 pwm_cycle = 1;