Subversion Repositories group.electronics

Rev

Rev 75 | Rev 77 | 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)
70
    0xc0,                          //   END_COLLECTION
71
    0xc0                           // END_COLLECTION
72
};
73
 
74
 
75
 
76
/* ------------------------------------------------------------------------- */
77
/* ------------------------ interface to USB driver ------------------------ */
78
/* ------------------------------------------------------------------------- */
79
 
80
uchar	usbFunctionSetup(uchar data[8])
81
{
82
usbRequest_t    *rq = (void *)data;
83
 
84
    //usbMsgPtr = reportBuffer;
85
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ 
86
        if(rq->bRequest == USBRQ_HID_GET_REPORT){ 
87
            return sizeof(reportBuffer);
88
        }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
89
            usbMsgPtr = &idleRate;
90
            return 1;
91
        }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
92
            idleRate = rq->wValue.bytes[1];
93
        }
94
    }else{
95
 
96
    }
97
	return 0;
98
}
99
 
100
 
101
/* ------------------------------------------------------------------------- */
102
/* ------------------------ Oscillator Calibration ------------------------- */
103
/* ------------------------------------------------------------------------- */
104
 
105
/* Calibrate the RC oscillator to 8.25 MHz. The core clock of 16.5 MHz is
106
 * derived from the 66 MHz peripheral clock by dividing. Our timing reference
107
 * is the Start Of Frame signal (a single SE0 bit) available immediately after
108
 * a USB RESET. We first do a binary search for the OSCCAL value and then
109
 * optimize this value with a neighboorhod search.
110
 * This algorithm may also be used to calibrate the RC oscillator directly to
111
 * 12 MHz (no PLL involved, can therefore be used on almost ALL AVRs), but this
112
 * is wide outside the spec for the OSCCAL value and the required precision for
113
 * the 12 MHz clock! Use the RC oscillator calibrated to 12 MHz for
114
 * experimental purposes only!
115
 */
116
static void calibrateOscillator(void)
117
{
118
uchar       step = 128;
119
uchar       trialValue = 0, optimumValue;
120
int         x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
121
 
122
    /* do a binary search: */
123
    do{
124
        OSCCAL = trialValue + step;
125
        x = usbMeasureFrameLength();    /* proportional to current real frequency */
126
        if(x < targetValue)             /* frequency still too low */
127
            trialValue += step;
128
        step >>= 1;
129
    }while(step > 0);
130
    /* We have a precision of +/- 1 for optimum OSCCAL here */
131
    /* now do a neighborhood search for optimum value */
132
    optimumValue = trialValue;
133
    optimumDev = x; /* this is certainly far away from optimum */
134
    for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
135
        x = usbMeasureFrameLength() - targetValue;
136
        if(x < 0)
137
            x = -x;
138
        if(x < optimumDev){
139
            optimumDev = x;
140
            optimumValue = OSCCAL;
141
        }
142
    }
143
    OSCCAL = optimumValue;
144
}
145
/*
146
Note: This calibration algorithm may try OSCCAL values of up to 192 even if
147
the optimum value is far below 192. It may therefore exceed the allowed clock
148
frequency of the CPU in low voltage designs!
149
You may replace this search algorithm with any other algorithm you like if
150
you have additional constraints such as a maximum CPU clock.
151
For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g.
152
ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in
153
both regions.
154
*/
155
 
156
void    usbEventResetReady(void)
157
{
158
    /* Disable interrupts during oscillator calibration since
159
     * usbMeasureFrameLength() counts CPU cycles.
160
     */
161
    cli();
162
    calibrateOscillator();
163
    sei();
164
    eeprom_write_byte(0, OSCCAL);   /* store the calibrated value in EEPROM */
165
}
166
 
167
 
168
void usbSendHidReport(uchar * data, uchar len) {
169
        while(1)
170
        {
171
                usbPoll();
172
                if (usbInterruptIsReady())
173
                {
174
                        usbSetInterrupt(data, len);
175
                        break;
176
                }
177
        }
178
}
179
 
180
 
181
int main(void)
182
{
183
uchar   i;
184
uchar   calibrationValue;
185
 
186
    calibrationValue = eeprom_read_byte(0); /* calibration value from last time */
187
    if(calibrationValue != 0xff){
188
        OSCCAL = calibrationValue;
189
    }
190
 
191
    odDebugInit();
192
    usbDeviceDisconnect();
193
    for(i=0;i<20;i++){  /* 300 ms disconnect */
194
        _delay_ms(15);
195
    }
196
 
197
    usbDeviceConnect();
198
    wdt_enable(WDTO_1S);
199
 
200
  PCMSK |= (( 1 << PCINT3 ) | ( 1 << PCINT4 )); //enable encoder pins interrupt sources
201
  GIMSK |= ( 1 << PCIE ); //enable pin change interupts
202
 
203
  DDRB          = 0B00000001;
204
  PORTB         = 0B00000000;
205
 
206
    usbInit();
207
    sei();
208
 
76 pfowler 209
    reportBuffer.axis0 = 0;
210
    reportBuffer.axis1 = 0;
211
    reportBuffer.axis2 = 0;
212
    reportBuffer.buttons = 0;
75 pfowler 213
 
214
 
215
 
216
 
76 pfowler 217
 
75 pfowler 218
    for(;;){    /* main event loop */
219
        wdt_reset();
220
        usbPoll();
221
 
222
        if(usbInterruptIsReady()){ 
223
		usbSendHidReport(&reportBuffer, sizeof(reportBuffer));
224
        }
225
    }
226
    return 0;
227
}
228
 
229
void pcInterrupt(uint8_t pcint) {
230
 
231
        switch (pcint) {
232
                case 0: pcInt[pcint].current = PINB; break;
233
        }
234
        pcInt[pcint].mask = pcInt[pcint].current ^ pcInt[pcint].last;
235
        pcInt[pcint].last = pcInt[pcint].current;
236
 
237
        if (pcInt[pcint].mask == 0)
238
		return;
239
 
240
        // Check which pin caused the interrupt. If they both
241
        //  equal 0, the pin that interrupted is the direction
242
        if (rbi(pcInt[pcint].current, PCINT3) == 0
243
                && rbi(pcInt[pcint].current, PCINT4) == 0
244
                && rbi(pcInt[pcint].mask, PCINT4) ) {
76 pfowler 245
 
75 pfowler 246
                        if (reportBuffer.axis2 < 32500)
247
                                reportBuffer.axis2 += 200;
76 pfowler 248
 
249
 
75 pfowler 250
        } else if (rbi(pcInt[pcint].current, PCINT3) == 0
251
                && rbi(pcInt[pcint].current, PCINT4) == 0
252
                && rbi(pcInt[pcint].mask, PCINT3) ) {
76 pfowler 253
 
75 pfowler 254
                        if (reportBuffer.axis2 > -32500)
255
                                reportBuffer.axis2 -= 200;
76 pfowler 256
 
257
 
75 pfowler 258
        }
259
 
260
        // Clear the mask so we know we've delth with it
261
        pcInt[pcint].mask = 0;
262
}
263
 
264
ISR(PCINT0_vect) {
265
        pcInterrupt(0);
266
}