xwkm 发表于 2013-1-31 01:09:40

请问工程师:LGT的V-USB是如何移植的

我使用了obdev.at的V-USB进行修改。但是有个问题,就是obdev的V-USB中的底层汇编代码,指令速度有差别的我全部都加了NOP。然后IO口读出写入的我也注意到了IO同步的问题。可是现在这个20M的东西下载到MCU里就是不工作。但是12M的却工作的很好。
希望那个移植的工程师出来赐教一下。
我自己移植的代码:/* Name: usbdrvasm20.inc
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Jeroen Benschop
* Based on usbdrvasm16.inc from Christian Starkjohann
* Creation Date: 2008-03-05
* Tabsize: 4
* Copyright: (c) 2008 by Jeroen Benschop and OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* Revision: $Id: usbdrvasm20.inc 740 2009-04-13 18:23:31Z cs $
*/

/* Do not link this file! Link usbdrvasm.S instead, which includes the
* appropriate implementation!
*/

/*
General Description:
This file is the 20 MHz version of the asssembler part of the USB driver. It
requires a 20 MHz crystal (not a ceramic resonator and not a calibrated RC
oscillator).

See usbdrv.h for a description of the entire driver.

Since almost all of this code is timing critical, don't change unless you
really know what you are doing! Many parts require not only a maximum number
of CPU cycles, but even an exact number of cycles!
*/

#define leap2   x3
#ifdef __IAR_SYSTEMS_ASM__
#define nextInst    $+2
#else
#define nextInst    .+0
#endif

;max stack usage: = 12 bytes
;nominal frequency: 20 MHz -> 13.333333 cycles per bit, 106.666667 cycles per byte
; Numbers in brackets are clocks counted from center of last sync bit
; when instruction starts
;register use in receive loop:
; shift assembles the byte currently being received
; x1 holds the D+ and D- line state
; x2 holds the previous line state
; x4 (leap)is used to add a leap cycle once every three bytes received
; X3 (leap2) is used to add a leap cycle once every three stuff bits received
; bitcnt is used to determine when a stuff bit is due
; cnt holds the number of bytes left in the receive buffer

USB_INTR_VECTOR:
        sbrs        bootcot,0 //如果bootcot的0位被设置
        jmp                UNUSED1_vtr        //跳转到真正的int0(bootcot=0)
;order of registers pushed: YL, SREG YH, , bitcnt, shift, x1, x2, x3, x4, cnt
    push    YL                  ;[-28] push only what is necessary to sync with edge ASAP
    in      YL, SREG            ;[-26]
    push    YL                  ;[-25]
    push    YH                  ;[-23]
;----------------------------------------------------------------------------
; Synchronize with sync pattern:
;----------------------------------------------------------------------------
;sync byte (D-) pattern LSb to MSb: 01010100
;sync up with J to K edge during sync pattern -- use fastest possible loops
;The first part waits at most 1 bit long since we must be in sync pattern.
;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
;waitForJ, ensure that this prerequisite is met.
waitForJ:
    inc   YL
    ;sbis    USBIN, USBMINUS
    in                YL,USBIN
    sbrs        YL        ,USBMINUS
    brne    waitForJ      ; just make sure we have ANY timeout
waitForK:
;The following code results in a sampling window of < 1/4 bit which meets the spec.
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK            ;[-18]
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK
    in                YL,         USBIN
    sbrs    YL,         USBMINUS
    rjmp    foundK
#if USB_COUNT_SOF
    lds   YL, usbSofCount
    inc   YL
    sts   usbSofCount, YL
#endif/* USB_COUNT_SOF */
#ifdef USB_SOF_HOOK
    USB_SOF_HOOK
#endif
    rjmp    sofError
foundK:                         ;[-16]
;{3, 5} after falling D- edge, average delay: 4 cycles
;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample
;use 1 bit time for setup purposes, then sample again. Numbers in brackets
;are cycles from center of first sync (double K) bit after the instruction
    push    bitcnt            ;[-16]
        nop                         ;[-15]
    lds   YL, usbInputBufOffset;[-14]
        nop                         ;[-13]
    clr   YH                  ;[-12]
    subi    YL, lo8(-(usbRxBuf));[-11]
    sbci    YH, hi8(-(usbRxBuf));[-10]
    push    shift               ;[-9]
        nop                         ;[-8]
    ldi   shift,0x40          ;[-7] set msb to "1" so processing bit7 can be detected
    nop2                        ;[-6]
        nop                         ;[-5]
    ldi   bitcnt, 5         ;[-4]
    ;sbis    USBIN, USBMINUS   ;[-3] we want two bits K (sample 3 cycles too early)
        in      x1,    USBIN                        ;1
        sbrs        x1,    USBMINUS                        ;1
    rjmp    haveTwoBitsK      ;[-2]
    pop   shift               ;[-1] undo the push from before
    pop   bitcnt            ;
    nop                                                        ;
    rjmp    waitForK            ; this was not the end of sync, retry
