■ 最新版 HIDsph05 +HidTerm (Ver.050) トップページに戻る (変更日2011/02/28)
|
|
|
USB接続 ツーワイヤ 通信機能付、HID
デバドラ使用 高速版AVRライタ(オープン・ソース) |
◎ USB接続
ツーワイヤ 通信機能付、HID デバドラ使用 高速版AVRライタ(オープン・ソース)
HID(Human Interface Device)とはヒューマンインターフェースデバイスの略で、
マウスやキーボードなど、人間がコンピュータに働きかけるための機器のことです。
(デバドラとはデバイスドライバの略です)
*** VER.034 から050 へ変更しました *** (2010/09/19)
VER.034 から050 への変更点
・Windows7 での動作確認しました。(Win98、Win2K、WinXp、VISTA、Windows7対応) |
・USB通信プログラム(usbdrvasm.S)中のCRC計算プログラム(usbCrc16Append)を 約5倍に高速化しました。これによりOHCIホスト(マイコンからNAKを返したとき、 7.3micro秒後にPC側から再送信(INトークン13micro秒+NAK応答13micro秒)が 起きること)による不具合(マイコン側でのCRC計算に時間がかかり、ホスト(PC)が タイムアウトしてしまう)に対応しました。 更に、OHCIに対処するために、ホストへのNAK応答を「usbPoll()」ループ中から 割り込み応答ルーチンに移動しました。 なお、usbdrvを変更することによりUSB通信プログラム部分は8Byte増えています。 また、コード縮小のために、r4とGPIOR2のbit4を占有しています。 |
・HIDsph-マスタ(mega168)間、マスタ(mega168)-スレーブ(tiny2313)間の 通信方式をシリアルからマイコンハード(USI)による2線通信に変更しました。 (SCLは共有、データは各1本で合計3本使用。シリアルプログラミングの3本と共用) これにより、回路の簡単化、シリアル ポート/コントローラの開放をしました。 また、マスタ(mega168)18本、スレーブ(tiny2313)13本、HIDsph
4本(inのみ)、 の計 35 I/O がマスタから利用できるようになりました。 |
・HIDsph のコードが増えたことへの対処に、irukaさんのcrt1.Sを使用しました。 これにより52Byte縮小されています。 http://hp.vector.co.jp/authors/VA000177/html/AVRUSB_Tips.html
- zd510700 |
ダウンロードHIDsph050comm05.zip
(252K)
・手配線ではありますが、3個のAVRにプログラム書き込み済みのボードをお分けします。
送料、税込み2000円。 詳しくは「お問い合わせページ」にてお尋ねください。
・ファームウェア(U1)はライタ機能のみ使用の場合、1744(0x6D0)バイト使用しています。
残り304(0x130)バイト。 ツーワイヤー通信機能も使用の場合は残り30バイトです。
LDO(Low Drop Out)レギュレータ部分は旧判と同じようにシリコンダイオード(1N4148等)2個を 直列接続した回路で代用が可能です。(C3のバイパスコンデンサは必要) 但し、その場合には、PC供給のUSB電源電圧が4.5V以上の必要があります。(規格では最小4.07V) |
U3(スレーブ)側のライトはAVRSPH コマンドに「-S[V|W|P|F]」オプション付加で可能です。 |
USB Vendor-ID、Product-IDは当方が保有しています。 非営利の場合はそのまま変更せずに使用してください。 非営利での使用で、他の用途に使用する時は、デバイスドライバは HIDのまま使用し、Product名の最初の1文字が「I」で始まるように 変更して使用してください。 非営利での使用で、同時に複数台を同じPCに接続し、各々区別する必要の ある時は、シリアルナンバの最後の1字のみを変更して使用してください。 非営利以外で使用する場合は、メールにてお尋ねください。 |
ソースコードのライセンスはGPL2(GNU GPL ver.2)です。 しかし、なるべく、大きな変更や改良をした場合は公開するようにしてください。 プログラム(含むオブジェクト)、回路図などの著作物の著作権に関しては、 放棄はしませんが、非営利の場合はご自由にお使いください。 |
ファームウェアのUSBドライバはObjective Development Software社のBootLoadHIDを 基にしました。 AVRへの書き込み方式は瓶詰堂さんのHIDaspを参考にしました。 ファームウェアのコンパイルにはフリーソフトWinAVRを使用しました。 PC側書き込みソフトのコンパイルにはフリーソフトMinGWを使用しました。(MS−DDK不要です) なお、PC側書き込みソフトは瓶詰堂さんのHIDasp対応のavrspxを 参考にすればAVRSPXに組み込み易くなっています。 |
お尋ね、御質問等は ymori@myd.0am.jp (森芳喜) 宛てにお願いします。 (コピー・アンド・ペーストでメールソフトの宛先に貼り付けてください) |
◎ CRC計算ルーチン(usbdrvasm.S)のソースコード(抜粋)
; unsigned
table(unsigned char x) ; { ; unsigned value; ; ; value = (unsigned)x << 6; ; value ^= (unsigned)x << 7; ; if(parity_even_bit(x)) ; value ^= 0xc001; ; return value; ; } ; unsigned
usbCrc16(unsigned char *argPtr, unsigned char argLen) ; { ; unsigned crc =
0xffff; ; ; while(argLen--) ; crc = table(lo8(crc) ^ *argPtr++) ^
hi8(crc); ; return ~crc; ; } usbCrc16Append: ;(+8) ;usbCrc16: ;mov
ptrL, argPtrL ;mov
ptrH, argPtrH ldi
ptrL, lo8(usbTxBuf+1) ldi
ptrH, hi8(usbTxBuf+1) ldi
resCrcL, 0xFF ldi
resCrcH, 0xFF rjmp
usbCrc16LoopTest usbCrc16ByteLoop: ld
byte, ptr+ eor
byte, resCrcL ; byte<x>
^= crcL ; byte is now 'x' in table() clr
resCrcL mov
tempH, byte ; tempH:crcL =
x << 8 lsr
byte ror
resCrcL eor
tempH, byte ; tempH:crcL ^=
x << 7, tempH:crcL = (x << 8) ^ (x << 7) mov
byte, tempH ; for parity lsr
tempH ror
resCrcL ; tempH:crcL
>>= 1, tempH:crcL = (x << 6) ^ (x << 7) eor
resCrcL, resCrcH; tempH:crcL ^= crcH, tempH:crcL = (x << 6) ^ (x
<< 7) ^ crcH mov
resCrcH, tempH
; compute parity of 'x' lsr
resCrcH eor
resCrcH, byte sbrc
resCrcH, 4 inc
resCrcH andi
resCrcH, 0x01 ; crcH =
parity(byte<x>) ? 1 : 0 ;
resCrcH is now parity(x) eor
resCrcL, resCrcH
; low byte of if(parity(x)) value ^= 0xC001; neg
resCrcH andi
resCrcH, 0xC0 ; crc ^= (byte
? 0xC001 : 0) eor
resCrcH, tempH
; high byte of if(parity(x)) value ^= 0xc001; usbCrc16LoopTest: subi
argLen, 1 brsh
usbCrc16ByteLoop com
resCrcL com
resCrcH st
ptr+, resCrcL st
ptr+, resCrcH ret |
◎ HIDsph050(HIDsphDESC for ATtiny2313) のソースコード(抜粋)
// " sphDESC.C
Ver.051 2010/09/23 MORIYOSHI DENSHI
CO.,LTD. COPYRIGHT(C) MAR.2009 "; #if
(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC) static uchar serbuf[32+0]; // =0; #define SerRoutine 1 #endif #if SerRoutine #define offsetR
UBRRL #else static uchar offset;
// data already processed in current transfer #endif static uchar
usbData[33]; #define page_mode
GPIOR0 PROGMEM char usbHidReportDescriptor[33]
= { 0x06, 0x00, 0xff, // USAGE_PAGE (Generic
Desktop) 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) 0x85, 0x02, //
REPORT_ID (2) 0x95,
7, // REPORT_COUNT (7)
0x09, 0x00,
// USAGE (Undefined) 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) 0x85, 0x04, //
REPORT_ID (4) 0x95,
39, // REPORT_COUNT (39) 0x09, 0x00, // USAGE
(Undefined) 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) 0xc0 // END_COLLECTION }; #define wait GPIOR1 static void
delay(uchar d) { while(d--); } static uint8_t
usi_trans(uchar data) { USICR = (1 << USIWM0) | (1
<< USICS1) | (1 << USICLK); //MYD100923 USIDR = data; USISR = (1<<USISIF) |
(1<<USIOIF) | (1<<USIPF) | 0; //MYD100923 do{ delay(wait); USICR = (1 << USIWM0) | (1
<< USICS1) | (1 << USICLK) | (1 << USITC); } while(!(USISR & (1 <<
USIOIF)) ); return USIDR; } uchar usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (void *)data; uchar rval; //MYD091021 rval=0; if(rq->bRequest ==
USBRQ_HID_SET_REPORT){ #if SerRoutine offsetR = 0; //@ #else offset = 0; #endif rval = 0xFF; }else if(rq->bRequest ==
USBRQ_HID_GET_REPORT){ usbMsgPtr = usbData; usbData[0] = rq->wValue.bytes[0];
// report ID rval = 8; if(usbData[0] == 4) { rval = 40; } } return rval; //MYD091021 (-6) } uchar
usbFunctionWrite(uchar *data, uchar len) { uchar i, d1, d2; #if SerRoutine uchar offset; offset = offsetR; //@ #define tcnt UBRRH #else static uchar tcnt; //MYD091021 (-6) #endif d2 = data[2]; //@ (-0) d1 = data[1]; //@ (-0) if(offset == 0 && !(d1 &
0x40)) { usbData[1] = d2; if(d1 == 2) { // SET_LED #if SerRoutine USICR = (1<<USIWM1) |
(1<<USIWM0) | (1<<USICS1); #else USICR = 0; #endif PORTB = data[3]; //@ (-12) |
((data[4] & (1<<PB7)) ? 0 : 0xE0); //if(data[4] == 0x55) DDRB =
data[5]; // (+1) if(data[4] & (1<<PB2))
//@ (-4) DDRB = data[4]; #if !SerRoutine else DDRB |= (1<<PB7);
// (+6) #endif usbData[2] = PIND; //@ (+4) }else if(d1 == 18) { // Set wait wait = d2; }else if(d1 == 16) { // SPI for(i = 0; i < 4; i++) { usbData[i+1] = usi_trans(data[i+2]); } }else if(d1 == 20) { // Page set page_mode = d2; page_addr.b.hbyte = data[3]; page_addr.b.lbyte = data[4]; } }else{ if(offset == 0) { // Page buf tcnt = (d1 & 0x07) + 2; i = 2; }else /* if(!(reportId == 4
&& offset < 32)) tcnt = 0; else */ { tcnt = (offset > 32-8) ?
32-offset : 8; i = 0; } while(i < tcnt) { usi_trans(page_mode); usi_trans(page_addr.b.hbyte); usi_trans(page_addr.b.lbyte); usbData[++offset] =
usi_trans(data[i++]); if(page_mode & 0x88) { //
EEPROM or Flash(P=Hi) page_addr.w++; page_mode &= ~0x08; }else{ page_mode |= 0x08; } } } #if SerRoutine offsetR = offset; //@ #endif return 1; } #if SerRoutine #define UsbRetSts
serbuf[0] #define SerRXbuff
serbuf[1] #define UsbwV0 serbuf[16] #define UsbwV1 serbuf[17] #define UsbwI0 serbuf[18] #define UsbwL1 serbuf[21] #define SerTXbuff
serbuf[22] // use at host(Hub
driver) IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION /*uchar
usbFunctionDescriptor(struct usbRequest *rq) { // bRequest==6 GET_DESCRIPTOR uchar i, *pser, *prq; pser =
&serbuf[16]; prq = &rq->wValue.bytes[0]; i=6; do *pser++ = *prq++; while(--i); // serbuf[6+16] = rq->bmRequestType; // serbuf[0+16] = rq->wValue.bytes[0]; // serbuf[1+16] = rq->wValue.bytes[1]; // serbuf[2+16] = rq->wIndex.bytes[0]; // serbuf[3+16] = rq->wIndex.bytes[1]; // serbuf[4+16] = rq->wLength.bytes[0]; // serbuf[5+16] = rq->wLength.bytes[1]; usbMsgPtr = serbuf; // &serbuf[16] return 7; }*/ #endif int main(void) { #if SerRoutine uchar usstxd, ussrxd; #define usslvsts
GPIOR2 #endif // initialize hardware PORTD = (1<<PD6) | (1<<PD5)
| (1<<PD1) | (1<<PD0); //
pullups // no pullups on USB
pins DDRD = 0x7F & ~USBMASK &
~(1<<PD6) & ~(1<<PD5) & ~(1<<PD2) &
~(1<<PD1) & ~(1<<PD0); // all inputs except
USB data #if SerRoutine USICR = (1<<USIWM1) |
(1<<USIWM0) | (1<<USICS1); PORTB = 0xF8; // no pullup PB7,5 on USI // ~RST Hi, activeLED off DDRB = (1<<PB7) | (1<<PB6) |
(1<<PB4) | (1<<PB3) | (1<<PB2); USISR = (1<<USISIF) |
(1<<USIOIF) | (1<<USIPF) | 1; #else PORTB = 0xF8; // pullups PB7,6,5,1,0 DDRB = (1<<PB4) | (1<<PB3) |
(1<<PB2); #endif usbInit(); sei(); while(1) { // main event loop usbPoll(); #if SerRoutine //void serLoop() { uchar retStsRX, retStsTX; uchar *dest,
*src; retStsRX = UsbRetSts & 0x0F; retStsTX = UsbRetSts >> 4; if(UsbwV1 & 0x80) { uchar i; UsbwV1 &= 0x7F; if(UsbwV1 == 0x60) { // PORTB set
& TXbuffer flush retStsTX = 0; //@ (+2) PORTB = UsbwV0; //@ (+8) usslvsts &= ~(1<<7);
//@ (+2) if(retStsRX < 6) serbuf[6] =
PIND; //@ (+10) }else{ if( (i = (UsbwV1 & 0x07)) && (retStsTX < 7) ) {
//@ UsbwL1 = UsbwV0; dest = &SerTXbuff +
retStsTX; src = &UsbwI0; retStsTX += i; do *dest++ = *src++;
while(--i); //@ i-- } if(retStsRX >= 7) { retStsRX -= 6; dest = &SerRXbuff; src =
&SerRXbuff+6; lc: i = 9; do *dest++ = *src++;
while(--i); }else{ retStsRX = 0; } } } if( (usslvsts & (1<<6))
&& (retStsRX < 15) ) { *(&SerRXbuff + (retStsRX++)) =
ussrxd; usslvsts &= ~(1<<6); } if(retStsTX && !(usslvsts &
(1<<7)) ) { usstxd = SerTXbuff; usslvsts |= (1<<7); --retStsTX; dest = &SerTXbuff; src =
&SerTXbuff+1; goto lc; } UsbRetSts = ((retStsTX << 4) &
0xFF) | retStsRX; //@@ (-10) } //void ussint() { if(USISR & (1<<USIOIF)) { //
counter over flow DDRB &= ~(1<<PB5); //USISR = 0; USISR |= (1<<USIOIF); } if(USISR & (1<<USISIF)) { //
start condition if(USISR & (1<<USIPF)) {
// stop condition :: data received ussrxd = USIDR; usslvsts |= (1<<6); }else{ if(PORTB & (1<<4))
DDRB |= (1<<PB5); if(USIDR & (1<<1)) { uchar tmp; tmp = (PIND & 0x23); //
(+10) if(PIND & 0x40) tmp |=
(1<<2); // (+4) tmp |= usslvsts; tmp ^= 0xC0; USIDR = tmp; }else{ USIDR = usstxd; usslvsts &=
~(1<<7); } } USISR = (1<<USIOIF) |
(1<<USIPF) | 0; USISR |= (1<<USISIF); } } #endif } } |