Subversion Repositories group.electronics

Rev

Rev 76 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
75 pfowler 1
/* Name: main.c
2
 * Project: EasyLogger
3
 * Author: Christian Starkjohann
4
 * Creation Date: 2006-04-23
5
 * Tabsize: 4
6
 * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
7
 * License: Proprietary, free under certain conditions. See Documentation.
8
 * This Revision: $Id$
9
 */
10
 
11
#include <avr/io.h>
12
#include <avr/wdt.h>
13
#include <avr/eeprom.h>
14
#include <avr/interrupt.h>
15
#include <avr/pgmspace.h>
16
#include <util/delay.h>
17
 
18
#include "usbdrv.h"
19
#include "oddebug.h"
20
#include "config.h"
21
 
22
#ifndef NULL
23
#define NULL    ((void *)0)
24
#endif
25
 
26
/* ------------------------------------------------------------------------- */
27
 
28
struct {
29
	union {
30
		int16_t axis[3];
31
		struct {
32
			int16_t axis0:16;
33
			int16_t axis1:16;
34
			int16_t axis2:16;
35
		};
76 pfowler 36
		uint8_t buttons;
37
		struct {
38
			int8_t b1:1;
39
			int8_t b2:2;
40
			int8_t reserved:6;
41
		};
75 pfowler 42
	};
43
} reportBuffer;
44
 
45
 
46
volatile struct {
47
        uint8_t current;
48
        uint8_t last;
49
        uint8_t mask;
50
} pcInt[1];
51
 
52
static uchar    idleRate;           /* in 4 ms units */
53
 
54
/* ------------------------------------------------------------------------- */
55
 
56
const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
57
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
58
    0x09, 0x05,                    // USAGE (Game Pad)
59
    0xa1, 0x01,                    // COLLECTION (Application)
60
    0x09, 0x01,                    //   USAGE (Pointer)
61
    0xa1, 0x00,                    //   COLLECTION (Physical)
62
    0x09, 0x30,                    //     USAGE (X)
63
    0x09, 0x31,                    //     USAGE (Y)
64
    0x09, 0x38,                    //     USAGE (Y)
65
    0x16, 0x00, 0x80,		   //	  Log Min -32768
66
    0x26, 0xff, 0x7f,		   //	  Log max 32768
67
    0x75, 0x10,                    //     REPORT_SIZE (16)
68
    0x95, 0x03,                    //     REPORT_COUNT (2)
69
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
77 pfowler 70
 
71
    0x05, 0x09,                    //     USAGE_PAGE (Button)
72
    0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
73
    0x29, 0x02,                    //     USAGE_MAXIMUM (Button 2)
74
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
75
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
76
    0x75, 0x01,                    //     REPORT_SIZE (1)
77
    0x95, 0x02,                    //     REPORT_COUNT (2)
78
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
79
 
80
    0x75, 0x01,                    //     REPORT_SIZE (1)
81
    0x95, 0x06,                    //     REPORT_COUNT (6)
82
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
83
 
75 pfowler 84
    0xc0,                          //   END_COLLECTION
85
    0xc0                           // END_COLLECTION
86
};
87
 
88
 
89
 
90
/* ------------------------------------------------------------------------- */
91
/* ------------------------ interface to USB driver ------------------------ */
92
/* ------------------------------------------------------------------------- */
93
 
94
uchar	usbFunctionSetup(uchar data[8])
95
{
96
usbRequest_t    *rq = (void *)data;
97
 
98
    //usbMsgPtr = reportBuffer;
99
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ 
100
        if(rq->bRequest == USBRQ_HID_GET_REPORT){ 
101
            return sizeof(reportBuffer);
102
        }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
103
            usbMsgPtr = &idleRate;
104
            return 1;
105
        }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
106
            idleRate = rq->wValue.bytes[1];
107
        }
108
    }else{
109
 
110
    }
111
	return 0;
112
}
113
 
114
 
115
/* ------------------------------------------------------------------------- */
116
/* ------------------------ Oscillator Calibration ------------------------- */
117
/* ------------------------------------------------------------------------- */
118
 
119
/* Calibrate the RC oscillator to 8.25 MHz. The core clock of 16.5 MHz is
120
 * derived from the 66 MHz peripheral clock by dividing. Our timing reference
121
 * is the Start Of Frame signal (a single SE0 bit) available immediately after
122
 * a USB RESET. We first do a binary search for the OSCCAL value and then
123
 * optimize this value with a neighboorhod search.
124
 * This algorithm may also be used to calibrate the RC oscillator directly to
125
 * 12 MHz (no PLL involved, can therefore be used on almost ALL AVRs), but this
126
 * is wide outside the spec for the OSCCAL value and the required precision for
127
 * the 12 MHz clock! Use the RC oscillator calibrated to 12 MHz for
128
 * experimental purposes only!
129
 */
