| ; usbduxfast_firmware.asm |
| ; Copyright (C) 2004,2009 Bernd Porr, Bernd.Porr@f2s.com |
| ; |
| ; 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; either version 2 of the License, or |
| ; (at your option) any later version. |
| ; |
| ; 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. |
| ; |
| ; You should have received a copy of the GNU General Public License |
| ; along with this program; if not, write to the Free Software |
| ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| ; |
| ; |
| ; Firmware: usbduxfast_firmware.asm for usbdux.c |
| ; Description: Firmware for usbduxfast |
| ; Devices: [ITL] USB-DUX (usbdux.o) |
| ; Author: Bernd Porr <Bernd.Porr@f2s.com> |
| ; Updated: 17 Apr 2009 |
| ; Status: stable |
| ; |
| ;;; |
| ;;; |
| ;;; |
| |
| .inc fx2-include.asm |
| |
| .equ WFLOADED,70H ; waveform is loaded |
| |
| .org 0000h ; after reset the processor starts here |
| ljmp main ; jump to the main loop |
| |
| .org 0043h ; the IRQ2-vector |
| ljmp jmptbl ; irq service-routine |
| |
| .org 0100h ; start of the jump table |
| |
| jmptbl: ljmp sudav_isr |
| nop |
| ljmp sof_isr |
| nop |
| ljmp sutok_isr |
| nop |
| ljmp suspend_isr |
| nop |
| ljmp usbreset_isr |
| nop |
| ljmp hispeed_isr |
| nop |
| ljmp ep0ack_isr |
| nop |
| ljmp spare_isr |
| nop |
| ljmp ep0in_isr |
| nop |
| ljmp ep0out_isr |
| nop |
| ljmp ep1in_isr |
| nop |
| ljmp ep1out_isr |
| nop |
| ljmp ep2_isr |
| nop |
| ljmp ep4_isr |
| nop |
| ljmp ep6_isr |
| nop |
| ljmp ep8_isr |
| nop |
| ljmp ibn_isr |
| nop |
| ljmp spare_isr |
| nop |
| ljmp ep0ping_isr |
| nop |
| ljmp ep1ping_isr |
| nop |
| ljmp ep2ping_isr |
| nop |
| ljmp ep4ping_isr |
| nop |
| ljmp ep6ping_isr |
| nop |
| ljmp ep8ping_isr |
| nop |
| ljmp errlimit_isr |
| nop |
| ljmp spare_isr |
| nop |
| ljmp spare_isr |
| nop |
| ljmp spare_isr |
| nop |
| ljmp ep2isoerr_isr |
| nop |
| ljmp ep4isoerr_isr |
| nop |
| ljmp ep6isoerr_isr |
| nop |
| ljmp ep8isoerr_isr |
| |
| |
| ;; dummy isr |
| sof_isr: |
| sudav_isr: |
| sutok_isr: |
| suspend_isr: |
| usbreset_isr: |
| hispeed_isr: |
| ep0ack_isr: |
| spare_isr: |
| ep0in_isr: |
| ep0out_isr: |
| ep1out_isr: |
| ep1in_isr: |
| ibn_isr: |
| ep0ping_isr: |
| ep1ping_isr: |
| ep2ping_isr: |
| ep4ping_isr: |
| ep6ping_isr: |
| ep8ping_isr: |
| errlimit_isr: |
| ep2isoerr_isr: |
| ep4isoerr_isr: |
| ep6isoerr_isr: |
| ep8isoerr_isr: |
| ep6_isr: |
| ep2_isr: |
| ep8_isr: |
| |
| push dps |
| push dpl |
| push dph |
| push dpl1 |
| push dph1 |
| push acc |
| push psw |
| |
| ;; clear the USB2 irq bit and return |
| mov a,EXIF |
| clr acc.4 |
| mov EXIF,a |
| |
| pop psw |
| pop acc |
| pop dph1 |
| pop dpl1 |
| pop dph |
| pop dpl |
| pop dps |
| |
| reti |
| |
| |
| ;;; main program |
| ;;; basically only initialises the processor and |
| ;;; then engages in an endless loop |
| main: |
| mov dptr,#REVCTL |
| mov a,#00000011b ; allows skip |
| lcall syncdelaywr |
| |
| mov DPTR,#CPUCS ; CPU control register |
| mov a,#00010000b ; 48Mhz |
| lcall syncdelaywr |
| |
| mov dptr,#IFCONFIG ; switch on IFCLK signal |
| mov a,#10100010b ; gpif, 30MHz |
| lcall syncdelaywr |
| |
| mov dptr,#FIFORESET |
| mov a,#80h |
| lcall syncdelaywr |
| mov a,#8 |
| lcall syncdelaywr |
| mov a,#2 |
| lcall syncdelaywr |
| mov a,#4 |
| lcall syncdelaywr |
| mov a,#6 |
| lcall syncdelaywr |
| mov a,#0 |
| lcall syncdelaywr |
| |
| mov dptr,#INTSETUP ; IRQ setup register |
| mov a,#08h ; enable autovector |
| lcall syncdelaywr |
| |
| lcall initeps ; init the isochronous data-transfer |
| |
| lcall initGPIF |
| |
| ;;; main loop |
| |
| mloop2: |
| lcall gpif_run |
| sjmp mloop2 ; do nothing. The rest is done by the IRQs |
| |
| |
| gpif_run: |
| mov a,WFLOADED |
| jz no_trig ; do not trigger |
| mov a,GPIFTRIG ; GPIF status |
| anl a,#80h ; done bit |
| jz no_trig ; GPIF busy |
| |
| ;;; gpif has stopped |
| mov a,#06h ; RD,EP6 |
| mov GPIFTRIG,a |
| no_trig: |
| ret |
| |
| |
| |
| initGPIF: |
| mov DPTR,#EP6CFG ; BLK data from here to the host |
| mov a,#11100000b ; Valid, quad buffering |
| lcall syncdelaywr ; write |
| |
| mov dptr,#EP6FIFOCFG |
| mov a,#00001001b ; autoin, wordwide |
| lcall syncdelaywr |
| |
| mov dptr,#EP6AUTOINLENH |
| mov a,#00000010b ; 512 bytes |
| lcall syncdelaywr ; write |
| |
| mov dptr,#EP6AUTOINLENL |
| mov a,#00000000b ; 0 |
| lcall syncdelaywr ; write |
| |
| mov dptr,#GPIFWFSELECT |
| mov a,#11111100b ; waveform 0 for FIFO RD |
| lcall syncdelaywr |
| |
| mov dptr,#GPIFCTLCFG |
| mov a,#10000000b ; tri state for CTRL |
| lcall syncdelaywr |
| |
| mov dptr,#GPIFIDLECTL |
| mov a,#11111111b ; all CTL outputs high |
| lcall syncdelaywr |
| mov a,#11111101b ; reset counter |
| lcall syncdelaywr |
| mov a,#11111111b ; reset to high again |
| lcall syncdelaywr |
| |
| mov a,#00000010b ; abort when full |
| mov dptr,#EP6GPIFFLGSEL |
| lcall syncdelaywr |
| |
| mov a,#00000001b ; stop when buffer overfl |
| mov dptr,#EP6GPIFPDFSTOP |
| lcall syncdelaywr |
| |
| mov a,#0 |
| mov dptr,#GPIFREADYCFG |
| lcall syncdelaywr |
| |
| mov a,#0 |
| mov dptr,#GPIFIDLECS |
| lcall syncdelaywr |
| |
| ; waveform 1 |
| ; this is a dummy waveform which is used |
| ; during the upload of another waveform into |
| ; wavefrom 0 |
| ; it branches directly into the IDLE state |
| mov dptr,#0E420H |
| mov a,#00111111b ; branch to IDLE |
| lcall syncdelaywr |
| |
| mov dptr,#0E428H ; opcode |
| mov a,#00000001b ; deceision point |
| lcall syncdelaywr |
| |
| mov dptr,#0E430H |
| mov a,#0FFH ; output is high |
| lcall syncdelaywr |
| |
| mov dptr,#0E438H |
| mov a,#0FFH ; logic function |
| lcall syncdelaywr |
| |
| ; signals that no waveform 0 is loaded so far |
| mov WFLOADED,#0 ; waveform flag |
| |
| ret |
| |
| |
| |
| ;;; initilise the transfer |
| ;;; It is assumed that the USB interface is in alternate setting 1 |
| initeps: |
| mov DPTR,#EP4CFG |
| mov a,#10100000b ; valid, bulk, out |
| lcall syncdelaywr |
| |
| mov dptr,#EP4BCL ; "arm" it |
| mov a,#00h |
| lcall syncdelaywr ; wait until we can write again |
| lcall syncdelaywr ; wait |
| lcall syncdelaywr ; wait |
| |
| mov DPTR,#EP8CFG |
| mov a,#0 ; disable EP8, it overlaps with EP6!! |
| lcall syncdelaywr |
| |
| mov dptr,#EPIE ; interrupt enable |
| mov a,#00100000b ; enable irq for ep4 |
| lcall syncdelaywr ; do it |
| |
| mov dptr,#EPIRQ ; clear IRQs |
| mov a,#00100100b |
| movx @dptr,a |
| |
| mov DPTR,#USBIE ; USB int enable register |
| mov a,#0 ; SOF etc |
| movx @DPTR,a ; |
| |
| mov DPTR,#GPIFIE ; GPIF int enable register |
| mov a,#0 ; done IRQ |
| movx @DPTR,a ; |
| |
| mov EIE,#00000001b ; enable INT2 in the 8051's SFR |
| mov IE,#80h ; IE, enable all interrupts |
| |
| ret |
| |
| |
| ;;; interrupt-routine for ep4 |
| ;;; receives the channel list and other commands |
| ep4_isr: |
| push dps |
| push dpl |
| push dph |
| push dpl1 |
| push dph1 |
| push acc |
| push psw |
| push 00h ; R0 |
| push 01h ; R1 |
| push 02h ; R2 |
| push 03h ; R3 |
| push 04h ; R4 |
| push 05h ; R5 |
| push 06h ; R6 |
| push 07h ; R7 |
| |
| mov dptr,#0f400h ; FIFO buffer of EP4 |
| movx a,@dptr ; get the first byte |
| |
| mov dptr,#ep4_jmp ; jump table for the different functions |
| rl a ; multiply by 2: sizeof sjmp |
| jmp @a+dptr ; jump to the jump table |
| |
| ep4_jmp: |
| sjmp storewaveform ; a=0 |
| sjmp init_ep6 ; a=1 |
| |
| init_ep6: |
| ; stop ep6 |
| ; just now do nothing |
| |
| ljmp over_wf |
| |
| |
| storewaveform: |
| mov WFLOADED,#0 ; waveform flag |
| |
| mov dptr,#EP6FIFOCFG |
| mov a,#00000000b ; |
| lcall syncdelaywr |
| |
| mov dptr,#GPIFABORT |
| mov a,#0ffh ; abort all transfers |
| lcall syncdelaywr |
| |
| wait_f_abort: |
| mov a,GPIFTRIG ; GPIF status |
| anl a,#80h ; done bit |
| jz wait_f_abort ; GPIF busy |
| |
| mov dptr,#GPIFWFSELECT |
| mov a,#11111101b ; select dummy waveform |
| movx @dptr,a |
| lcall syncdelay |
| |
| mov dptr,#FIFORESET |
| mov a,#80h ; NAK |
| lcall syncdelaywr |
| mov a,#6 ; reset EP6 |
| lcall syncdelaywr |
| mov a,#0 ; normal op |
| lcall syncdelaywr |
| |
| ; change to dummy waveform 1 |
| mov a,#06h ; RD,EP6 |
| mov GPIFTRIG,a |
| |
| ; wait a bit |
| mov r2,255 |
| loopx: |
| djnz r2,loopx |
| |
| ; abort waveform if not already so |
| mov dptr,#GPIFABORT |
| mov a,#0ffh ; abort all transfers |
| lcall syncdelaywr |
| |
| ; wait again |
| mov r2,255 |
| loopx2: |
| djnz r2,loopx2 |
| |
| ; check for DONE |
| wait_f_abort2: |
| mov a,GPIFTRIG ; GPIF status |
| anl a,#80h ; done bit |
| jz wait_f_abort2 ; GPIF busy |
| |
| ; upload the new waveform into waveform 0 |
| mov AUTOPTRH2,#0E4H ; XDATA0H |
| lcall syncdelay |
| mov AUTOPTRL2,#00H ; XDATA0L |
| lcall syncdelay |
| |
| mov AUTOPTRH1,#0F4H ; EP4 high |
| lcall syncdelay |
| mov AUTOPTRL1,#01H ; EP4 low |
| lcall syncdelay |
| |
| mov AUTOPTRSETUP,#7 ; autoinc and enable |
| lcall syncdelay |
| |
| mov r2,#20H ; 32 bytes to transfer |
| |
| wavetr: |
| mov dptr,#XAUTODAT1 |
| movx a,@dptr |
| lcall syncdelay |
| mov dptr,#XAUTODAT2 |
| movx @dptr,a |
| lcall syncdelay |
| djnz r2,wavetr |
| |
| mov dptr,#EP6FIFOCFG |
| mov a,#00001001b ; autoin, wordwide |
| lcall syncdelaywr |
| |
| mov dptr,#GPIFWFSELECT |
| mov a,#11111100b |
| movx @dptr,a |
| lcall syncdelay |
| |
| mov dptr,#FIFORESET |
| mov a,#80h ; NAK |
| lcall syncdelaywr |
| mov a,#6 ; reset EP6 |
| lcall syncdelaywr |
| mov a,#0 ; normal op |
| lcall syncdelaywr |
| |
| mov dptr,#0E400H+10H; waveform 0: first CTL byte |
| movx a,@dptr ; get it |
| orl a,#11111011b ; force all bits to one except the range bit |
| mov dptr,#GPIFIDLECTL |
| lcall syncdelaywr |
| |
| mov WFLOADED,#1 ; waveform flag |
| |
| ; do the common things here |
| over_wf: |
| mov dptr,#EP4BCL |
| mov a,#00h |
| movx @DPTR,a ; arm it |
| lcall syncdelay ; wait |
| movx @DPTR,a ; arm it |
| lcall syncdelay ; wait |
| |
| ;; clear INT2 |
| mov a,EXIF ; FIRST clear the USB (INT2) interrupt request |
| clr acc.4 |
| mov EXIF,a ; Note: EXIF reg is not 8051 bit-addressable |
| |
| mov DPTR,#EPIRQ ; |
| mov a,#00100000b ; clear the ep4irq |
| movx @DPTR,a |
| |
| pop 07h |
| pop 06h |
| pop 05h |
| pop 04h ; R4 |
| pop 03h ; R3 |
| pop 02h ; R2 |
| pop 01h ; R1 |
| pop 00h ; R0 |
| pop psw |
| pop acc |
| pop dph1 |
| pop dpl1 |
| pop dph |
| pop dpl |
| pop dps |
| reti |
| |
| |
| ;; need to delay every time the byte counters |
| ;; for the EPs have been changed. |
| |
| syncdelay: |
| nop |
| nop |
| nop |
| nop |
| nop |
| nop |
| nop |
| nop |
| nop |
| ret |
| |
| |
| syncdelaywr: |
| lcall syncdelay |
| movx @dptr,a |
| ret |
| |
| |
| .End |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |