Subversion Repositories group.electronics

Rev

Rev 150 | Go to most recent revision | 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
21
#define INPUT_REFRESH 5
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
	// Receive rotary data
144
	i2cbb_Start();
145
	i2cbb_Write( (display[dis].address << 1) + 1 );
146
	hw += (int8_t)i2cbb_Read(1);
147
	sw += (int8_t)i2cbb_Read(1);
148
	i2cbb_Stop();
149
 
150
	display[dis].version = ((uint16_t)hw << 8) | ((uint16_t)sw);
151
}
152
 
153
// Get the user input data from each display board
139 pfowler 154
static void updateInput() {
150 pfowler 155
	uint8_t i;
156
	for (i = 0; i < DISPLAYS_ATTACHED; i++) {
152 pfowler 157
		// Request for the rotary data
150 pfowler 158
		i2cbb_Init();
159
		i2cbb_Start();
160
		i2cbb_Write( display[i].address << 1 );
152 pfowler 161
		i2cbb_Write( I2C_GET_ROTARY_DATA );
150 pfowler 162
		i2cbb_Stop();
139 pfowler 163
 
152 pfowler 164
		// Receive rotary data
150 pfowler 165
		i2cbb_Start();
166
		i2cbb_Write( (display[i].address << 1) + 1 );
167
		display[i].rotary += (int8_t)i2cbb_Read(1);
168
		i2cbb_Stop();
139 pfowler 169
 
152 pfowler 170
		// Reset the rotary on display board
150 pfowler 171
		i2cbb_Init();
172
		i2cbb_Start();
173
		i2cbb_Write( display[i].address << 1 );
152 pfowler 174
		i2cbb_Write( I2C_RESET_ROTARY );
150 pfowler 175
		i2cbb_Stop();
139 pfowler 176
 
152 pfowler 177
		// Request the button data
150 pfowler 178
		i2cbb_Init();
179
		i2cbb_Start();
180
		i2cbb_Write( display[i].address << 1 );
152 pfowler 181
		i2cbb_Write( I2C_GET_BUTTON_DATA );
150 pfowler 182
		i2cbb_Stop();
139 pfowler 183
 
152 pfowler 184
		// Receive the button data
150 pfowler 185
		i2cbb_Start();
186
		i2cbb_Write( (display[i].address << 1) + 1 );
187
		display[i].buttons = i2cbb_Read(1);
188
		i2cbb_Stop();
189
	}
139 pfowler 190
 
191
}
192
 
152 pfowler 193
// The the display digit display buffer to the board
194
// We can select which display to update as this can
195
//  get slow if updates are being done all the time,
196
//  which might affect the user input data tasks
137 pfowler 197
static void updateDisplay(uint8_t dis) {
198
    cbi(PORTB, PB0);
139 pfowler 199
 
200
    // Send the display buffer to display board
137 pfowler 201
    i2cbb_Init();
202
    i2cbb_Start();
150 pfowler 203
    i2cbb_Write( display[dis].address << 1);
152 pfowler 204
    i2cbb_Write( I2C_SET_DIGITS );
137 pfowler 205
    uint8_t n;
139 pfowler 206
    for (n=0; n<10; n++) {
150 pfowler 207
    	uint8_t send = (n << 4) | display[dis].value[n];
139 pfowler 208
    	i2cbb_Write( send );
137 pfowler 209
    }
210
    i2cbb_Stop();
139 pfowler 211
 
152 pfowler 212
 
139 pfowler 213
    // Send the decimal point
214
	i2cbb_Init();
215
	i2cbb_Start();
152 pfowler 216
	i2cbb_Write( display[dis].address << 1 );
217
	i2cbb_Write( I2C_SET_DECIMAL_PTS );
139 pfowler 218
	i2cbb_Write((uint8_t)(display[dis].decpts>>8));
219
	i2cbb_Write((uint8_t)display[dis].decpts);
220
	i2cbb_Stop();
221
 
152 pfowler 222
 
137 pfowler 223
    sbi(PORTB, PB0);
224
}
225
 
