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