// ATmega88P // V-USB HIDクラスのデバイス // 『昼夜逆転』工作室 http://jsdiy.web.fc2.com /* base: V-USB/examples/hid-data buffer 256byte(SRAM) Feature Report = 256byte Input Report = 8byte Output Report = 16byte 【動作内容】 fertureレポートで256byte送受信できる。 outputレポートでホストからデバイスへ16byte送信できる。 PC0〜PC5をスイッチ・オンすると(GNDとショート)、PORTCの状態がインタラプト転送でホストへ通知される。 */ /* 【ポート対応】 ATmega88P x:存在しない(PC6はRESET) -:空き bit 7 6 5 4 3 2 1 0 portB Xtl Xtl - - - - - - クリスタル portC x x sw sw sw sw sw sw スイッチ portD - - - - D+ D- - - -- 【ATmega88P】 |CCCCCC---BBBBB| |543210GRV54321| > | |601234VG675670| |CDDDDD--BBDDDB| 【ヒューズビット】(ftavrw.exe -rf) ※工場出荷設定は Low:01100010, Hi:11011111 ※[vusb-20120109/examples/hid-data/firmware/Makefile]参照 Low: 11011111 (DF) ||||++++-- CKSEL[3:0] システムクロック選択 ||++-- SUT[1:0] 起動時間 |+-- CKOUT (0:PB0にシステムクロックを出力) +-- CKDIV8 クロック分周初期値 (1:1/1, 0:1/8) High:11-11110 (DE) |||||+++-- BODLEVEL[2:0] (111:無, 110:1.8V, 101:2.7V, 100:4.3V) ||||+-- EESAVE (消去でEEPROMを 1:消去, 0:保持) |||+-- WDTON (1:WDT通常動作, 0:WDT常時ON) ||+-- SPIEN (1:ISP禁止, 0:ISP許可) ※Parallel時のみ |+-- DWEN (On-Chipデバッグ 1:無効, 0:有効) +-- RSTDISBL (RESETピン 1:有効, 0:無効(PC6)) Ext: -----001 (F9) ||+-- BOOTRST ※データシート参照 ++-- BOOTSZ[1:0] ※データシート参照 【ビルド環境】 Atmel AVR Studio 5 (Version: 5.1.208) 最適化オプション: -Os AVRGCC Version: 3.3.1.27 ATmega88P 12MHz(クリスタル振動子) 【更新履歴】 2012/03/27 v1.00 Program: 2256 bytes (27.5% Full) Data: 322 bytes (31.4% Full) */ #include #include #include /* for sei() */ #include /* for _delay_ms() */ #include #include /* required by usbdrv.h */ #include "usbdrv.h" //#include "oddebug.h" /* This is also an example for using debug macros */ /* ------------------------------------------------------------------------- */ /* ----------------------------- USB interface ----------------------------- */ /* ------------------------------------------------------------------------- */ PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { // USB report descriptor 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0xa1, 0x01, // COLLECTION (Application) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) bit //14byte 0x09, 0x00, // USAGE (Undefined) 0x95, 0x08, // REPORT_COUNT (8) 0x81, 0x02, // INPUT (Data,Var,Abs) //6 0x09, 0x00, // USAGE (Undefined) 0x95, 0x10, // REPORT_COUNT (16) 0x10:16, 0x80:128, 0xFE:254 0x91, 0x02, // OUTPUT (Data,Var,Abs) //6 0x09, 0x00, // USAGE (Undefined) 0x96, 0x00, 0x01, // REPORT_COUNT (256) Lo-Hi, 0x00-0x01:256, 0x00-0x02:512, 0x00-0x04:1024 0xb1, 0x02, // FEATURE (Data,Var,Abs) //7 0xc0 // END_COLLECTION }; /* Since we define only one feature report, we don't use report-IDs (which * would be the first byte of the report). The entire report consists of 128 * opaque data bytes. */ /* The following variables store the status of the current data transfer */ //static uchar currentAddress; //static uchar bytesRemaining; //改造 #define USER_BUF_SIZE 256 //byte #define FEATURE_REPORT_SIZE 256 #define INPUT_REPORT_SIZE 8 #define OUTPUT_REPORT_SIZE 16 static uint16_t currentAddress; static uint16_t bytesRemaining; static uint8_t userBuf[USER_BUF_SIZE]; static uint8_t reportType, reportID; static uint8_t prevPinValue; void portInit() { DDRC = 0b00000000; //all PORTC = 0b00111111; //pull-up PC5-PC0 _delay_us(1); prevPinValue = PINC; } uint8_t isPinChanged(uint8_t* nowPinValue) { *nowPinValue = PINC; uint8_t isChange = (prevPinValue != *nowPinValue) ? 1 : 0; //true/false値を明示的に prevPinValue = *nowPinValue; return isChange; } /* ------------------------------------------------------------------------- */ /* usbFunctionRead() is called when the host requests a chunk of data from * the device. For more information see the documentation in usbdrv/usbdrv.h. */ uchar usbFunctionRead(uchar *data, uchar len) { if(len > bytesRemaining) len = bytesRemaining; //eeprom_read_block(data, (uchar *)0 + currentAddress, len); { uint8_t i; for (i = 0; i < len; i++) data[i] = userBuf[currentAddress + i]; } currentAddress += len; bytesRemaining -= len; return len; } /* usbFunctionWrite() is called when the host sends a chunk of data to the * device. For more information see the documentation in usbdrv/usbdrv.h. */ uchar usbFunctionWrite(uchar *data, uchar len) { if(bytesRemaining == 0) return 1; /* end of transfer */ if(len > bytesRemaining) len = bytesRemaining; //eeprom_write_block(data, (uchar *)0 + currentAddress, len); { uint8_t i; for (i = 0; i < len; i++) userBuf[currentAddress + i] = data[i]; } currentAddress += len; bytesRemaining -= len; return bytesRemaining == 0; /* return 1 if this was the last chunk */ } /* ------------------------------------------------------------------------- */ //ReportType:input(1),output(2),feature(3) #define USBHID_REPORTTYPE_INPUT 1 #define USBHID_REPORTTYPE_OUTPUT 2 #define USBHID_REPORTTYPE_FEATURE 3 usbMsgLen_t usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (void *)data; if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* HID class request */ if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte:[1]), ReportID (lowbyte:[0]) */ reportType = rq->wValue.bytes[1]; reportID = rq->wValue.bytes[0]; if (reportType == USBHID_REPORTTYPE_FEATURE) bytesRemaining = FEATURE_REPORT_SIZE; else bytesRemaining = INPUT_REPORT_SIZE; currentAddress = 0; return USB_NO_MSG; /* use usbFunctionRead() to obtain data */ }else if(rq->bRequest == USBRQ_HID_SET_REPORT){ reportType = rq->wValue.bytes[1]; reportID = rq->wValue.bytes[0]; if (reportType == USBHID_REPORTTYPE_FEATURE) bytesRemaining = FEATURE_REPORT_SIZE; else bytesRemaining = OUTPUT_REPORT_SIZE; currentAddress = 0; return USB_NO_MSG; /* use usbFunctionWrite() to receive data from host */ } }else{ /* ignore vendor type requests, we don't use any */ } return 0; } /* ------------------------------------------------------------------------- */ int main(void) { uchar i; uint8_t pinValue; wdt_enable(WDTO_1S); /* Even if you don't use the watchdog, turn it off here. On newer devices, * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! */ /* RESET status: all port bits are inputs without pull-up. * That's the way we need D+ and D-. Therefore we don't need any * additional hardware initialization. */ portInit(); // odDebugInit(); // DBG1(0x00, 0, 0); /* debug output: main starts */ 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(); sei(); // DBG1(0x01, 0, 0); /* debug output: main loop starts */ for(;;){ /* main event loop */ // DBG1(0x02, 0, 0); /* debug output: main loop iterates */ wdt_reset(); usbPoll(); if(isPinChanged(&pinValue) && usbInterruptIsReady()){ // only if previous data was sent uint8_t p[] = { pinValue, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; usbSetInterrupt(p, 8); } } return 0; }