;FX2-Firmware für ADC2USB, haftmann#software 11/04
;Für zwei 16-bit-A/D-Wandler, die am GPIF angeschlossen sind
;Im Hauptprogramm wird nur ein dptr benutzt (also kein DPS), nur Registerbank 0
;Zu übersetzen mit ASEM51; ggf. EEPROM-Datei erstellen mit HEX2BIX -i -f 0xC2
;Nur für EZ-USB FX2, 480 Mbit/s! Läuft eingeschränkt auch mit 12 Mbit/s.
;Außerdem wird ein serieller D/A-Wandler TDA1543 angesteuert, der eine
;präzise Sinusschwingung mit einstellbaren ca. 400 Hz erzeugt.
;Die Kurvenform kommt von der hinten stehenden Tabelle...
$nopaging
$nosymbols
$nomod51
$nolist
$include(ezusbfx2.mcu)
$include(makros.i51)
$list
$genonly ;das "Innere" von Makros
$condonly ;das "Innere" von IFxx
always_renum equ 0
;###############
;## Schaltung ##
;###############
;PortA (Pinzuordnung endgültig seit 17.12.04)
ADC_RESET BIT IOA.0 ;ADU-Rücksetzen (Firmware-Start)
ADC_CS BIT IOA.1 ;Schaltkreisauswahl für die A/D-Wandler
Led3 BIT IOA.2 ;Weitere LED (Debug), zz. freies Pin
Led BIT IOA.3 ;Gelbe USB-Leuchtdiode
Led2 BIT IOA.4 ;Grüne LED, High-Speed- und USB-Fehler-Anzeige?
Dau_BCK BIT IOA.5 ;Dieser serielle DAU wäre viel besser am
Dau_WS BIT IOA.6 ;synchron-seriellen Port angeschlossen,
Dau_Data BIT IOA.7 ;aber per Ping-Pong geht es hier auch
;PortB ist Datenbus LOW-Teil
;PortC existiert am 56pol. Gehäuse nicht
;PortD ist Datenbus HIGH-Teil
;PortE existiert am 56pol. Gehäuse nicht
;CTL0 = A/D-Umsetzer CONVST (Start der Umsetzung; beide ADUs)
;CTL1 = A/D-Umsetzer RD0 (Lese-Leitung erster ADU)
;CTL2 = A/D-Umsetzer RD1 (Lese-Leitung zweiter ADU)
;RDY0, RDY1 sind ungenutzt (offene Eingänge bspw. mit Ucc oder BUSY verbinden!)
;-----------
;## DATEN ## Datenbereich wird beim Einschalten mit Nullen gelöscht
;-----------
DSEG AT 20h
IntReq: ds 1 ;für USB-Interruptrequests, bitadressierbar
bits: ds 1
LedBlink BIT bits.0
Led2Blink BIT bits.1
HighSpeed BIT bits.5
Configuration: ds 1 ;hier: Null (adressiert) oder Eins (konfig.)
AltSetting: ds 1 ;hier: Null (Bulk), Eins (ISO) oder Zwei (INT)
DSEG AT 30h
LedTime: ds 1 ;"Nachblinkzeit" der LED in ms
BlinkF: ds 1 ;"Blinkfrequenz" in ms (halbe Periode)
Blink: ds 1 ;Blink-Zähler
FrameCnt: ds 1 ;zum Mitzählen "ganzer" Rahmen
Led2Time: ds 1 ;"Nachleuchtzeit" der HS-LED
WirklichVoll: ds 1 ;Um ADU-ChipAuswahl nicht sporadisch zu steuern
;Für den DAU: dptr1 zeigt permanent in die Kurventabelle ab 1000h bis 2000h
a0: ds 1 ;3-Byte-Addierwert pro DAC-Ausgabe
a1: ds 1 ;auf DPH0:DPL0:dpd1:dpd0
a2: ds 1 ;= Round(Wunschfrequenz[Hz]*2684,35)
dpd0: ds 1 ;16 "Nachkomma-Bits" für dptr1
dpd1: ds 1
;--------------
;## PROGRAMM ##
;--------------
;--> Dieses Programm kommt beinahe ohne Interrupts aus! <--
;Nach dieser Fallstudie frage ich mich, wieso Anchor/Cypress dem Anwender
;einen Bären mit 'zig Interrupts aufbinden will, wobei die Beispielquellen
;nichts anderes machen als in der ISR ein Bit zu setzen und im Hauptprogramm
;abzufragen (Polling). Dazu sind doch Interrupt-Request-Bits da!
;Nur für's Resume [Fortsetzen] schien eine Mini-ISR unumgänglich zu sein.
;(Naja, Schlafmodus und Resume sind hier ganz nettes Beiwerk...)
CSEG AT 0
ajmp main
ORG TIMER0
ajmp T0ISR
WaveDat: ;Nur eine Wellenform wird benötigt, 1 MSa/s, 48 IFCLK-Takte
;Alternative Zeiten sind zweckmäßig für geringere Abtastrate bei Full-Speed
;maximal 256 kSa/s, jitterfrei 250 kSa/s, 192 IFCLK-Takte
;Für HighSpeed wird WAVEDATA+1 auf 04h (statt 94h) modifiziert!
db 28,144+4,3,3,3,3,3,7 ;LenBr für FullSpeed (Zeit in Takten)
db 0,16,2,0,0,2,0,0 ;Opcode (2=Abtasten, 16=Interrupt)
db 0FEh,0FFh,0FDh,0FDh,0FFh,0FBh,0FBh,0FFh ;Output
db 0,0,0,0,0,0,0,3Fh ;LFun (ungenutzt)
;Normalerweise würden 500 Bytes pro Mikrorahmen (FS: 1000 Bytes pro Rahmen)
;zur Übertragung ausreichen, aber am Oszibild machte sich Jitter bemerkbar,
;daher sind die FIFOs leicht größer als notwendig dimensioniert.
ORG 33h ;RESUME-ISR (erforderlich, sonst geht das Wecken nicht)
clr EICON.4
reti
;================================
;== Zeichenketten-Umwurstelung ==
;================================
ReadUTF8:
;UTF8/8859-1 -> Unicode-Konvertierung (Unicode-16 für USB)
;Um das EEPROM-File kleiner und den Quelltext leichter pflegbar zu machen...
;PE: dptr=Quell-UTF8; jedes "falsche" UTF8 wird als ISO-8859-1 interpretiert!
; (Damit kann man in Westeuropa immer mit ISO-8859-1 arbeiten.)
; DPS.0=0!
;PA: r7:r6=Unicode-16
; dptr vorgerückt
;VR: A,R4,R5,R6,R7,dptr,Flags
;LZ: Stark vom Zeichensatz abhängig, bei reinem ASCII 14 Takte
movx a,@dptr
inc dptr
mov r6,a ;R6 enthält fortan erstes Byte für Rückfall
jnb ACC.7,utf1 ;normales ASCII
jnb ACC.6,utf1 ;kein gültiges UTF8-Führungsbyte
jnb ACC.5,utf2 ;2-Byte-UTF8
jb ACC.4,utf1 ;kein 3-Byte-UTF8
utf2: anl a,#3Fh
jz utf1
dec a
jz utf1
inc a
rr a
rr a
mov r5,a ;geANDetes und geschobenes Führungsbyte
movx a,@dptr
jnb ACC.7,utf1 ;kein gültiges Trail-Byte
jb ACC.6,utf1 ;ebenso
clr ACC.7
xch a,r5 ;R5=geANDetes Folgebyte, A=höheres Byte
mov r4,a ;R4=höheres Byte (Bits 7:6 oben, 10:8 unten)
anl a,#0C0h
orl a,r5
xch a,r4 ;R4=niederwertiges Byte, A=höheres Byte
anl a,#0Fh ;3 Datenbits 10:8 und 1 "Testbit"
mov r7,a ;R7 setzen (höheres Byte)
jnb ACC.3,okay2 ;war 2-Byte-Kode
push DPL0
push DPH0 ;retten zur Restaurierung (fehlt "dec dptr")
inc dptr
movx a,@dptr ;drittes Byte
jb ACC.6,utf1r ;kein Folgebyte, ganze Kette verwerfen
jbc ACC.7,utf3 ;und #0:R6 (»Windows-Zeichensatz«) annehmen
utf1r:
pop DPH0 ;dptr zurückstellen
pop DPL0
utf1: mov r7,#0
ret
utf3:
mov r5,a
mov a,r4 ;R5=geANDetes drittes Byte, A="mittleres" Byte
rr a
rr a
mov r4,a ;R4=rechtsgeschobenes "mittleres" Byte
anl a,#0C0h ;Bit 7:6
orl a,r5 ;A=Bit 7:0
xch a,r4 ;Low-Teil fertig, in R4, A="mittleres" Byte
anl a,#3Fh ;Bit 13:8
xch a,r7 ;nach R7, A=höchstes Byte (nur 2 Bits 15:14)
rr a
rr a
anl a,#0C0h
orl a,r7 ;High-Teil fertig
mov r7,a ;in R7
add a,#-8
jnc utf1r ;zu klein, ungültig!
pop ACC
pop ACC
okay2: mov a,r4
mov r6,a ;R6:=R4 (Low-Teil) setzen
inc dptr
ret
MakeString: ;USB-String-Deskriptor (erst) bei Anforderung zusammenbauen
;PE: R2=String-Nummer (in nullterminierter Kette)
;PA: StringPuffer gefüllt mit USB-String-Deskriptor
;VR: R0=0,R2=0,R4,R5,R6,R7,dptr
;LZ: Etwa linear mit R2 zunehmend!
mov dptr,#StringDescriptors
inc r2
sjmp ms2
ms1: movx a,@dptr
inc dptr
jnz ms1
ms2: djnz r2,ms1
push MPAGE
mov MPAGE,#HIGH(StringPuffer)
mov r0,#0
mov r7,#3 ;"String-Deskriptor"
ms3: mov a,r6
ST ;(zunächst wird eine falsche Länge gesetzt)
inc r0
mov a,r7
ST ;"Zeichen", High-Byte
inc r0
call ReadUTF8
mov a,r6
orl a,r7
jnz ms3
mov a,r0
ST 0 ;Länge in Bytes nachtragen
pop MPAGE
ret
SetGpif:
;Setzt EP2 und GPIF in Abhängigkeit von <Configuration> und <AltSetting>:
;GpifAbort, FifoReset, Ep2Cfg, AutoInLen, Ep2Cfg, WAVEDATA[1], GpifTc, GpifTrig
ST GpifAbort ;GPIF abwürgen für Registerzugriff
SyncDelay
ST FifoReset,80h ;IN-Ende frei machen, FIFO leeren (?)
SyncDelay
ST ,2
SyncDelay
ST ,0
SyncDelay
mov r2,a ;Ungültiger EP2 (a=0)
jnb Configuration.0,Ep2Tot ;wenn Null
mov dptr,#64 ;Full Speed: 64-Byte-Stückelung
mov a,#11110000b ;INT IN, 4 x 512 Byte
jb AltSetting.1,Ep2Set ;wenn 2 (gibts nur bei High Speed)
mov a,#11100000b ;BULK IN, 4 x 512 Byte
jnb AltSetting.0,Ep2Set ;wenn Null
mov a,#11011000b ;ISO IN, 4 x 1024 Byte
mov dptr,#1020 ;Full Speed: 1020 (1023 wäre krumm) Bytes
Ep2Set: mov r2,#144+4 ;lange warten (3 µs extra) für 250 kSa/s
jnb HighSpeed,Ep2FS
clr ACC.3 ;es reicht ein 512-Byte-Endpoint
mov r2,#4 ;kurz warten für 1 MSa/s
Ep2Tot: mov dptr,#512 ;High Speed: stets 512 Bytes pro µRahmen
Ep2FS: ST EP2Cfg ;(sowohl BULK als auch ISO als auch INT)
mov a,DPH0
ST EP2AutoInLenH ;das "Quantum" setzen, 64, 512 oder 1020
mov a,DPL0
ST NEXT
mov a,r2
jz Ep2Ok ;unkonfiguriert gibt's kein GPIF
STORE WAVEDATA+1 ;Zeit setzen
SyncDelay
ST EP2FifoCfg,00001001b ;AutoIn, kein ZeroLenIn
ST GpifTcB3,0FFh ;Langen Transfer aktivieren
mov GpifTrig,#4+2-2 ;GPIF starten
Ep2Ok: ret
;=========================
;== Routinen für Ende 0 == ;PE: R0=SETUPDAT, R4=SDAT[0], R5=SDAT[2]
;========================= c=0 R6=SDAT[4], R7=SDAT[5]
GetStatus:
cjne r4,#80h,gs_no_dev ;GS_DEVICE
nullin: clr a ;kein WakeUp(Bit1), kein SelfPower(Bit0)
wordin: inc MPAGE
ST EP0BUF
ST NEXT,0
dec MPAGE
ST EP0BCL,2
ret
gs_no_dev:
cjne r4,#81h,gs_no_if ;GS_INTERFACE
jmp nullin ;auch zwei Nullen melden
gs_no_if:
cjne r4,#82h,err ;GS_ENDPOINT
cjne r6,#82h,err ;EP2IN?
LD EP2CS ;STALL-Bit angeln
anl a,#01h
jmp wordin
ClearFeature:
cjne r4,#02h,err ;ENDPOINT OUT
cjne r5,#00h,err ;einziges Feature: STALL
cjne r6,#82h,err ;nur EP2IN
ST EP2CS,0 ;STALL entfernen
ResTog2:
ST TOGCTL,12h ;Toggle-Bit adressieren
setb ACC.5 ;WRITEDELAY
ST ;Togglebit zurücksetzen
ret
SetFeature:
cjne r4,#2,err ;FT_ENDPOINT
cjne r5,#0,err ;einziges Feature: STALL
ST EP2CS,1 ;STALL setzen
ret
err: setb c
ret
GetDescriptor:
cjne r4,#80h,err ;nur DEVICE_IN
LD SETUPDAT+3
cjne a,#01h,gd_no_dev ;GD_DEVICE
mov dptr,#DeviceDescriptor
gd_sto: mov a,DPH0
ST SUDPTRH
mov a,DPL0
ST NEXT
ret
gd_no_dev:
cjne a,#02h,gd_no_conf ;GD_CONFIGURATION
mov dptr,#ConfigDescFS
jnb HighSpeed,gd_sto
mov dptr,#ConfigDescHS
jmp gd_sto
gd_no_conf:
cjne a,#03h,gd_no_str ;GD_STRING
mov a,r5
mov r2,a
add a,#-5 ;Nur 0..4 zulassen
jc err
call MakeString
mov dptr,#StringPuffer
jmp gd_sto
gd_no_str:
cjne a,#06h,gd_no_qual ;GD_QUALIFIER
mov dptr,#DeviceQualifier
jmp gd_sto
gd_no_qual:
cjne a,#07h,err ;GD_OTHERSPEED
mov dptr,#ConfigDescHS
jnb HighSpeed,gd_sto
mov dptr,#ConfigDescFS
jmp gd_sto
GetConfiguration:
cjne r4,#80h,err ;nur DEVICE_IN
mov a,Configuration ;Entweder konfiguriert oder unkonfiguriert
gi: inc MPAGE
ST EP0BUF
dec MPAGE
ST EP0BCL,1
retu: ret
SetConfiguration:
cjne r4,#0,err ;nur DEVICE_OUT
mov a,r5
add a,#-2
jc err ;nur Konfiguration 0 oder 1
mov Configuration,r5
jmp SetGpif ;GPIF ein/auschhalten usw.
GetAltSet:
cjne r4,#81h,err ;nur INTERFACE IN
mov a,AltSetting
jmp gi
SetAltSet:
cjne r4,#1,err ;nur INTERFACE OUT
mov a,#-2
jnb HighSpeed,sa1 ;-2 bei Full Speed
dec a ;-3 bei High Speed
sa1: add a,r5
jc err ;maximal 1 (FS) bzw. 2 (HS) zulässig
mov AltSetting,r5
jmp SetGpif ;Endpoint konfigurieren usw.
SetFreq: ;hersteller-spezifischer Request F0h zum Setzen/Abfragen der
;fein einstellbaren Frequenz; Datenphase: 4 Bytes (3 genutzt)
LD SETUPDAT+6 ;Länge Low
cjne a,#4,err2
LD SETUPDAT+7 ;Länge High
jnz err2
mov AutoPtrH1,#HIGH(EP0BUF)
mov AutoPtrL1,#LOW(EP0BUF)
mov dptr,#XAutoDat1
mov a,r4
jb ACC.7,GetFreq
ST EP0BCL ;EP0Out-Puffer aktivieren
wd: mov a,EP01STAT
jb ACC.0,wd ;Warten auf EP0-Daten (Endlosschleife!)
clr EA ;Daten = Round(Wunschfrequenz[Hz]*2684,35)
LOAD
mov a0,a
LOAD
mov a1,a
LOAD
mov a2,a
setb EA
ret
GetFreq: ;Wunschfrequenz[Hz] = Daten/2684,35
mov a,a0
STORE
mov a,a1
STORE
mov a,a2
STORE
STORE ,0
markok: ST EP0BCL,4
ret
SUD_Tab:
ajmp GetStatus ;0
ajmp ClearFeature ;1
err2: ajmp err ;2
ajmp SetFeature ;3
ajmp err ;4
ajmp err ;5, sollte nicht vorkommen
ajmp GetDescriptor ;6
ajmp err ;7 SetDescriptor
ajmp GetConfiguration;8
ajmp SetConfiguration;9
ajmp GetAltSet ;10
ajmp SetAltSet ;11
;ajmp err ;12 SyncFrame
HandleSUD:
;Unterprogramm zur Behandlung von SetUpData
;liefert CY=1 für EP0STALL
LD SETUPDAT ;SETUPDAT -> R4
mov r4,a
LD NEXT ;SETUPDAT+1 -> Programmverteiler
mov r7,a
CJE a,#0F0h,SetFreq
add a,#-12
jc err2
LD NEXT ;SETUPDAT+2 -> R5
mov r5,a
LD SETUPDAT+4 ;SETUPDAT+4 -> R6
mov r6,a
LD NEXT ;SETUPDAT+5 -> R7
xch a,r7
JMPTBL SUD_Tab ;mit c=0 Routinen anspringen
;=====================
;== DAU-Ansteuerung ==
;=====================
;Hätten wir ein 100+poliges Gehäuse, könnte man wunderschön das serielle
;Port im Modus 0 (synchron) benutzen.
;Beim 56poligen bleibt nur der Ausweg des Ping-Pong-Verfahrens.
;Es reicht geradeso für 1 Kanal mit satten 48 kSa/s und 16 bit
T0ISR:
;Für diese ISR belässt das Hauptprogramm folgende Register unberührt:
;dptr1, r1 ;Aufruf+Ansprung 7
push PSW ;2
push ACC ;2
inc DPS ;2 dptr1 verwenden
inc DPH1 ;2
movx a,@dptr ;2 Sinustabelle, High-Byte
REPT 8 ;Zwischensumme 10
rlc a ;1
mov Dau_Data,C ;2
clr Dau_BCK ;2 Low-Zeit = 160 ns (mindestens 22 ns)
setb Dau_BCK ;2
ENDM ;Zwischensumme 56
dec DPH1 ;2
movx a,@dptr ;2 Low-Byte
dec DPS ;2
REPT 7 ;Zwischensumme 6
rlc a ;1
mov Dau_Data,C ;2
clr Dau_BCK ;2
setb Dau_BCK ;2
ENDM ;Zwischensumme 49
setb Dau_WS ;2
rlc a ;1
mov Dau_Data,C ;2
clr Dau_BCK ;2
setb Dau_BCK ;2
anl IOA,#1Fh ;3 !!Anpassen bei Änderung der Bit-Zuweisung!!
;clr Dau_Data ;2
;clr Dau_WS ;2
;clr Dau_BCK ;2
setb Dau_BCK ;2
;Zwischensumme 17 (14)
mov a,dpd0 ;2
add a,a0 ;2
mov dpd0,a ;2
mov a,dpd1 ;2
addc a,a1 ;2
mov dpd1,a ;2
mov a,DPL1 ;2
addc a,a2 ;2
mov DPL1,a ;2
jnc skh ;3
mov a,DPH1 ;2
swap a ;1 Die "1" ins Low-Nibble retten
add a,#20h ;2
swap a ;1
mov DPH1,a ;2 High-Nibble unverändert (=1) lassen
;Zwischensumme 29
skh:
pop ACC ;2
pop PSW ;2
reti ;4
;Zwischensumme 8
;Gesamtsumme 182 = 15,2 µs
;=== Warte-Hilfsbefehl, Argument R4 = Wartezeit in 1 µs ===
;wait: inc r4 ;Wir brauchen 4x6=24 Takte pro Durchlauf
w1: inc dptr ;kurzer Befehl mit langer Dauer!
inc dptr ;3 Takte, 12 MHz / 3 => 0,25 µs/Befehl
inc dptr
djnz r4,w1 ;3 Takte
ret
;=== LED-Spielerei ===
StartLed:
;Start des LED-Blinkens mit a=Blinkperiodendauer, 0=Maximum
;Blinkt die LED bereits, wird nur die künftige Blinkperiode gesetzt
;VR: A,R0=LOW(OUTA)
mov LedTime,a ;Zeitzähler (Monoflop) neu starten
mov BlinkF,a ;Blinkfrequenz setzen
jb LedBlink,nost
mov Blink,a
setb LedBlink
clr Led ;LED ausschalten (Zugriff beginnt)
nost: ret
SetWaveData:
;Setzt Bytes der Zustandsmaschine
;PE: r2=Anzahl Bytes, dptr=Byte-Zeiger
mov AUTOPTRH2,#HIGH(WAVEDATA)
mov AUTOPTRL2,#LOW(WAVEDATA)
mov AUTOPTRH1,DPH0
mov AUTOPTRL1,DPL0
fill: mov dptr,#XAUTODAT1
movx a,@dptr
inc dptr ;#XAUTODAT2
movx @dptr,a
djnz r2,fill
ret
;=====================
;== Initialisierung ==
;=====================
main:
mov SP,#7Fh
mov CKCON,#00000000b ;Handbremse für "movx" lösen
mov MPAGE,#HIGH(CPUCS) ;7Eh
ST GpifAbort
ST CPUCS,00010000b ;CPU auf 48 MHz, kein CLK48
mov r0,#8
mov r3,#78h
clr a
clr_ram:mov @r0,a
inc r0
djnz r3,clr_ram
mov IOA,a
mov DPS,a ;sicherheitshalber
dec a
mov OEA,a
mov OEC,a ;100+Pin: Strom sparen
mov OEE,a
setb EICON.5 ;Resume-Interrupt (auch bei EA=0)
mov a2,#12 ;Vorgabe: f = 50000/2048*12 = 293 Hz
;ndone: ;mov a,GpifTrig
;jnb ACC.7,ndone
ST IfConfig,11001110b ;48 MHz intern, ASYNC, Master-Modus
mov AutoPtrSetup,#7 ;Autoptr aktivieren
mov dptr,#WaveDat
mov r2,#32
call SetWaveData
;alle Endpoints bis zur Konfiguration totlegen
ST EP1OutCfg,0
ST NEXT ;EP1INCFG
ST NEXT ;EP2CFG
ST NEXT ;EP4CFG
ST NEXT ;EP6CFG
ST NEXT ;EP8CFG
;ReNummerieren, um eigene bandbreiten-angepasste Beschreiber zu liefern
;Wieder-Aufzählung ist am vorhandenen String-Deskriptor detektierbar
LD USBCS
IF not always_renum
jnb ACC.7,nohs ;HSM-Bit (wenn schon mit High-Speed gestartet)
setb HighSpeed
setb Led2
mov r2,a
STORE WAVEDATA+1,04h ;Zeit ändern
mov a,r2
nohs: jb ACC.1,noren ;ReNum überspringen, falls vom EEPROM geladen
ENDIF
setb ACC.3 ;DisCon
ST
setb ACC.1 ;ReNum
ST
mov r5,#24 ;1,5 Sekunden warten
mov r3,#0
w2: call w1 ;verputzt R4=0
djnz r3,w2 ;braucht 65 ms
djnz r5,w2
xch a,r4 ;A=0
dec a ;A=0FFh
ST USBIRQ ;alle alten Interruptanforderungen löschen
;ST IBNIRQ
;ST NAKIRQ
;ST EPIRQ
ST GPIFIRQ
ST USBERRIRQ
xch a,r4
clr ACC.3 ;DisCon
ST USBCS
noren:
setb Led ;LED einschalten
setb ADC_RESET ;ADU aktivieren
;ST GpifTcB3,0FFh ;GPIF "unendlich" arbeiten lassen
mov DPL1,#LOW(Sinustabelle)
mov DPH1,#HIGH(Sinustabelle)
;Sinustabelle berechnen(?)
;Timer0 aktivieren
mov TH0,#-80 ;ergibt 4 MHz / 80 = 50 kHz (20 µs)
mov TMOD,#00000010b ;8-bit-Zähler mit Auto-Reload
mov IE,#10000010b ;globale und Timer0-Interrupt ein
;setb PT0 ;Kommentar entfernen bei weiteren Interrupts!
setb TR0 ;Timer starten
;===================
;== Hauptschleife ==
;===================
mainloop:
LD USBIRQ ;USB-Interrupts prüfen
jz nu4 ;Kurzschluss-Sprung
ST ;alle Anforderungen löschen
mov IntReq,a
jnb IntReq.0,nu0 ;SUDAV-Anforderung?
clr a ;lang (Blinken mit 2 Hz)
call StartLed
call HandleSUD
LD EP0CS ;BUSY-Bit belassen
mov ACC.0,c ;Ep0Stall-Bit einsetzen
setb ACC.7 ;HSNAK setzen
ST
nu0:
jnb IntReq.1,nu1 ;SOF-Anforderung?
LD USBFRAMEL
CJE a,FrameCnt,nu1 ;Nur "ganze" Rahmen interessieren hier!
mov FrameCnt,a
ST GpifTcB3,0FFh ;GPIF "unendlich" arbeiten lassen
;Zugriff auf dieses Reg. unzulässig?
jnb Led2Blink,n2
djnz Led2Time,n2
cpl Led2 ;grüne LED umschalten
clr Led2Blink
n2:
jnb LedBlink,nu1 ;LED blinkt?
djnz Blink,nbl
cpl Led
mov Blink,BlinkF
nbl: djnz LedTime,nu1
setb Led ;Nach paar Millisekunden bleibt das Licht an
clr LedBlink
nu1:
jnb IntReq.3,nu3 ;Einschlaf-Anforderung?
;Irgendwie kommt es beim Busaufzählen zu 2 Einschlaf-Aufforderungen,
;die zum "Defekt" des USB-Gerätes führen.
;Dazu muss SET CONFIURATION abgewartet werden!
mov a,Configuration
jz nu3
clr HighSpeed ;muss zu Full Speed zurückfallen
clr Led2
mov OEA,#0 ;alles hochohmig und Energie sparend
mov PCON,#31h ;Tiefschlaf hier
mov OEA,#0FFh ;Tiefschlaf beendet
nu3:
jnb IntReq.4,nu4 ;USB-Reset?
;ohne Behandlung folgt Absturz beim Booten mit angestecktem Gerät!
mov Configuration,#0
call ResTog2 ;etwa wie SetInterface (=SetAltSetting)
nu4:
jnb IntReq.5,nu5 ;HSGrant
setb HighSpeed
setb Led2
call SetGpif
nu5:
;LD EPIRQ geht nicht mit ISO!
SyncDelay
LD GpifIrq
SyncDelay
ST ;alle Anforderungen löschen
jnb ACC.1,nu6 ;GPIF: Aktivität?
mov a,#128
call StartLed ;LED schnell blinken lassen
nu6:
LD UsbErrIrq
ST ;alle Anforderungen löschen
jnb ACC.0,nu7 ;USB-Fehler am Limit?
ST ClrErrCnt ;Fehler-Zähler rücksetzen
mov Led2Time,#64 ;Zeit verlängern
jnb Led2Blink,nu7 ;wenn gesetzt, LED belassen
setb Led2Blink
cpl Led2 ;Grüne LED zeigt Fehler kurz an
nu7:
mov a,EP24FifoFlgs
rrc a ;Voll-Flag
jc voll
mov WirklichVoll,#1 ;umgehend ChipSelect aktivieren
voll: djnz WirklichVoll,nu8
mov ADC_CS,c ;A/D-Wandler deaktivieren wenn's voll bleibt
nu8:
; mov Led3,c
jmp mainloop
;USB-Deskriptoren
ALIGN 2
;********************************************
;** Antwort auf Get Descriptor: Device (1) **
;********************************************
;Geräte-Beschreiber (gleich für beide Geschwindigkeiten)
DeviceDescriptor:
db 18 ;bLength
db 1 ;bDescriptorType, 1=DEVICE
DWI 200h ;bcdUSB 2.0
db 0 ;bDeviceClass Multifunktion
db 0 ;bDeviceSubClass
db 0 ;bDeviceProtocol
db 64 ;bMaxPacketSize0
DWI 04B4h ;idVendor Cypress
DWI 8613h ;idProduct FX2
DWI 0004h ;bcdDevice Rev. D
db 1 ;iManufacturer (1)
db 2 ;iProduct (2)
db 0 ;iSerialNumber keine Seriennummer!
db 1 ;bNumConfigurations
;Geräte-Qualifizierer (gleich für beide Geschwindigkeiten)
DeviceQualifier:
db 10 ;bLength
db 6 ;bDescriptorType, 6=QUALIFIER
DWI 200h ;bcdUSB 2.0
db 0 ;bDeviceClass Multifunktion
db 0 ;bDeviceSubClass
db 0 ;bDeviceProtocol
db 64 ;bMaxPacketSize0
db 1 ;bNumConfigurations
db 0 ;bReserved
;********************************************
;** Antwort auf Get Descriptor: Config (2) **
;********************************************
ALIGN 2
ConfigDescFS: ;FullSpeed-Version
;Konfigurations-Beschreiber 0
db 9 ;bLength
db 2 ;bDescriptorType 2=CONFIG
DWI CfgEFS-ConfigDescFS ;wTotalLength
db 1 ;bNumInterfaces
db 1 ;bConfigurationValue (willkürliche Nummer dieser K.)
db 3 ;iConfiguration (3)
db 80h ;bmAttributes (Busversorgt, kein Aufwecken)
db 150/2 ;MaxPower (in 2 Milliampere), Problem am einfachen Hub
;Interface-Beschreiber 0, Alternative 0: ;ÄNDERUNG bei FX2-LP zweckmäßig
db 9 ;bLength
db 4 ;bDescriptorType 4=INTERFACE
db 0 ;bInterfaceNumber
db 0 ;bAlternateSetting
db 1 ;bNumEndpoints
db -1 ;bInterfaceClass hersteller-spezifisch
db -1 ;bInterfaceSubClass
db -1 ;bInterfaceProtocol
db 4 ;iInterface (4)
;Enden-Beschreiber C0I0A0:Bulk EP2IN (schlechte FIFO-Nutzung)
db 7 ;bLength
db 5 ;bDescriptorType 5=ENDPOINT
db 82h ;bEndpointAddress EP2IN
db 2 ;bmAttributes 2=Bulk
DWI 64 ;wMaxPacketSize
db 0 ;bInterval bedeutungslos bei Bulk IN
;Interface-Beschreiber 0, Alternative 1:
db 9 ;bLength
db 4 ;bDescriptorType 4=INTERFACE
db 0 ;bInterfaceNumber
db 1 ;bAlternateSetting
db 1 ;bNumEndpoints
db -1 ;bInterfaceClass hersteller-spezifisch
db -1 ;bInterfaceSubClass
db -1 ;bInterfaceProtocol
db 5 ;iInterface (5)
;Enden-Beschreiber C0I0A1:ISO EP2IN
db 7 ;bLength
db 5 ;bDescriptorType 5=ENDPOINT
db 82h ;bEndpointAddress EP2IN
db 1 ;bmAttributes 1=ISO, ohne Sync, Daten
DWI 1020 ;wMaxPacketSize
db 1 ;bInterval jeden Rahmen [2^(1-1)] = 1/ms
CfgEFS:
ALIGN 2
ConfigDescHS: ;HighSpeed-Version
;Konfigurations-Beschreiber 0
db 9 ;bLength
db 2 ;bDescriptorType 2=CONFIG
DWI CfgEHS-ConfigDescHS ;wTotalLength
db 1 ;bNumInterfaces
db 1 ;bConfigurationValue (willkürliche Nummer dieser K.)
db 3 ;iConfiguration (3)
db 80h ;bmAttributes (Busversorgt, kein Aufwecken)
db 260/2 ;MaxPower (in 2 Milliampere) 100 mA mehr als in FS
;Interface-Beschreiber 0, Alternative 0: ;ÄNDERUNG bei FX2-LP zweckmäßig
db 9 ;bLength
db 4 ;bDescriptorType 4=INTERFACE
db 0 ;bInterfaceNumber
db 0 ;bAlternateSetting
db 1 ;bNumEndpoints
db -1 ;bInterfaceClass hersteller-spezifisch
db -1 ;bInterfaceSubClass
db -1 ;bInterfaceProtocol
db 4 ;iInterface (4)
;Enden-Beschreiber C0I0A0:Bulk EP2IN
db 7 ;bLength
db 5 ;bDescriptorType 5=ENDPOINT
db 82h ;bEndpointAddress EP2IN
db 2 ;bmAttributes 2=Bulk
DWI 512 ;wMaxPacketSize
db 0 ;bInterval bedeutungslos bei Bulk IN
;Interface-Beschreiber 0, Alternative 1:
db 9 ;bLength
db 4 ;bDescriptorType 4=INTERFACE
db 0 ;bInterfaceNumber
db 1 ;bAlternateSetting
db 1 ;bNumEndpoints
db -1 ;bInterfaceClass hersteller-spezifisch
db -1 ;bInterfaceSubClass
db -1 ;bInterfaceProtocol
db 5 ;iInterface (5)
;Enden-Beschreiber C0I0A1:ISO EP2IN
db 7 ;bLength
db 5 ;bDescriptorType 5=ENDPOINT
db 82h ;bEndpointAddress EP2IN
db 1 ;bmAttributes 1=ISO, ohne Sync, Daten
DWI 512 ;wMaxPacketSize
db 1 ;bInterval jeden Mikrorahmen [2^(1-1)]
;Interface-Beschreiber 0, Alternative 2:
db 9 ;bLength
db 4 ;bDescriptorType 4=INTERFACE
db 0 ;bInterfaceNumber
db 2 ;bAlternateSetting
db 1 ;bNumEndpoints
db -1 ;bInterfaceClass hersteller-spezifisch
db -1 ;bInterfaceSubClass
db -1 ;bInterfaceProtocol
db 6 ;iInterface (6)
;Enden-Beschreiber C0I0A2:INT EP2IN
db 7 ;bLength
db 5 ;bDescriptorType 5=ENDPOINT
db 82h ;bEndpointAddress EP2IN
db 3 ;bmAttributes 3=INT
DWI 512 ;wMaxPacketSize
db 1 ;bInterval jeden Mikrorahmen [2^(1-1)]
CfgEHS:
;***=======******************************************
;** Etwaige Antwort auf Get Descriptor: String (3) **
;***=======******************************************
StringDescriptors:
;Wer Umlaute oder Chinesisch mag, muss für die folgenden Strings einen Editor
;benutzen, welcher entweder ISO-Latin1 oder UTF-8 speichert!
;(ASEM51 frisst aber keine Umlaute! Bug!)
db 0D0h,087h,0 ;Deutsch (0407h in UTF8)
db "Thomas Koch @ cypress.com",0
db "ADC2USB - Schnelle A/D-Wandler am USB",0
db "Busversorgt, kein Aufwecken",0
db "Interface ohne Bandbreite, nur Bulk",0
db "Interface mit ISO-Bandbreite",0
db "Interface mit Interrupt-Transfer, nur USB 2.0",0
ALIGN 256
StringPuffer: ds 100h ;Dieser Puffer darf Seitengrenze nicht überlappen!
ORG 1000h
SinusTabelle:
$include(sintab.i51)
END
Detected encoding: ANSI (CP1252) | 4
|
|