; The entire loop from waitForK until rjmp waitForK above must not exceed two
; bit times (= 27 cycles).

;----------------------------------------------------------------------------
; push more registers and initialize values while we sample the first bits:
;----------------------------------------------------------------------------
haveTwoBitsK:
    push    x1                  ;
    nop                                                        ;
    push    x2                  ;
    nop                                                        ;
    push    x3                  ; (leap2)
    nop                                                        ;
    ldi   leap2, 0x55         ; add leap cycle on 2nd,5th,8th,... stuff bit
    push    x4                  ; == leap
    nop                                                        ;
    ldi   leap, 0x55          ; skip leap cycle on 2nd,5th,8th,... byte received
    push    cnt               ;
    nop                                                        ;
    ldi   cnt, USB_BUFSIZE    ;
    ldi   x2, 1<<USBPLUS      ; current line state is K state. D+=="1", D-=="0"
bit0:      
    in      x1, USBIN         ; sample line state
    andi    x1, USBMASK         ; filter only D+ and D- bits
    nop                                                        ;
    rjmp    handleBit         ; make bit0 14 cycles long

;----------------------------------------------------------------------------
; Process bit7. However, bit 6 still may need unstuffing.
;----------------------------------------------------------------------------

b6checkUnstuff:
    dec   bitcnt            ;
    breq    unstuff6            ;
bit7:
    subi    cnt, 1            ; cannot use dec becaus it does not affect the carry flag
    brcs    overflow            ; Too many bytes received. Ignore packet
    in      x1, USBIN         ; sample line state
    andi    x1, USBMASK         ; filter only D+ and D- bits
    cpse    x1, x2            ; when previous line state equals current line state, handle "1"
    rjmp    b7handle0         ; when line state differs, handle "0"
    sec                         ;
    ror   shift               ; shift "1" into the data
    st      y+, shift         ; store the data into the buffer
    ldi   shift, 0x40         ; reset data for receiving the next byte
    subi    leap, 0x55          ; trick to introduce a leap cycle every 3 bytes
    brcc    nextInst            ; it will fail after 85 bytes. However low speed can only receive 11
    dec   bitcnt            ;
    brne    bit0                ;
    ldi   x1, 1               ; unstuffing bit 7
    in      bitcnt, USBIN       ; sample stuff bit
    rjmp    unstuff             ;

b7handle0:
    mov   x2,x1               ; Set x2 to current line state
    ldi   bitcnt, 6         ;
    lsr   shift               ; shift "0" into the data
    st      y+, shift         ; store data into the buffer
    ldi   shift, 0x40         ; reset data for receiving the next byte
    subi    leap, 0x55          ; trick to introduce a leap cycle every 3 bytes
    brcs    bit0                ; it will fail after 85 bytes. However low speed can only receive 11
    rjmp    bit0                ;



;----------------------------------------------------------------------------
; Handle unstuff
; x1==0xFF indicate unstuffing bit6
;----------------------------------------------------------------------------

unstuff6:
    ldi   x1,0xFF             ; indicate unstuffing bit 6
    in      bitcnt, USBIN       ;sample stuff bit
    nop                         ;fix timing
unstuff:                        ;b0-5b6   b7
    mov   x2,bitcnt         ;Set x2 to match line state
    subi    leap2, 0x55         ;delay loop
    brcs    nextInst            ;add one cycle every three stuff bits
    sbci    leap2,0             ;
    ldi   bitcnt,6            ;reset bit stuff counter
    andi    x2, USBMASK         ; only keep D+ and D-
    cpi   x1,0                ;
    brmi    bit7                ; finished unstuffing bit6 When x1<0
    breq    bitloop             ; --- finished unstuffing bit0-5 when x1=0
    nop                         ;------
    in      x1, USBIN         ;------ sample line state for bit0
    andi    x1, USBMASK         ;------ filter only D+ and D- bits
    nop                                                        ;--- ---   
    rjmp    handleBit         ;------ make bit0 14 cycles long

