Subversion Repositories group.NITPanels

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pfowler 1
#include <avr/io.h>
2
#include <avr/wdt.h>
3
#include <avr/interrupt.h>
4
#include <string.h>
5
#include <util/delay.h>
6
#include <stdlib.h>
7
 
24 pfowler 8
 
2 pfowler 9
#include "config.h"
10
#include "avrutil.h"
11
#include "hc595.h"
12
#include "twires.h"
13
 
14
 
15
#ifndef NULL
16
#define NULL    ((void *)0)
17
#endif
18
#ifndef PROTOTYPE
19
#define PROTOTYPE
20
#endif
21
 
22
 
23
void writeSegment(uint8_t digit, uint8_t value);
24
void pcInterrupt(void);
25
void receiveEvent(uint8_t bytes);
26
 
27
/* ------------------------------------------------------------------------- */
28
 
29
 
30
#ifndef TWI_RX_BUFFER_SIZE
31
#define TWI_RX_BUFFER_SIZE ( 16 )
32
#endif
33
 
34
volatile uint8_t user_debug = 0;
35
volatile uint8_t tmr0_ovf = 0;
36
volatile struct {
37
        uint8_t current;
38
        uint8_t last;
39
        uint8_t mask;
40
} pcInt;
41
 
42
volatile struct {
43
	int8_t outer;
44
	int8_t inner;
45
} input;
46
 
24 pfowler 47
uint8_t i2c_address = I2C_SLAVE_ADDR;
48
uint8_t disIdx = 0;
2 pfowler 49
volatile uint8_t disVal[] = {0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a};
50
volatile uint16_t disPt = 0x00;
51
 
24 pfowler 52
 
53
 
2 pfowler 54
int main(void) {
55
 
56
 
24 pfowler 57
#if HW_VERSION==0x01
58
	  /*
59
	  DDR : 1 = Output, 0 = Input
60
	  PORT: 1 = Pullup for Input, otherwise set output
61
	  PIN : Read input pin
62
	  */
2 pfowler 63
 
24 pfowler 64
	  /*
65
		PA0 -	Output		- HC595 DS
66
		PA1 - 	Output		- HC595 ST
67
		PA2 -	Output		- HC595 SH
68
		PA3 -	Output		- 4511 blanking
69
		PA4 -	SCK
70
		PA5 -	Output		- Decimal Point
71
		PA6 -	SDA
72
		PA7 -	Input, Pullup	- Flip button
73
	  */
74
	  DDRA          = 0B00101111;
75
	  PORTA         = 0B10001000;
76
	  /*
77
		PB0     - Input, PCInt, Pullup	- Rot1a
78
		PB1     - Input, PCInt, Pullup	- Rot1b
79
		PB2     - Input, Pullup		- Swap button
80
		PB3     - N/A			- Reset (Future - I2C address select)
81
	  */
82
	  DDRB          = 0B00000000;
83
	  PORTB         = 0B00000111;
84
#else
85
	  /*
86
	  DDR : 1 = Output, 0 = Input
87
	  PORT: 1 = Pullup for Input, otherwise set output
88
	  PIN : Read input pin
89
	  */
2 pfowler 90
 
24 pfowler 91
	  /*
92
		PA0 -	Input, Pullup			- i2c addr select 0 (Dip 1)
93
		PA1 - 	Input, Pullup			- i2c addr select 1 (Dip 2)
94
		PA2 -	Reset
95
	  */
96
	  DDRA          = 0B00000000;
97
	  PORTA         = 0B00000011;
98
	  /*
99
		PB0     - Input, PCInt0, Pullup	- Rot1a
100
		PB1     - Input, PCInt1, Pullup	- Rot1b
101
		PB2     - Input, PCInt2, Pullup	- Rot2a
102
		PB3     - Input, PCInt3, Pullup	- Rot2b
103
		PB4     - Input, Pullup			- Rot button
104
		PB5     - SDA
105
		PB6     - Input, Pullup			- Swap button
106
		PB7     - SCL
107
	  */
108
	  DDRB          = 0B00000000;
109
	  PORTB         = 0B01011111;
110
	  /*
111
		PD0     - Output				- Decimal point
112
		PD1     - Output				- 4511 Blanking
113
		PD2     - Output				- '95 DS   Ser
114
		PD3     - Output				- '95 SHCP Sck
115
		PD4     - Output				- '95 STCP Rsk
116
		PD5     - Input, Pullup			- Config (Dip 3)
117
		PD6     - Input, Pullup			- Config (Dip 4)
118
	  */
119
	  DDRD          = 0B00011111;
120
	  PORTD         = 0B01100010;
121
#endif
2 pfowler 122
 
123
    systime = 0;
124
    sysclockInit();
125
 
24 pfowler 126
#if HW_VERSION==0x01
127
    // hwver1 only has a single rotary shaft
2 pfowler 128
    PCMSK1 |= (( 1 << ROT_1A_PIN ) | ( 1 << ROT_1B_PIN ));
129
    GIMSK |= (1 << PCIE1);
24 pfowler 130
#else
131
    // hwver2 only has a selectable single/dual rotary shaft
132
    PCMSK |= (( 1 << ROT_1A_PIN ) | ( 1 << ROT_1B_PIN ) | ( 1 << ROT_2A_PIN ) | ( 1 << ROT_2B_PIN ));
133
    GIMSK |= (1 << PCIE);
134
#endif
2 pfowler 135
 
24 pfowler 136
    pcInt.last = ROT_PIN;
2 pfowler 137
    pcInt.current = pcInt.last;
138
    pcInt.mask = 0;
139
 
24 pfowler 140
#if HW_VERSION==0x02
141
    // hw vers 2 has selectable i2c address. Add the value of
142
    //  the selections to the default i2c address
143
    uint8_t i2c_add = ((!rbi(I2CADDR_PIN, I2CADDR_0)) << 1);
144
    i2c_add |= (!rbi(I2CADDR_PIN, I2CADDR_1));
145
    i2c_address += i2c_add;
146
#endif
147
 
148
    twires_begin(i2c_address);
2 pfowler 149
    twires_onReceive(receiveEvent);
150
 
151
    wdt_enable(WDTO_1S);	// Watchdog for 1 sec
152
    sei();			// Enable interrupts
153
 
154
    uint32_t refresh = systime;
155
 
24 pfowler 156
 
2 pfowler 157
    // Init and clear the displays
158
    hc595_init();
159
    hc595_write(0x00);
160
 
161
 
162
 
163
    for(;;){
164
    	 wdt_reset();
165
 
166
    	if (user_debug) {
167
    		disVal[9] = rbi(SB_INPUT, SB_PIN);
168
    		disVal[8] = rbi(FB_INPUT, FB_PIN);
169
    		disVal[0] = input.outer & 0x0f;
24 pfowler 170
    		disVal[1] = (input.outer >> 4);
2 pfowler 171
    	}
172
 
173
		if (pcInt.current != pcInt.last) {
174
			cli(); 		// Dont process interrupts for a bit
175
			pcInterrupt();
176
			sei();
177
		}
178
 
179
		if (systime > refresh) {
180
			writeSegment(disIdx, disVal[disIdx]);
181
			refresh = systime + DISPLAY_REFRESH;
182
			disIdx++;
183
			if (disIdx > 10) disIdx = 0;
184
		}
185
 
186
		twires_stop_check();
187
    }
188
    return 0;
189
}
190
 
