■ 最新版 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 での動作確認しました。Win98Win2KWinXpVISTAWindows7対応

   ・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.dip.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

 

    }

}