;----------------------------------------------------------------------------
; Receiver loop (numbers in brackets are cycles within byte after instr)
;----------------------------------------------------------------------------
bitloop:
    in      x1, USBIN         ; sample line state
    andi    x1, USBMASK         ; filter only D+ and D- bits
    breq    se0               ; both lines are low so handle se0
handleBit:
    cpse    x1, x2            ; when previous line state equals current line state, handle "1"
    rjmp    handle0             ; when line state differs, handle "0"
    sec                         ;
    ror   shift               ; shift "1" into the data
    brcs    b6checkUnstuff      ; When after shift C is set, next bit is bit7
    nop2                        ;
    dec   bitcnt            ;
    brne    bitloop             ;
    ldi   x1,0                ; indicate unstuff for bit other than bit6 or bit7
    in      bitcnt, USBIN       ; sample stuff bit
    nop                                                        ;
    rjmp    unstuff             ;

handle0:
    mov   x2, x1            ; Set x2 to current line state
    ldi   bitcnt, 6         ; reset unstuff counter.
    lsr   shift               ; shift "0" into the data
    brcs    bit7                ; When after shift C is set, next bit is bit7
    nop2                         ;
    rjmp    bitloop             ;
   
;----------------------------------------------------------------------------
; End of receive loop. Now start handling EOP
;----------------------------------------------------------------------------

macro POP_STANDARD ; 14 cycles
    pop   cnt
    pop   x4
    pop   x3
    pop   x2
    pop   x1
    pop   shift
    pop   bitcnt
    endm
macro POP_RETI   ; 7 cycles
    pop   YH
    pop   YL
    out   SREG, YL
    pop   YL
    endm



#include "asmcommon.inc"

; USB spec says:
; idle = J
; J = (D+ = 0), (D- = 1)
; K = (D+ = 1), (D- = 0)
; Spec allows 7.5 bit times from EOP to SOP for replies
; 7.5 bit times is 100 cycles. This implementation arrives a bit later at se0
; then specified in the include file but there is plenty of time

bitstuffN:
    eor   x1, x4          ;
    ldi   x2, 0         ;
    nop2                  ;
    out   USBOUT, x1      ; <-- out
    nop                                                ;
    rjmp    didStuffN       ;
   
bitstuff7:
    eor   x1, x4          ;
    ldi   x2, 0         ; Carry is zero due to brcc
    rol   shift         ; compensate for ror shift at branch destination
    nop2                  ;
    nop                                                ;
    rjmp    didStuff7       ;

sendNakAndReti:
    ldi   x3, USBPID_NAK;[-18]
    nop                                                ;[-17]
    rjmp    sendX3AndReti   ;[-16]
sendAckAndReti:
    ldi   cnt, USBPID_ACK ;[-17]
sendCntAndReti:
    mov   x3, cnt         ;[-16]
sendX3AndReti:
    ldi   YL, 20          ;[-15] x3==r20 address is 20
    ldi   YH, 0         ;[-14]
    ldi   cnt, 2          ;[-13]
;   rjmp    usbSendAndReti      fallthrough

;usbSend:
;pointer to data in 'Y'
;number of bytes in 'cnt' -- including sync byte
;uses: x1...x4, btcnt, shift, cnt, Y
;Numbers in brackets are time since first bit of sync pattern is sent
;We don't match the transfer rate exactly (don't insert leap cycles every third
;byte) because the spec demands only 1.5% precision anyway.
usbSendAndReti:             ; 12 cycles until SOP
    in      x2, USBDDR      ;[-12]
    ori   x2, USBMASK   ;[-11]
    sbi   USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
    nop                                                ;[-9]
    in      x1, USBOUT      ;[-8] port mirror for tx loop
    out   USBDDR, x2      ;[-7] <- acquire bus
; need not init x2 (bitstuff history) because sync starts with 0
    ldi   x4, USBMASK   ;[-6] exor mask
    ldi   shift, 0x80   ;[-5] sync byte is first byte sent
txByteLoop:
    ldi   bitcnt, 0x49    ;[-4]       binary 01001001
txBitLoop:
    sbrs    shift, 0      ;[-3]    
    eor   x1, x4          ;[-2]    
    out   USBOUT, x1      ;[-1]       <-- out N
    ror   shift         ;   
    ror   x2            ;