191
void receiveEvent(uint8_t bytes) {
192
	uint8_t cmd = twires_receive();
193
	bytes--;
194
	switch (cmd) {
195
		case (0x01): {
196
			// Send 2 bytes with version details
197
			twires_send(HW_VERSION);
198
			twires_send(SW_VERSION);
199
		}
200
			break;
201
		case (0x03): {
202
			// Enable debugging mode
203
			user_debug = twires_receive();
204
		}
205
			break;
206
		case (0x05): {
207
			// Receive n numbers of digits to DISPLAY_REFRESH
208
			// High nibble = segment number
209
			// Low nibble = digit to display
210
			while (bytes--) {
211
				uint8_t data = twires_receive();
24 pfowler 212
				disVal[data >> 4] = (data & 0x0f);
2 pfowler 213
			}
214
		}
215
			break;
24 pfowler 216
		case (0x06): {
217
			// Recive a digit to retrieve to value of
218
			uint8_t digit = twires_receive();
219
			uint8_t out = (digit << 4) | (disVal[digit] & 0x0f);
220
			twires_send(out);
221
		}
222
			break;
2 pfowler 223
		case (0x08): {
224
			// Recieve 2 bytes, for the decimal points
225
			//  5 bits used in eac byte
24 pfowler 226
			disPt = ((uint16_t)twires_receive() << 8);
2 pfowler 227
			disPt |= (uint16_t)twires_receive();
228
		}
229
			break;
230
		case (0x09): {
231
			// Reset the rotary
232
			input.outer = 0;
233
			input.inner = 0;
234
		}
235
			break;
236
		case (0x0a): {
237
			twires_send(input.outer);
238
		}
239
			break;
24 pfowler 240
#if HW_VERSION==0x02
2 pfowler 241
		case (0x0b): {
242
			twires_send(input.inner);
243
		}
244
			break;
24 pfowler 245
#endif
2 pfowler 246
		case (0x0c): {
247
			// Send that status of the buttons
248
			uint8_t out = (!rbi(SB_INPUT, SB_PIN)) << 1;
249
			out |= (!rbi(FB_INPUT, FB_PIN));
250
			twires_send(out);
251
		}
24 pfowler 252
			break;
253
#if HW_VERSION==0x02
2 pfowler 254
		case (0x0d): {
24 pfowler 255
			// Send all the config switch data
256
			uint8_t out = ((!rbi(I2CADDR_PIN, I2CADDR_0)) << 3);
257
			out |= ((!rbi(I2CADDR_PIN, I2CADDR_1)) << 2);
258
			out |= ((!rbi(CONFSW_PIN, CONFSW_1)) << 1);
259
			out |= (!rbi(CONFSW_PIN, CONFSW_0));
260
			twires_send(out);
2 pfowler 261
		}
24 pfowler 262
		break;
263
#endif
2 pfowler 264
		default: {
265
			// Don't know what it is, empty buffer
266
			while (twires_available())
267
				twires_receive();
268
		}
269
			break;
270
	}
271
}
272
 
