Subversion Repositories group.NITPanels

Rev

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