Subversion Repositories group.NITPanels

Rev

Rev 2 | Rev 10 | Go to most recent revision | 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/eeprom.h>
4
#include <avr/interrupt.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
 
8
#include "config.h"
9
#include "avrutil.h"
10
#include "usbdrv.h"
11
#include "i2cbb.h"
12
 
13
#define HW_VERSION 0x01
14
#define SW_VERSION 0x01
15
 
16
#ifndef NULL
17
#define NULL    ((void *)0)
18
#endif
19
 
20
#define DISPLAYS_ATTACHED 2
21
#define INPUT_REFRESH 50
9 pfowler 22
#define FULL_REFRESH  10
2 pfowler 23
 
24
#define I2C_GET_VERSION			0x01
25
#define I2C_SET_DEBUG			0x03
26
#define I2C_SET_DIGITS			0x05
27
#define I2C_SET_DECIMAL_PTS		0x08
28
#define I2C_RESET_ROTARY		0x09
29
#define I2C_GET_ROTARY_DATA 	0x0a
30
#define I2C_GET_BUTTON_DATA 	0x0c
31
 
32
#define USB_GET_VERSION		01
33
#define USB_SET_LATCH			20
34
#define USB_SET_DISPLAY1		21
35
#define USB_SET_DISPLAY2		22
9 pfowler 36
#define USB_SET_POINTS			23
2 pfowler 37
#define USB_GET_INPUT			30
38
 
39
 
40
void usbEventResetReady(void);
41
static void calibrateOscillator(void);
42
static void updateDisplay(uint8_t dis);
43
static void updateInput();
44
static void getDisplayVersion(uint8_t dis);
45
 
46
struct display_type {
47
	uint8_t address;
48
	uint8_t value[10];
49
	uint16_t decpts;
50
	uint16_t version;	// HB = HW, LB = SW
51
 
9 pfowler 52
	uint8_t refresh;	// Decimal point refresh
53
 
2 pfowler 54
	int8_t rotary;		// State of the rotary encoder
55
	uint8_t buttons;	// State of the buttons
56
} display[DISPLAYS_ATTACHED];
57
 
58
 
59
 
60
static uint8_t usbReplyBuf[8];
61
static uint8_t latchDisplay = 255;
62
 
63
 
64
volatile uint8_t tmr0_ovf = 0;
65
 
66
 
67
int main(void) {
68
	// calibration value from last time
69
	uchar   calibrationValue;
70
	calibrationValue = eeprom_read_byte(0);
71
	if(calibrationValue != 0xff){
72
		OSCCAL = calibrationValue;
73
	}
74
 
75
	/*
76
		DDR : 1 = Output, 0 = Input
77
		PORT: 1 = Pullup for Input, otherwise set output
78
		PIN : Read input pin
79
 
80
		PB0	-
81
		PB1	- 		- USB D- Low Speed
82
		PB2	-		- USB D+
83
		PB3	- 		- SCL i2c bb
84
		PB4	-		- SDA i2c bb
85
		PB5	-
86
	*/
87
	DDRB          = 0B00000001;
88
	PORTB         = 0B00000001;
89
 
90
 
91
    usbDeviceDisconnect();
92
    _delay_ms(500);
93
    usbDeviceConnect();
94
 
95
    systime = 0;
96
    uint32_t refresh = 0;
97
    sysclockInit();
98
 
99
    wdt_enable(WDTO_1S);
100
    usbInit();
101
    sei();
102
 
103
 
104
    // Setup the display data, blank each display
105
    uint8_t i;
106
    for (i=0; i<DISPLAYS_ATTACHED; i++) {
107
    	display[i].address = 0x26 + i;
9 pfowler 108
    	display[i].decpts = 0x0000;
109
    	display[i].refresh = 0;
2 pfowler 110
 
111
    	uint8_t j;
112
    	for (j=0; j<10; j++)
113
    		display[i].value[j] = 0x0a;
114
    	updateDisplay(i);
115
 
116
    	getDisplayVersion(i);
117
    }
118
 
119
    for(;;){
120
    	 wdt_reset();
121
    	 usbPoll();
122
 
123
    	// Latch requests from the the USB host
124
    	if (latchDisplay != 255) {
125
    		updateDisplay(latchDisplay);
126
    		latchDisplay = 255;
127
    	}
128
 
9 pfowler 129
    	for (i=0; i<DISPLAYS_ATTACHED; i++) {
130
    		if (display[i].refresh) {
131
    			i2cbb_Init();
132
				i2cbb_Start();
133
				i2cbb_Write( display[i].address << 1 );
134
				i2cbb_Write( I2C_SET_DECIMAL_PTS );
135
				i2cbb_Write((uint8_t)(display[i].decpts>>8));
136
				i2cbb_Write((uint8_t)display[i].decpts);
137
				i2cbb_Stop();
138
				display[i].refresh = 0;
139
    		}
140
 
141
    	}
142
 
2 pfowler 143
    	// Refresh time for getting user input data
144
		if (systime > refresh) {
145
			refresh = systime + INPUT_REFRESH;
146
			updateInput();
147
		}
148
    }
149
    return 0;
150
}
151
 
152
static void getDisplayVersion(uint8_t dis) {
153
	uint8_t hw = 0x00;
154
	uint8_t sw = 0x00;
155
 
156
	i2cbb_Init();
157
	i2cbb_Start();
158
	i2cbb_Write( display[dis].address << 1 );
159
	i2cbb_Write( I2C_GET_VERSION );
160
	i2cbb_Stop();
161
 
162
	i2cbb_Start();
163
	i2cbb_Write( (display[dis].address << 1) + 1 );
164
	hw += (int8_t)i2cbb_Read(1);
165
	sw += (int8_t)i2cbb_Read(1);
166
	i2cbb_Stop();
167
 
168
	display[dis].version = ((uint16_t)hw << 8) | ((uint16_t)sw);
169
}
170
 
171
// Get the user input data from each display board
172
static void updateInput() {
173
	uint8_t i;
174
	for (i = 0; i < DISPLAYS_ATTACHED; i++) {
175
		// Request for the rotary data
176
		i2cbb_Init();
177
		i2cbb_Start();
178
		i2cbb_Write( display[i].address << 1 );
179
		i2cbb_Write( I2C_GET_ROTARY_DATA );
180
		i2cbb_Stop();
181
 
182
		// Receive rotary data
183
		i2cbb_Start();
184
		i2cbb_Write( (display[i].address << 1) + 1 );
185
		display[i].rotary += (int8_t)i2cbb_Read(1);
186
		i2cbb_Stop();
187
 
188
		// Reset the rotary on display board
189
		i2cbb_Init();
190
		i2cbb_Start();
191
		i2cbb_Write( display[i].address << 1 );
192
		i2cbb_Write( I2C_RESET_ROTARY );
193
		i2cbb_Stop();
194
 
195
		// Request the button data
196
		i2cbb_Init();
197
		i2cbb_Start();
198
		i2cbb_Write( display[i].address << 1 );
199
		i2cbb_Write( I2C_GET_BUTTON_DATA );
200
		i2cbb_Stop();
201
 
202
		// Receive the button data
203
		i2cbb_Start();
204
		i2cbb_Write( (display[i].address << 1) + 1 );
205
		display[i].buttons = i2cbb_Read(1);
206
		i2cbb_Stop();
207
	}
208
 
209
}
210
 
211
// The the display digit display buffer to the board
212
// We can select which display to update as this can
213
//  get slow if updates are being done all the time,
214
//  which might affect the user input data tasks
215
static void updateDisplay(uint8_t dis) {
216
    cbi(PORTB, PB0);
217
 
218
    // Send the display buffer to display board
219
    uint8_t update = 0;
220
    uint8_t n;
221
    for (n=0; n<10; n++) {
222
    	if (rbi(display[dis].value[n], 7)) {
223
    		update = 1;
224
    		break;
225
    	}
226
    }
9 pfowler 227
 
2 pfowler 228
    if (!update) return;
229
 
230
    i2cbb_Init();
231
    i2cbb_Start();
232
    i2cbb_Write( display[dis].address << 1);
233
    i2cbb_Write( I2C_SET_DIGITS );
234
 
235
    for (n=0; n<10; n++) {
236
    	if (rbi(display[dis].value[n], 7)) {
237
    		cbi(display[dis].value[n], 7);
238
    		uint8_t send = (n << 4) | display[dis].value[n];
239
    		i2cbb_Write( send );
240
    	}
241
    }
242
    i2cbb_Stop();
243
 
244
    sbi(PORTB, PB0);
245
}
246
 
