One-key USB-HID
Posted: Tue Apr 21, 2009 2:21 am
Hi!
Im new at USB, but am trying to get my Atmega16 to work as a Onekey-keyboard. I downloadet the project from the examples page, but i am having problems compiling it. My programing skills isnt directly pushing the envelope, so it might just be a noob error, but could you help me?
The code is
and i get the Errors
I have added oddebug.c and usbdrv.c under sourcefiles
and iarcompat.h/oddebug.h/usbconfig-prototype.h/usbdrv.h under headerfiles.
What could be the reason that i get the "undefined reference"? error?
Help greately appreciated!
Regards
Alexander
Im new at USB, but am trying to get my Atmega16 to work as a Onekey-keyboard. I downloadet the project from the examples page, but i am having problems compiling it. My programing skills isnt directly pushing the envelope, so it might just be a noob error, but could you help me?
The code is
Code: Select all
/* Name: main.c
* Project: 1-Key Keyboard
* Author: Flip van den Berg - www.flipwork.nl
* Creation Date: 2008-10-06
* Based on AVR-USB drivers from Objective Developments - http://www.obdev.at/products/avrusb/index.html
*/
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdlib.h>
#include "usbdrv.h"
#include "oddebug.h"
#define BUTTON_PORT PORTB /* PORTx - register for button output */
#define BUTTON_PIN PINB /* PINx - register for button input */
#define BUTTON_BIT PB3 /* bit for button input/output */
/* ------------------------------------------------------------------------- */
static uchar reportBuffer[2]; /* buffer for HID reports */
static uchar idleRate; /* in 4 ms units */
static uchar reportCount; /* current report */
static uchar buttonState; /* stores state of button */
static uchar debounceTimeIsOver; /* for switch debouncing */
/* ------------------------------------------------------------------------- */
PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
};
/* We use a simplifed keyboard report descriptor which does not support the
* boot protocol. We don't allow setting status LEDs and we only allow one
* simultaneous key press (except modifiers). We can therefore use short
* 2 byte input reports.
* The report descriptor has been created with usb.org's "HID Descriptor Tool"
* which can be downloaded from http://www.usb.org/developers/hidpage/.
* Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
* for the second INPUT item.
*/
static void timerPoll(void)
{
static unsigned int timerCnt;
if(TIFR & (1 << TOV1)){
TIFR = (1 << TOV1); /* clear overflow */
if(++timerCnt >= 3){ // 3/63 sec delay for switch debouncing
timerCnt = 0;
debounceTimeIsOver = 1;
}
}
}
static void buildReport(void)
{
uchar key = 0; //if not changed by the if-statement below, then send an empty report
if(reportCount == 0){
if (buttonState == 1){ // if button is not pressed
key = 0x30; // key = ]
} else {
key = 0x2F; // key = [
}
}
reportCount++;
reportBuffer[0] = 0; /* no modifiers */
reportBuffer[1] = key;
}
static void checkButtonChange(void) {
uchar tempButtonValue = bit_is_clear(BUTTON_PIN, BUTTON_BIT); //status of switch is stored in tempButtonValue
if (tempButtonValue != buttonState && debounceTimeIsOver == 1){ //if status has changed and the debounce-delay is over
buttonState = tempButtonValue; // change buttonState to new state
debounceTimeIsOver = 0; // debounce timer starts
reportCount = 0; // start report
}
}
/* ------------------------------------------------------------------------- */
static void timerInit(void)
{
TCCR1B = 0x0b; /* select clock: 16.5M/1k -> overflow rate = 16.5M/256k = 62.94 Hz */
}
/* -------------------------------------------------------------------------------- */
/* ------------------------ interface to USB driver ------------------------ */
/* -------------------------------------------------------------------------------- */
uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
usbMsgPtr = reportBuffer;
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */
if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */
/* we only have one report type, so don't look at wValue */
buildReport();
return sizeof(reportBuffer);
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){
usbMsgPtr = &idleRate;
return 1;
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){
idleRate = rq->wValue.bytes[1];
}
}else{
/* no vendor specific requests implemented */
}
return 0;
}
/* ------------------------------------------------------------------------- */
/* ------------------------ Oscillator Calibration ------------------------- */
/* ------------------------------------------------------------------------- */
/* Calibrate the RC oscillator to 8.25 MHz. The core clock of 16.5 MHz is
* derived from the 66 MHz peripheral clock by dividing. Our timing reference
* is the Start Of Frame signal (a single SE0 bit) available immediately after
* a USB RESET. We first do a binary search for the OSCCAL value and then
* optimize this value with a neighboorhod search.
* This algorithm may also be used to calibrate the RC oscillator directly to
* 12 MHz (no PLL involved, can therefore be used on almost ALL AVRs), but this
* is wide outside the spec for the OSCCAL value and the required precision for
* the 12 MHz clock! Use the RC oscillator calibrated to 12 MHz for
* experimental purposes only!
*/
static void calibrateOscillator(void)
{
uchar step = 128;
uchar trialValue = 0, optimumValue;
int x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
/* do a binary search: */
do{
OSCCAL = trialValue + step;
x = usbMeasureFrameLength(); /* proportional to current real frequency */
if(x < targetValue) /* frequency still too low */
trialValue += step;
step >>= 1;
}while(step > 0);
/* We have a precision of +/- 1 for optimum OSCCAL here */
/* now do a neighborhood search for optimum value */
optimumValue = trialValue;
optimumDev = x; /* this is certainly far away from optimum */
for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
x = usbMeasureFrameLength() - targetValue;
if(x < 0)
x = -x;
if(x < optimumDev){
optimumDev = x;
optimumValue = OSCCAL;
}
}
OSCCAL = optimumValue;
}
/*
Note: This calibration algorithm may try OSCCAL values of up to 192 even if
the optimum value is far below 192. It may therefore exceed the allowed clock
frequency of the CPU in low voltage designs!
You may replace this search algorithm with any other algorithm you like if
you have additional constraints such as a maximum CPU clock.
For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g.
ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in
both regions.
*/
void usbEventResetReady(void)
{
calibrateOscillator();
eeprom_write_byte(0, OSCCAL); /* store the calibrated value in EEPROM */
}
/* ------------------------------------------------------------------------- */
/* --------------------------------- main ---------------------------------- */
/* ------------------------------------------------------------------------- */
int main(void)
{
uchar i;
uchar calibrationValue;
calibrationValue = eeprom_read_byte(0); /* calibration value from last time */
if(calibrationValue != 0xff){
OSCCAL = calibrationValue;
}
//odDebugInit();
usbInit();
usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */
i = 0;
while(--i){ /* fake USB disconnect for > 250 ms */
wdt_reset();
_delay_ms(1);
}
usbDeviceConnect();
wdt_enable(WDTO_1S);
/* turn on internal pull-up resistor for the switch */
BUTTON_PORT |= _BV(BUTTON_BIT);
timerInit();
sei();
for(;;){ /* main event loop */
wdt_reset();
usbPoll();
/* A USB keypress cycle is defined as a scancode being present in a report, and
then absent from a later report. To press and release the Caps Lock key, instead of
holding it down, we need to send the report with the Caps Lock scancode and
then an empty report. */
if(usbInterruptIsReady() && reportCount < 2){ /* we can send another key */
buildReport();
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
checkButtonChange();
timerPoll();
}
return 0;
}
and i get the Errors
Code: Select all
Build started 21.4.2009 at 02:16:17
avr-gcc.exe -mmcu=atmega16 -Wall -gdwarf-2 -O0 -MD -MP -MT main.o -MF dep/main.o.d -c ../main.c
In file included from ../main.c:13:
c:/winavr-20090313/lib/gcc/../../avr/include/util/delay.h:85:3: warning: #warning "F_CPU not defined for <util/delay.h>"
c:/winavr-20090313/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warning "Compiler optimizations disabled; functions from <util/delay.h> won't work as designed"
avr-gcc.exe -mmcu=atmega16 main.o usbdrv.o oddebug.o -o onek.elf
main.o: In function `calibrateOscillator':
C:\Documents and Settings\Alexander\Mina dokument\program\onek\default/../main.c:162: undefined reference to `usbMeasureFrameLength'
C:\Documents and Settings\Alexander\Mina dokument\program\onek\default/../main.c:172: undefined reference to `usbMeasureFrameLength'
usbdrv.o: In function `usbSetInterrupt':
C:\Documents and Settings\Alexander\Mina dokument\program\onek\default/../usbdrv.c:249: undefined reference to `usbCrc16Append'
usbdrv.o: In function `usbBuildTxBlock':
C:\Documents and Settings\Alexander\Mina dokument\program\onek\default/../usbdrv.c:484: undefined reference to `usbCrc16Append'
make: *** [onek.elf] Error 1
Build failed with 4 errors and 2 warnings...
I have added oddebug.c and usbdrv.c under sourcefiles
and iarcompat.h/oddebug.h/usbconfig-prototype.h/usbdrv.h under headerfiles.
What could be the reason that i get the "undefined reference"? error?
Help greately appreciated!
Regards
Alexander