Subversion Repositories group.electronics

Rev

Rev 76 | Go to most recent revision | Details | 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
//static uchar    reportBuffer[6];    /* buffer for HID reports */
29
volatile int16_t  axis[3];
30
 
31
struct {
32
	union {
33
		int16_t axis[3];
34
		struct {
35
			int16_t axis0:16;
36
			int16_t axis1:16;
37
			int16_t axis2:16;
38
		};
39
	};
40
} reportBuffer;
41
 
42
 
43
volatile struct {
44
        uint8_t current;
45
        uint8_t last;
46
        uint8_t mask;
47
} pcInt[1];
48
 
49
static uchar    idleRate;           /* in 4 ms units */
50
 
51
/* ------------------------------------------------------------------------- */
52
 
53
const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
54
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
55
    0x09, 0x05,                    // USAGE (Game Pad)
56
    0xa1, 0x01,                    // COLLECTION (Application)
57
    0x09, 0x01,                    //   USAGE (Pointer)
58
    0xa1, 0x00,                    //   COLLECTION (Physical)
59
    0x09, 0x30,                    //     USAGE (X)
60
    0x09, 0x31,                    //     USAGE (Y)
61
    0x09, 0x38,                    //     USAGE (Y)
62
    0x16, 0x00, 0x80,		   //	  Log Min -32768
63
    0x26, 0xff, 0x7f,		   //	  Log max 32768
64
    0x75, 0x10,                    //     REPORT_SIZE (16)
65
    0x95, 0x03,                    //     REPORT_COUNT (2)
66
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
67
    0xc0,                          //   END_COLLECTION
68
    0xc0                           // END_COLLECTION
69
};
70
 
71
 
72
 
73
/* ------------------------------------------------------------------------- */
74
/* ------------------------ interface to USB driver ------------------------ */
75
/* ------------------------------------------------------------------------- */
76
 
77
uchar	usbFunctionSetup(uchar data[8])
78
{
79
usbRequest_t    *rq = (void *)data;
80
 
81
    //usbMsgPtr = reportBuffer;
82
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ 
83
        if(rq->bRequest == USBRQ_HID_GET_REPORT){ 
84
            return sizeof(reportBuffer);
85
        }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
86
            usbMsgPtr = &idleRate;
87
            return 1;
88
        }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
89
            idleRate = rq->wValue.bytes[1];
90
        }
91
    }else{
92
 
93
    }
94
	return 0;
95
}
96
 
97
 
98
/* ------------------------------------------------------------------------- */
99
/* ------------------------ Oscillator Calibration ------------------------- */
100
/* ------------------------------------------------------------------------- */
101
 
102
/* Calibrate the RC oscillator to 8.25 MHz. The core clock of 16.5 MHz is
103
 * derived from the 66 MHz peripheral clock by dividing. Our timing reference
104
 * is the Start Of Frame signal (a single SE0 bit) available immediately after
105
 * a USB RESET. We first do a binary search for the OSCCAL value and then
106
 * optimize this value with a neighboorhod search.
107
 * This algorithm may also be used to calibrate the RC oscillator directly to
108
 * 12 MHz (no PLL involved, can therefore be used on almost ALL AVRs), but this
109
 * is wide outside the spec for the OSCCAL value and the required precision for
110
 * the 12 MHz clock! Use the RC oscillator calibrated to 12 MHz for
111
 * experimental purposes only!
112
 */
113
static void calibrateOscillator(void)
114
{
115
uchar       step = 128;
116
uchar       trialValue = 0, optimumValue;
117
int         x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
118
 
119
    /* do a binary search: */
120
    do{
121
        OSCCAL = trialValue + step;
122
        x = usbMeasureFrameLength();    /* proportional to current real frequency */
123
        if(x < targetValue)             /* frequency still too low */
124
            trialValue += step;
125
        step >>= 1;
126
    }while(step > 0);
127
    /* We have a precision of +/- 1 for optimum OSCCAL here */
128
    /* now do a neighborhood search for optimum value */
129
    optimumValue = trialValue;
130
    optimumDev = x; /* this is certainly far away from optimum */
131
    for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
132
        x = usbMeasureFrameLength() - targetValue;
133
        if(x < 0)
134
            x = -x;
135
        if(x < optimumDev){
136
            optimumDev = x;
137
            optimumValue = OSCCAL;
138
        }
139
    }
140
    OSCCAL = optimumValue;
141
}
142
/*
143
Note: This calibration algorithm may try OSCCAL values of up to 192 even if
144
the optimum value is far below 192. It may therefore exceed the allowed clock
145
frequency of the CPU in low voltage designs!
146
You may replace this search algorithm with any other algorithm you like if
147
you have additional constraints such as a maximum CPU clock.
148
For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g.
149
ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in
150
both regions.
151
*/
152
 
153
void    usbEventResetReady(void)
154
{
155
    /* Disable interrupts during oscillator calibration since
156
     * usbMeasureFrameLength() counts CPU cycles.
157
     */
158
    cli();
159
    calibrateOscillator();
160
    sei();
161
    eeprom_write_byte(0, OSCCAL);   /* store the calibrated value in EEPROM */
162
}
163
 
164
 
165
void usbSendHidReport(uchar * data, uchar len) {
166
        while(1)
167
        {
168
                usbPoll();
169
                if (usbInterruptIsReady())
170
                {
171
                        usbSetInterrupt(data, len);
172
                        break;
173
                }
174
        }
175
}
176
 
177
 
178
int main(void)
179
{
180
uchar   i;
181
uchar   calibrationValue;
182
 
183
    calibrationValue = eeprom_read_byte(0); /* calibration value from last time */
184
    if(calibrationValue != 0xff){
185
        OSCCAL = calibrationValue;
186
    }
187
 
188
    odDebugInit();
189
    usbDeviceDisconnect();
190
    for(i=0;i<20;i++){  /* 300 ms disconnect */
191
        _delay_ms(15);
192
    }
193
 
194
    usbDeviceConnect();
195
    wdt_enable(WDTO_1S);
196
 
197
  PCMSK |= (( 1 << PCINT3 ) | ( 1 << PCINT4 )); //enable encoder pins interrupt sources
198
  GIMSK |= ( 1 << PCIE ); //enable pin change interupts
199
 
200
  DDRB          = 0B00000001;
201
  PORTB         = 0B00000000;
202
 
203
    usbInit();
204
    sei();
205
 
206
    axis[0] = 0;
207
    axis[1] = 0;
208
    axis[2] = 0;
209
 
210
    reportBuffer.axis0 = axis[0];
211
    reportBuffer.axis1 = axis[1];
212
    reportBuffer.axis2 = axis[2];
213
 
214
 
215
    //reportBuffer[1] = 0xff;
216
 
217
    for(;;){    /* main event loop */
218
        wdt_reset();
219
        usbPoll();
220
 
221
        if(usbInterruptIsReady()){ 
222
            //usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
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) ) {
245
                        if (reportBuffer.axis2 < 32500)
246
                                reportBuffer.axis2 += 200;
247
        } else if (rbi(pcInt[pcint].current, PCINT3) == 0
248
                && rbi(pcInt[pcint].current, PCINT4) == 0
249
                && rbi(pcInt[pcint].mask, PCINT3) ) {
250
                        if (reportBuffer.axis2 > -32500)
251
                                reportBuffer.axis2 -= 200;
252
        }
253
 
254
        // Clear the mask so we know we've delth with it
255
        pcInt[pcint].mask = 0;
256
}
257
 
258
ISR(PCINT0_vect) {
259
        pcInterrupt(0);
260
}