Nav:  [home][elec][periph][usb-fx2][software] > [local_examples]
 
Go:  [local] [io] [advanced] [fx2pipe]
← [What are these? Why?]

Electronics -- USB-FX2: Simple Software Examples

A collection of simple software for the USB-FX2 board (all purely local, i.e. not using the IO lines on the board).

Download All Examples in an Archive

In order to try the examples on this page, you should download this tarball since the code on this page does not contain the necessary include files which are (of course) part of the archive.

Source: usb-fx2-local-examples-0.5.tar.gz   [12kb gzipped source tarball]
Version:0.5   (2010-04-05)
Author:Wolfgang Wieser   (report bugs here)
License:GNU GPL (Version 2)
Requires:libusb, cycfx2prog

Building an example source is simple: Just enter the directory and type make. Then, call make run as root to have it executed. Be sure to have the USB-FX2 board connected and to have cycfx2prog in the PATH environment variable and that the usbtest module is not loaded.

Note: All these examples have been tested with my USB-FX2 board connected to a Debian Linux box running kernel-2.6.15 and libusb-0.1.11. The USB-FX2 was connected to a USB-2.0 (high speed) port on a VIA-based PCI expansion card (however, native on-board USB-2.0 works as well).

If you experience trouble, please fix them and drop me a note. Also check out the troubleshooting hints.

Hello World in RAM

This is the easiest program of all. It can be used to test that firmware download works correctly and to verify that the USB-FX2's '8051 processor is actually alive. Here's the source (in archive: hello_world_ram/hello.c):

void main(void)
{
    // We have 16kb of RAM (0x4000) and the program will only occupy the
    // first couple of bytes so the address 0x3000 is surely unused.
    // To be compatible with the non-LP version (CY7C.. without A suffix)
    // which has just 8kb RAM, use 0x1000 instead of 0x3000.
    xdata char *dest=(xdata char*)0x1000;
    
    // Put content into that portion of RAM. This is the hello world
    // string in Caesar chiffre (offset 1)...
    const char *src="Gdkkn+\x1fvnqkc \x1fSghr\x1fhr\x1fxntq\x1f"
                    "EW1\x1f""an`qc-";
    while(*src)
    {  *dest++ = *src++ + 1;  }
    
    // Loop endlessly...
    for(;;);
}

So, the program simply copies the string in src into dest at address 0x1000 thereby decrypting the trivial Caesar chiffre with offset 1. (This is just done to be really sure that the 8051 actually does compute something.)

We compile this and then run it:

user@bash# make
sdcc -mmcs51 -I../include hello.c
root@bash# make run
cycfx2prog prg:hello.ihx run delay:100 reset dram:0x1000,37
Using ID 04b4:8613 on 006.002.
Putting 8051 into reset.
Programming 8051 using "hello.ihx".
Putting 8051 out of reset.
Delay: 100 msec
Putting 8051 into reset.
Dumping 37 bytes of RAM at 0x1000:
  0x0000 48656c6c6f2c2077 6f726c6421205468 697320697320796f 7572204658322062    Hello, world! This is your FX2 b
  0x0020 6f6172642e                                                             oard.

So, make first compiles hello.c into hello.ihx. This Intel hex file is then programmed onto the USB-FX2 board using cycfx2prog's prg command. Then, the run command starts the '8051, we give it a 100msec delay and then reset it and read 37 bytes at the RAM location 0x1000 using dram. That's the hello world message!

Hello World Across USB

Now that the '8051 is working properly, we can have the hello world message transferred via the USB using bulk IO. ("But didn't we transfer it via USB in the above example?", you will ask. Sure, but we used vendor-specific commands which are available when the '8051 is kept in reset which is not what we want in any real-life case.)

Let's have a look at the important parts of the code; the complete source is in the archive at hello_world_usb/hello.c.

static void Initialize(void)
{
    CPUCS=0x10;                  // 48 MHz, CLKOUT output disabled.
    IFCONFIG=0xc0;   SYNCDELAY;  // Internal IFCLK, 48MHz; A,B as normal ports.
    REVCTL=0x03;     SYNCDELAY;  // See TRM...
    EP6CFG=0xe2;     SYNCDELAY;  // 1110 0010 (bulk IN, 512 bytes, double-buffered)
    FIFORESET=0x80;  SYNCDELAY;  // NAK all requests from host.
    FIFORESET=0x82;  SYNCDELAY;  // Reset individual EP (2,4,6,8)
    FIFORESET=0x84;  SYNCDELAY;
    FIFORESET=0x86;  SYNCDELAY;
    FIFORESET=0x88;  SYNCDELAY;
    FIFORESET=0x00;  SYNCDELAY;  // Resume normal operation.
}