didStuffN:
    nop2                  ;
    nop                     ;
    cpi   x2, 0xfc      ;
    brcc    bitstuffN       ;
    lsr   bitcnt          ;
    brcc    txBitLoop       ;
    brne    txBitLoop       ;

    sbrs    shift, 0      ;
    eor   x1, x4          ;
didStuff7:
    out   USBOUT, x1      ;[-1] <-- out 7
    ror   shift         ;
    ror   x2            ;
    nop                     ;
    cpi   x2, 0xfc      ;
    brcc    bitstuff7       ;
    ld      shift, y+       ;
    nop                                                ;
    dec   cnt             ;
    brne    txByteLoop      ;
;make SE0:
    cbr   x1, USBMASK   ; prepare SE0
    lds   x2, usbNewDeviceAddr;
    lsl   x2            ; we compare with left shifted address
    out   USBOUT, x1      ; <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
    subi    YL, 20 + 2      ; Only assign address on data packets, not ACK/NAK in x3
    sbci    YH, 0         ;
;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
;set address only after data packet was sent, not after handshake
    breq    skipAddrAssign;
    sts   usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
skipAddrAssign:
;end of usbDeviceAddress transfer
    ldi   x2, 1<<USB_INTR_PENDING_BIT; int0 occurred during TX -- clear pending flag
    USB_STORE_PENDING(x2)   ;
    ori   x1, USBIDLE   ;
    in      x2, USBDDR      ;
    cbr   x2, USBMASK   ; set both pins to input
    mov   x3, x1          ;
    cbr   x3, USBMASK   ; configure no pullup on both pins
    ldi   x4, 5         ;
se0Delay:
    dec   x4            ;
    brne    se0Delay      ;
    out   USBOUT, x1      ; <-- out J (idle) -- end of SE0 (EOP signal)
    out   USBDDR, x2      ; <-- release bus now
    out   USBOUT, x3      ; <-- ensure no pull-up resistors are active
    nop                                                ;
    rjmp    doReturn                ;

logicgreen 发表于 2013-1-31 10:20:16

因为PC的USB1.0是以1.5Mhz为同步时钟的,所以以12Mhz,24Mhz时钟去同步就是整数采样,理论没有误差累计,更稳定。

xwkm 发表于 2013-1-31 10:35:57

logicgreen 发表于 2013-1-31 10:20 static/image/common/back.gif
因为PC的USB1.0是以1.5Mhz为同步时钟的,所以以12Mhz,24Mhz时钟去同步就是整数采样,理论没有误差累计,更 ...

但是事实上V-USB 也有20M,18M的版本啊。况且24M的你们也没移植。我只好用调分频系数的方法

zyin123 发表于 2013-6-3 22:02:54

现在的版本不是直接可以修改CPU频率么?为什么要这么麻烦呢?楼主是想要传输速度提升上去么?

xwkm 发表于 2013-6-4 18:31:41

zyin123 发表于 2013-6-3 22:02 static/image/common/back.gif
现在的版本不是直接可以修改CPU频率么?为什么要这么麻烦呢?楼主是想要传输速度提升上去么? ...

你当CPU频率可以随便改吗……那都有驱动程序对应的。
现在就只有12M 16M 12.8M 20M 18M的CPU频率被支持。

zyin123 发表于 2013-6-5 18:59:58

xwkm 发表于 2013-6-4 18:31 static/image/common/back.gif
你当CPU频率可以随便改吗……那都有驱动程序对应的。
现在就只有12M 16M 12.8M 20M 18M的CPU频率被支持。 ...

是的,最大就到20M了

xwkm 发表于 2013-6-8 18:14:07

zyin123 发表于 2013-6-5 18:59 static/image/common/back.gif
是的,最大就到20M了

所以我才要移植36M和22M的。

ybx520 发表于 2013-6-8 20:37:56

发表于 2013-1-31 10:20:16 |只看该作者
因为PC的USB1.0是以1.5Mhz为同步时钟的,所以以12Mhz,24Mhz时钟去同步就是整数采样,理论没有误差累计,更稳定

有24M的版本吗?不懂汇编.

Yawgmoth 发表于 2015-1-24 14:09:16

可能还是时钟同步方面的问题 不如先查看下波形
页: [1]
查看完整版本: 请问工程师:LGT的V-USB是如何移植的