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