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