// This will put some data into the EP6 buffer and make it ready for
// transmission.
static void SetUpBufToTransfer(void)
{
    // First, copy the data into the EP6 buffer.
    xdata unsigned char *dest=EP6FIFOBUF;
    const char *src=
        "Hello world! Your FX2 is talking to you via the USB line.";
    unsigned char len=0;
    while(*src)
    {  *dest++=*src++;  ++len;  }
    // Append call serial in decimal: Skipped here; see real code!
    
    // Arm the endpoint. Be sure to set BCH before BCL because BCL access
    // actually arms the endpoint.
    SYNCDELAY;  EP6BCH=0;
    SYNCDELAY;  EP6BCL=len;
    
    // That's all we gonna do; the data will be transmitted the next time
    // a bulk read is performed by the host.
}

void main(void)
{
    Initialize();
    
    for(;;)
    {
        // Wait for the EP6 buffer to become non-full.
        if(!(EP6CS & (1<<3)))
        {  SetUpBufToTransfer();  }
    }
}

The Initialize() function does all the first-time initialisation of the FX2LP chip. It sets up endpoint 6 (IN direction, i.e. USB-FX2 to host computer), for bulk transfers. In an endless loop, we commit a hello world message buffer to the endpoint each time a buffer gets free. (There are 2 such buffers since it's double-buffered in this example.)

Here is the output of make run:

cycfx2prog prg:hello.ihx run delay:10 dbulk:6,-512,5
Using ID 04b4:8613 on 006.002.
Putting 8051 into reset.
Programming 8051 using "hello.ihx".
Putting 8051 out of reset.
Delay: 10 msec
Reading <=512 bytes from EP adr 0x86
  0x0000 48656c6c6f20776f 726c642120596f75 7220465832206973 2074616c6b696e67    Hello world! Your FX2 is talking
  0x0020 20746f20796f7520 7669612074686520 555342206c696e65 2e202830303029       to you via the USB line. (000)
Reading <=512 bytes from EP adr 0x86
  0x0000 48656c6c6f20776f 726c642120596f75 7220465832206973 2074616c6b696e67    Hello world! Your FX2 is talking
  0x0020 20746f20796f7520 7669612074686520 555342206c696e65 2e202830303129       to you via the USB line. (001)
Reading <=512 bytes from EP adr 0x86
  0x0000 48656c6c6f20776f 726c642120596f75 7220465832206973 2074616c6b696e67    Hello world! Your FX2 is talking
  0x0020 20746f20796f7520 7669612074686520 555342206c696e65 2e202830303229       to you via the USB line. (002)
Reading <=512 bytes from EP adr 0x86
  0x0000 48656c6c6f20776f 726c642120596f75 7220465832206973 2074616c6b696e67    Hello world! Your FX2 is talking
  0x0020 20746f20796f7520 7669612074686520 555342206c696e65 2e202830303329       to you via the USB line. (003)
Reading <=512 bytes from EP adr 0x86
  0x0000 48656c6c6f20776f 726c642120596f75 7220465832206973 2074616c6b696e67    Hello world! Your FX2 is talking
  0x0020 20746f20796f7520 7669612074686520 555342206c696e65 2e202830303429       to you via the USB line. (004)
sleep 1
cycfx2prog dbulk:6,-512
Using ID 04b4:8613 on 006.002.
Reading <=512 bytes from EP adr 0x86
  0x0000 48656c6c6f20776f 726c642120596f75 7220465832206973 2074616c6b696e67    Hello world! Your FX2 is talking
  0x0020 20746f20796f7520 7669612074686520 555342206c696e65 2e202830303529       to you via the USB line. (005)

This time, the dbulk command was used to read 5 bulk data packets from endpoint 6. After that, we wait for a second and read another one to see that the FX2 is still alive and did not loose any packets. (See the call serial number at the end of the message; the code for that is not included in the listing above but in the real source.)

String Filter Across USB

Now, upstream (i.e. IN direction) seems to work, so let's test two-way communication. This example program will send strings over endpoint 2 to the USB-FX2 board which will convert all lower-space characters to upper-space and send the result back. (It is meant to work for short strings less than 512 bytes).

Here is the stripped-down source (complete source in convert_string/convert.c):

static void Initialize(void)
{
    CPUCS=0x10;                  // 48 MHz, CLKOUT output disabled.
    IFCONFIG=0xc0;   SYNCDELAY;  // Internal IFCLK, 48MHz; A,B as normal ports.
    REVCTL=0x03;     SYNCDELAY;  // See TRM...
    EP6CFG=0xe2;     SYNCDELAY;  // 1110 0010 (bulk IN, 512 bytes, double-buffered)
    EP2CFG=0xa2;     SYNCDELAY;  // 1010 0010 (bulk OUT, 512 bytes, double-buffered)
    FIFORESET=0x80;  SYNCDELAY;  // NAK all requests from host.
    FIFORESET=0x82;  SYNCDELAY;  // Reset individual EP (2,4,6,8)
    FIFORESET=0x84;  SYNCDELAY;
    FIFORESET=0x86;  SYNCDELAY;
    FIFORESET=0x88;  SYNCDELAY;
    FIFORESET=0x00;  SYNCDELAY;  // Resume normal operation.
    EP2FIFOCFG=0x00; SYNCDELAY;  // Make sure AUTOOUT=0.
    OUTPKTEND=0x82;  SYNCDELAY;  // Be sure to clear the 2 buffers...
    OUTPKTEND=0x82;  SYNCDELAY;  // ...(double-buffered) (required!).
}

// This will read the EP2 data and put it into EP6 for transmission.
static void ProcessSendData(void)
{
    xdata const unsigned char *src=EP2FIFOBUF;
    xdata unsigned char *dest=EP6FIFOBUF;
    unsigned int len = ((int)EP2BCH)<<8 | EP2BCL;
    unsigned int i;
    for(i=0; i<len; i++,src++,dest++)
    {
        if(*src>='a' && *src<='z')
        {  *dest=*src-'a'+'A';  }
        else
        {  *dest=*src;  }
    }
    
    // "Skip" the received OUT packet to "forget" it (see TRM p. 9-26):
    SYNCDELAY;  OUTPKTEND=0x82;
    
    // Arm the endpoint. Be sure to set BCH before BCL because BCL access
    // actually arms the endpoint.
    SYNCDELAY;  EP6BCH=len>>8;
    SYNCDELAY;  EP6BCL=len&0xff;
}

void main(void)
{
    Initialize();
    
    for(;;)
    {
        // Wait for input on EP2 (EP2 non-empty).
        if(!(EP2CS & (1<<2)))
        {
            // Wait for EP6 buffer to become non-full so that we don't
            // overwrite content.
            while(EP6CS & (1<<3));
            ProcessSendData();
        }
    }
}

We must make sure that AUTOOUT is disabled so that the '8051 can inspect the which arrives from the host data. It will then copy the data buffer from endpoint 2 to endpoint 6 thereby converting lower-case to upper-case characters. Then, it will make the FX2 forget about the arrived packet (via assignment to OUTPKTEND) because otherwise the FX2 will not ACK the packet to the host since it will wait infinitely to be clocked out of the GPIF side (i.e. the IO lines to external logic which are not connected right now). Then, the converted data in the endpoint 6 is armed for transmission by assigning EP6BCL.

In order not to overwrite packets, the processing of an incoming buffer is only done if the output has a free buffer (the EP6CS bit 3 test).

Here is the output of make run:

cycfx2prog prg:convert.ihx run delay:10 sbulk:2,Hello_World dbulk:6,-512
Using ID 04b4:8613 on 006.002.
Putting 8051 into reset.
Programming 8051 using "convert.ihx".
Putting 8051 out of reset.
Delay: 10 msec
Sending 11 bytes to EP adr 0x02
Reading <=512 bytes from EP adr 0x86
  0x0000 48454c4c4f5f574f 524c44                                                HELLO_WORLD
cycfx2prog sbulk:2,"This is another test :)" dbulk:6,-512
Using ID 04b4:8613 on 006.002.
Sending 23 bytes to EP adr 0x02
Reading <=512 bytes from EP adr 0x86
  0x0000 5448495320495320 414e4f5448455220 54455354203a29                       THIS IS ANOTHER TEST :)
cycfx2prog sbulk:2,"String one first" sbulk:2,"String two afterwards" dbulk:6,-512 dbulk:6,-512
Using ID 04b4:8613 on 006.002.
Sending 16 bytes to EP adr 0x02
Sending 21 bytes to EP adr 0x02
Reading <=512 bytes from EP adr 0x86
  0x0000 535452494e47204f 4e45204649525354                                      STRING ONE FIRST
Reading <=512 bytes from EP adr 0x86
  0x0000 535452494e472054 574f204146544552 5741524453                           STRING TWO AFTERWARDS

As one can see, it works pretty well. Since the communication is double-buffered in the FX2 in both directions, it is possible to send up to 4 bulk packets before reading the first one. Feel free to test this...


[home] [site map]
Valid HTML 4.01!
Copyright © 2006-2010 by Wolfgang Wieser
Last modified: 2010-04-05 13:10:58