Updated usbdux firmware files. The udev hotplug mechanism
[comedilib.git] / etc / hotplug / usb / usbduxsigma / usbduxsigma_firmware.asm
1 ;   usbdux_firmware.asm
2 ;   Copyright (C) 2010,2011 Bernd Porr, Bernd.Porr@f2s.com
3 ;   For usbduxsigma.c 0.5+
4 ;
5 ;   This program is free software; you can redistribute it and/or modify
6 ;   it under the terms of the GNU General Public License as published by
7 ;   the Free Software Foundation; either version 2 of the License, or
8 ;   (at your option) any later version.
9 ;
10 ;   This program is distributed in the hope that it will be useful,
11 ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ;   GNU General Public License for more details.
14 ;
15 ;   You should have received a copy of the GNU General Public License
16 ;   along with this program; if not, write to the Free Software
17 ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 ;
19 ;
20 ; Firmware: usbduxsigma_firmware.asm for usbduxsigma.c
21 ; Description: University of Stirling USB DAQ & INCITE Technology Limited
22 ; Devices: [ITL] USB-DUX-SIGMA (usbduxsigma.ko)
23 ; Author: Bernd Porr <Bernd.Porr@f2s.com>
24 ; Updated: 24 Jul 2011
25 ; Status: testing
26 ;
27 ;;;
28 ;;;
29 ;;;
30         
31         .inc    fx2-include.asm
32
33 ;;; a couple of flags
34         .equ    CMD_FLAG,80h    ; flag for the next in transfer
35         .equ    PWMFLAG,81h     ; PWM on or off?
36         .equ    MAXSMPL,82H     ; maximum number of samples, n channellist
37         .equ    MUXSG0,83H      ; content of the MUXSG0 register
38
39 ;;; actual code
40         .org    0000h           ; after reset the processor starts here
41         ljmp    main            ; jump to the main loop
42
43         .org    0043h           ; the IRQ2-vector
44         ljmp    jmptbl          ; irq service-routine
45         
46         .org    0100h           ; start of the jump table
47
48 jmptbl: ljmp    sudav_isr
49         nop
50         ljmp    sof_isr
51         nop
52         ljmp    sutok_isr
53         nop
54         ljmp    suspend_isr
55         nop
56         ljmp    usbreset_isr
57         nop
58         ljmp    hispeed_isr
59         nop
60         ljmp    ep0ack_isr
61         nop
62         ljmp    spare_isr
63         nop
64         ljmp    ep0in_isr
65         nop
66         ljmp    ep0out_isr
67         nop
68         ljmp    ep1in_isr
69         nop
70         ljmp    ep1out_isr
71         nop
72         ljmp    ep2_isr
73         nop
74         ljmp    ep4_isr
75         nop
76         ljmp    ep6_isr
77         nop
78         ljmp    ep8_isr
79         nop
80         ljmp    ibn_isr
81         nop
82         ljmp    spare_isr
83         nop
84         ljmp    ep0ping_isr
85         nop
86         ljmp    ep1ping_isr
87         nop
88         ljmp    ep2ping_isr
89         nop
90         ljmp    ep4ping_isr
91         nop
92         ljmp    ep6ping_isr
93         nop
94         ljmp    ep8ping_isr
95         nop
96         ljmp    errlimit_isr
97         nop
98         ljmp    spare_isr
99         nop
100         ljmp    spare_isr
101         nop
102         ljmp    spare_isr
103         nop
104         ljmp    ep2isoerr_isr
105         nop
106         ljmp    ep4isoerr_isr
107         nop
108         ljmp    ep6isoerr_isr
109         nop
110         ljmp    ep8isoerr_isr
111
112         
113         ;; dummy isr
114 sudav_isr:      
115 sutok_isr:      
116 suspend_isr:    
117 usbreset_isr:   
118 hispeed_isr:    
119 ep0ack_isr:     
120 spare_isr:      
121 ep0in_isr:      
122 ep0out_isr:     
123 ep1in_isr:      
124 ibn_isr:        
125 ep0ping_isr:    
126 ep1ping_isr:    
127 ep2ping_isr:    
128 ep4ping_isr:    
129 ep6ping_isr:    
130 ep8ping_isr:    
131 errlimit_isr:   
132 ep2isoerr_isr:  
133 ep4isoerr_isr:  
134 ep6isoerr_isr:  
135 ep8isoerr_isr:
136 ep6_isr:
137 ep2_isr:
138 ep4_isr:        
139
140         push    dps
141         push    dpl
142         push    dph
143         push    dpl1
144         push    dph1
145         push    acc
146         push    psw
147
148         ;; clear the USB2 irq bit and return
149         mov     a,EXIF
150         clr     acc.4
151         mov     EXIF,a
152
153         pop     psw
154         pop     acc 
155         pop     dph1 
156         pop     dpl1
157         pop     dph 
158         pop     dpl 
159         pop     dps
160         
161         reti
162
163                 
164 ;;; main program
165 ;;; basically only initialises the processor and
166 ;;; then engages in an endless loop
167 main:
168         mov     DPTR,#CPUCS     ; CPU control register
169         mov     a,#00010000b    ; 48Mhz
170         lcall   syncdelaywr
171
172         mov     dptr,#REVCTL
173         mov     a,#00000011b    ; allows skip
174         lcall   syncdelaywr
175
176         mov     IP,#0           ; all std 8051 int have low priority
177         mov     EIP,#0FFH       ; all FX2 interrupts have high priority
178         
179         mov     dptr,#INTSETUP  ; IRQ setup register
180         mov     a,#08h          ; enable autovector
181         lcall   syncdelaywr
182
183         mov     dptr,#PORTCCFG
184         mov     a,#0
185         lcall   syncdelaywr
186
187         lcall   initAD          ; init the ports to the converters
188
189         lcall   initeps         ; init the isochronous data-transfer
190
191 ;;; main loop, rest is done as interrupts
192 mloop2: nop
193
194 ;;; pwm
195         mov     r0,#PWMFLAG     ; pwm on?
196         mov     a,@r0           ; get info
197         jz      mloop2          ; it's off
198
199         mov     a,GPIFTRIG      ; GPIF status
200         anl     a,#80h          ; done bit
201         jz      mloop2          ; GPIF still busy
202
203         mov     a,#01h          ; WR,EP4, 01 = EP4
204         mov     GPIFTRIG,a      ; restart it
205
206         sjmp    mloop2          ; loop for ever
207
208
209 ;;; initialise the ports for the AD-converter
210 initAD:
211         mov     r0,#MAXSMPL     ; length of channellist
212         mov     @r0,#0          ; we don't want to accumlate samples
213
214         mov     OEA,#11100000b  ; PortA7,A6,A5 Outputs
215         mov     IOA,#01100000b  ; /CS = 1 and START = 0
216         mov     dptr,#IFCONFIG  ; switch on clock on IFCLK pin
217         mov     a,#10100000b    ; gpif, 30MHz, internal IFCLK -> 15MHz for AD
218         lcall   syncdelaywr
219
220         mov     SCON0,#013H     ; ser rec en, TX/RX: stop, 48/12MHz=4MHz clock
221         
222         mov     dptr,#PORTECFG
223         mov     a,#00001000b    ; special function for port E: RXD0OUT
224         lcall   syncdelaywr
225
226         ret
227
228
229 ;;; send a byte via SPI
230 ;;; content in a, dptr1 is changed
231 ;;; the lookup is done in dptr1 so that the normal dptr is not affected
232 ;;; important: /cs needs to be reset to 1 by the caller: IOA.5
233 sendSPI:
234         inc     DPS
235         
236         ;; bit reverse
237         mov     dptr,#swap_lut  ; lookup table
238         movc    a,@a+dptr       ; reverse bits
239
240         ;; clear interrupt flag, is used to detect
241         ;; successful transmission
242         clr     SCON0.1         ; clear interrupt flag
243
244         ;; start transmission by writing the byte
245         ;; in the transmit buffer
246         mov     SBUF0,a         ; start transmission
247
248         ;; wait for the end of the transmission
249 sendSPIwait:
250         mov     a,SCON0         ; get transmission status
251         jnb     ACC.1,sendSPIwait       ; loop until transmitted
252
253         inc     DPS
254         
255         ret
256
257
258
259         
260 ;;; receive a byte via SPI
261 ;;; content in a, dptr is changed
262 ;;; the lookup is done in dptr1 so that the normal dptr is not affected
263 ;;; important: the /CS needs to be set to 1 by the caller via "setb IOA.5"
264 recSPI:
265         inc     DPS
266         
267         clr     IOA.5           ; /cs to 0      
268
269         ;; clearning the RI bit starts reception of data
270         clr     SCON0.0
271
272 recSPIwait:
273         ;; RI goes back to 1 after the reception of the 8 bits
274         mov     a,SCON0         ; get receive status
275         jnb     ACC.0,recSPIwait; loop until all bits received
276
277         ;; read the byte from the buffer
278         mov     a,SBUF0         ; get byte
279         
280         ;; lookup: reverse the bits
281         mov     dptr,#swap_lut  ; lookup table
282         movc    a,@a+dptr       ; reverse the bits
283
284         inc     DPS
285         
286         ret
287
288
289
290         
291 ;;; reads a register
292 ;;; register address in a
293 ;;; returns value in a
294 registerRead:
295         anl     a,#00001111b    ; mask out the index to the register
296         orl     a,#01000000b    ; 010xxxxx indicates register read
297         clr     IOA.5           ; ADC /cs to 0
298         lcall   sendSPI         ; send the command over
299         lcall   recSPI          ; read the contents back
300         setb    IOA.5           ; ADC /cs to 1
301         ret
302
303
304
305 ;;; writes to a register
306 ;;; register address in a
307 ;;; value in r0
308 registerWrite:
309         push    acc
310         anl     a,#00001111b    ; mask out the index to the register
311         orl     a,#01100000b    ; 011xxxxx indicates register write
312
313         clr     IOA.5           ; ADC /cs to 0  
314
315         lcall   sendSPI         ;
316         mov     a,r0
317         lcall   sendSPI
318
319         setb    IOA.5           ; ADC /cs to 1
320         pop     acc
321
322         lcall   registerRead    ; check if the data has arrived in the ADC
323         mov     0f0h,r0         ; register B
324         cjne    a,0f0h,registerWrite ; something went wrong, try again
325         
326         ret
327
328
329
330 ;;; initilise the endpoints
331 initeps:
332         mov     dptr,#FIFORESET
333         mov     a,#80H          
334         movx    @dptr,a         ; reset all fifos
335         mov     a,#2    
336         movx    @dptr,a         ; 
337         mov     a,#4            
338         movx    @dptr,a         ; 
339         mov     a,#6            
340         movx    @dptr,a         ; 
341         mov     a,#8            
342         movx    @dptr,a         ; 
343         mov     a,#0            
344         movx    @dptr,a         ; normal operat
345         
346         mov     DPTR,#EP2CFG
347         mov     a,#10010010b    ; valid, out, double buff, iso
348         movx    @DPTR,a
349
350         mov     dptr,#EP2FIFOCFG
351         mov     a,#00000000b    ; manual
352         movx    @dptr,a
353
354         mov     dptr,#EP2BCL    ; "arm" it
355         mov     a,#00h
356         movx    @DPTR,a         ; can receive data
357         lcall   syncdelay       ; wait to sync
358         movx    @DPTR,a         ; can receive data
359         lcall   syncdelay       ; wait to sync
360         movx    @DPTR,a         ; can receive data
361         lcall   syncdelay       ; wait to sync
362         
363         mov     DPTR,#EP1OUTCFG
364         mov     a,#10100000b    ; valid
365         movx    @dptr,a
366
367         mov     dptr,#EP1OUTBC  ; "arm" it
368         mov     a,#00h
369         movx    @DPTR,a         ; can receive data
370         lcall   syncdelay       ; wait until we can write again
371         movx    @dptr,a         ; make shure its really empty
372         lcall   syncdelay       ; wait
373
374         mov     DPTR,#EP6CFG    ; ISO data from here to the host
375         mov     a,#11010010b    ; Valid
376         movx    @DPTR,a         ; ISO transfer, double buffering
377
378         mov     DPTR,#EP8CFG    ; EP8
379         mov     a,#11100000b    ; BULK data from here to the host
380         movx    @DPTR,a         ;
381
382         ;; enable interrupts
383         mov     dptr,#EPIE      ; interrupt enable
384         mov     a,#10001000b    ; enable irq for ep1out,8
385         movx    @dptr,a         ; do it
386
387         mov     dptr,#EPIRQ     ; clear IRQs
388         mov     a,#10001000b
389         movx    @dptr,a
390         
391         mov     DPTR,#USBIE     ; USB int enables register
392         mov     a,#2            ; enables SOF (1ms/125us interrupt)
393         movx    @DPTR,a         ; 
394
395         mov     EIE,#00000001b  ; enable INT2/USBINT in the 8051's SFR
396         mov     IE,#80h         ; IE, enable all interrupts
397
398         ret
399
400
401 ;;; Reads one ADC channel from the converter and stores
402 ;;; the result at dptr
403 readADCch:
404         ;; we do polling: we wait until DATA READY is zero
405         mov     a,IOA           ; get /DRDY
406         jb      ACC.0,readADCch ; wait until data ready (DRDY=0)
407         
408         ;; reading data is done by just dropping /CS and start reading and
409         ;; while keeping the IN signal to the ADC inactive
410         clr     IOA.5           ; /cs to 0
411         
412         ;; 1st byte: STATUS
413         lcall   recSPI          ; index
414         movx    @dptr,a         ; store the byte
415         inc     dptr            ; increment pointer
416
417         ;; 2nd byte: MSB
418         lcall   recSPI          ; data
419         movx    @dptr,a
420         inc     dptr
421
422         ;; 3rd byte: MSB-1
423         lcall   recSPI          ; data
424         movx    @dptr,a
425         inc     dptr
426
427         ;; 4th byte: LSB
428         lcall   recSPI          ; data
429         movx    @dptr,a
430         inc     dptr
431         
432         ;; got all bytes
433         setb    IOA.5           ; /cs to 1
434         
435         ret
436
437         
438
439 ;;; interrupt-routine for SOF
440 sof_isr:
441         push    dps
442         push    dpl
443         push    dph
444         push    dpl1
445         push    dph1
446         push    acc
447         push    psw
448         push    00h             ; R0
449         push    01h             ; R1
450         push    02h             ; R2
451         push    03h             ; R3
452         push    04h             ; R4
453         push    05h             ; R5
454         push    06h             ; R6
455         push    07h             ; R7
456
457         clr     IE.7            ; make sure that no other int's disturbe us
458         
459         mov     a,EP2468STAT
460         anl     a,#20H          ; full?
461         jnz     epfull          ; EP6-buffer is full
462
463         clr     IOA.7           ; stop converter, START = 0
464
465         ;; make sure that we are starting with the first channel
466         mov     r0,#MUXSG0      ;
467         mov     a,@r0           ; get config of MUXSG0
468         mov     r0,a
469         mov     a,#04H          ; MUXSG0
470         lcall   registerWrite   ; this resets the channel sequence
471
472         setb    IOA.7           ; start converter, START = 1
473         
474         ;; get the data from the ADC as fast as possible and transfer it
475         ;; to the EP buffer
476         mov     dptr,#0f800h    ; EP6 buffer
477         mov     a,IOD           ; get DIO D
478         movx    @dptr,a         ; store it
479         inc     dptr            ; next byte
480         mov     a,IOC           ; get DIO C
481         movx    @dptr,a         ; store it
482         inc     dptr            ; next byte
483         mov     a,IOB           ; get DIO B
484         movx    @dptr,a         ; store it
485         inc     dptr            ; next byte
486         mov     a,#0            ; just zero
487         movx    @dptr,a         ; pad it up
488         inc     dptr            ; algin along a 32 bit word
489
490         mov     r0,#MAXSMPL     ; number of samples to transmit
491         mov     a,@r0           ; get them
492         mov     r1,a            ; counter
493
494         ;; main loop, get all the data
495 eptrans:        
496         lcall   readADCch       ; get one reading
497         djnz    r1,eptrans      ; do until we have all content transf'd
498
499         clr     IOA.7           ; stop converter, START = 0
500
501         ;; arm the endpoint and send off the data
502         mov     DPTR,#EP6BCH    ; byte count H
503         mov     a,#0            ; is zero
504         lcall   syncdelaywr     ; wait until we can write again
505         
506         mov     r0,#MAXSMPL     ; number of samples to transmit
507         mov     a,@r0           ; get them
508         rl      a               ; a=a*2
509         rl      a               ; a=a*2
510         add     a,#4            ; four bytes for DIO
511         mov     DPTR,#EP6BCL    ; byte count L
512         lcall   syncdelaywr     ; wait until we can write again
513
514 epfull:
515         ;; do the D/A conversion
516         mov     a,EP2468STAT
517         anl     a,#01H          ; empty
518         jnz     epempty         ; nothing to get
519
520         mov     dptr,#0F000H    ; EP2 fifo buffer
521         lcall   dalo            ; conversion
522
523         mov     dptr,#EP2BCL    ; "arm" it
524         mov     a,#00h
525         lcall   syncdelaywr     ; wait for the rec to sync
526         lcall   syncdelaywr     ; wait for the rec to sync
527
528 epempty:        
529         ;; clear INT2
530         mov     a,EXIF          ; FIRST clear the USB (INT2) interrupt request
531         clr     acc.4
532         mov     EXIF,a          ; Note: EXIF reg is not 8051 bit-addressable
533         
534         mov     DPTR,#USBIRQ    ; points to the SOF
535         mov     a,#2            ; clear the SOF
536         movx    @DPTR,a
537
538 nosof:
539         setb    IE.7            ; re-enable global interrupts
540         
541         pop     07h
542         pop     06h
543         pop     05h
544         pop     04h             ; R4
545         pop     03h             ; R3
546         pop     02h             ; R2
547         pop     01h             ; R1
548         pop     00h             ; R0
549         pop     psw
550         pop     acc 
551         pop     dph1 
552         pop     dpl1
553         pop     dph 
554         pop     dpl 
555         pop     dps
556         reti
557
558
559 reset_ep8:
560         ;; erase all data in ep8
561         mov     dptr,#FIFORESET
562         mov     a,#80H          ; NAK
563         lcall   syncdelaywr
564         mov     dptr,#FIFORESET
565         mov     a,#8            ; reset EP8
566         lcall   syncdelaywr
567         mov     dptr,#FIFORESET
568         mov     a,#0            ; normal operation
569         lcall   syncdelaywr
570         ret
571
572
573 reset_ep6:
574         ;; throw out old data
575         mov     dptr,#FIFORESET
576         mov     a,#80H          ; NAK
577         lcall   syncdelaywr
578         mov     dptr,#FIFORESET
579         mov     a,#6            ; reset EP6
580         lcall   syncdelaywr
581         mov     dptr,#FIFORESET
582         mov     a,#0            ; normal operation
583         lcall   syncdelaywr
584         ret
585
586
587 ;;; configure the ADC converter
588 ;;; the dptr points to the init data:
589 ;;; CONFIG 0,1,3,4,5,6
590 ;;; note that CONFIG2 is omitted
591 configADC:      
592         clr     IOA.7           ; stops ADC: START line of ADC = L
593         setb    IOA.5           ; ADC /cs to 1
594
595         ;; just in case something has gone wrong
596         nop
597         nop
598         nop
599
600         mov     a,#11000000b    ; reset the ADC
601         clr     IOA.5           ; ADC /cs to 0  
602         lcall   sendSPI
603         setb    IOA.5           ; ADC /cs to 1  
604
605         movx    a,@dptr         ;
606         inc     dptr
607         mov     r0,a
608         mov     a,#00H          ; CONFIG0
609         lcall   registerWrite
610
611         movx    a,@dptr         ;
612         inc     dptr
613         mov     r0,a
614         mov     a,#01H          ; CONFIG1
615         lcall   registerWrite
616
617         movx    a,@dptr         ;
618         inc     dptr
619         mov     r0,a
620         mov     a,#03H          ; MUXDIF
621         lcall   registerWrite
622
623         movx    a,@dptr         ;
624         inc     dptr
625         mov     r0,#MUXSG0
626         mov     @r0,a           ; store it for reset purposes
627         mov     r0,a
628         mov     a,#04H          ; MUXSG0
629         lcall   registerWrite
630         
631         movx    a,@dptr         ;
632         inc     dptr
633         mov     r0,a
634         mov     a,#05H          ; MUXSG1
635         lcall   registerWrite
636         
637         movx    a,@dptr         ;
638         inc     dptr
639         mov     r0,a
640         mov     a,#06H          ; SYSRED
641         lcall   registerWrite
642
643         ret
644
645         
646 ;;; interrupt-routine for ep1out
647 ;;; receives the channel list and other commands
648 ep1out_isr:
649         push    dps
650         push    dpl
651         push    dph
652         push    dpl1
653         push    dph1
654         push    acc
655         push    psw
656         push    00h             ; R0
657         push    01h             ; R1
658         push    02h             ; R2
659         push    03h             ; R3
660         push    04h             ; R4
661         push    05h             ; R5
662         push    06h             ; R6
663         push    07h             ; R7
664
665         clr     IE.7            ; block other interrupts
666                 
667         mov     dptr,#0E780h    ; FIFO buffer of EP1OUT
668         movx    a,@dptr         ; get the first byte
669         mov     r0,#CMD_FLAG    ; pointer to the command byte
670         mov     @r0,a           ; store the command byte for ep8
671
672         mov     dptr,#ep1out_jmp; jump table for the different functions
673         rl      a               ; multiply by 2: sizeof sjmp
674         jmp     @a+dptr         ; jump to the jump table
675         ;; jump table, corresponds to the command bytes defined
676         ;; in usbdux.c
677 ep1out_jmp:
678         sjmp    startadc        ; a=0
679         sjmp    single_da       ; a=1
680         sjmp    config_digital_b; a=2
681         sjmp    write_digital_b ; a=3
682         sjmp    initsgADchannel ; a=4
683         sjmp    nothing         ; a=5
684         sjmp    nothing         ; a=6
685         sjmp    pwm_on          ; a=7
686         sjmp    pwm_off         ; a=8
687
688 nothing:
689         ljmp    over_da
690
691 pwm_on:
692         lcall   startPWM
693         sjmp    over_da
694
695 pwm_off:
696         lcall   stopPWM
697         sjmp    over_da
698
699 initsgADchannel:
700         mov     dptr,#0e781h    ; FIFO buffer of EP1OUT
701         lcall   configADC       ; configures the ADC esp sel the channel
702
703         lcall   reset_ep8       ; reset FIFO: get rid of old bytes
704         ;; Save new A/D data in EP8. This is the first byte
705         ;; the host will read during an INSN. If there are
706         ;; more to come they will be handled by the ISR of
707         ;; ep8.
708         lcall   ep8_ops         ; get A/D data
709                 
710         sjmp    over_da
711
712         
713 ;;; config AD:
714 ;;; we write to the registers of the A/D converter
715 startadc:
716         mov     dptr,#0e781h    ; FIFO buffer of EP1OUT from 2nd byte
717
718         movx    a,@dptr         ; get length of channel list
719         inc     dptr
720         mov     r0,#MAXSMPL
721         mov     @r0,a           ; length of the channel list
722
723         lcall   configADC       ; configures all registers
724
725         lcall   reset_ep6       ; reset FIFO
726         
727         ;; load new A/D data into EP6
728         ;; This must be done. Otherwise the ISR is never called.
729         ;; The ISR is only called when data has _left_ the
730         ;; ep buffer here it has to be refilled.
731         lcall   ep6_arm         ; fill with dummy data
732         
733         sjmp    over_da
734
735 ;;; Single DA conversion. The 2 bytes are in the FIFO buffer
736 single_da:
737         mov     dptr,#0e781h    ; FIFO buffer of EP1OUT
738         lcall   dalo            ; conversion
739         sjmp    over_da
740
741 ;;; configure the port B as input or output (bitwise)
742 config_digital_b:
743         mov     dptr,#0e781h    ; FIFO buffer of EP1OUT
744         movx    a,@dptr         ; get the second byte
745         inc     dptr
746         mov     OEB,a           ; set the output enable bits
747         movx    a,@dptr         ; get the second byte
748         inc     dptr
749         mov     OEC,a
750         movx    a,@dptr         ; get the second byte
751         inc     dptr
752         mov     OED,a
753         sjmp    over_da
754         
755 ;;; Write one byte to the external digital port B
756 ;;; and prepare for digital read
757 write_digital_b:
758         mov     dptr,#0e781h    ; FIFO buffer of EP1OUT
759         movx    a,@dptr         ; command[1]
760         inc     dptr
761         mov     OEB,a           ; output enable
762         movx    a,@dptr         ; command[2]
763         inc     dptr
764         mov     OEC,a
765         movx    a,@dptr         ; command[3]
766         inc     dptr
767         mov     OED,a 
768         movx    a,@dptr         ; command[4]
769         inc     dptr
770         mov     IOB,a           ;
771         movx    a,@dptr         ; command[5]
772         inc     dptr
773         mov     IOC,a
774         movx    a,@dptr         ; command[6]
775         inc     dptr
776         mov     IOD,a
777
778         lcall   reset_ep8       ; reset FIFO of ep 8
779
780         ;; fill ep8 with new data from port B
781         ;; When the host requests the data it's already there.
782         ;; This must be so. Otherwise the ISR is not called.
783         ;; The ISR is only called when a packet has been delivered
784         ;; to the host. Thus, we need a packet here in the
785         ;; first instance.
786         lcall   ep8_ops         ; get digital data
787
788         ;; 
789         ;; for all commands the same
790 over_da:        
791         mov     dptr,#EP1OUTBC
792         mov     a,#00h
793         lcall   syncdelaywr     ; arm
794         lcall   syncdelaywr     ; arm
795         lcall   syncdelaywr     ; arm
796
797         ;; clear INT2
798         mov     a,EXIF          ; FIRST clear the USB (INT2) interrupt request
799         clr     acc.4
800         mov     EXIF,a          ; Note: EXIF reg is not 8051 bit-addressable
801
802         mov     DPTR,#EPIRQ     ; 
803         mov     a,#00001000b    ; clear the ep1outirq
804         movx    @DPTR,a
805
806         setb    IE.7            ; re-enable interrupts
807
808         pop     07h
809         pop     06h
810         pop     05h
811         pop     04h             ; R4
812         pop     03h             ; R3
813         pop     02h             ; R2
814         pop     01h             ; R1
815         pop     00h             ; R0
816         pop     psw
817         pop     acc 
818         pop     dph1 
819         pop     dpl1
820         pop     dph 
821         pop     dpl 
822         pop     dps
823         reti
824
825
826         
827 ;;; all channels
828 dalo:
829         movx    a,@dptr         ; number of bytes to send out
830         inc     dptr            ; pointer to the first byte
831         mov     r0,a            ; counter
832 nextDA: 
833         movx    a,@dptr         ; get the byte
834         inc     dptr            ; point to the high byte
835         mov     r3,a            ; store in r3 for writeDA
836         movx    a,@dptr         ; get the channel number
837         inc     dptr            ; get ready for the next channel
838         lcall   writeDA         ; write value to the DAC
839         djnz    r0,nextDA       ; next channel
840         ret
841
842
843
844 ;;; D/A-conversion:
845 ;;; channel number in a
846 ;;; value in r3
847 writeDA:
848         anl     a,#00000011b    ; 4 channels
849         mov     r1,#6           ; the channel number needs to be shifted up
850 writeDA2:
851         rl      a               ; bit shift to the left
852         djnz    r1,writeDA2     ; do it 6 times
853         orl     a,#00010000b    ; update outputs after write
854         mov     r2,a            ; backup
855         mov     a,r3            ; get byte
856         anl     a,#11110000b    ; get the upper nibble
857         mov     r1,#4           ; shift it up to the upper nibble
858 writeDA3:
859         rr      a               ; shift to the upper to the lower
860         djnz    r1,writeDA3
861         orl     a,r2            ; merge with the channel info
862         clr     IOA.6           ; /SYNC of the DA to 0
863         lcall   sendSPI         ; send it out to the SPI
864         mov     a,r3            ; get data again
865         anl     a,#00001111b    ; get the lower nibble
866         mov     r1,#4           ; shift that to the upper
867 writeDA4:
868         rl      a
869         djnz    r1,writeDA4
870         anl     a,#11110000b    ; make sure that's empty
871         lcall   sendSPI
872         setb    IOA.6           ; /SYNC of the DA to 1
873 noDA:   ret
874         
875
876
877 ;;; arm ep6: this is just a dummy arm to get things going
878 ep6_arm:
879         mov     DPTR,#EP6BCH    ; byte count H
880         mov     a,#0            ; is zero
881         lcall   syncdelaywr     ; wait until the length has arrived
882         
883         mov     DPTR,#EP6BCL    ; byte count L
884         mov     a,#1            ; is one
885         lcall   syncdelaywr     ; wait until the length has been proc
886         ret
887         
888
889
890 ;;; converts one analog/digital channel and stores it in EP8
891 ;;; also gets the content of the digital ports B,C and D depending on
892 ;;; the COMMAND flag
893 ep8_ops:
894         mov     dptr,#0fc01h    ; ep8 fifo buffer
895         clr     a               ; high byte
896         movx    @dptr,a         ; set H=0
897         mov     dptr,#0fc00h    ; low byte
898         mov     r0,#CMD_FLAG
899         mov     a,@r0
900         movx    @dptr,a         ; save command byte
901
902         mov     dptr,#ep8_jmp   ; jump table for the different functions
903         rl      a               ; multiply by 2: sizeof sjmp
904         jmp     @a+dptr         ; jump to the jump table
905         ;; jump table, corresponds to the command bytes defined
906         ;; in usbdux.c
907 ep8_jmp:
908         sjmp    ep8_err         ; a=0, err
909         sjmp    ep8_err         ; a=1, err
910         sjmp    ep8_err         ; a=2, err
911         sjmp    ep8_dio         ; a=3, digital read
912         sjmp    ep8_sglchannel  ; a=4, analog A/D
913         sjmp    ep8_err         ; a=5, err
914         sjmp    ep8_err         ; a=6, err
915
916         ;; read one A/D channel
917 ep8_sglchannel:
918         mov     DPTR,#0fc01h    ; EP8 FIFO
919         setb    IOA.7           ; start converter, START = 1
920         lcall   readADCch       ; get one reading
921         clr     IOA.7           ; stop the converter, START = 0
922
923         sjmp    ep8_send        ; send the data
924
925         ;; read the digital lines
926 ep8_dio:        
927         mov     DPTR,#0fc01h    ; store the contents of port B
928         mov     a,IOB           ; in the next
929         movx    @dptr,a         ; entry of the buffer
930         inc     dptr
931         mov     a,IOC           ; port C
932         movx    @dptr,a         ; next byte of the EP
933         inc     dptr
934         mov     a,IOD
935         movx    @dptr,a         ; port D
936         
937 ep8_send:       
938         mov     DPTR,#EP8BCH    ; byte count H
939         mov     a,#0            ; is zero
940         lcall   syncdelaywr
941         
942         mov     DPTR,#EP8BCL    ; byte count L
943         mov     a,#10H          ; 16 bytes, bec it's such a great number...
944         lcall   syncdelaywr     ; send the data over to the host
945
946 ep8_err:        
947         ret
948
949
950
951 ;;; EP8 interrupt is the endpoint which sends data back after a command
952 ;;; The actual command fills the EP buffer already
953 ;;; but for INSNs we need to deliver more data if the count > 1
954 ep8_isr:        
955         push    dps
956         push    dpl
957         push    dph
958         push    dpl1
959         push    dph1
960         push    acc
961         push    psw
962         push    00h             ; R0
963         push    01h             ; R1
964         push    02h             ; R2
965         push    03h             ; R3
966         push    04h             ; R4
967         push    05h             ; R5
968         push    06h             ; R6
969         push    07h             ; R7
970                 
971         lcall   ep8_ops
972         
973         ;; clear INT2
974         mov     a,EXIF          ; FIRST clear the USB (INT2) interrupt request
975         clr     acc.4
976         mov     EXIF,a          ; Note: EXIF reg is not 8051 bit-addressable
977
978         mov     DPTR,#EPIRQ     ; 
979         mov     a,#10000000b    ; clear the ep8irq
980         movx    @DPTR,a
981
982         pop     07h
983         pop     06h
984         pop     05h
985         pop     04h             ; R4
986         pop     03h             ; R3
987         pop     02h             ; R2
988         pop     01h             ; R1
989         pop     00h             ; R0
990         pop     psw
991         pop     acc 
992         pop     dph1 
993         pop     dpl1
994         pop     dph 
995         pop     dpl 
996         pop     dps
997         reti
998
999
1000
1001 ;;; GPIF waveform for PWM
1002 waveform:
1003         ;;      0     1     2     3     4     5     6     7(not used)
1004         ;; len (gives 50.007Hz)
1005         .db     195,  195,  195,  195,  195,  195,  1,    1
1006
1007         ;; opcode
1008         .db     002H, 006H, 002H, 002H, 002H, 002H, 002H, 002H
1009         
1010         ;; out
1011         .db     0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH
1012
1013         ;; log
1014         .db     000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H
1015
1016
1017 stopPWM:
1018         mov     r0,#PWMFLAG     ; flag for PWM
1019         mov     a,#0            ; PWM (for the main loop)
1020         mov     @r0,a           ; set it
1021
1022         mov     dptr,#IFCONFIG  ; switch off GPIF
1023         mov     a,#10100000b    ; gpif, 30MHz, internal IFCLK
1024         lcall   syncdelaywr
1025         ret
1026         
1027
1028 ;;; init PWM
1029 startPWM:
1030         mov     dptr,#IFCONFIG  ; switch on IFCLK signal
1031         mov     a,#10100010b    ; gpif, 30MHz, internal IFCLK
1032         lcall   syncdelaywr
1033
1034         mov     OEB,0FFH        ; output to port B
1035
1036         mov     DPTR,#EP4CFG
1037         mov     a,#10100000b    ; valid, out, bulk
1038         movx    @DPTR,a
1039
1040         ;; reset the endpoint
1041         mov     dptr,#FIFORESET
1042         mov     a,#80h          ; NAK
1043         lcall   syncdelaywr
1044         mov     a,#84h          ; reset EP4 + NAK
1045         lcall   syncdelaywr
1046         mov     a,#0            ; normal op
1047         lcall   syncdelaywr
1048
1049         mov     dptr,#EP4BCL
1050         mov     a,#0H           ; discard packets
1051         lcall   syncdelaywr     ; empty FIFO buffer
1052         lcall   syncdelaywr     ; empty FIFO buffer
1053
1054         ;; aborts all transfers by the GPIF
1055         mov     dptr,#GPIFABORT
1056         mov     a,#0ffh         ; abort all transfers
1057         lcall   syncdelaywr
1058
1059         ;; wait for GPIF to finish
1060 wait_f_abort:
1061         mov     a,GPIFTRIG      ; GPIF status
1062         anl     a,#80h          ; done bit
1063         jz      wait_f_abort    ; GPIF busy
1064
1065         mov     dptr,#GPIFCTLCFG
1066         mov     a,#10000000b    ; tri state for CTRL
1067         lcall   syncdelaywr
1068
1069         mov     dptr,#GPIFIDLECTL
1070         mov     a,#11110000b    ; all CTL outputs low
1071         lcall   syncdelaywr
1072
1073         ;; abort if FIFO is empty
1074         mov     a,#00000001b    ; abort if empty
1075         mov     dptr,#EP4GPIFFLGSEL
1076         lcall   syncdelaywr
1077
1078         ;; 
1079         mov     a,#00000001b    ; stop if GPIF flg
1080         mov     dptr,#EP4GPIFPFSTOP
1081         lcall   syncdelaywr
1082
1083         ;; transaction counter
1084         mov     a,#0ffH
1085         mov     dptr,#GPIFTCB3
1086         lcall   syncdelaywr
1087
1088         ;; transaction counter
1089         mov     a,#0ffH
1090         mov     dptr,#GPIFTCB2
1091         lcall   syncdelaywr
1092
1093         ;; transaction counter
1094         mov     a,#0ffH         ; 512 bytes
1095         mov     dptr,#GPIFTCB1
1096         lcall   syncdelaywr
1097
1098         ;; transaction counter
1099         mov     a,#0ffH
1100         mov     dptr,#GPIFTCB0
1101         lcall   syncdelaywr
1102
1103         ;; RDY pins. Not used here.
1104         mov     a,#0
1105         mov     dptr,#GPIFREADYCFG
1106         lcall   syncdelaywr
1107
1108         ;; drives the output in the IDLE state
1109         mov     a,#1
1110         mov     dptr,#GPIFIDLECS
1111         lcall   syncdelaywr
1112
1113         ;; direct data transfer from the EP to the GPIF
1114         mov     dptr,#EP4FIFOCFG
1115         mov     a,#00010000b    ; autoout=1, byte-wide
1116         lcall   syncdelaywr
1117
1118         ;; waveform 0 is used for FIFO out
1119         mov     dptr,#GPIFWFSELECT
1120         mov     a,#00000000b
1121         movx    @dptr,a
1122         lcall   syncdelay
1123
1124         ;; transfer the delay byte from the EP to the waveform
1125         mov     dptr,#0e781h    ; EP1 buffer
1126         movx    a,@dptr         ; get the delay
1127         mov     dptr,#waveform  ; points to the waveform
1128         mov     r2,#6           ; fill 6 bytes
1129 timloop:
1130         movx    @dptr,a         ; save timing in a xxx
1131         inc     dptr
1132         djnz    r2,timloop      ; fill the 6 delay bytes
1133
1134         ;; load waveform
1135         mov     AUTOPTRH2,#0E4H ; XDATA0H
1136         lcall   syncdelay
1137         mov     AUTOPTRL2,#00H  ; XDATA0L
1138         lcall   syncdelay
1139
1140         mov     dptr,#waveform  ; points to the waveform
1141         
1142         mov     AUTOPTRSETUP,#7 ; autoinc and enable
1143         lcall   syncdelay
1144
1145         mov     r2,#20H         ; 32 bytes to transfer
1146
1147 wavetr:
1148         movx    a,@dptr
1149         inc     dptr
1150         push    dpl
1151         push    dph
1152         push    dpl1
1153         push    dph1
1154         mov     dptr,#XAUTODAT2
1155         movx    @dptr,a
1156         lcall   syncdelay
1157         pop     dph1 
1158         pop     dpl1
1159         pop     dph 
1160         pop     dpl
1161         djnz    r2,wavetr
1162
1163         mov     dptr,#OUTPKTEND
1164         mov     a,#084H
1165         lcall   syncdelaywr
1166         lcall   syncdelaywr
1167
1168         mov     r0,#PWMFLAG     ; flag for PWM
1169         mov     a,#1            ; PWM (for the main loop)
1170         mov     @r0,a           ; set it
1171
1172         ret
1173
1174         
1175
1176 ;; need to delay every time the byte counters
1177 ;; for the EPs have been changed.
1178
1179 syncdelay:
1180         nop
1181         nop
1182         nop
1183         nop
1184         nop
1185         nop
1186         nop
1187         nop
1188         nop
1189         ret
1190
1191 syncdelaywr:
1192         movx    @dptr,a
1193         lcall   syncdelay
1194         ret
1195
1196
1197
1198         .org    1F00h           ; lookup table at the end of memory
1199
1200 swap_lut:
1201 .db 0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136
1202 .db 72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100
1203 .db 228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220
1204 .db 60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10
1205 .db 138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166
1206 .db 102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94
1207 .db 222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9
1208 .db 137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165
1209 .db 101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93
1210 .db 221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11
1211 .db 139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167
1212 .db 103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95
1213 .db 223,63,191,127,255
1214
1215
1216
1217         
1218 .End
1219
1220