Subversion Repositories group.electronics

Rev

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

Rev Author Line No. Line
130 pfowler 1
#include <avr/io.h>
2
#include <avr/wdt.h>
136 pfowler 3
#include <avr/eeprom.h>
130 pfowler 4
#include <avr/interrupt.h>
136 pfowler 5
#include <avr/pgmspace.h>
130 pfowler 6
#include <util/delay.h>
7
 
8
#include "config.h"
9
#include "avrutil.h"
136 pfowler 10
#include "usbdrv.h"
11
#include "i2cbb.h"
130 pfowler 12
 
152 pfowler 13
#define HW_VERSION 0x01
14
#define SW_VERSION 0x01
130 pfowler 15
 
16
#ifndef NULL
17
#define NULL    ((void *)0)
18
#endif
19
 
152 pfowler 20
#define DISPLAYS_ATTACHED 2
154 pfowler 21
#define INPUT_REFRESH 50
152 pfowler 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
 
139 pfowler 38
void usbEventResetReady(void);
136 pfowler 39
static void calibrateOscillator(void);
137 pfowler 40
static void updateDisplay(uint8_t dis);
139 pfowler 41
static void updateInput();
152 pfowler 42
static void getDisplayVersion(uint8_t dis);
130 pfowler 43
 
139 pfowler 44
struct display_type {
45
	uint8_t address;
46
	uint8_t value[10];
47
	uint16_t decpts;
152 pfowler 48
	uint16_t version;	// HB = HW, LB = SW
136 pfowler 49
 
150 pfowler 50
	int8_t rotary;		// State of the rotary encoder
139 pfowler 51
	uint8_t buttons;	// State of the buttons
150 pfowler 52
} display[DISPLAYS_ATTACHED];
136 pfowler 53
 
139 pfowler 54
 
55
 
56
static uint8_t usbReplyBuf[8];
152 pfowler 57
static uint8_t latchDisplay = 255;
139 pfowler 58
 
59
 
130 pfowler 60
volatile uint8_t tmr0_ovf = 0;
61
 
136 pfowler 62
 
