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