247
// The USB functions to transmit/receive data from USB host.
248
usbMsgLen_t usbFunctionSetup(uchar data[8])
249
{
250
    usbRequest_t    *rq = (void *)data;
251
 
252
	switch (rq->bRequest ) {
253
		// Request for a display boards digits to be updated
254
		case USB_SET_LATCH: {
255
			latchDisplay = rq->wValue.bytes[0];;
256
			break;
257
		}
258
 
9 pfowler 259
		case USB_SET_POINTS: {
260
			display[0].decpts = rq->wValue.word;
261
			display[1].decpts = rq->wIndex.word;
262
 
263
			display[0].refresh = 1;
264
			display[1].refresh = 1;
265
		}
266
 
2 pfowler 267
		// Sets the display boards digit buffer. Only on display
268
		//  board is updated per request. Also does decimal points
269
		case USB_SET_DISPLAY1: {
270
			uint8_t dis = rq->wValue.bytes[1];
271
			uint8_t dig = rq->wValue.bytes[0];
272
			uint8_t val = rq->wIndex.bytes[0];
273
 
274
			if ((display[dis].value[dig] & 0x0f) != val) {
275
				display[dis].value[dig] = val;
276
				sbi(display[dis].value[dig], 7);
277
			}
278
			break;
279
		}
280
 
281
		// Return the user input data all at once. Its populated from
282
		//  buffered data from the updateInput() function.
283
		case USB_GET_INPUT: {
284
			uint8_t i;
285
			for (i=0; i<DISPLAYS_ATTACHED; i++) {
286
				usbReplyBuf[(i*2)] = display[i].buttons;
287
				usbReplyBuf[(i*2+1)] = display[i].rotary;
288
				display[i].rotary = 0;
289
			}
290
			usbMsgPtr = usbReplyBuf;
291
			return sizeof(usbReplyBuf);
292
			break;
293
		}
294
 
295
		// Return the version numbers for the controller board
296
		//  and for all attached display boards.
297
		case USB_GET_VERSION: {
298
			usbReplyBuf[0] = HW_VERSION;
299
			usbReplyBuf[1] = SW_VERSION;
300
			uint8_t i;
301
			for (i=0; i<DISPLAYS_ATTACHED; i++) {
302
				usbReplyBuf[2+(i*2)] = (uint8_t)(display[i].version >> 8);
303
				usbReplyBuf[2+(i*2)+1] = (uint8_t)(display[i].version && 0xff);
304
			}
305
			usbMsgPtr = usbReplyBuf;
306
			return sizeof(usbReplyBuf);
307
			break;
308
		}
309
 
310
	}
311
	return 0;
312
}
313
 
314
static void calibrateOscillator(void) {
315
    uchar step = 128;
316
    uchar trialValue = 0, optimumValue;
317
    int x, optimumDev;
318
    int targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
319
 
320
    /* do a binary search: */
321
    do {
322
        OSCCAL = trialValue + step;
323
        x = usbMeasureFrameLength();    /* proportional to current real frequency */
324
        if(x < targetValue)             /* frequency still too low */
325
            trialValue += step;
326
        step >>= 1;
327
    } while(step > 0);
328
    /* We have a precision of +/- 1 for optimum OSCCAL here */
329
    /* now do a neighborhood search for optimum value */
330
    optimumValue = trialValue;
331
    optimumDev = x; /* this is certainly far away from optimum */
332
    for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
333
        x = usbMeasureFrameLength() - targetValue;
334
        if(x < 0)
335
            x = -x;
336
        if(x < optimumDev){
337
            optimumDev = x;
338
            optimumValue = OSCCAL;
339
        }
340
    }
341
    OSCCAL = optimumValue;
342
}
343
 
344
 
345
void usbEventResetReady(void) {
346
    cli();
347
    calibrateOscillator();
348
    sei();
349
    eeprom_write_byte(0, OSCCAL);   /* store the calibrated value in EEPROM */
350
}
351
 
352
ISR(TIM0_OVF_vect) {
353
 
354
	tmr0_ovf++;
355
 
356
	// Clk/1 TCCR0B = (1<< CS00);
357
	//20.0Mhz, 1ms = 78ovf
358
	//16.5Mhz, 1ms = 64ovf
359
	//16.0Mhz, 1ms = 62ovf
360
	//12.0Mhz, 1ms = 46ovf
361
	// 8.0Mhz, 1ms = 31ovf
362
	// 8.0Mhz, .5ms = 15ovf, 160r
363
 
364
	if (tmr0_ovf>=64) {
365
			systime++;
366
			tmr0_ovf = 0;
367
	}
368
 
369
}