130 pfowler 63
int main(void) {
139 pfowler 64
	// calibration value from last time
136 pfowler 65
	uchar   calibrationValue;
139 pfowler 66
	calibrationValue = eeprom_read_byte(0);
136 pfowler 67
	if(calibrationValue != 0xff){
68
		OSCCAL = calibrationValue;
69
	}
130 pfowler 70
 
136 pfowler 71
	/*
72
		DDR : 1 = Output, 0 = Input
73
		PORT: 1 = Pullup for Input, otherwise set output
74
		PIN : Read input pin
130 pfowler 75
 
136 pfowler 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
 
137 pfowler 86
 
136 pfowler 87
    usbDeviceDisconnect();
137 pfowler 88
    _delay_ms(500);
136 pfowler 89
    usbDeviceConnect();
90
 
130 pfowler 91
    systime = 0;
139 pfowler 92
    uint32_t refresh = 0;
130 pfowler 93
    sysclockInit();
94
 
139 pfowler 95
    wdt_enable(WDTO_1S);
136 pfowler 96
    usbInit();
139 pfowler 97
    sei();
130 pfowler 98
 
136 pfowler 99
 
152 pfowler 100
    // Setup the display data, blank each display
137 pfowler 101
    uint8_t i;
150 pfowler 102
    for (i=0; i<DISPLAYS_ATTACHED; i++) {
103
    	display[i].address = 0x26 + i;
104
    	display[i].decpts = 0x00;
105
 
139 pfowler 106
    	uint8_t j;
107
    	for (j=0; j<10; j++)
108
    		display[i].value[j] = 0x0a;
137 pfowler 109
    	updateDisplay(i);
152 pfowler 110
 
111
    	getDisplayVersion(i);
139 pfowler 112
    }
137 pfowler 113
 
130 pfowler 114
    for(;;){
115
    	 wdt_reset();
136 pfowler 116
    	 usbPoll();
130 pfowler 117
 
152 pfowler 118
    	// Latch requests from the the USB host
119
    	if (latchDisplay != 255) {
120
    		updateDisplay(latchDisplay);
121
    		latchDisplay = 255;
130 pfowler 122
    	}
123
 
152 pfowler 124
    	// Refresh time for getting user input data
139 pfowler 125
		if (systime > refresh) {
150 pfowler 126
			refresh = systime + INPUT_REFRESH;
139 pfowler 127
			updateInput();
128
		}
130 pfowler 129
    }
130
    return 0;
131
}
132
 
152 pfowler 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
139 pfowler 153
static void updateInput() {
150 pfowler 154
	uint8_t i;
155
	for (i = 0; i < DISPLAYS_ATTACHED; i++) {
152 pfowler 156
		// Request for the rotary data
150 pfowler 157
		i2cbb_Init();
158
		i2cbb_Start();
159
		i2cbb_Write( display[i].address << 1 );
152 pfowler 160
		i2cbb_Write( I2C_GET_ROTARY_DATA );
150 pfowler 161
		i2cbb_Stop();
139 pfowler 162
 
152 pfowler 163
		// Receive rotary data
150 pfowler 164
		i2cbb_Start();
165
		i2cbb_Write( (display[i].address << 1) + 1 );
166
		display[i].rotary += (int8_t)i2cbb_Read(1);
167
		i2cbb_Stop();
139 pfowler 168
 
152 pfowler 169
		// Reset the rotary on display board
150 pfowler 170
		i2cbb_Init();
171
		i2cbb_Start();
172
		i2cbb_Write( display[i].address << 1 );
152 pfowler 173
		i2cbb_Write( I2C_RESET_ROTARY );
150 pfowler 174
		i2cbb_Stop();
139 pfowler 175
 
152 pfowler 176
		// Request the button data
150 pfowler 177
		i2cbb_Init();
178
		i2cbb_Start();
179
		i2cbb_Write( display[i].address << 1 );
152 pfowler 180
		i2cbb_Write( I2C_GET_BUTTON_DATA );
150 pfowler 181
		i2cbb_Stop();
139 pfowler 182
 
152 pfowler 183
		// Receive the button data
150 pfowler 184
		i2cbb_Start();
185
		i2cbb_Write( (display[i].address << 1) + 1 );
186
		display[i].buttons = i2cbb_Read(1);
187
		i2cbb_Stop();
188
	}
139 pfowler 189
 
190
}
191
 
152 pfowler 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
137 pfowler 196
static void updateDisplay(uint8_t dis) {
197
    cbi(PORTB, PB0);
139 pfowler 198
 
199
    // Send the display buffer to display board
154 pfowler 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
 
137 pfowler 210
    i2cbb_Init();
211
    i2cbb_Start();
150 pfowler 212
    i2cbb_Write( display[dis].address << 1);
152 pfowler 213
    i2cbb_Write( I2C_SET_DIGITS );
154 pfowler 214
 
139 pfowler 215
    for (n=0; n<10; n++) {
154 pfowler 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
    	}
137 pfowler 221
    }
222
    i2cbb_Stop();
139 pfowler 223
 
152 pfowler 224
 
139 pfowler 225
    // Send the decimal point
154 pfowler 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
    }
139 pfowler 235
 
152 pfowler 236
 
137 pfowler 237
    sbi(PORTB, PB0);
238
}
239
 
152 pfowler 240
// The USB functions to transmit/receive data from USB host.
139 pfowler 241
usbMsgLen_t usbFunctionSetup(uchar data[8])
242
{
243
    usbRequest_t    *rq = (void *)data;
136 pfowler 244
 
139 pfowler 245
	switch (rq->bRequest ) {
152 pfowler 246
		// Request for a display boards digits to be updated
139 pfowler 247
		case USB_SET_LATCH: {
152 pfowler 248
			latchDisplay = rq->wValue.bytes[0];;
139 pfowler 249
			break;
250
		}
152 pfowler 251
 
252
		// Sets the display boards digit buffer. Only on display
253
		//  board is updated per request. Also does decimal points
139 pfowler 254
		case USB_SET_DISPLAY1: {
255
			uint8_t dis = rq->wValue.bytes[1];
256
			uint8_t dig = rq->wValue.bytes[0];
152 pfowler 257
			uint8_t dp = rq->wIndex.bytes[1];
139 pfowler 258
			uint8_t val = rq->wIndex.bytes[0];
152 pfowler 259
 
154 pfowler 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) {
139 pfowler 267
				sbi(display[dis].decpts, 1 << dig);
154 pfowler 268
			} else {
139 pfowler 269
				cbi(display[dis].decpts, 1 << dig);
154 pfowler 270
			}
152 pfowler 271
 
139 pfowler 272
			break;
273
		}
152 pfowler 274
 
275
		// Return the user input data all at once. Its populated from
276
		//  buffered data from the updateInput() function.
139 pfowler 277
		case USB_GET_INPUT: {
150 pfowler 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
			}
152 pfowler 284
			usbMsgPtr = usbReplyBuf;
285
			return sizeof(usbReplyBuf);
286
			break;
287
		}
150 pfowler 288
 
152 pfowler 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
			}
139 pfowler 299
			usbMsgPtr = usbReplyBuf;
300
			return sizeof(usbReplyBuf);
152 pfowler 301
			break;
139 pfowler 302
		}
303
 
304
	}
305
	return 0;
136 pfowler 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
 
132 pfowler 346
ISR(TIM0_OVF_vect) {
130 pfowler 347
 
132 pfowler 348
	tmr0_ovf++;
130 pfowler 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
131 pfowler 356
	// 8.0Mhz, .5ms = 15ovf, 160r
130 pfowler 357
 
132 pfowler 358
	if (tmr0_ovf>=64) {
130 pfowler 359
			systime++;
360
			tmr0_ovf = 0;
361
	}
362
 
363
}