130
static void calibrateOscillator(void)
131
{
132
uchar       step = 128;
133
uchar       trialValue = 0, optimumValue;
134
int         x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
135
 
136
    /* do a binary search: */
137
    do{
138
        OSCCAL = trialValue + step;
139
        x = usbMeasureFrameLength();    /* proportional to current real frequency */
140
        if(x < targetValue)             /* frequency still too low */
141
            trialValue += step;
142
        step >>= 1;
143
    }while(step > 0);
144
    /* We have a precision of +/- 1 for optimum OSCCAL here */
145
    /* now do a neighborhood search for optimum value */
146
    optimumValue = trialValue;
147
    optimumDev = x; /* this is certainly far away from optimum */
148
    for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
149
        x = usbMeasureFrameLength() - targetValue;
150
        if(x < 0)
151
            x = -x;
152
        if(x < optimumDev){
153
            optimumDev = x;
154
            optimumValue = OSCCAL;
155
        }
156
    }
157
    OSCCAL = optimumValue;
158
}
159
/*
160
Note: This calibration algorithm may try OSCCAL values of up to 192 even if
161
the optimum value is far below 192. It may therefore exceed the allowed clock
162
frequency of the CPU in low voltage designs!
163
You may replace this search algorithm with any other algorithm you like if
164
you have additional constraints such as a maximum CPU clock.
165
For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g.
166
ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in
167
both regions.
168
*/
169
 
170
void    usbEventResetReady(void)
171
{
172
    /* Disable interrupts during oscillator calibration since
173
     * usbMeasureFrameLength() counts CPU cycles.
174
     */
175
    cli();
176
    calibrateOscillator();
177
    sei();
178
    eeprom_write_byte(0, OSCCAL);   /* store the calibrated value in EEPROM */
179
}
180
 
181
 
182
void usbSendHidReport(uchar * data, uchar len) {
183
        while(1)
184
        {
185
                usbPoll();
186
                if (usbInterruptIsReady())
187
                {
188
                        usbSetInterrupt(data, len);
189
                        break;
190
                }
191
        }
192
}
193
 
194
 
195
int main(void)
196
{
197
uchar   i;
198
uchar   calibrationValue;
199
 
200
    calibrationValue = eeprom_read_byte(0); /* calibration value from last time */
201
    if(calibrationValue != 0xff){
202
        OSCCAL = calibrationValue;
203
    }
204
 
205
    odDebugInit();
206
    usbDeviceDisconnect();
207
    for(i=0;i<20;i++){  /* 300 ms disconnect */
208
        _delay_ms(15);
209
    }
210
 
211
    usbDeviceConnect();
212
    wdt_enable(WDTO_1S);
213
 
214
  PCMSK |= (( 1 << PCINT3 ) | ( 1 << PCINT4 )); //enable encoder pins interrupt sources
215
  GIMSK |= ( 1 << PCIE ); //enable pin change interupts
216
 
217
  DDRB          = 0B00000001;
218
  PORTB         = 0B00000000;
219
 
220
    usbInit();
221
    sei();
222
 
76 pfowler 223
    reportBuffer.axis0 = 0;
224
    reportBuffer.axis1 = 0;
225
    reportBuffer.axis2 = 0;
226
    reportBuffer.buttons = 0;
75 pfowler 227
 
228
    for(;;){    /* main event loop */
229
        wdt_reset();
230
        usbPoll();
231
 
232
        if(usbInterruptIsReady()){ 
233
		usbSendHidReport(&reportBuffer, sizeof(reportBuffer));
77 pfowler 234
    		reportBuffer.buttons = 0;
75 pfowler 235
        }
236
    }
237
    return 0;
238
}
239
 
240
void pcInterrupt(uint8_t pcint) {
241
 
242
        switch (pcint) {
243
                case 0: pcInt[pcint].current = PINB; break;
244
        }
245
        pcInt[pcint].mask = pcInt[pcint].current ^ pcInt[pcint].last;
246
        pcInt[pcint].last = pcInt[pcint].current;
247
 
248
        if (pcInt[pcint].mask == 0)
249
		return;
250
 
251
        // Check which pin caused the interrupt. If they both
252
        //  equal 0, the pin that interrupted is the direction
253
        if (rbi(pcInt[pcint].current, PCINT3) == 0
254
                && rbi(pcInt[pcint].current, PCINT4) == 0
255
                && rbi(pcInt[pcint].mask, PCINT4) ) {
76 pfowler 256
 
75 pfowler 257
                        if (reportBuffer.axis2 < 32500)
258
                                reportBuffer.axis2 += 200;
76 pfowler 259
 
77 pfowler 260
			reportBuffer.b1 = 1;
76 pfowler 261
 
75 pfowler 262
        } else if (rbi(pcInt[pcint].current, PCINT3) == 0
263
                && rbi(pcInt[pcint].current, PCINT4) == 0
264
                && rbi(pcInt[pcint].mask, PCINT3) ) {
76 pfowler 265
 
75 pfowler 266
                        if (reportBuffer.axis2 > -32500)
267
                                reportBuffer.axis2 -= 200;
76 pfowler 268
 
77 pfowler 269
			reportBuffer.b2 = 1;
76 pfowler 270
 
75 pfowler 271
        }
272
 
273
        // Clear the mask so we know we've delth with it
274
        pcInt[pcint].mask = 0;
275
}
276
 
277
ISR(PCINT0_vect) {
278
        pcInterrupt(0);
279
}