152 pfowler 226
// The USB functions to transmit/receive data from USB host.
139 pfowler 227
usbMsgLen_t usbFunctionSetup(uchar data[8])
228
{
229
    usbRequest_t    *rq = (void *)data;
136 pfowler 230
 
139 pfowler 231
	switch (rq->bRequest ) {
152 pfowler 232
		// Request for a display boards digits to be updated
139 pfowler 233
		case USB_SET_LATCH: {
152 pfowler 234
			latchDisplay = rq->wValue.bytes[0];;
139 pfowler 235
			break;
236
		}
152 pfowler 237
 
238
		// Sets the display boards digit buffer. Only on display
239
		//  board is updated per request. Also does decimal points
139 pfowler 240
		case USB_SET_DISPLAY1: {
241
			uint8_t dis = rq->wValue.bytes[1];
242
			uint8_t dig = rq->wValue.bytes[0];
152 pfowler 243
			uint8_t dp = rq->wIndex.bytes[1];
139 pfowler 244
			uint8_t val = rq->wIndex.bytes[0];
245
			display[dis].value[dig] = val;
152 pfowler 246
 
139 pfowler 247
			if (dp)
248
				sbi(display[dis].decpts, 1 << dig);
249
			else
250
				cbi(display[dis].decpts, 1 << dig);
152 pfowler 251
 
252
			//display[dis].decpts |= dp << dig;
253
 
139 pfowler 254
			break;
255
		}
152 pfowler 256
 
257
		// Return the user input data all at once. Its populated from
258
		//  buffered data from the updateInput() function.
139 pfowler 259
		case USB_GET_INPUT: {
150 pfowler 260
			uint8_t i;
261
			for (i=0; i<DISPLAYS_ATTACHED; i++) {
262
				usbReplyBuf[(i*2)] = display[i].buttons;
263
				usbReplyBuf[(i*2+1)] = display[i].rotary;
264
				display[i].rotary = 0;
265
			}
152 pfowler 266
			usbMsgPtr = usbReplyBuf;
267
			return sizeof(usbReplyBuf);
268
			break;
269
		}
150 pfowler 270
 
152 pfowler 271
		// Return the version numbers for the controller board
272
		//  and for all attached display boards.
273
		case USB_GET_VERSION: {
274
			usbReplyBuf[0] = HW_VERSION;
275
			usbReplyBuf[1] = SW_VERSION;
276
			uint8_t i;
277
			for (i=0; i<DISPLAYS_ATTACHED; i++) {
278
				usbReplyBuf[2+(i*2)] = (uint8_t)(display[i].version >> 8);
279
				usbReplyBuf[2+(i*2)+1] = (uint8_t)(display[i].version && 0xff);
280
			}
139 pfowler 281
			usbMsgPtr = usbReplyBuf;
282
			return sizeof(usbReplyBuf);
152 pfowler 283
			break;
139 pfowler 284
		}
285
 
286
	}
287
	return 0;
136 pfowler 288
}
289
 
290
static void calibrateOscillator(void) {
291
    uchar step = 128;
292
    uchar trialValue = 0, optimumValue;
293
    int x, optimumDev;
294
    int targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
295
 
296
    /* do a binary search: */
297
    do {
298
        OSCCAL = trialValue + step;
299
        x = usbMeasureFrameLength();    /* proportional to current real frequency */
300
        if(x < targetValue)             /* frequency still too low */
301
            trialValue += step;
302
        step >>= 1;
303
    } while(step > 0);
304
    /* We have a precision of +/- 1 for optimum OSCCAL here */
305
    /* now do a neighborhood search for optimum value */
306
    optimumValue = trialValue;
307
    optimumDev = x; /* this is certainly far away from optimum */
308
    for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
309
        x = usbMeasureFrameLength() - targetValue;
310
        if(x < 0)
311
            x = -x;
312
        if(x < optimumDev){
313
            optimumDev = x;
314
            optimumValue = OSCCAL;
315
        }
316
    }
317
    OSCCAL = optimumValue;
318
}
319
 
320
 
321
void usbEventResetReady(void) {
322
    cli();
323
    calibrateOscillator();
324
    sei();
325
    eeprom_write_byte(0, OSCCAL);   /* store the calibrated value in EEPROM */
326
}
327
 
132 pfowler 328
ISR(TIM0_OVF_vect) {
130 pfowler 329
 
132 pfowler 330
	tmr0_ovf++;
130 pfowler 331
 
332
	// Clk/1 TCCR0B = (1<< CS00);
333
	//20.0Mhz, 1ms = 78ovf
334
	//16.5Mhz, 1ms = 64ovf
335
	//16.0Mhz, 1ms = 62ovf
336
	//12.0Mhz, 1ms = 46ovf
337
	// 8.0Mhz, 1ms = 31ovf
131 pfowler 338
	// 8.0Mhz, .5ms = 15ovf, 160r
130 pfowler 339
 
132 pfowler 340
	if (tmr0_ovf>=64) {
130 pfowler 341
			systime++;
342
			tmr0_ovf = 0;
343
	}
344
 
345
}