]>
Commit | Line | Data |
---|---|---|
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 | ||
60 | jmptbl: 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 | |
126 | sudav_isr: | |
127 | sutok_isr: | |
128 | suspend_isr: | |
129 | usbreset_isr: | |
130 | hispeed_isr: | |
131 | ep0ack_isr: | |
132 | spare_isr: | |
133 | ep0in_isr: | |
134 | ep0out_isr: | |
09c949f6 BP |
135 | ibn_isr: |
136 | ep0ping_isr: | |
137 | ep1ping_isr: | |
138 | ep2ping_isr: | |
139 | ep4ping_isr: | |
140 | ep6ping_isr: | |
141 | ep8ping_isr: | |
142 | errlimit_isr: | |
143 | ep2isoerr_isr: | |
144 | ep4isoerr_isr: | |
145 | ep6isoerr_isr: | |
146 | ep8isoerr_isr: | |
147 | ep6_isr: | |
148 | ep2_isr: | |
149 | ep4_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 | |
175 | ep1in_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 |
218 | isr0: | |
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 | ||
269 | noepsubmit: | |
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 | |
293 | main: | |
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 | |
318 | mloop2: 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 | |
336 | initAD: | |
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 | |
364 | sendSPI: | |
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 | |
380 | sendSPIwait: | |
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" | |
395 | recSPI: | |
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 | ||
403 | recSPIwait: | |
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 | |
425 | registerRead: | |
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 | |
439 | registerWrite: | |
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 | |
462 | initeps: | |
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 | |
540 | readADCch: | |
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 | |
573 | sof_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 | ||
597 | sof_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 | |
639 | epfull: | |
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 |
653 | epempty: |
654 | mov a,IOA ; conversion running? | |
655 | jb ACC.7,sofend | |
656 | ||
657 | lcall DAsend | |
658 | ||
659 | sofend: | |
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 | ||
669 | nosof: | |
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 | ||
688 | reset_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 | ||
702 | reset_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 | |
720 | configADC: | |
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 | |
777 | ep1out_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 | |
804 | ep1out_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 | |
816 | nothing: | |
817 | ljmp over_da | |
818 | ||
819 | pwm_on: | |
820 | lcall startPWM | |
821 | sjmp over_da | |
822 | ||
823 | pwm_off: | |
824 | lcall stopPWM | |
825 | sjmp over_da | |
826 | ||
827 | initsgADchannel: | |
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 |
842 | startadcint: |
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 | |
851 | startadc: | |
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 |
855 | startadc2: | |
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 | |
882 | single_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) | |
888 | config_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 | |
903 | write_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 | |
936 | over_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 |
972 | dalo: |
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 | 979 | nextDAlo: |
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 | |
993 | DAsend: | |
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 | |
999 | nextDA: | |
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 | 1009 | DAret: |
09c949f6 BP |
1010 | ret |
1011 | ||
1012 | ||
1013 | ||
1014 | ;;; D/A-conversion: | |
1015 | ;;; channel number in a | |
1016 | ;;; value in r3 | |
1017 | writeDA: | |
1018 | anl a,#00000011b ; 4 channels | |
1019 | mov r1,#6 ; the channel number needs to be shifted up | |
1020 | writeDA2: | |
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 | |
1028 | writeDA3: | |
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 | |
1037 | writeDA4: | |
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 |
1043 | noDA: ret |
1044 | ||
1045 | ||
1046 | ||
1047 | ;;; arm ep6: this is just a dummy arm to get things going | |
1048 | ep6_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 | |
1063 | ep8_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 | |
1077 | ep8_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 | |
1087 | ep8_sglchannel: | |
09c949f6 | 1088 | setb IOA.7 ; start converter, START = 1 |
dba12691 BP |
1089 | ;; we do polling: we wait until DATA READY is zero |
1090 | sglchwait: | |
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 | |
1100 | ep8_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 | ||
1111 | ep8_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 | ||
1120 | ep8_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 | |
1128 | ep8_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 | |
1176 | waveform: | |
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 | ||
1191 | stopPWM: | |
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 | |
1203 | startPWM: | |
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 | |
1234 | wait_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 | |
1303 | timloop: | |
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 | ||
1321 | wavetr: | |
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 | ||
1353 | syncdelay: | |
1354 | nop | |
1355 | nop | |
1356 | nop | |
1357 | nop | |
1358 | nop | |
1359 | nop | |
1360 | nop | |
1361 | nop | |
1362 | nop | |
1363 | ret | |
1364 | ||
1365 | syncdelaywr: | |
1366 | movx @dptr,a | |
1367 | lcall syncdelay | |
1368 | ret | |
1369 | ||
1370 | ||
1371 | ||
1372 | .org 1F00h ; lookup table at the end of memory | |
1373 | ||
1374 | swap_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 |