Used in the EXCELLENT Atapchi: World's Smallest Low-speed USB Analyzer
;California dreamin' (aka SX USB Virtual Peripheral) Version 1.00 ;Copyright (C) 2001 Michael Hetherington ;chinook@pacific.net.sg ; ;This program is free software; you can redistribute it and/or ;modify it under the terms of the GNU General Public License ;as published by the Free Software Foundation. ;This program is distributed in the hope that it will be useful, ;but WITHOUT ANY WARRANTY; without even the implied warranty of ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;GNU General Public License for more details. ;SX28AC enumerates as generic USB keyboard and types the lyrics of "California dreamin'" ;on every press of led toggling key (Caps Lock, Scroll Lock and Num Lock). ;Works perfectly with Windows 2000 PC and any text editor. ;It has not been tested on Macs or Unix platform yet. ;Power can be driven from USB port, however independent 5V source is recommended. ;The following design does not meet all USB requirements ;and provides just an example of simple interface to USB using Scenix MCU and widely ;available components: ;bus driver 74LCX125 ;Resonator - 50 MHz (Murata) ;Environment - SX Key DEVICE SX28L,oscxtmax,turbo,stackx_optionx RESET Start rx_lo equ 1 ; D+ USB line rx_hi equ 2 ; D- USB line pulled by 1.5K to 3.3V comp equ 3 ; comparator output tx_lo equ 4 ; drive D+ tx_hi equ 5 ; drive D- oe equ 6 ; line driver output enable (inverted) usb_port equ rb usb_port_tris equ %10001110 rx_lo_pin equ rb.1 ; respective IC pins rx_hi_pin equ rb.2 comp_pin equ rb.3 tx_lo_pin equ rb.4 tx_hi_pin equ rb.5 oe_pin equ rb.6 ;********************************************************************************** ; Buffer break-down ; Starting address $03 ; We have 8 buffers to store data ;********************************************************************************** address_lo equ $30 sync_bit equ 7 ; to keep synchronized (10001000100....) ep1_in equ 6 ; to keep respective token packets ep0_in equ 5 ; to give ACK, NACK or STALL ep0_out equ 4 setup equ 3 all_data equ 2 ; all incoming data ep1_data equ 1 ; buffer of 14 bytes to keep IN data ep0_data equ 0 ; buffer of 14 bytes to keep IN data and OUT data ;********************************************************************************** ; Token packets buffers are underutilised ; Use upper address for handshake packets ; Starting address $09 ;********************************************************************************** address_hi equ $90 ack equ 6 nack equ 5 stall equ 4 ;********************************************************************************** ; For USB interface execution of interrupt will be done ; every 20-25 cycles to catch the start of a packet. ; Once the packet arrived 1,5 MHz acquisition rate should be maintained. ; With 50MHz resonator it means interrupt executes every 33 cycles 3 times and ; every 34 cycles 1 time, this cycle will be called leap cycle (after leap year) ;********************************************************************************** int_idle equ 25 int_active equ 33 int_leap equ 34 usb_states equ $08 ;main body state machine int_states equ $09 ;interrupt state machine buffer_count equ $0A ;bit transmit/receive counter in buffers temp equ $0B ;register to hold function specific values ;holds current value of rb usb_mask equ $0C ;masking different buffers on reset and address ;change packet_rx equ $0D ;packet mask while Rx packet_tx equ $0D ;packet mask while Tx reset_timer equ $0D ;monitor the time out for the bus ;to detect reset conditions for Rx tx_timer equ $0E ;the number of bits to send ;it is loaded with the value of ;usb_ep0_counter or usb_ep1_counter usb_flags equ $0F ;general flags flg_setup equ usb_flags.0 ;setup packet was received flg_out equ usb_flags.1 ;out packet was received flg_ep0_send equ usb_flags.2 ;data is ready for transmission from ep0 flg_ep0_in equ usb_flags.3 ;in packet for ep0 is received flg_ep1_send equ usb_flags.4 ;data is ready for transmission from ep1 flg_ep1_in equ usb_flags.5 ;in packet for ep1 is received flg_ep0_data equ usb_flags.6 ;data 0/1 toggle for ep0 flg_ep1_data equ usb_flags.7 ;data 0/1 toggle for ep1 org $10 USB_BANK = $ usb_hold equ $10 ;the same memory cell usb_ep0_byte equ $11 ;keeps temporary variables usb_sub_states equ $12 ;substates of main state machine usb_ep0_table_s equ $13 ;ep0 tx table start usb_ep0_table_e equ $14 ;ep0 tx table end usb_ep1_table_s equ $15 ;ep1 tx table start usb_ep1_table_e equ $16 ;ep1 tx table end usb_buffer equ $17 usb_address equ $18 usb_temp equ $19 usb_bit_stuff equ $1A usb_bit_count equ $1B usb_ep0_counter equ $1C ;the number of bits to send on EP0 IN packet usb_ep1_counter equ $1D ;the number of bits to send on EP1 IN packet usb_crc5 equ $1F usb_crc16_hi equ $1F usb_crc16_lo equ $1E org 0 Interrupt mov temp,rb mov w,int_states add PC,w IDLE_loc = $ ;*********************************************************************************** ; IDLE STATE ; D- stays high ; D+ stays low ;*********************************************************************************** sb temp.rx_hi ;catch the start of a packet: jmp IDLE_x ;when D- falls clr reset_timer ;if D- stays high clear timer mov w,#-int_idle retiw IDLE_x inc reset_timer ;monitor the line for reset condition snz jmp BUS_RESET_loc sb usb_port.comp ;if the output of comp falls ;which means D+ went up, the start of the jmp BUS_SYNC_loc ;packet is detected mov w,#-int_idle ;get ready to receive retiw BUS_RESET_loc ;*********************************************************************************** ; BUS RESET STATE ; Single ended 0 is detected for the period of 8uS ;*********************************************************************************** Bus_reset bank USB_BANK clr usb_address ;naturally, address is 0 now mov usb_states,#(USB_RESET_loc-USB_RESET_loc) mov int_states,#(IDLE_loc - IDLE_loc) clr reset_timer ;leave interrupt in idle state mov w,#-int_idle ;update the usb buffer contents retiw ;in the main body BUS_SYNC_loc = $ ;*********************************************************************************** ; BUS SYNCHRONIZATION STATE ; We have to synchronize SX clock with coming data based on sync pattern ; D- lo hi lo hi lo hi lo lo ; D+ hi lo hi lo hi lo hi hi ; This state is over when we catch the start of D- lo ;*********************************************************************************** mov packet_rx,#$01 ; mov int_states,#(RECEIVE_SYNC_loc-IDLE_loc) mov fsr,#address_lo clrb ind.all_data ;seed with 0 all data buffer clrb ind.ep0_data ;seed with 0 endpoint data buffer mov fsr,#address_hi :loop1 snb comp_pin ;while output of comp is low, do not care jmp :loop2 ;once it is high, start searching for low jmp :loop1 :loop2 sb comp_pin ;catch low of comp_pin jmp BUS_SYNC_x jmp :loop2 BUS_SYNC_x mov RTCC,#($FF-$28) ;IMPORTANT! reti ;to keep synchronized the value ;in RTCC should be aroud: ;$FF - #int_active - (3 to 10) cycles RECEIVE_SYNC_loc = $ ;*********************************************************************************** ; RECEIVE SYCHRONIZATION STATE ; OK the clock is synchronized but we are in the middle of sync pattern ; to get the first data bit lets look for two consecutive low's of D- ;*********************************************************************************** inc packet_rx ;once we have two low's snb temp.comp ;it is the last bit of SYNC clr packet_rx mov w,#(RECEIVE_loc-IDLE_loc) snb flg_setup ;if the prevoius packet was setup ;receive data mov w,#(RECEIVE_SETUP_loc - IDLE_loc) snb packet_rx.1 mov int_states,w snb packet_rx.1 clr packet_rx mov buffer_count,#$30 ;always start with the firts byte ;in the buffer mov w,#-int_active retiw RECEIVE_loc = $ ;*********************************************************************************** ; RECEIVE PACKET STATE ; The most time hungry state ; Receive and store all packets, check what packet arrived ;*********************************************************************************** mov fsr,buffer_count ;load fsr with the buffer address snb temp.comp jmp :high :low mov w,#%00000100 ;record received packet xor ind,w snb ind.all_data ;is one of token packets mov w,#$FF xor w,ind or packet_rx,w inc fsr ;save the state of rb setb fsr.4 ;for the future clrb ind.all_data mov buffer_count,fsr mov w,#-int_active snb ind.sync_bit mov w,#-int_leap retiw :high sb temp.rx_hi jmp EOP_loc clr w snb ind.all_data mov w,#$FF xor w,ind or packet_rx,w inc fsr ;save the state of rb setb fsr.4 setb ind.all_data mov buffer_count,fsr mov w,#-int_active snb ind.sync_bit mov w,#-int_leap retiw RECEIVE_SETUP_loc = $ ;*********************************************************************************** ; RECEIVE SETUP STATE ; Setup packet data, actually there is no need to check what type of packet arrived ; but we are going to do it anyway just in case one more setup packet arrives ; EP0 IN buffer is used for OUT as well ;*********************************************************************************** mov fsr,buffer_count ;load fsr with the buffer address snb temp.comp jmp :high :low mov w,#%00000001 ;record received packet xor ind,w snb ind.ep0_data ;is one of token packets mov w,#$FF xor w,ind or packet_rx,w inc fsr ;save the state of rb setb fsr.4 ;for the future clrb ind.ep0_data mov buffer_count,fsr mov w,#-int_active snb ind.sync_bit mov w,#-int_leap retiw :high sb temp.rx_hi jmp EOP_loc clr w snb ind.ep0_data mov w,#$FF xor w,ind or packet_rx,w inc fsr ;save the state of rb setb fsr.4 setb ind.ep0_data mov buffer_count,fsr mov w,#-int_active snb ind.sync_bit mov w,#-int_leap retiw EOP_loc = $ ;*********************************************************************************** ; END OF PACKET STATE ;*********************************************************************************** ;check packets first bank USB_BANK sb packet_rx.setup jmp :setup ;setup packet arrived sb packet_rx.ep0_out jmp :Endpoint0_out ;endpoint 0 out packet arrived sb packet_rx.ep1_in jmp :Endpoint1_in sb packet_rx.ep0_in jmp :Endpoint0_in ;no packets identified, check previous packet snb flg_setup jmp :ack_setup ; ACK setup snb flg_out jmp :ack_out ; ACK out snb flg_ep0_in jmp :release_ep0 snb flg_ep1_in jmp :release_ep1 :no_reply mov w,#(IDLE_loc-IDLE_loc) ;If we can not identify the packet mov int_states,w ;keep cool, do not reply mov rtcc,#($FF-$0A) ;return to interrupt as fast reti ;as possible :setup setb flg_setup mov w,#(IDLE_loc-IDLE_loc) mov int_states,w mov rtcc,#($FF-$0F) ;return to interrupt as fast reti ;as possible :Endpoint0_out setb flg_out mov w,#(IDLE_loc-IDLE_loc) mov int_states,w mov rtcc,#($FF-$0A) ;return to interrupt as fast reti ;as possible :Endpoint1_in sb flg_ep1_send ;anything to send? jmp :nack ;if not NACK setb flg_ep1_in ;set IN packet flag on mov w,#(TRANSMIT_loc-IDLE_loc) mov int_states,w mov packet_tx,#%11111101 ;set transmit mask clrb usb_port.oe ;enable output mov buffer_count,#$30 mov tx_timer,usb_ep1_counter mov rtcc,#($FF-$21) ;wait about 1 bit before transmit reti :Endpoint0_in sb flg_ep0_send ;anything to send? jmp :nack ;if not, NACK setb flg_ep0_in ;set IN packet flag on mov w,#(TRANSMIT_loc-IDLE_loc) mov int_states,w mov packet_tx,#%11111110 ;set transmit mask clrb usb_port.oe ;enable output mov buffer_count,#$30 mov tx_timer,usb_ep0_counter mov rtcc,#($FF-$21) ;wait about 1 bit before transmit reti :ack_setup clrb flg_setup mov w,#(USB_SETUP_loc - USB_RESET_loc) mov usb_states,w jmp :ack :ack_out clrb flg_out ;that's where have to check what jmp :ack ;out packet data packet is about ;in our case it would be just ;some configuration settings so ;so ACK them and skip without a second ;thought :release_ep0 clrb flg_ep0_send ;that's where we have to check properly clrb flg_ep0_in ;if ACK from the host is received jmp :no_reply ;but lets just skip it :release_ep1 clrb flg_ep1_send clrb flg_ep1_in jmp :no_reply :nack mov w,#(TRANSMIT_loc-IDLE_loc) mov int_states,w mov buffer_count,#$78 mov packet_tx,#%11011111 mov tx_timer,#$10 ;NACK is only 16 bit long mov rtcc,#($FF-$21) ;wait about 1 bit before transmit reti :ack mov w,#(TRANSMIT_loc-IDLE_loc) mov int_states,w mov buffer_count,#$78 mov packet_tx,#%10111111 mov tx_timer,#$10 ;ACK is only 16 bit long mov rtcc,#($FF-$42) ;wait about 2 bit before transmit reti TRANSMIT_loc = $ ;*********************************************************************************** ; TRANSMIT STATE ;*********************************************************************************** clrb usb_port.oe ;enable output mov fsr,buffer_count mov w,/packet_tx and w,ind sz jmp :dont_toggle_bus xor usb_port,#%00110000 ;tx_lo equ 4 ;tx_hi equ 5 :dont_toggle_bus mov w,#(EOP_TRANSMIT_loc-IDLE_loc) dec tx_timer snz mov int_states,w inc buffer_count setb buffer_count.4 mov w,#-int_active snb ind.sync_bit mov w,#-int_leap retiw EOP_TRANSMIT_loc = $ ;*********************************************************************************** ; EOP TRANSMIT STATE ;*********************************************************************************** clrb usb_port.tx_hi ;hold SE0 for 2 bits clrb usb_port.tx_lo ;it is one of the traps ;once eop is > 3 bits ;host will not accept the mov w,#(END_TRANSMIT_loc-IDLE_loc) ;packet snb tx_timer.0 mov int_states,w inc tx_timer mov w,#-int_active retiw END_TRANSMIT_loc setb usb_port.tx_hi mov w,#(IDLE_loc - IDLE_loc) mov int_states,w setb usb_port.oe ;disable output mov rtcc,#($FF-$0F) ;return to interrupt as fast as reti ;possible ;*********************************************************************************** ; TOKEN ; The macro calls supporting function Token to fill in ; token buffers based on the current usb_address ;*********************************************************************************** TOKEN MACRO 3 mov usb_mask,#\1 ;set the buffer mov usb_temp,#\2 ;set the value of PID mov usb_hold,#\3 ;hold the endpoint number call Set_token ENDM ;*********************************************************************************** ; HANDSHAKE ; To fill respective USB buffers with handshake packets ;*********************************************************************************** HANDSHAKE MACRO 2 ;********************************************************************************** ; PID ;********************************************************************************** mov usb_mask,#\1 mov usb_hold,#\2 call Set_handshake ENDM ;********************************************************************************** ; Start ;********************************************************************************** Start mov ra,#%0000 mov rc,#%00000000 mov !ra,#%11111110 ;all input mov !rc,#%11111111 ;all input mov !rb,#usb_port_tris clrb usb_port.tx_lo setb usb_port.tx_hi setb usb_port.oe mode $08 mov !rb,#$00 ;enable comparator mode $0F clr fsr ;reset all ram banks :zero_ram sb fsr.4 ;are we on low half of bank? setb fsr.3 ;If so, don't touch regs 0-7 clr ind ;clear using indirect addressing incsz fsr ;repeat until done jmp :zero_ram mov fsr,#$30 ;seed the bit stream :bit_stream setb fsr.4 setb ind.sync_bit add fsr,#4 sc jmp :bit_stream bank USB_BANK mov usb_states,#(USB_INTERRUPT_loc - USB_RESET_loc) mov int_states,#(BUS_RESET_loc - IDLE_loc) mov !OPTION,#%10001000 ;Enable RTCC rollover interrupt ;RTCC inc on clock cycle, no prescaler jmp @Main org $200 ;********************************************************************************** ; MAIN ; state machine ; 1. RESET - initialise all buffers ; 2. SETUP packet received - get ready to process it ; 3. INTERRUPT transfer ;********************************************************************************** Main mov w,usb_states add PC,w USB_RESET_loc = $ jmp _USB_RESET USB_SETUP_loc = $ jmp _USB_SETUP USB_INTERRUPT_loc = $ jmp _USB_INTERRUPT ;********************************************************************************** ; CONTROL ; state machine ;********************************************************************************** USB_CONTROL_loc = $ bank USB_BANK mov w,usb_sub_states add PC,w REQUEST_loc = $ jmp _REQUEST STANDARD_Req_loc = $ jmp _STANDARD_Req ADDRESSED_loc = $ jmp _ADDRESSED DESCRIPTOR_loc = $ jmp _DESCRIPTOR LOAD_loc = $ jmp _LOAD CLASS_Req_loc = $ jmp _CLASS ;********************************************************************************** ; SUPPORTING FUNCTIONS ; Jump tabel ;********************************************************************************** Bit_push jmp _Bit_push Bit_pull jmp _Bit_pull Crc5_calculate jmp _Crc5_calculate Crc16_calculate jmp _Crc16_calculate Set_token jmp _Set_token Set_handshake jmp _Set_handshake Load_ep0_0 jmp _Load_ep0_0 Load_ep0 jmp @_Load_ep0 Load_ep1 jmp @_Load_ep1 ;********************************************************************************** _USB_RESET ;Based on the current usb_address ;fill in: TOKEN %10111111,%01101001,%00000001 ;Endpoint 1 IN packet TOKEN %11011111,%01101001,%00000000 ;Endpoint 0 IN packet TOKEN %11101111,%11100001,%00000000 ;Endpoint 0 OUT packet TOKEN %11110111,%00101101,%00000000 ;SETUP packet HANDSHAKE %10111111,%11010010 ;ACK HANDSHAKE %11011111,%01011010 ;NACK ;HANDSHAKE %11101111,%00011110 ;STALL mov usb_states,#(USB_INTERRUPT_loc - USB_RESET_loc) jmp Main _USB_SETUP mov usb_states,#(USB_CONTROL_loc - USB_RESET_loc) mov usb_sub_states,#(REQUEST_loc - REQUEST_loc) jmp Main _REQUEST mov usb_buffer,#$38 ;skip PID mov usb_bit_stuff,#$06 ;set bit stuffing mov usb_mask,#%11111110 ;ep0_in buffer mov usb_bit_count,#$08 ;always one byte setb flg_ep0_data ;after setup ep0 responds with DATA 1 call Bit_pull mov w,#(STANDARD_Req_loc - REQUEST_loc) snb usb_temp.5 ;if bit 5 = 0 - standard request ;if bit 5 = 1 - class request mov w,#(CLASS_Req_loc - REQUEST_loc) mov usb_sub_states,w jmp Main _STANDARD_Req mov usb_bit_count,#$08 call Bit_pull cje usb_temp,#$05,:set_address cje usb_temp,#$06,:get_descriptor ;all other requests would be acknowledged call Load_ep0_0 mov usb_states,#(USB_INTERRUPT_loc - USB_RESET_loc) jmp Main :set_address mov usb_bit_count,#$08 ;get the new USB address call Bit_pull mov usb_address,usb_temp ;save the new address call Load_ep0_0 mov usb_sub_states,#(ADDRESSED_loc - REQUEST_loc) jmp Main :get_descriptor mov usb_sub_states,#(DESCRIPTOR_loc - REQUEST_loc) jmp Main _ADDRESSED mov w,#(USB_RESET_loc - USB_RESET_loc) sb flg_ep0_send ;once the status stage is over ;update all buffers with new address ;token and handshake packets mov usb_states,w jmp Main _DESCRIPTOR mov usb_bit_count,#$08 ;as descriptor number is in the 4th byte call Bit_pull ;we have to skip one byte mov usb_bit_count,#$08 call Bit_pull ;standard cje usb_temp,#$01,:device cje usb_temp,#$02,:configuration ;class specific cje usb_temp,#$22,:report ;other descriptors are not supported call Load_ep0_0 mov usb_states,#(USB_INTERRUPT_loc - USB_RESET_loc) jmp Main :device mov usb_ep0_table_s,#(Device_ds - EP0_table_s) mov usb_ep0_table_e,#(Device_de - EP0_table_s) mov usb_sub_states,#(LOAD_loc - REQUEST_loc) jmp Main :configuration mov usb_bit_count,#$08 ;skip one byte call Bit_pull mov usb_bit_count,#$08 ;skip one more byte call Bit_pull mov usb_bit_count,#$08 ;as descriptor size is in the 7th byte call Bit_pull cje usb_temp,#$09,:basic ;if the given size is only 9 byte, ;load basic descriptor ;otherwise load full :full mov usb_ep0_table_s,#(Config_ds - EP0_table_s) mov usb_ep0_table_e,#(Endpoint_de - EP0_table_s) mov usb_sub_states,#(LOAD_loc - REQUEST_loc) jmp Main :basic mov usb_ep0_table_s,#(Config_ds - EP0_table_s) mov usb_ep0_table_e,#(Config_de - EP0_table_s) mov usb_sub_states,#(LOAD_loc - REQUEST_loc) jmp Main :report mov usb_ep0_table_s,#(Report_ds - EP0_table_s) mov usb_ep0_table_e,#(Report_de - EP0_table_s) mov usb_sub_states,#(LOAD_loc - REQUEST_loc) jmp Main _LOAD call Load_ep0 cjb usb_ep0_table_s,usb_ep0_table_e,Main mov usb_states,#(USB_INTERRUPT_loc - USB_RESET_loc) jmp Main _CLASS = $ mov usb_bit_count,#$08 call Bit_pull cjne usb_temp,#$09,:nothing ;if it is set_report request ;send the song mov usb_ep1_table_s,#(Hello_s - EP1_table_s) mov usb_ep1_table_e,#(Hello_e - EP1_table_s) :nothing call Load_ep0_0 ;class requests are not supported ;just acknowledged mov usb_states,#(USB_INTERRUPT_loc - USB_RESET_loc) jmp Main _USB_INTERRUPT = $ call Load_ep1 jmp Main ;********************************************************************************** ; Bit_push ; Supporting function to store data in endpoint 0 and endpoint 1 buffers ; for transmission to host (buffer mask is %11111110 and %11111101) ; usb_temp is the source of data ; usb_bit_count is the number of bits to store (8 for data, 7 for address, etc) ; usb_buffer is the address from which to start ; Bit stuffing is provided ;********************************************************************************** _Bit_push sb usb_mask.0 inc usb_ep0_counter sb usb_mask.1 inc usb_ep1_counter test usb_bit_stuff sz jmp :bit_push_resume sb usb_mask.0 inc usb_ep0_counter ;one more bit sb usb_mask.1 inc usb_ep1_counter mov usb_bit_stuff,#$06 mov w,usb_mask mov fsr,usb_buffer and ind,w bank USB_BANK inc usb_buffer setb usb_buffer.4 :bit_push_resume rr usb_temp sc jmp :zero_bit :one_bit dec usb_bit_stuff mov fsr,usb_buffer mov w,/usb_mask or ind,w jmp Bit_push_x :zero_bit mov usb_bit_stuff,#$06 mov fsr,usb_buffer mov w,usb_mask and ind,w Bit_push_x bank USB_BANK inc usb_buffer setb usb_buffer.4 decsz usb_bit_count jmp _Bit_push retp ;********************************************************************************** ; Bit_pull ; Retrieve data from receive buffer (buffer mask %11111110). ; Due to our device configuration only endpoint 0 supports OUT ; packets. This function gets rid of bit stuffing and returns in ; usb_temp the number of bits specified in usb_bit_count ; usb_buffer is the address of the first bit to start with. ;********************************************************************************** _Bit_pull test usb_bit_stuff sz jmp :bit_pull_resume mov usb_bit_stuff,#$06 inc usb_buffer setb usb_buffer.4 :bit_pull_resume mov fsr,usb_buffer mov w,/usb_mask and w,ind bank USB_BANK snz jmp :zero_bit :one_bit dec usb_bit_stuff stc rr usb_temp jmp Bit_pull_x :zero_bit mov usb_bit_stuff,#$06 clc rr usb_temp Bit_pull_x inc usb_buffer setb usb_buffer.4 decsz usb_bit_count jmp _Bit_pull retp ;********************************************************************************** ; Crc5_calculate, the MSb is in usb_crc5.0 ;********************************************************************************** _Crc5_calculate clc rr usb_crc5 mov w,#%00010100 snb usb_temp.0 jmp :one_bit :zero_bit snc xor usb_crc5,w jmp Crc5_calculate_x :one_bit sc xor usb_crc5,w Crc5_calculate_x rr usb_temp decsz usb_bit_count jmp _Crc5_calculate retp ;********************************************************************************** ; Crc16_calculate, the MSb is in usb_crc16_lo.0 ;********************************************************************************** _Crc16_calculate clc rr usb_crc16_hi rr usb_crc16_lo mov w,#%10100000 snb usb_temp.0 jmp :one_bit :zero_bit snc xor usb_crc16_hi,w mov w,#%00000001 snc xor usb_crc16_lo,w jmp Crc16_calculate_x :one_bit sc xor usb_crc16_hi,w mov w,#%00000001 sc xor usb_crc16_lo,w Crc16_calculate_x rr usb_temp decsz usb_bit_count jmp _Crc16_calculate retp ;********************************************************************************** ; Set_token ;********************************************************************************** _Set_token mov usb_buffer,#address_lo ;all token buffers start at address_lo mov usb_bit_stuff,#$06 ;initialise bit stuffing mov usb_bit_count,#$08 ;PID is always 8-bit long mov usb_crc5,#%00011111 ;seed crc5 with all 1's call Bit_push ;********************************************************************************** ; Address ; as it belongs to the data field, calculate crc ;********************************************************************************** mov usb_temp,usb_address mov usb_bit_count,#$07 ;address is only 7-bit long call Crc5_calculate ;start calculating Crc5 mov usb_temp,usb_address mov usb_bit_count,#$07 call Bit_push ;fill in the buffer ;********************************************************************************** ; Endpoint ;********************************************************************************** mov usb_temp,usb_hold ;set the endpoint number mov usb_bit_count,#$04 ;the number is 4-bit long call Crc5_calculate mov usb_temp,usb_hold mov usb_bit_count,#$04 call Bit_push ;********************************************************************************** ; Crc5 ;********************************************************************************** xor usb_crc5,#$FF ;invert CRC5 mov usb_temp,usb_crc5 mov usb_bit_count,#$05 call Bit_push mov fsr,usb_buffer mov w,/usb_mask ;why don't we add 1's or ind,w ;in case EOP is detected late inc fsr setb fsr.4 or ind,w bank USB_BANK retp ;********************************************************************************** ; Set_handshake ;********************************************************************************** _Set_handshake ;********************************************************************************** ; Synchronization ;********************************************************************************** mov usb_buffer,#$78 ;the actual handshake starts from ;address_hi, however we save sync pattern ;starting $78, because we need to send ;handshakes too mov usb_bit_stuff,#$06 ;nobody needs it for handshake, too small mov usb_temp,#%10000000 ;sync mov usb_bit_count,#$08 call Bit_push mov usb_bit_count,#$08 ;always 8 mov usb_temp,usb_hold ;********************************************************************************** ; Pid ;********************************************************************************** call Bit_push mov fsr,usb_buffer mov w,/usb_mask ;why don't we add 1's or ind,w ;in case EOP is detected late inc fsr setb fsr.4 or ind,w bank USB_BANK retp ;********************************************************************************** ; Load_ep0_0 ; load IN buffer for endpoint 0 with 0 bytes of data ;********************************************************************************** _Load_ep0_0 mov usb_buffer,#address_lo ;the actual handshake starts from mov usb_bit_stuff,#$06 mov usb_mask,#%11111110 mov usb_temp,#%10000000 ;sync mov usb_bit_count,#$08 clr usb_ep0_counter call Bit_push mov usb_bit_count,#$08 mov usb_temp,#%01001011 ;always DATA1 pid call Bit_push mov usb_bit_count,#$08 mov usb_temp,#%00000000 ;crc16 inverted call Bit_push mov usb_bit_count,#$08 mov usb_temp,#%00000000 ;crc16 inverted call Bit_push setb flg_ep0_send ;there is something to send retp org $500 ;********************************************************************************** ; Load_ep0 ; load IN buffer for endpoint 0 with data from the table ; starting address usb_ep0_table_s ;********************************************************************************** _Load_ep0 ;********************************************************************************** ; Synchronization ; is first ;********************************************************************************** cjae usb_ep0_table_s,usb_ep0_table_e,_Load_ep0_x snb flg_ep0_send jmp _Load_ep0_x ;do not load anything if send flag ;is set or there is nothing to send mov usb_ep0_byte,#$09 ;set the number of bytes counter mov usb_buffer,#address_lo mov usb_bit_stuff,#$06 mov usb_bit_count,#$08 ;always 8 mov usb_crc16_hi,#$FF ;seed crc16 registers mov usb_crc16_lo,#$FF mov usb_temp,#%10000000 ;start with sync mov usb_mask,#%11111110 ;set to IN endpoint 0 buffer clr usb_ep0_counter call @Bit_push ;********************************************************************************** ; Pid ; Data 0/1 ;********************************************************************************** mov w,#%11000011 snb flg_EP0_data mov w,#%01001011 mov usb_temp,w xor usb_flags,#%01000000 ;toggle DATA 1/0 mov usb_bit_count,#$08 call @Bit_push ;DATA 1/0 ;********************************************************************************** ; 8 or less bytes ; of real data ;********************************************************************************** :data cjae usb_ep0_table_s,usb_ep0_table_e,:crc16 dec usb_ep0_byte snz jmp :crc16 mov w,usb_ep0_table_s call EP0_table mov usb_temp,w mov usb_bit_count,#$08 call @Crc16_calculate mov w,usb_ep0_table_s call EP0_table mov usb_temp,w mov usb_bit_count,#$08 call @Bit_push inc usb_ep0_table_s jmp :data ;********************************************************************************** ; 2 bytes ; of CRC ;********************************************************************************** :crc16 mov usb_temp,usb_crc16_lo xor usb_temp,#$FF mov usb_bit_count,#$08 call @Bit_push mov usb_temp,usb_crc16_hi xor usb_temp,#$FF mov usb_bit_count,#$08 call @Bit_push setb flg_ep0_send ;set flag for sending retp _Load_ep0_x retp org $700 ;********************************************************************************** ; Load_ep1 ; load IN buffer for endpoint 0 with data from the table ; starting address usb_ep1_table_s ;********************************************************************************** _Load_ep1 ;********************************************************************************** ; Synchronization ; is first ;********************************************************************************** snb flg_ep1_send jmp _Load_ep1_x ;do not load anything if send flag ;is set or there is nothing to send mov usb_buffer,#address_lo mov usb_bit_stuff,#$06 mov usb_bit_count,#$08 ;always 8 mov usb_crc16_hi,#$FF ;seed crc16 registers mov usb_crc16_lo,#$FF mov usb_temp,#%10000000 ;start with sync mov usb_mask,#%11111101 ;set usb_mask to IN endpoint 1 buffer clr usb_ep1_counter call @Bit_push ;********************************************************************************** ; Pid ; Data 0/1 ;********************************************************************************** clr usb_hold mov usb_temp,#%11000011 sb flg_EP1_data jmp :data0 :data1 ;for data 1 packet send make code cjae usb_ep1_table_s,usb_ep1_table_e,_Load_ep1_x mov w,usb_ep1_table_s call EP1_table mov usb_hold,w inc usb_ep1_table_s mov usb_temp,#%01001011 :data0 ;for data 0 packet send break code mov usb_bit_count,#$08 xor usb_flags,#%10000000 ;toggle DATA 1/0 call @Bit_push ;DATA 1/0 ;********************************************************************************** ; Always 8 bytes ; of real data ;********************************************************************************** DATABYTE MACRO clr usb_temp mov usb_bit_count,#$08 call @Crc16_calculate clr usb_temp mov usb_bit_count,#$08 call @Bit_push ENDM DATABYTE ;byte 0 - $00 DATABYTE ;byte 1 - $00 mov usb_temp,usb_hold ;byte 2 - $00 for DATA 0 mov usb_bit_count,#$08 ; value from EP1_table call @Crc16_calculate ; for DATA 1 mov usb_temp,usb_hold mov usb_bit_count,#$08 call @Bit_push DATABYTE ;byte 3 - $00 DATABYTE ;byte 4 - $00 DATABYTE ;byte 5 - $00 DATABYTE ;byte 6 - $00 DATABYTE ;byte 7 - $00 ;********************************************************************************** ; 2 bytes ; of CRC ;********************************************************************************** :crc16 mov usb_temp,usb_crc16_lo xor usb_temp,#$FF mov usb_bit_count,#$08 call @Bit_push mov usb_temp,usb_crc16_hi xor usb_temp,#$FF mov usb_bit_count,#$08 call @Bit_push setb flg_ep1_send ;set flag for sending retp _Load_ep1_x retp org $400 EP0_table jmp PC+w EP0_table_s = $ retw $80 retw $06 retw $00 retw $01 retw $00 retw $00 retw $40 retw $00 Device_ds = $ retw (Device_de - Device_ds) ;length retw $01 ;type retw $00,$01 ;USB specifications 1.0 retw $00 ;class code retw $00 ;subclass code retw $00 ;protocol retw $08 ;max.packet size retw $88,88 ;vendor ID retw $02,00 ;product ID retw $01,00 ;device release number retw $00 ;manufacturer string descriptor index retw $00 ;product string descriptor index retw $00 ;serial number string descriptor retw $01 ;number of possible configurations Device_de = $ Config_ds = $ retw (Config_de - Config_ds) ;length retw $02 ;type retw (Endpoint_de - Config_ds),$00 ;total data length retw $01 ;interface supported retw $01 ;configuration value retw $00 ;string descriptor index retw $A0 ;configuration retw $32 ;maximum power consumption Config_de = $ Inter_ds = $ retw (Inter_de - Inter_ds) ;length retw $04 ;type retw $00 ;number of interfaces retw $00 ;alternate settings retw $01 ;number of endpoints retw $03 ;class code retw $01 ;subclass code retw $01 ;protocol code retw $00 ;string index Inter_de = $ Class_ds = $ retw (Class_de - Class_ds) ;length retw $21 ;type retw $00,$01 ;HID class release number retw $00 ;country code retw $01 ;number of HID descriptors to follow retw $22 ;report descriptor type retw (Report_de - Report_ds),$00 ;total length of report descriptor Class_de = $ Endpoint_ds = $ retw (Endpoint_de - Endpoint_ds) ;length retw $05 ;type retw $81 ;encoded address (IN to endpoint 1) retw $03 ;endpoint attribute retw $08,$00 ;max. packet size retw $0A ;polling interval Endpoint_de = $ ;********************************************************************************** ; Generic USB keyboard report, as give at page 70 of ; Device Class Definition for Human Interface Devices (HID) ;********************************************************************************** Report_ds = $ retw $05,$01 ;generic desktop retw $09,$06 ;keyboard retw $A1,$01 ;collection (application) retw $05,$07 ;key codes retw $19,$E0 ;usage minimum retw $29,$E7 ;usage maximum retw $15,$00 ;logical minimum retw $25,$00 ;logical maximum retw $75,$01 ;report size retw $95,$08 ;report count (8 bytes) retw $81,$02 ;input (data, variable, absolute) retw $95,$01 ;report count retw $75,$08 ;report size retw $81,$01 ;input (constant) retw $95,$05 ;report count retw $75,$01 ;report size retw $05,$08 ;leds retw $19,$01 ;usage minimum retw $29,$05 ;usage maximum retw $91,$02 ;output (data, variable, absolute) retw $95,$03 ;report count retw $75,$01 ;report size retw $91,$01 ;output (constant) retw $95,$06 ;report count retw $75,$08 ;report size retw $15,$00 ;logical minimum retw $25,$65 ;logical maximum retw $05,$07 ;key codes retw $19,$00 ;usage minimum retw $29,$65 ;usage maximum retw $81,00 ;input retw $C0 ;end collection Report_de = $ org $600 EP1_table jmp PC+w EP1_table_s = $ Hello_s = $ retw $28 ;To my parents retw $17,$12,$2C,$10,$1C,$2C,$13,$04,$15,$08,$11,$17,$16,$28,$28 ;All the leaves are brown and the sky is gray retw $04,$0F,$0F,$2C,$17,$0B,$08,$2C,$0F,$08,$04,$19,$08,$16,$2C retw $04,$15,$08,$2C,$05,$15,$12,$1A,$11,$2C,$04,$11,$07,$2C retw $17,$0B,$08,$2C,$16,$0E,$1C,$2C,$0C,$16,$2C,$0A,$15,$04,$1C,$28 ;I've been for a walk on a winter's day retw $0C,$34,$19,$08,$2C,$05,$08,$08,$11,$2C,$09,$12,$15,$2C,$04,$2C,$1A,$04,$0F,$0E,$2C retw $12,$11,$2C,$04,$2C,$1A,$0C,$11,$17,$08,$15,$34,$16,$2C,$07,$04,$1C,$28 ;I'd be safe and warm if I was in L.A. retw $0C,$34,$07,$2C,$05,$08,$2C,$16,$04,$09,$08,$2C,$04,$11,$07,$2C retw $1A,$04,$15,$10,$2C,$0C,$09,$2C,$0C,$2C,$1A,$04,$16,$2C retw $0C,$11,$2C,$0F,$37,$04,$37,$28 ;California dreamin' on such a winter's day retw $06,$04,$0F,$0C,$09,$12,$15,$11,$0C,$04,$2C,$07,$15,$08,$04,$10,$0C,$11,$34,$2C retw $12,$11,$2C,$16,$18,$06,$0B,$2C,$04,$2C,$1A,$0C,$11,$17,$08,$15,$34,$16,$2C retw $07,$04,$1C,$28 Hello_e = $
Questions:
I've been reading about the atapchi USB analyser.James Newton replies: The author would be the person to contact. I'm not aware of a kit being available.+
Can I buy one from someone ?
Anyone know if there are any for sale
I have no idea what it would cost but I am willing to pay a reasonable price
file: /Techref/scenix/lib/io/dev/keys/usbdemo-mh.htm, 38KB, , updated: 2005/3/25 17:07, local time: 2024/11/20 01:34,
owner: MDH-pacific-468,
3.14.134.31:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://linistepper.com/Techref/scenix/lib/io/dev/keys/usbdemo-mh.htm"> SX Keyboard IO - California Dreamin SX USB Keyboard Demo</A> |
Did you find what you needed? |