📄 usb_to_serial.asm
字号:
pop A ;
reti ;
;****************************************************************
; ISR: Ep1_Isr
;****************************************************************
; The EndPoint1 interrupt is used to handle IN transfers
; when data is to be passed to the host from the device
;****************************************************************
Ep1_Isr:
push A
di ; Enable Interrupts for RX.
; If ACKD is not set, ignore this interrupt.
iord EP1_MODE ;
and A, ACKD ;
jz Ep1_Isr_Done ;
;----------------------------------------------------------------
mov A, NAK_IN ; Clear ACKD
iowr EP1_MODE ;
iord EP1_COUNT ; Toggle Data toggle
xor A, DATA_TOGGLE ;
iowr EP1_COUNT ;
mov A, TRUE ; load_ep1 = TRUE
mov [load_ep1], A ;
;----------------------------------------------------------------
Ep1_Isr_Done:
pop A ;
reti ;
;****************************************************************
; ISR: Ep2_Isr
;****************************************************************
; The Endpoint 2 Interrupt Service Routine (Ep2_Isr) is used to
; handle OUT transfers when data is to be passed from host to
; device.
;****************************************************************
Ep2_Isr:
push A ;
ei ;
; If last packet wasn't ACK'd, exit.
iord EP2_MODE ;
and A, ACKD ;
jz Ep2_Isr_Done ;
;----------------------------------------------------------------
Ep2_Isr_Process:
mov A, NAK_OUT ; Clear ACKD
iowr EP2_MODE ;
mov A, [output_count] ;
and A, OUTPUT_COUNT ;
mov [tx_byte_count], A ;
;----------------------------------------------------------------
; If serial port has not been configured,
; ignore tx_byte_count, DTR and RTS
; controls.
mov A, [serial_configured] ;
and A, TRUE ;
jz Enable_Ack ;
;----------------------------------------------------------------
; Update DTR based on request from host.
Control_Dtr:
mov A, [output_report + 0] ;
and A, OUTPUT_DTR ;
jz Control_Dtr_Low ;
mov A, ~DTR ;
and [output_port_shadow], A ;
jmp Control_Rts ;
Control_Dtr_Low:
mov A, DTR ;
or [output_port_shadow], A ;
;----------------------------------------------------------------
; Update RTS based on request from host.
Control_Rts:
mov A, [output_report + 0] ;
and A, OUTPUT_RTS ;
jz Control_Rts_Low ;
mov A, ~RTS ;
and [output_port_shadow], A ;
mov A, ((~RTS) & RTS) ;
jmp Write_Output ;
Control_Rts_Low:
mov A, RTS ;
or [output_port_shadow], A ;
mov A, RTS ;
Write_Output:
mov [rts_shadow], A ;
mov A, [output_port_shadow] ;
iowr OUTPUT_PORT ;
;----------------------------------------------------------------
; If tx_byte_count is not 0, set tx_pending.
mov A, [tx_byte_count] ;
cmp A, 00h ;
jz Enable_Ack ;
mov A, TRUE ;
mov [tx_pending], A ;
jmp Ep2_Isr_Done ;
;----------------------------------------------------------------
; If tx_pending is FALSE, set EP2_MODE
; to ACK_OUT.
Enable_Ack:
mov A, [tx_pending] ;
cmp A, TRUE ;
jz Ep2_Isr_Done ;
mov A, ACK_OUT ;
iowr EP2_MODE ;
;----------------------------------------------------------------
; Restore environment and exit ISR.
Ep2_Isr_Done:
pop A ;
reti ;
;****************************************************************
; FUNCTION: Main
;****************************************************************
; The Main routine handles serial communication with the device.
; It times all recieves and transmit and calls on all the proper
; subroutines to handle certain events.
;****************************************************************
Main:
IFDEF 0
; DEBUG: Load control report with 9600 baud 8/N/1
mov A, 00h ;
mov [control_report + 0], A ;
mov A, C2h ;
mov [control_report + 1], A ;
mov A, 00h ;
mov [control_report + 2], A ;
mov A, 00h ;
mov [control_report + 3], A ;
mov A, 03h ;
mov [control_report + 4], A ;
mov A, 00h ;
mov [output_report + 0], A ;
mov A, 0Ah ;
mov [output_report + 1], A ;
mov A, 30h ;
mov [output_report + 2], A ;
mov A, 31h ;
mov [output_report + 3], A ;
mov A, 32h ;
mov [output_report + 4], A ;
mov A, 33h ;
mov [output_report + 5], A ;
mov A, 34h ;
mov [output_report + 6], A ;
mov A, 35h ;
mov [output_report + 7], A ;
mov A, 36h ;
mov [output_report + 8], A ;
mov A, 37h ;
mov [output_report + 9], A ;
mov A, 38h ;
mov [output_report + 10], A ;
mov A, 39h ;
mov [output_report + 11], A ;
call Setup_Serial ;
call Ep2_Isr_Process ;
mov A, TRUE ;
mov [tx_pending], A ;
ENDIF
;----------------------------------------------------------------
Main_Loop:
mov A, [load_ep1] ; If load_ep1 flag,
cmp A, TRUE ;
jnz Check_Setup_Flag ;
call Load_Ep1_Fifo ; Load_Ep1
;----------------------------------------------------------------
Check_Setup_Flag:
mov A, [setup_serial] ; If setup_serial flag,
cmp A, TRUE ;
jnz Check_Tx_Pending ;
call Setup_Serial ; Setup_Serial
;----------------------------------------------------------------
Check_Tx_Pending:
mov A, [tx_pending] ; If tx_pending flag,
cmp A, TRUE ;
jnz Idle ;
call Tx_Data ; Tx_Data
;----------------------------------------------------------------
Idle:
iowr WDT ;
jmp Main_Loop ;
INCLUDE "SERIAL.ASM"
;****************************************************************
; ISR: Ep0_Isr
;****************************************************************
; The EndPoint0 interrupt is used for control transfers.
; The enumeration process will take place here.
;****************************************************************
Ep0_Isr:
push A ;
iord EP0_MODE ; Save the EP0 mode register
mov [ep0_mode_shadow], A ;
and A, ACKD ;
jz Ep0_Isr_Done ;
;----------------------------------------------------------------
.start:
mov A, [ep0_mode_shadow] ; If a setup was received
and A, SETUP_RXD ;
jz .out ;
call Ep0_Setup ; handle it
jmp .exit ; and exit
;----------------------------------------------------------------
.out:
mov A, [ep0_mode_shadow] ; If an OUT was received
and A, OUT_RXD ;
jz .in ;
call Ep0_Out ; handle it
jmp .exit ; and exit
;----------------------------------------------------------------
.in:
mov A, [ep0_mode_shadow] ; If an IN was received
and A, IN_RXD ;
jz .exit ;
call Ep0_In ; handle it
;----------------------------------------------------------------
; As long as there is no setup pending,
; write the next mode.
.exit:
iord EP0_MODE ;
and A, SETUP_RXD ;
jnz Ep0_Isr_Done ;
;
mov A, [ep0_next_mode] ;
iowr EP0_MODE ;
;----------------------------------------------------------------
Ep0_Isr_Done: ;
pop A ;
reti ;
;****************************************************************
; Ep0_Setup handles the case when the packet is a setup packet.
; It checks whether the data valid bit is set, that the count is
; 10, and that the data toggle is 0
;****************************************************************
Ep0_Setup:
mov A, NAK_IN_OUT ;
iowr EP0_MODE ;
iord EP0_COUNT ;
and A, DATA_VALID ; is the data valid bit set
jz Stall_In_Out ; if not then stall
iord EP0_COUNT ;
and A, CNT_MSK ;
cmp A, 0Ah ; is the count 10
jnz Stall_In_Out ; if not then stall
iord EP0_COUNT ;
and A, DATA_TOGGLE ; is the data toggle bit 0
jnz Stall_In_Out ; if not then stall
call Stage_One ; process the setup packet
ret ;
;****************************************************************
; Ep0_Out handles an out transaction. This occurs in the data
; stage of a control write or in the status phase of a control
; read.
;****************************************************************
Ep0_Out:
mov A, [ep0_next_mode] ;
and A, MODE ;
cmp A, ACK_OUT_STATUS_IN ;
jnz Stall_In_Out ;
; mov A, [ep0_mode_shadow] ;
; and A, MODE ;
; cmp A, NAK_OUT_STATUS_IN ;
; jnz Stall_In_Out ;
mov A, TRUE ;
mov [setup_serial], A ;
mov X, SIZEOF_CONTROL_REPORT ;
Fill_Config_Buffer: ;
mov A, [X + (ep0_fifo -1)] ;
mov [X + (control_report - 1)], A ;
dec X ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -