Commits

Anonymous committed 5cc0667

Bulkloop example to demonstrate slightly more complex library routines.

Comments (0)

Files changed (6)

 lights:
  A really simple program that cycles the lights on the CY3864 development board.
 
-
+bulkloop:
+ Demonstrations:
+  * looping data on endpoints.
+  * Custom device descriptor.
+  * Vendor commands.
+  * Usb jump table.
+  * serial IO
 

examples/bulkloop/Makefile

+INCLUDES = -I../../include
+LIBS = fx2.lib -L../../lib
+CC = sdcc -mmcs51 --code-size 0x2000 --xram-loc 0x3000 \
+	 -Wl"-b DSCR_AREA = 0x2000" \
+	 -Wl"-b INT2JT = 0x2200"
+
+BASENAME = bulkloop
+DSCR = dscr.rel
+
+$(BASENAME).ihx: $(BASENAME).c $(DSCR)
+	$(CC) $(INCLUDES) $(BASENAME).c $(DSCR) $(LIBS)
+
+$(DSCR): dscr_asm
+	cp dscr_asm dscr.asm
+	asx8051 -logs dscr.asm
+
+$(BASENAME).bix: $(BASENAME).ihx
+	objcopy -I ihex -O binary $(BASENAME).ihx $(BASENAME).bix
+
+clean:
+	rm -f *.{asm,ihx,lnk,lst,map,mem,rel,rst,sym,adb,cdb,bix}
+
+.PHONY:run bix
+run: $(BASENAME).bix
+	python load.py
+
+bix: $(BASENAME).bix
+
+
+reset:
+	$(CYCFX2PROG) reset

examples/bulkloop/bulkloop.c

+
+#include <stdio.h>
+
+#include <fx2regs.h>
+#include <fx2macros.h>
+#include <serial.h>
+#include <delay.h>
+#include <usbjt.h>
+#include <lights.h>
+#include <setupdat.h>
+
+
+#define SYNCDELAY() SYNCDELAY4
+#define REARMVAL 0x80
+#define REARM() EP2BCL=REARMVAL
+
+
+
+volatile WORD bytes;
+volatile bit gotbuf;
+volatile BYTE icount;
+volatile bit got_sud;
+DWORD lcount;
+bit on;
+
+void main() {
+
+ d2off();
+ on=0;
+ lcount=0;
+ got_sud=FALSE;
+ icount=0;
+ gotbuf=FALSE;
+ bytes=0;
+
+ // renumerate
+ RENUMERATE(); 
+ 
+
+ SETCPUFREQ(CLK_48M);
+ SETIF48MHZ();
+ sio0_init(57600);
+ 
+ 
+ USE_USB_INTS(); 
+ ENABLE_SUDAV();
+ ENABLE_SOF();
+ 
+ 
+ // only valid endpoints are 2/6
+ EP2CFG = 0xA2; // 10100010
+ SYNCDELAY();
+ EP6CFG = 0xE2; // 11100010 
+ SYNCDELAY();
+ EP1INCFG &= ~bmVALID;
+ SYNCDELAY();
+ EP1OUTCFG &= ~bmVALID;
+ SYNCDELAY();
+ EP4CFG &= ~bmVALID;
+ SYNCDELAY();
+ EP8CFG &= ~bmVALID;
+ SYNCDELAY(); 
+ 
+ 
+ // arm ep2
+ EP2BCL = 0x80; // write once
+ SYNCDELAY();
+ EP2BCL = 0x80; // do it again
+
+ 
+ // make it so we enumberate
+ 
+
+ EA=1; // global interrupt enable 
+ printf ( "Done initializing stuff\n" );
+
+ 
+ d3off();
+ 
+ while(TRUE) {
+ 
+  if ( got_sud ) {
+      printf ( "Handle setupdata\n" );
+      handle_setupdata(); 
+      got_sud=FALSE;
+  }
+
+  if ( !(EP2468STAT & bmEP2EMPTY) ) {
+       printf ( "ep2 out received data\n" );
+      if  ( !(EP2468STAT & bmEP6FULL) ) { // wait for at least one empty in buffer
+                 WORD i;
+                 printf ( "Sending data to ep6 in\n");
+    
+                 bytes = MAKEWORD(EP2BCH,EP2BCL);
+                 
+                 for (i=0;i<bytes;++i) EP6FIFOBUF[i] = EP2FIFOBUF[i];
+                 
+                 // can copy whole string w/ autoptr instead.
+                 // or copy directly from one buf to another
+
+                 // ARM ep6 out
+                 EP6BCH=MSB(bytes);
+                 SYNCDELAY();
+                 EP6BCL=LSB(bytes); 
+
+                 REARM(); // ep2
+                 //printf ( "Re-Armed ep2\n" );
+
+         }
+   }
+ }
+
+}
+
+// copied routines from setupdat.h
+
+// value (low byte) = ep
+#define VC_EPSTAT 0xB1
+
+BOOL handle_vendorcommand(BYTE cmd) {
+
+ switch ( cmd ) {
+ 
+     case VC_EPSTAT:
+        {         
+         xdata BYTE* pep= ep_addr(SETUPDAT[2]);
+         printf ( "ep %02x\n" , *pep );
+         if (pep) {
+          EP0BUF[0] = *pep;
+          EP0BCH=0;
+          EP0BCL=1;
+          return TRUE;
+         } 
+        }
+     default:
+          printf ( "Need to implement vendor command: %02x\n", cmd );
+ }
+ return FALSE;
+}
+
+// this firmware only supports 0,0
+BOOL handle_get_interface(BYTE ifc, BYTE* alt_ifc) { 
+ printf ( "Get Interface\n" );
+ if (ifc==0) {*alt_ifc=0; return TRUE;} else { return FALSE;}
+}
+BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc) { 
+ printf ( "Set interface %d to alt: %d\n" , ifc, alt_ifc );
+ 
+ if (ifc==0&&alt_ifc==0) {
+    return TRUE;
+ } else 
+    return FALSE;
+}
+
+// get/set configuration
+BYTE handle_get_configuration() {
+ return 1; 
+ }
+BOOL handle_set_configuration(BYTE cfg) { 
+ return cfg==1 ? TRUE : FALSE; // we only handle cfg 1
+}
+
+
+// copied usb jt routines from usbjt.h
+void sudav_isr() interrupt SUDAV_ISR {
+  
+  got_sud=TRUE;
+  CLEAR_SUDAV();
+}
+
+bit on5;
+xdata WORD sofct=0;
+void sof_isr () interrupt SOF_ISR using 1 {
+    ++sofct;
+    if(sofct==8000) { // about 8000 sof interrupts per second at high speed
+        on5=!on5;
+        if (on5) d5on(); else d5off();
+        sofct=0;
+    }
+    CLEAR_SOF();
+}
+
+void sutok_isr() interrupt SUTOK_ISR {}
+void suspend_isr() interrupt SUSPEND_ISR {}
+void usbreset_isr() interrupt USBRESET_ISR {}
+void hispeed_isr() interrupt HISPEED_ISR {}
+void ep0ack_isr() interrupt EP0ACK_ISR {}
+void ep0in_isr() interrupt EP0IN_ISR {}
+void ep0out_isr() interrupt EP0OUT_ISR {}
+void ep1in_isr() interrupt EP1IN_ISR {}
+void ep1out_isr() interrupt EP1OUT_ISR {}
+void ep2_isr() interrupt EP2_ISR {}
+void ep4_isr() interrupt EP4_ISR {}
+void ep6_isr() interrupt EP6_ISR {}
+void ep8_isr() interrupt EP8_ISR {}
+void ibn_isr() interrupt IBN_ISR {}
+void ep0ping_isr() interrupt EP0PING_ISR {}
+void ep1ping_isr() interrupt EP1PING_ISR {}
+void ep2ping_isr() interrupt EP2PING_ISR {}
+void ep4ping_isr() interrupt EP4PING_ISR {}
+void ep6ping_isr() interrupt EP6PING_ISR {}
+void ep8ping_isr() interrupt EP8PING_ISR {}
+void errlimit_isr() interrupt ERRLIMIT_ISR {}
+void ep2isoerr_isr() interrupt EP2ISOERR_ISR {}
+void ep4isoerr_isr() interrupt EP4ISOERR_ISR {}
+void ep6isoerr_isr() interrupt EP6ISOERR_ISR {}
+void ep8isoerr_isr() interrupt EP8ISOERR_ISR {}
+void spare_isr() interrupt RESERVED_ISR {}
+void ep2pf_isr() interrupt EP2PF_ISR{}
+void ep4pf_isr() interrupt EP4PF_ISR{}
+void ep6pf_isr() interrupt EP6PF_ISR{}
+void ep8pf_isr() interrupt EP8PF_ISR{}
+void ep2ef_isr() interrupt EP2EF_ISR{}
+void ep4ef_isr() interrupt EP4EF_ISR{}
+void ep6ef_isr() interrupt EP6EF_ISR{}
+void ep8ef_isr() interrupt EP8EF_ISR{}
+void ep2ff_isr() interrupt EP2FF_ISR{}
+void ep4ff_isr() interrupt EP4FF_ISR{}
+void ep6ff_isr() interrupt EP6FF_ISR{}
+void ep8ff_isr() interrupt EP8FF_ISR{}
+void gpifdone_isr() interrupt GPIFDONE_ISR{}
+void gpifwf_isr() interrupt GPIFWF_ISR{}

examples/bulkloop/dscr_asm

+; this is a the default 
+; full speed and high speed 
+; descriptors found in the TRM
+; change however you want but leave 
+; the descriptor pointers so the setupdat.c file works right
+ 
+
+.module DEV_DSCR 
+
+; descriptor types
+; same as setupdat.h
+DSCR_DEVICE_TYPE=1
+DSCR_CONFIG_TYPE=2
+DSCR_STRING_TYPE=3
+DSCR_INTERFACE_TYPE=4
+DSCR_ENDPOINT_TYPE=5
+DSCR_DEVQUAL_TYPE=6
+
+; for the repeating interfaces
+DSCR_INTERFACE_LEN=9
+DSCR_ENDPOINT_LEN=7
+
+; endpoint types
+ENDPOINT_TYPE_CONTROL=0
+ENDPOINT_TYPE_ISO=1
+ENDPOINT_TYPE_BULK=2
+ENDPOINT_TYPE_INT=3
+
+    .globl	_dev_dscr, _dev_qual_dscr, _highspd_dscr, _fullspd_dscr, _dev_strings, _dev_strings_end
+; These need to be in code memory.  If
+; they aren't you'll have to manully copy them somewhere
+; in code memory otherwise SUDPTRH:L don't work right
+    .area	DSCR_AREA	(CODE)
+
+_dev_dscr:
+	.db	dev_dscr_end-_dev_dscr    ; len
+	.db	DSCR_DEVICE_TYPE		  ; type
+	.dw	0x0002					  ; usb 2.0
+	.db	0xff  					  ; class (vendor specific)
+	.db	0xff					  ; subclass (vendor specific)
+	.db	0xff					  ; protocol (vendor specific)
+	.db	64						  ; packet size (ep0)
+	.dw	0xB404					  ; vendor id 
+	.dw	0x0410					  ; product id
+	.dw	0x0100					  ; version id
+	.db	1		                  ; manufacturure str idx
+	.db	2				          ; product str idx	
+	.db	0				          ; serial str idx 
+	.db	1			              ; n configurations
+dev_dscr_end:
+
+_dev_qual_dscr:
+	.db	dev_qualdscr_end-_dev_qual_dscr
+	.db	DSCR_DEVQUAL_TYPE
+	.dw	0x0002                              ; usb 2.0
+	.db	0xff
+	.db	0xff
+	.db	0xff
+	.db	64                                  ; max packet
+	.db	1									; n configs
+	.db	0									; extra reserved byte
+dev_qualdscr_end:
+
+_highspd_dscr:
+	.db	highspd_dscr_end-_highspd_dscr      ; dscr len											;; Descriptor length
+	.db	DSCR_CONFIG_TYPE
+    ; can't use .dw because byte order is different
+	.db	(highspd_dscr_realend-_highspd_dscr) % 256 ; total length of config lsb
+	.db	(highspd_dscr_realend-_highspd_dscr) / 256 ; total length of config msb
+	.db	1								 ; n interfaces
+	.db	1								 ; config number
+	.db	0								 ; config string
+	.db	0x80                             ; attrs = bus powered, no wakeup
+	.db	0x32                             ; max power = 100ma
+highspd_dscr_end:
+
+; all the interfaces next 
+; NOTE the default TRM actually has more alt interfaces
+; but you can add them back in if you need them.
+; here, we just use the default alt setting 1 from the trm
+	.db	DSCR_INTERFACE_LEN
+	.db	DSCR_INTERFACE_TYPE
+	.db	0				 ; index
+	.db	0				 ; alt setting idx
+	.db	2				 ; n endpoints	
+	.db	0xff			 ; class
+	.db	0xff
+	.db	0xff
+	.db	3	             ; string index	
+
+; endpoint 2 out
+	.db	DSCR_ENDPOINT_LEN
+	.db	DSCR_ENDPOINT_TYPE
+	.db	0x02				;  ep2 dir=OUT and address
+	.db	ENDPOINT_TYPE_BULK	; type
+	.db	0x00				; max packet LSB
+	.db	0x02				; max packet size=512 bytes
+	.db	0x00				; polling interval
+
+; endpoint 6 in
+	.db	DSCR_ENDPOINT_LEN
+	.db	DSCR_ENDPOINT_TYPE
+	.db	0x86				;  ep6 dir=in and address
+	.db	ENDPOINT_TYPE_BULK	; type
+	.db	0x00				; max packet LSB
+	.db	0x02				; max packet size=512 bytes
+	.db	0x00				; polling interval
+
+highspd_dscr_realend:
+
+_fullspd_dscr:
+	.db	fullspd_dscr_end-_fullspd_dscr      ; dscr len
+	.db	DSCR_CONFIG_TYPE
+    ; can't use .dw because byte order is different
+	.db	(fullspd_dscr_realend-_fullspd_dscr) % 256 ; total length of config lsb
+	.db	(fullspd_dscr_realend-_fullspd_dscr) / 256 ; total length of config msb
+	.db	1								 ; n interfaces
+	.db	1								 ; config number
+	.db	0								 ; config string
+	.db	0x80                             ; attrs = bus powered, no wakeup
+	.db	0x32                             ; max power = 100ma
+fullspd_dscr_end:
+
+; all the interfaces next 
+; NOTE the default TRM actually has more alt interfaces
+; but you can add them back in if you need them.
+; here, we just use the default alt setting 1 from the trm
+	.db	DSCR_INTERFACE_LEN
+	.db	DSCR_INTERFACE_TYPE
+	.db	0				 ; index
+	.db	0				 ; alt setting idx
+	.db	2				 ; n endpoints	
+	.db	0xff			 ; class
+	.db	0xff
+	.db	0xff
+	.db	3	             ; string index	
+
+; endpoint 2 out
+	.db	DSCR_ENDPOINT_LEN
+	.db	DSCR_ENDPOINT_TYPE
+	.db	0x02				;  ep2 dir=OUT and address
+	.db	ENDPOINT_TYPE_BULK	; type
+	.db	0x40				; max packet LSB
+	.db	0x00				; max packet size=64 bytes
+	.db	0x00				; polling interval
+
+; endpoint 6 in
+	.db	DSCR_ENDPOINT_LEN
+	.db	DSCR_ENDPOINT_TYPE
+	.db	0x86				;  ep6 dir=in and address
+	.db	ENDPOINT_TYPE_BULK	; type
+	.db	0x40				; max packet LSB
+	.db	0x00				; max packet size=64 bytes
+	.db	0x00				; polling interval
+
+fullspd_dscr_realend:
+
+.even
+
+_dev_strings:
+; sample string
+_string0:
+	.db	string0end-_string0 ; len
+	.db	DSCR_STRING_TYPE
+    .db 0x09, 0x04     ; who knows
+string0end:
+; add more strings here
+
+_string1:
+    .db string1end-_string1
+    .db DSCR_STRING_TYPE
+    .ascii 'H'
+    .db 0
+    .ascii 'i'
+    .db 0
+string1end:
+
+_string2:
+    .db string2end-_string2
+    .db DSCR_STRING_TYPE
+    .ascii 'T'
+    .db 0
+    .ascii 'h'
+    .db 0
+    .ascii 'e'
+    .db 0
+    .ascii 'r'
+    .db 0
+    .ascii 'e'
+    .db 0
+string2end:
+
+_string3:
+    .db string3end-_string3
+    .db DSCR_STRING_TYPE
+    .ascii 'i'
+    .db 0
+    .ascii 'F'
+    .db 0
+    .ascii 'a'
+    .db 0
+    .ascii 'c'
+    .db 0
+    .ascii 'e'
+    .db 0
+string3end:
+    
+_dev_strings_end:
+    .dw 0x0000   ; just in case someone passes an index higher than the end to the firmware

examples/bulkloop/load.py

+
+from fx2load import *
+
+openfx2()
+reset_bix('bulkloop.bix')

examples/bulkloop/test.py

+import struct
+from fx2load import *
+
+openfx2(0x04b4,0x1004)
+
+# send 100 shorts to ep2
+
+buf=struct.pack ( 'H'*100, *[i for i in range(100)] )
+f.ep_bulk( buf, 0x02, 1000)
+
+# read them back out
+buf='\x00'*200  
+f.ep_bulk( buf, 0x86, 1000)
+
+print struct.unpack ( 'H'*100, buf )