Subversion Repositories group.NITPanels

Rev

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