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