A51 MACRO ASSEMBLER SPEAKER 01/28/2001 14:47:27 PAGE 1 MACRO ASSEMBLER A51 V6.10 OBJECT MODULE PLACED IN .\SPEAKER.OBJ ASSEMBLER INVOKED BY: C:\Keil\C51\BIN\A51.EXE .\SPEAKER.A51 REGISTERBANK(0) SET(SMALL) DEBUG EP LOC OBJ LINE 0040 0088 0089 008A 008C 00A8 00E8 0091 00D8 0092 0086 7FE1 7FF0 7F71 7F60 7FE8 7FD4 7FB4 7F00 7EC0 7E80 7FB5 7FC5 7FB7 7FAC 7FA9 7FAD 7FAA 7FAE +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 SOURCE NAME Speaker ; ; Copyright (C) 2001, Intel Corporation ; All rights reserved. ; Permission is hereby granted to merge this program code with other program ; material to create a derivative work. This derivative work may be distributed ; in compiled object form only. Any other publication of this program, in any form, ; without the explicit permission of the copyright holder is prohibited. ; ; Send questions and comments to John.Hyde@intel.com ; ; ; Derived from BAL Version 3.5 ; ; This is a simple 8-bit mono speaker example (suitable for speech and sound effects). ; It is an Audio Class device with a single (16KHz) sampling frequency ; The hardware includes a USBSIMM, latching DAC and an op amp ; ; This version works dScope monSIO0.hex (uses Serial Port 0, loads at 1200H) ; EP0Size EQU 64 ; For EZ-USB ; ;$include (Declare.A51) ; This module declares the variables and constants used in the examples ; It is common to all of the examples ; ; Declare Special Function Registers used TimerControl DATA 088H TimerMode DATA 089H Timer0Low DATA 08AH Timer0High DATA 08CH EI DATA 0A8H EIE DATA 0E8H ; EZ-USB specific EXIF DATA 091H ; EZ-USB specific EICON DATA 0D8H ; EZ-USB specific PageReg DATA 092H ; EZ-USB specific, used with MOVX @Ri DPS DATA 086H ; EZ-USB specific, used with dual data pointers ; ; "External" memory locations used, EZ-USB specific ; Note that most of these variables are in Page 7FH IsoOutValid EQU 07FE1H EP8OutStartAddr EQU 07FF0H EP8OutBCL EQU 07F71H EP8OutData EQU 07F60H SETUPDAT EQU 07FE8H SUDPTR EQU 07FD4H EP0Control EQU 07FB4H EP0InBuffer EQU 07F00H EP0OutBuffer EQU 07EC0H ; Not in Page 7FH EP1InBuffer EQU 07E80H ; Not in Page 7FH IN0ByteCount EQU 07FB5H Out0ByteCount EQU 07FC5H IN1ByteCount EQU 07FB7H IN07IEN EQU 07FACH IN07IRQ EQU 07FA9H OUT07IEN EQU 07FADH OUT07IRQ EQU 07FAAH USBIEN EQU 07FAEH A51 MACRO ASSEMBLER 2 7FAB 7FD6 7FA6 7FA5 7F93 7F94 7F95 7F96 7F97 7F98 7F99 7F9A 7F9B 7F9C 7F9D 7F9E ---0020 0000 0001 0002 0003 0004 0021 0040 0040 0041 0043 0043 0044 0045 0046 0047 0048 0048 0049 004A 004B 004C 004D 004E 004F 0050 0051 0060 0060 ---0000 0212E2 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 SPEAKER 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 01/28/2001 14:47:27 PAGE USBIRQ EQU USBControl EQU I2CData EQU I2CControl EQU PortA_Config EQU PortB_Config EQU PortC_Config EQU PortA_OUT EQU PortB_OUT EQU PortC_OUT EQU PortA_PINS EQU PortB_PINS EQU PortC_PINS EQU PortA_OE EQU PortB_OE EQU PortC_OE EQU ; ; Byte Variables 07FABH 07FD6H 07FA6H 07FA5H 07F93H 07F94H 07F95H 07F96H 07F97H 07F98H 07F99H 07F9AH 07F9BH 07F9CH 07F9DH 07F9EH DSEG FLAGS: DS ; Bit Variables Configured EQU STALL EQU SendData EQU IsDescriptor EQU SetAddress EQU ; MonitorSpace: DS DataSpace: ReplyCount: DS ReplyBuffer: DS CurrentConfiguration: DS AltSetting: DS SaveDPH: DS SaveDPL: DS SaveLength: DS SetupData: RequestType: DS Request: DS wValueLow: DS wValueHigh: DS wIndexLow: DS wIndexHigh: DS wLengthLow: DS wLengthHigh: DS ; INT0counter: DS SOFcounter: DS AT 20H 1 ; This register is bit-addressable FLAGS.0 FLAGS.1 FLAGS.2 FLAGS.3 FLAGS.4 ; ; ; ; ; 1FH ; Used by Dscope 1 2 ; Byte count for following buffer ; Buffer for immediate reply 1 1 1 1 1 ; Some examples support > 1 configurations ; Speaker has two alternate settings (0, 1) ; Needed to save Descriptor Pointer .. ; .. for descriptors > EP0Size ; Number of bytes still to send ; Buffer in direct access memory ORG 60H IsoDataBuffer: DS Is this device configured Need to STALL endpoint 0 Need to send data to PC Host Enable a shortcut reply Set the SIE address 1 1 1 1 1 1 1 1 1 1 ; Put on a xxx00000B boundary 16 ;$include (EZInt.A51) ; This module contains all the EZUSB-specific hardware code ; This module also contains all of the interrupt vector declarations and ; the first level interrupt servicing (register save, call subroutine, ; clear interrupt source, restore registers, return) ; Suspend and Resume are handled totally in this module ; ; A Reset sends us to Program space location 0 CSEG AT 0 ; Code space USING 0 ; Reset forces Register Bank 0 LJMP Reset ; A51 MACRO ASSEMBLER 3 000B 000B 02121C 0043 0043 021200 1200 1200 1203 1204 1207 1208 120B 120C 120F 1210 1213 1214 1217 1218 02126A 00 02124D 00 02121B 00 02121B 00 02122F 00 02121B 00 02123C 121B 121B 121B 121B 121B 121B 121B 121B 121B 121B 121B 121B 121B 121B 121B 121B 32 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 SPEAKER 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 01/28/2001 14:47:27 PAGE ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; The interrupt vector table is also located here EZ-USB has two levels of USB interrupts: 1-the main level is described in this table (at ORG 43H) 2-there are 21 sources of USB interrupts and these are described in USB_ISR This means that two levels of acknowledgement and clearing will be required LJMP INT0_ISR ; Features not used are commented out ORG 0BH LJMP Timer0_ISR ORG 13H LJMP INT1_ISR ORG 1BH LJMP Timer1_ISR ORG 23H LJMP UART0_ISR ORG 2BH LJMP Timer2_ISR ORG 33H LJMP WakeUp_ISR ORG 3BH LJMP UART1_ISR ORG 43H LJMP USB_ISR ; Auto Vector will replace byte 45H ORG 4BH LJMP I2C_ISR ORG 1200H ; Load above monSIO0.hex USB_ISR:LJMP SUDAV_ISR DB 0 ; Pad entries to 4 bytes LJMP SOF_ISR DB 0 LJMP SUTOK_ISR DB 0 LJMP Suspend_ISR DB 0 LJMP USBReset_ISR DB 0 LJMP Reserved DB 0 LJMP EP0In_ISR ; DB 0 ; Comment out features not used ; LJMP EP0Out_ISR ; DB 0 ; LJMP EP1In_ISR ; DB 0 ; LJMP EP1Out_ISR ; DB 0 ; End of Interrupt Vector tables ; When a feature is used insert the required interrupt processing here ; The example use only used Endpoints 0 and 1 and also SOF for timing Reserved: INT0_ISR: INT1_ISR: Timer1_ISR: UART0_ISR: Timer2_ISR: UART1_ISR: I2C_ISR: SUTOK_ISR: EP0Out_ISR: EP1In_ISR: EP1Out_ISR: Suspend_ISR: WakeUp_ISR: Not_Used: ; Should not get any of these RETI A51 MACRO ASSEMBLER 4 121C 121C 121E 121F 1220 1221 1222 1225 1227 D2D3 C6 F3 C6 08 53080F C2D3 32 1228 1228 122A 122C 122E E591 C2E4 F591 22 122F 122F C200 1231 9010AB 1234 1234 1236 1238 123A 123B 123C 123C 123E 1240 1243 1246 1248 1248 124B 124D 124D 124F 1251 1253 1254 1256 1256 1258 1259 125A 125B 125D 125F 125F 1261 1262 1263 5128 747F C583 F0 32 E547 6008 854583 854682 51B7 9001A9 80E7 7F10 7960 7871 E2 6009 7860 E2 F7 09 DFFB 8006 E56F F7 09 DFFC 1265 9002AB 1268 80CA 126A 126A 126D 1270 1272 754700 907FE8 7848 7F08 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 SPEAKER 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 01/28/2001 14:47:27 PAGE Timer0_ISR: ; Timer0 has just overflowed. ; This routine must be as fast as possible. Note that it changes no flags SETB RS0 ; Use alternate register bank RB1 XCH A, @R0 ; Save A and GetNextValue. MOVX @R1, A ; Send next sample to DAC XCH A, @R0 ; Restore A INC R0 ; Point to next entry ANL 8, #00001111B ; Memory 8 = R0 in RB1. Maintain a circular buffer CLR RS0 RETI ; Interrupt flag is cleared by the hardware ClearINT2: MOV CLR MOV RET ; Tell the hardware that we're done A, EXIF ACC.4 EXIF, A ; Clear the Interrupt 2 bit USBReset_ISR: ; Bus has been Reset, move to DEFAULT state CLR Configured MOV DPTR, #(1000H OR LOW(USBIRQ)) ExitISR: ; Common exit for all ISR's ; On entry DPH = Interrupt ID, DPL = LOW(Interrupt Register) CALL ClearINT2 MOV A, #7FH ; EZ-USB I/O Register Page XCH A, DPH MOVX @DPTR, A ; Clear source of interrupt RETI EP0In_ISR: MOV JZ MOV MOV CALL NoMoreToSend: MOV JMP ; A prepared packet has been read by PC host A, SaveLength ; Do I have any more data to send? NoMoreToSend DPH, SaveDPH ; Retreive descriptor pointer DPL, SaveDPL SendNextPieceOfDescriptor DPTR, #(100H OR LOW(IN07IRQ)) ExitISR SOF_ISR: ; A Start-Of-Frame packet has been received MOV R7, #16 ; We need 16 samples every frame MOV R1, #IsoDataBuffer MOV R0, #LOW(EP8outBCL) ; Point to (low) of bytes received MOVX A, @R0 ; Did we get a sample in the last frame? JZ RepeatLastSample GetNewSamples: MOV R0, #LOW(EP8OutData) GNSLoop:MOVX A, @R0 ; Copy ISO data to direct access buffer MOV @R1, A INC R1 DJNZ R7, GNSLoop SJMP Done RepeatLastSample: MOV A, IsoDataBuffer+15 ; Get last sample RLSLoop:MOV @R1, A INC R1 DJNZ R7, RLSLoop ; Done: MOV DPTR, #(200H OR LOW(USBIRQ)) JMP ExitISR SUDAV_ISR: MOV MOV MOV MOV SaveLength, #0 DPTR, #SETUPDAT R0, #SetupData R7, #8 ; A Setup packet has been received ; Clear any pending transactions (if any) ; Copy packet to direct access memory A51 MACRO ASSEMBLER 5 SPEAKER 1274 1275 1276 1277 1278 127A 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 E0 F6 A3 08 DFFA 716A 127C 200126 127F 300216 1282 200324 1285 1288 128A 128C 128D 128E 1290 1291 1293 1294 1294 1297 1297 1298 1298 129A 129A 129D 129E 129F 12A0 12A3 12A5 12A5 12A7 12A9 12A9 12AA 12AC 12AE 12AF 12B0 12B2 12B4 12B6 12B6 12B7 12B7 12B7 12B8 907F01 7842 7F02 E6 F0 1582 18 DFF9 E6 907FB5 F0 7F02 907FB4 E0 4F F0 9001AB 808F 7F03 80F1 FF E54F 7008 EF C3 954E E54E 5001 EF FF 754700 12BB C3 12BC 9440 12BE 4015 12C0 F547 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 01/28/2001 14:47:27 PAGE CopySD: MOVX A, @DPTR MOV @R0, A INC DPTR INC R0 DJNZ R7, CopySD CALL ServiceSetupPacket ; Handle the decode of the Setup packet ; if SetAddress { Update SIE address } // NOP on EZ-USB ; if STALL { Stall the endpoint } ; if SendData { ; if IsDescriptor { send DPTR->descriptor, A = length } ; else { send ReplyBuffer } ; } JB STALL, SendSTALL JNB SendData, HandShake JB IsDescriptor, LoadEP0 ; Send data in ReplyBuffer MOV DPTR, #EP0InBuffer+1 MOV R0, #ReplyBuffer+1 MOV R7, #2 ; Copy the two byte buffer CopyRB: MOV A, @R0 MOVX @DPTR, A DEC DPL DEC R0 DJNZ R7, CopyRB MOV A, @R0 ; Get BufferCount SendEP0InBuffer: MOV DPTR, #In0ByteCount StartXfer: MOVX @DPTR, A ; This write initiates the transfer HandShake: ; Handshake with host MOV R7, #00000010b ; Set HSNAK to tell the SIE that we're done SetEP0Control: MOV DPTR, #EP0Control MOVX A, @DPTR ORL A, R7 MOVX @DPTR, A ; We're done MOV DPTR, #(100H OR LOW(USBIRQ)) JMP ExitISR SendSTALL: ; Invalid Request was received MOV R7, #00000011b ; Set EP0STALL and HSNAK JMP SetEP0Control LoadEP0: ; Send the data pointed to by DPTR MOV R7, A ; Save LENGTH ; Need to return the smaller of "Requested Length" and "Actual Length" ; If "Requested Length" > 255 then use "Actual Length" ; There are no descriptors > 255 in this example MOV A, wLengthHigh JNZ UseActual MOV A, R7 ; Retreive LENGTH CLR C SUBB A, wLengthLow MOV A, wLengthLow ; This does not affect Carry JNC UsewLengthLow UseActual: MOV A, R7 UsewLengthLow: SendNextPieceOfDescriptor: ; DPTR -> Descriptor to be sent MOV R7, A ; Save LENGTH again MOV SaveLength, #0 ; Default case, overwrite if necessary ; Do I have more than a single packet to send? CLR C SUBB A, #EP0Size JC SendPacket ; Need to send multiple packets. ; Calculate and save address of next packet, send next packet now MOV SaveLength, A ; Send these next time A51 MACRO ASSEMBLER 6 SPEAKER 12C2 12C4 12C6 12C8 12C9 12CB 12CE 12D1 12D3 12D5 12D5 12D6 12D7 12D9 12DA 12DB 12DC 12DD 12DF 12E0 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 7F40 C083 C082 EF 71AD 858345 858246 D082 D083 EF FE 7800 E0 F2 A3 08 DEFA EF 80B2 12E2 12E2 7581DF 12E5 75927F 12E8 12EA 12EB 12ED 12EE 12F0 12F1 12F3 12F4 12F5 78D6 E2 54F3 F2 7158 E2 4406 F2 E4 F520 12F7 12F7 12F9 12FB 12FC 12FD 12FE 12FF 1300 1301 1302 1303 1304 1305 1306 1308 1309 130B 7893 799C 04 F2 F3 08 09 14 F2 F4 F3 08 09 74C3 F2 74C2 F3 130C E589 130E 54F0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 01/28/2001 14:47:27 PAGE MOV PUSH PUSH MOV CALL MOV MOV POP POP SendPacket: MOV MOV MOV CopySTD:MOVX MOVX INC INC DJNZ MOV JMP R7, #EP0Size DPH DPL A, R7 BumpDPTR SaveDPH, DPH SaveDPL, DPL DPL DPH A, R7 R6, A R0, #LOW(EP0InBuffer) A, @DPTR @R0, A DPTR R0 R6, CopySTD A, R7 SendEP0InBuffer ; Save current pointer ; Retreive length ; Retreive length ; Save length in R6 for move ; PageReg = 7FH = HIGH(EP0InBuffer) ; Retrieve LENGTH ;$include (EZMain.A51) ; This module initializes the microcontroller then executes MAIN forever ; It is hardware dependant Reset: MOV MOV SP, #0DFH PageReg, #7FH ; Initialize the Stack ; Allows MOVX Ri to access EZ-USB memory MOV MOVX ANL MOVX CALL MOVX ORL MOVX CLR MOV R0, #Low(USBControl) A, @R0 A, #11110011b @R0, A Wait200msec A, @R0 A, #00000110b @R0, A A FLAGS, A ; Simulate a disconnect InitializeIOSystem: ; Clear DISCON, DISCOE ; ; ; ; Give the host time to react Reconnect with this new identity Set DISCOE to enable pullup resistor Set RENUM so that 8051 handles USB requests ; Start in Default state ; Setup for Simmbus A and B=output ; C=External RD#,WR#,TD0,TR0 ; PageReg = 7F = HIGH(PortA_Config) MOV R0, #LOW(PortA_Config) MOV R1, #LOW(PortA_OE) INC A ; MOVX @R0, A ; MOVX @R1, A ; INC R0 ; INC R1 ; DEC A ; MOVX @R0, A ; CPL A ; MOVX @R1, A ; INC R0 ; INC R1 ; MOV A, #11000011b ; MOVX @R0, A ; MOV A, #11000010b MOVX @R1, A ; ; Use Timer 0 since dScope is using 1 (or MOV A, TimerMode ANL A, #11110000B ; = 00000001B Alternate function on bit 0 = Timer0 Out Enable PortA for Input[7:1], Output[0] Point to PortB_Config Point to PortB_OE = 0 No alternate functions = 0FFH Enable PortB for Output Point to PortC_Config Point to PortC_OE Alternate functions on [7,6,1,0] Most alternate functions are outputs 2) Program Timer0 without changing Timer1 A51 MACRO ASSEMBLER 7 SPEAKER 1310 4402 1312 F589 1314 758C80 1317 758A9B starting 131A 131A 78E1 131C 7401 131E F2 131F 18 1320 E4 1321 F2 1322 78F0 1324 F2 1325 1325 7401 1327 78AC 1329 F2 132A 08 132B E4 132C F2 132D 08 132E 7413 +1 +1 +1 +1 389 390 391 392 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 1330 1331 1332 1334 1335 1335 1337 1339 133B 133D 133E 133F 1340 1342 F2 08 7401 F2 1344 1346 1348 1349 1349 134A 134D 78AB 7402 F2 D2D3 7870 7997 7F10 E4 18 F6 DFFC C2D3 E2 30E1FC D28C 134F 75E801 1352 75A892 1355 1355 00 1356 80FD 1358 1358 135A 135A 135D 1360 1361 1363 1365 7FC8 758600 90FB50 A3 E582 4583 70F9 01/28/2001 14:47:27 PAGE ORL MOV MOV MOV A, #00000010B TimerMode, A Timer0High, #128 Timer0Low, #(255-100) ; Timer0 = 8 bit auto reload ; 128 x 2MHz = 64usec ; First interrupt will occur 50usec after InitializeEndpoints: MOV R0, #LOW(IsoOutValid) ; MOV A, #00000001B ; MOVX @R0, A ; DEC R0 ; CLR A MOVX @R0, A ; MOV R0, #LOW(EP8OutStartAddr) MOVX @R0, A ; InitializeInterruptSystem: ; MOV A, #00000001b MOV R0, #LOW(IN07IEN) MOVX @R0, A ; INC R0 CLR A MOVX @R0, A ; INC R0 MOV A, #00010011b ; Enable USBReset, (Resume, Suspend,) SOF MOVX @R0, A INC R0 MOV A, #00000001b MOVX @R0, A ; InitializeInterruptVariables: SETB RS0 ; MOV R0, #IsoDataBuffer+16 MOV R1, #LOW(PortB_Out) MOV R7, #16 CLR A IIVLoop:DEC R0 MOV @R0, A DJNZ R7, IIVLoop CLR RS0 ; ; Synchronize start of Timer0 with SOF MOV R0, #LOW(USBIRQ) MOV A, #00000010B MOVX @R0, A ; WaitForNextSOF: MOVX A, @R0 JNB ACC.1, WaitForNextSOF SETB TimerControl.4 ; ; MOV EIE, #00000001B ; MOV EI, #10010010B ; ; EZ-USB uses Endpoints 8-15 for iso traffic We'll use EP8, double buffered Enable EP8 OUT Point to IsoInValid Disable EP8-15 In Use the beginning of the ISO buffer First initialize the USB level Enable interrupts from EP0IN only Disable interrupts from OUT Endpoints 0-7 and SUDAV INTs Enable Auto Vectoring for USB interrupts Select RB1 (used to service INT0) Go back to RB0 for MAIN Clear pending SOF Start Timer0 Now enable the main level Enable INT2 = USB Interrupt (only) Enable interrupt subsystem and Ser0 for dScope and Timer0 ; Initialization Complete. ; MAIN: NOP ; Not much of a main loop for this example JMP MAIN ; All actions are initiated by interrupts ; We are a slave, we wait to be told what to do Wait200msec: MOV Wait1msec: MOV MOV More: INC MOV ORL JNZ R7, #200 DPS, #0 DPTR, #-1200 DPTR A, DPL A, DPH More ; A delay loop ; Select primary DPTR ; ; ; ; 3 + + + cycles 2 2 3 = 10 cycles x 1200 = 1msec A51 MACRO ASSEMBLER 8 SPEAKER 1367 DFF1 1369 22 +1 +1 +1 +1 +1 +1 +1 +1 455 456 457 458 459 460 461 462 463 464 465 466 467 468 +1 +1 469 470 MOV ANL SendData, C A, #01011100b +1 +1 +1 +1 +1 +1 471 472 473 474 475 476 JNZ MOV MOV ANL JC JNB BadRequest A, RequestType C, ACC.0 C, ACC.1 BadRequest ACC.5, NotB5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 477 478 479 480 481 482 483 484 485 486 487 488 489 MOV ANL SWAP MOV A, #00000011b A, #00000011b A R7, A +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 ; Since the table only contains byte offsets, it is important that all these routines +1 +1 +1 516 517 518 ; within one page (100H) of Subroutines ; V3.0 - CommandTable moved outside of this one page limited space CommandTable: ---136A 136A E548 136C A2E7 to P +1 +1 +1 +1 01/28/2001 14:47:27 PAGE DJNZ RET R7, Wait1msec ;$include (Decode.A51) ; This module is common to all of the examples. ; It decodes the USB Setup Packets and generates appropriate responses. ; Interpretation of Reports is handled by MAIN ; CSEG ServiceSetupPacket: MOV A, RequestType MOV C, ACC.7 ; Bit 7 = 1 means IO device needs to send data C Host 136E 9202 1370 545C BadRequest 1372 7035 1374 E548 1376 A2E0 1378 82E1 137A 402D 137C 30E502 [1, ; IF RequestType[6.4.3.2] = 1 THEN goto ; IF RequestType[1&0] = 1 THEN goto BadRequest ; IF RequestType[5] = 1 THEN RequestType[1,0] = 1] 137F 1381 1383 1384 7403 5403 C4 FF 1385 1387 1389 138B 138D 138F E549 54F0 701E E549 540F 4F 1390 to 1390 1393 1396 1399 139B 139D 139F 13A2 13A4 13A5 13A8 754001 754100 754200 C204 C201 C203 9013B6 71AD E0 9013F6 73 13A9 13A9 D201 13AB 22 13AC 13AC 13AD 13AD 13AF 13B1 13B3 13B5 E0 2582 F582 5002 0583 22 NotB5: MOV A, Request ANL A, #11110000b JNZ BadRequest MOV A, Request ANL A, #00001111b ORL A, R7 ; CALL CorrectSubroutine CorrectSubroutine: MOV MOV MOV CLR CLR CLR MOV CALL MOVX MOV JMP BadRequest: SETB RET NextDPTR: MOVX BumpDPTR: ADD MOV JNC INC Skip: RET ReplyCount, #1 ReplyBuffer, #0 ReplyBuffer+1, #0 SetAddress STALL IsDescriptor DPTR, #CommandTable BumpDPTR A, @DPTR DPTR, #Subroutines @A+DPTR ; Set CommandIndex[5,4] = RequestType[1,0] ; Save HI nibble of CommandIndex ; Set CommandIndex[3,0] = Request[3,0] ; Check if Request > 15 ; Only 13 are defined today, handle in table ; goto CommandTable(CommandIndex) ; Jump to the subroutine that DPTR is pointing ; Set up a default reply ; Clear all flags ; Point to entry ; Get the offset ; Go to the correct Subroutine ; Decoded a Bad Request, STALL the Endpoint STALL ; Support routines ; Returns (DPTR + byte DPTR is pointing to) A, @DPTR ; Returns (DPTR + ACC) A, DPL DPL, A Skip DPH ; Need 16 bit arithmetic here are 13B6 A51 MACRO ASSEMBLER 9 13B6 13B7 13B8 13B9 13BA 13BB 13BC 13BD 13BE 13BF 13C0 13C1 13C2 13C3 13C4 13C5 0A 00 00 00 00 03 39 00 06 12 00 00 00 00 00 00 13C6 13C7 13C8 13C9 13CA 13CB 13CC 13CD 13CE 13CF 13D0 13D1 13D2 13D3 13D4 13D5 0E 00 00 00 00 00 00 00 00 00 30 20 00 00 00 00 13D6 13D7 13D8 13D9 13DA 13DB 13DC 13DD 13DE 13DF 13E0 13E1 13E2 13E3 13E4 13E5 0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13E6 13E7 13E8 13E9 13EA 13EB 13EC 13ED 13EE 13EF 13F0 13F1 13F2 13F3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 SPEAKER 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 01/28/2001 14:47:27 PAGE ; First 16 commands are for the Device DB LOW(Device_Get_Status - Subroutines) DB LOW(Device_Clear_Feature - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Device_Set_Feature - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Set_Address - Subroutines) DB LOW(Get_Descriptor - Subroutines) DB LOW(Set_Descriptor - Subroutines) DB LOW(Get_Configuration - Subroutines) DB LOW(Set_Configuration - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) ; Next 16 commands are for the Interface DB LOW(Interface_Get_Status - Subroutines) DB LOW(Interface_Clear_Feature - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Interface_Set_Feature - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Get_Class_Descriptor - Subroutines) DB LOW(Set_Class_Descriptor - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Get_Interface - Subroutines) DB LOW(Set_Interface - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) ; Next 16 commands are for the Endpoint DB LOW(Endpoint_Get_Status - Subroutines) DB LOW(Endpoint_Clear_Feature - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Endpoint_Set_Feature - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Endpoint_Sync_Frame - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) ; Next 16 commands are Class Requests DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) A51 MACRO ASSEMBLER 10 SPEAKER 13F4 00 13F5 00 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 13F6 13F6 13F6 13F6 13F6 13F6 13F6 13F6 13F6 13F6 13F6 13F6 13F6 13F6 13F6 D201 13F8 22 13F9 13F9 D204 13FB 22 13FC 13FC 854341 13FF 22 1400 1400 754101 Powered(=1) 1403 22 1404 1404 1404 754002 1407 22 1408 1408 E54A 140A 6004 140C 14 140D 70E7 140F 04 1410 1410 F543 1412 13 1413 9200 1415 22 1416 1416 E54C 1418 14 1419 70DB 141B E54A 141D 6003 141F 14 1420 70D4 1422 854A44 1425 22 1426 1426 E54C 1428 14 1429 70CB 142B 854441 142E 22 142F 142F D203 01/28/2001 14:47:27 PAGE DB LOW(Invalid - Subroutines) DB LOW(Invalid - Subroutines) Subroutines: ; ; Many requests are INVALID for this example Set_Descriptor: ; Our Descriptors are static Set_Class_Descriptor: ; Our Descriptors are static Get_Class_Descriptor: ; We have no features that the PC host can read Set_Idle: ; V3.0 Optional command, not supported Get_Idle: ; V3.0 Optional command, not supported Device_Set_Feature: ; We have no features that can be set or cleared Interface_Set_Feature: ; We have no features that can be set or cleared Endpoint_Set_Feature: ; We have no features that can be set or cleared Endpoint_Clear_Feature: ; V3.0 We have no features that can be set or cleared Device_Clear_Feature: ; We have no features that can be set or cleared Interface_Clear_Feature: ; We have no features that can be set or cleared Endpoint_Sync_Frame: ; We are not an Isonchronous device Invalid: SETB Reply: RET STALL ; Invalid Request made, STALL the Endpoint Set_Address: SETB RET SetAddress ; Set the address that the SIE will respond to Get_Configuration: ; Respond with CurrentConfiguration MOV ReplyBuffer, CurrentConfiguration RET Device_Get_Status: ; Only two bits of Device Status are defined MOV ReplyBuffer, #1 ; Bit 1=Remote Wakeup(=0), Bit 0=Self RET Interface_Get_Status: Endpoint_Get_Status: MOV ReplyCount, #2 RET Set_Configuration: MOV A, wValueLow JZ Deconfigured DEC A JNZ Invalid INC A Deconfigured: MOV CurrentConfiguration, A RRC A MOV Configured, C RET Set_Interface: MOV A, wIndexLow DEC A JNZ Invalid MOV A, wValueLow JZ OKtoSet DEC A JNZ Invalid OKtoSet:MOV AltSetting, wValueLow RET Get_Interface: MOV A, wIndexLow DEC A JNZ Invalid MOV ReplyBuffer, AltSetting RET Get_Descriptor: SETB IsDescriptor ; Interface Status is currently defined as 0 ; Need a two byte 0 response ; Valid values are 0 and 1 ; Restore wValueLow ; Copy bit 0 into C ; Set Interface 1 Alternate setting ; Check PC Host is using interface #1 ; Valid values are 0 and 1 ; Return Interface 1 Alternate setting ; Check PC Host is using interface #1 ; Host wants to know who/what we are A51 MACRO ASSEMBLER 11 SPEAKER 1431 1433 1434 1437 1439 143A 143D 143F 1441 1442 1442 1443 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 ;$include (DTables.A51) ; This module declares the descriptors ; ; This example has one Device Descriptor with: ; One Configuration - 8-bit mono PCM speaker ; Two Interfaces: ; AudioControl - with two units ; AudioStreaming - with two ALT settings ; Multiple Sting Descriptors - to aid the user ; CSEG DeviceDescriptor: DB 18, 1 ; Length, Type DB 10H, 1 ; USB Rev 1.1 (=0110H, low=10H, High=01H) DB 0, 0, 0 ; Class, Subclass and Protocol DB EP0Size DB 42H, 42H, 9H, 0, 0, 1 ; Vendor ID, Product ID and Version +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 DB 1, 2, 0 ; Manufacturer, Product & Serial# Names DB 1 ; #Configs ConfigurationDescriptor: DB 9, 2 ; Length, Type DB LOW(ConfigLength), HIGH(ConfigLength) DB 2, 1, 0 ; #Interfaces, Configuration#, Config. Name DB 10000000b ; Attributes = Bus Powered DB 250 ; Max. Power is 250x2 = 500mA AudioControlInterface: DB 9, 4 ; Length, Type DB 0, 0, 0 ; ID, No alternate setting, only uses EP0 DB 1 ; Class = Audio DB 1 ; Sub-class = Audio Control DB 0 ; Protocol DB 3 ; Interface name E54B 14 901458 601D 14 90146A 7003 7464 22 14 70B1 1445 9014CE 1448 E54A 144A 144A 600A 144C FF 144D 71AC 144F E0 Backsto 01/28/2001 14:47:27 PAGE MOV A, wValueHigh DEC A ; Valid Values are 1, 2 and 3 MOV DPTR, #DeviceDescriptor JZ ReturnLength DEC A MOV DPTR, #ConfigurationDescriptor JNZ TryString MOV A, #ConfigLength RET TryString: DEC A JNZ Invalid ; Request is for a String Descriptor MOV DPTR, #String0 ; Point to String 0 MOV A, wValueLow ; Get String Index NextString: JZ ReturnLength MOV R7, A ; Save String Index CALL NextDPTR MOVX A, @DPTR ; Get the String Length (= 0 means we're at p) 1450 1452 1453 1454 1456 1456 1457 60A4 EF 14 80F4 E0 22 0062 ---1458 1458 145A 145C 145F 1460 1464 1466 1469 146A 146A 146C 146E 1471 1472 1473 1473 1475 1478 1479 147A 147B 1201 1001 000000 40 42420900 0001 010200 01 0902 6400 020100 80 FA 0904 000000 01 01 00 03 JZ Invalid MOV A, R7 DEC A JMP NextString ReturnLength: MOVX A, @DPTR RET ; Error check: this MUST be on within a WithinSamePage EQU $ - Subroutines ; ; Asked for a string I don't have ; Check if we are there yet ; Get Descriptor Length (first byte) page of Subroutines A51 MACRO ASSEMBLER 12 SPEAKER 147C 147C 0924 147E 01 147F 0001 1481 1E00 1483 01 1484 01 1485 1485 0C24 1487 02 1488 01 1489 0101 148B 00 148C 01 148D 0000 148F 00 1490 00 1491 1491 0924 1493 03 1494 02 1495 0103 1497 00 1498 01 1499 00 001E 149A 149A 0904 149C 010000 149F 01 14A0 02 14A1 00 14A2 04 14A3 14A3 0904 14A5 010101 14A8 01 14A9 02 14AA 00 14AB 04 14AC 14AC 0724 14AE 01 14AF 01 14B0 01 14B1 0200 14B3 14B3 0B24 14B5 02 14B6 01 14B7 01 14B8 01 14B9 08 14BA 01 14BB 803E00 14BE 14BE 0905 14C0 08 14C1 09 14C2 1000 14C4 01 14C5 00 14C6 00 14C7 14C7 0725 14C9 01 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 01/28/2001 14:47:27 PAGE AudioControlClassInterface: DB 9, 24H ; Length, Type = CS_INTERFACE DB 1 ; Subtype = HEADER DB 0, 1 ; Audio Device Class spec release (ver 1.0) DB LOW(ClassLength), HIGH(ClassLength) DB 1 ; Number of AudioStreaming interfaces DB 1 ; AudioStreaming interface ID InputTerminalDescriptor: DB 12, 24H ; Length, Type = CS_INTERFACE DB 2 ; Subtype = INPUT_TERMINAL DB 1 ; Terminal ID DB 1,1 ; Terminal type = USB streaming DB 0 ; Terminal association (none) DB 1 ; Number of logical output channels DW 0 ; Channel configuration = mono DB 0 ; Channel name DB 0 ; Terminal name OutputTerminalDescriptor: DB 9, 24H ; Length, Type = CS_INTERFACE DB 3 ; Subtype = OUTPUT_TERMINAL DB 2 ; Terminal ID DB 1,3 ; Terminal type = Speaker DB 0 ; Terminal association (none) DB 1 ; ID of the source terminal DB 0 ; Terminal name ClassLength EQU $-AudioControlClassInterface AudioStreamingInterfaceAlt0: DB 9, 4 ; Length, Type DB 1, 0, 0 ; ID, Alternate setting, only uses EP0 DB 1 ; Class = Audio DB 2 ; Sub-class = Audio Streaming DB 0 ; Protocol DB 4 ; Interface name AudioStreamingInterfaceAlt1: DB 9, 4 ; Length, Type DB 1, 1, 1 ; ID, Alternate setting, Uses isochronous endpoint DB 1 ; Class = Audio DB 2 ; Sub-class = Audio Streaming DB 0 ; Protocol DB 4 ; Interface name AudioStreamingClassInterface: DB 7, 24H ; Length, Type DB 1 ; Subtype = AS_GENERAL DB 1 ; Terminal connected to DB 1 ; Interface delay DB 2, 0 ; Audio Data Format = PCM8 FormatTypeDescriptor: DB 11, 24H ; Length, Type DB 2 ; Subtype = FORMAT_TYPE DB 1 ; Type 1 DB 1 ; Number of physical channels DB 1 ; Number of bytes in an audio subframe DB 8 ; Number of bits per sample DB 1 ; Number of frequencies supported DB 80H, 3EH, 0 ; 16000Hz EndpointDescriptor: DB 9, 5 ; Length, Type DB 00001000B ; OUT Endpoint 8 DB 00001001B ; Transfer type = ADAPTIVE, ISOCHRONOUS DB 16, 0 ; Maximum packet size DB 1 ; Polling interval DB 0 ; Refresh (unused) DB 0 ; Endpoint used for syschronization info (unused) ClassEndpointDescriptor: DB 7, 25H ; Length, Type DB 1 ; Subtype = EP_GENERAL A51 MACRO ASSEMBLER 13 SPEAKER 01/28/2001 14:47:27 PAGE 14CA 00 14CB 00 14CC 0000 0064 14CE 14CE 04030904 14D2 14D2 2C03 14D4 55005300 14D8 42002000 14DC 44006500 14E0 73006900 14E4 67006E00 14E8 2000 14EA 42007900 14EE 20004500 14F2 78006100 14F6 6D007000 14FA 6C006500 14FE 14FE 1E03 1500 53006900 1504 6D007000 1508 6C006500 150C 2000 150E 53007000 1512 65006100 1516 6B006500 151A 7200 151C 1A03 151E 41007500 1522 64006900 1526 6F00 1528 43006F00 152C 6E007400 1530 72006F00 1534 6C00 1536 1E03 1538 41007500 153C 64006900 1540 6F00 1542 53007400 1546 72006500 154A 61006D00 154E 69006E00 1552 6700 1554 1554 00 +1 +1 +1 +1 +1 +1 +1 +1 +1 781 782 783 784 785 786 787 788 789 +1 790 DB +1 +1 +1 791 792 793 String2: DB DB ; Product Name (String3-String2),3 "S",0,"i",0,"m",0,"p",0,"l",0,"e",0," ",0 +1 794 DB "S",0,"p",0,"e",0,"a",0,"k",0,"e",0,"r",0 +1 +1 795 796 String3:DB DB +1 797 DB +1 +1 798 799 String4:DB DB +1 800 DB +1 +1 +1 801 802 803 804 805 806 EndOfDescriptors: DB 0 DB 0 ; Attributes (none) DB 0 ; Lock delay units (unused) DW 0 ; Lock delay (unused) Configlength EQU $-ConfigurationDescriptor String0: ; Declare the UNICODE strings DB 4, 3, 9, 4 ; Only English language strings supported String1: ; Manufacturer DB (String2-String1),3 ; Length, Type DB "U",0,"S",0,"B",0," ",0,"D",0,"e",0,"s",0,"i",0,"g",0,"n",0," ", 0 END "B",0,"y",0," ",0,"E",0,"x",0,"a",0,"m",0,"p",0,"l",0,"e",0 (String4-String3),3 "A",0,"u",0,"d",0,"i",0,"o",0 "C",0,"o",0,"n",0,"t",0,"r",0,"o",0,"l",0 (EndOfDescriptors-String4),3 "A",0,"u",0,"d",0,"i",0,"o",0 "S",0,"t",0,"r",0,"e",0,"a",0,"m",0,"i",0,"n",0,"g",0 ; Backstop for String Descriptors