SX Microcontroller based Keyboard IO

California Dreamin SX USB Keyboard Demo

by Michael Hetherington

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	0ドルA		;bit transmit/receive counter in buffers		
temp		equ	0ドルB		;register to hold function specific values
					;holds current value of rb
usb_mask	equ	0ドルC		;masking different buffers on reset and address
					;change
packet_rx	equ	0ドルD		;packet mask while Rx
packet_tx	equ	0ドルD		;packet mask while Tx
reset_timer	equ	0ドルD		;monitor the time out for the bus
					;to detect reset conditions for Rx
tx_timer	equ	0ドルE		;the number of bits to send
					;it is loaded with the value of
					;usb_ep0_counter or usb_ep1_counter
usb_flags	equ	0ドルF		;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	1ドルA
usb_bit_count	equ	1ドルB
usb_ep0_counter	equ	1ドルC		;the number of bits to send on EP0 IN packet 
usb_ep1_counter	equ	1ドルD		;the number of bits to send on EP1 IN packet
usb_crc5	equ	1ドルF
usb_crc16_hi	equ	1ドルF
usb_crc16_lo	equ	1ドルE
		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-0ドルA)		 ;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-0ドルF)		 ;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-0ドルA)		 ;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-0ドルF)		;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	0ドルF
		
		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	0ドルA				;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,ドル2ドルC,10,ドル1ドルC,2ドルC,13,ドル04,ドル15,ドル08,ドル11,ドル17,ドル16,ドル28,ドル28ドル
			;All the leaves are brown and the sky is gray
		retw	04,ドル0ドルF,0ドルF,2ドルC,17,ドル0ドルB,08,ドル2ドルC,0ドルF,08,ドル04,ドル19,ドル08,ドル16,ドル2ドルC
		retw	04,ドル15,ドル08,ドル2ドルC,05,ドル15,ドル12,ドル1ドルA,11,ドル2ドルC,04,ドル11,ドル07,ドル2ドルC
		retw	17,ドル0ドルB,08,ドル2ドルC,16,ドル0ドルE,1ドルC,2ドルC,0ドルC,16,ドル2ドルC,0ドルA,15,ドル04,ドル1ドルC,28ドル
			;I've been for a walk on a winter's day
		retw	0ドルC,34,ドル19,ドル08,ドル2ドルC,05,ドル08,ドル08,ドル11,ドル2ドルC,09,ドル12,ドル15,ドル2ドルC,04,ドル2ドルC,1ドルA,04,ドル0ドルF,0ドルE,2ドルC
		retw	12,ドル11,ドル2ドルC,04,ドル2ドルC,1ドルA,0ドルC,11,ドル17,ドル08,ドル15,ドル34,ドル16,ドル2ドルC,07,ドル04,ドル1ドルC,28ドル
			;I'd be safe and warm if I was in L.A.
		retw	0ドルC,34,ドル07,ドル2ドルC,05,ドル08,ドル2ドルC,16,ドル04,ドル09,ドル08,ドル2ドルC,04,ドル11,ドル07,ドル2ドルC
		retw	1ドルA,04,ドル15,ドル10,ドル2ドルC,0ドルC,09,ドル2ドルC,0ドルC,2ドルC,1ドルA,04,ドル16,ドル2ドルC
		retw	0ドルC,11,ドル2ドルC,0ドルF,37,ドル04,ドル37,ドル28ドル
			;California dreamin' on such a winter's day
		retw	06,ドル04,ドル0ドルF,0ドルC,09,ドル12,ドル15,ドル11,ドル0ドルC,04,ドル2ドルC,07,ドル15,ドル08,ドル04,ドル10,ドル0ドルC,11,ドル34,ドル2ドルC
		retw	12,ドル11,ドル2ドルC,16,ドル18,ドル06,ドル0ドルB,2ドルC,04,ドル2ドルC,1ドルA,0ドルC,11,ドル17,ドル08,ドル15,ドル34,ドル16,ドル2ドルC
		retw	07,ドル04,ドル1ドルC,28ドル
				
Hello_e		=	$

Questions:


file: /Techref/scenix/lib/io/dev/keys/usbdemo-mh.htm, 38KB, , updated: 2005年3月25日 18:07, local time: 2025年9月2日 01:49, owner: MDH-pacific-468,
40.74.122.252:LOG IN

©2025 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?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://techref.massmind.org/techref/scenix/lib/io/dev/keys/usbdemo-mh.htm"> SX Keyboard IO - California Dreamin SX USB Keyboard Demo</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here:
if you want a response, please enter your email address:
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?

Welcome to massmind.org!

Welcome to techref.massmind.org!

.

AltStyle によって変換されたページ (->オリジナル) /