273
void writeSegment(uint8_t digit, uint8_t value) {
274
	cbi(BL_PORT, BL_PIN);			// Blank the 4511
275
	cbi(DP_PORT, DP_PIN);			// Drop the DP before changing digit
276
 
277
	hc595_write((value << 4) | (9-(digit & 0x0f))); //Write the value and digit
278
	if (rbi(disPt, digit)) sbi(DP_PORT, DP_PIN);		// Add DP if required
279
	sbi(BL_PORT, BL_PIN);			// Enable the 4511
280
}
281
 
282
void pcInterrupt() {
283
	pcInt.mask = pcInt.current ^ pcInt.last;
284
	pcInt.last = pcInt.current;
285
 
24 pfowler 286
	if (!pcInt.mask)
287
		return;
2 pfowler 288
 
24 pfowler 289
	// Check which pin caused the interrupt. If they both
290
	//  equal 0 || 1, the pin that interrupted is the direction
291
	if (((rbi(pcInt.current, ROT_1A_PIN) == 1 &&
292
				rbi(pcInt.current, ROT_1B_PIN) == 1) ||
293
		 (rbi(pcInt.current, ROT_1A_PIN) == 0 &&
294
				rbi(pcInt.current, ROT_1B_PIN) == 0))) {
2 pfowler 295
 
24 pfowler 296
		if (rbi(pcInt.mask, ROT_1A_PIN) ) {
297
			input.outer -= 1;
298
		  } else if (rbi(pcInt.mask, ROT_1B_PIN) ) {
299
			input.outer += 1;
300
		}
301
	}
2 pfowler 302
 
24 pfowler 303
#if HW_VERSION==0x02
304
	if (((rbi(pcInt.current, ROT_2A_PIN) == 1 &&
305
				rbi(pcInt.current, ROT_2B_PIN) == 1) ||
306
		 (rbi(pcInt.current, ROT_2A_PIN) == 0 &&
307
				rbi(pcInt.current, ROT_2B_PIN) == 0))) {
2 pfowler 308
 
24 pfowler 309
		if (rbi(pcInt.mask, ROT_2A_PIN) ) {
310
			input.inner -= 1;
311
		  } else if (rbi(pcInt.mask, ROT_2B_PIN) ) {
312
			input.inner += 1;
313
		}
314
	}
315
#endif
316
	// Clear the mask so we know we've dealt with it
317
	// Shouldn't be required now that 'doInt' has been removed
318
	//pcInt.mask = 0;
319
 
2 pfowler 320
}
24 pfowler 321
#if HW_VERSION==0x01
2 pfowler 322
ISR(PCINT1_vect) {
24 pfowler 323
#else
324
ISR(PCINT_B_vect) {
325
#endif
326
	pcInt.current = ROT_PIN;
2 pfowler 327
}
328
 
24 pfowler 329
 
330
 
331
#if HW_VERSION==0x01
2 pfowler 332
ISR(TIM0_OVF_vect) {
24 pfowler 333
#else
334
ISR(TIMER0_OVF_vect) {
335
#endif
2 pfowler 336
    tmr0_ovf++;
337
 
338
	// Clk/1 TCCR0B = (1<< CS00);
339
	//20.0Mhz, 1ms = 78ovf
340
	//16.5Mhz, 1ms = 64ovf
341
	//16.0Mhz, 1ms = 62ovf
342
	//12.0Mhz, 1ms = 46ovf
343
	// 8.0Mhz, 1ms = 31ovf
344
	// 8.0Mhz, .5ms = 15ovf, 160r
345
 
346
	if (tmr0_ovf>=15) {
347
			systime++;
348
			tmr0_ovf = 0;
349
	}
350
 
351
}