]> git.proxmox.com Git - mirror_linux-firmware.git/blob - usbdux/usbduxsigma_firmware.asm
usbdux: usbduxsigma: Changed address and updated date
[mirror_linux-firmware.git] / usbdux / usbduxsigma_firmware.asm
1 ; usbdux_firmware.asm
2 ; Copyright (C) 2010,2011,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: 25 Jun 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
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