|
|
SDK for ZTEX FPGA Boards - Example
ZTEX provides a powerful Open Source SDK for the host software and the EZ-USB FX2 und FX3 USB controller.
(For FPGA development Xilinx software is used.)
This page gives an impression of the SDK usage.
Although note that development of own firmware becomes obsolete for many applications if default firmware is used.
Many other and more complex examples are part of the SDK.
Firmware
The firmware defines two endpoints. Data is read from host through endpoint 4, converted to uppercase and written back to endpoint 2.
Because USB descriptors and ISR's are created automatically by the Firmware kit, the source code is quite compact:
Firmware for EZ-USB FX2: ucecho-fx2.c
#include[ztex-conf.h] // Loads the configuration macros, see ztex-conf.h for available macros
#include[ztex-utils.h] // include basic functions
// define endpoints 2 and 4, both belong to interface 0 (in/out are seen from the host
EP_CONFIG(2,0,BULK,IN,512,2);
EP_CONFIG(4,0,BULK,OUT,512,2);
// this product string is also used for identification by the host software
#define[PRODUCT_STRING]["ucecho for EZ-USB devices"]
// include the main part of the firmware kit, define the descriptors, ...
#include[ztex.h]
void main(void)
{
WORD i,size,j;
BYTE b;
// init everything
init_USB();
REVCTL = 0x0;
SYNCDELAY;
IFCONFIG = bmBIT7; // Internal source, 48MHz
SYNCDELAY;
EP2CS &= ~bmBIT0; // stall = 0
SYNCDELAY;
EP4CS &= ~bmBIT0; // stall = 0
SYNCDELAY;
EP2FIFOCFG = 0;
SYNCDELAY;
EP4FIFOCFG = 0;
SYNCDELAY;
FIFORESET = 0x80; // reset FIFO ...
SYNCDELAY;
FIFORESET = 0x02; // ... for EP 2
SYNCDELAY;
FIFORESET = 0x04; // ... for EP 4
SYNCDELAY;
FIFORESET = 0x00;
SYNCDELAY;
EP4BCL = 0x80; // skip package, (re)arm EP4
SYNCDELAY;
EP4BCL = 0x80; // skip package, (re)arm EP4
SYNCDELAY;
while (1) {
if ( !(EP4CS & bmBIT2) ) { // EP4 is not empty
size = (EP4BCH << 8) | EP4BCL;
if ( size>0 && size<=512 && !(EP2CS & bmBIT3)) {// EP2 is not full
j = 0;
for ( i=0; i<size; i++ ) {
b = EP4FIFOBUF[i]; // data from EP4 ...
if ( b>=(BYTE)'a' && b<=(BYTE)'z' ) { // ... is converted to uppercase ...
b-=32;
j++;
}
EP2FIFOBUF[i] = b; // ... and written back to EP2 buffer
}
EP2BCH = size >> 8;
SYNCDELAY;
EP2BCL = size & 255; // arm EP2
}
SYNCDELAY;
EP4BCL = 0x80; // skip package, (re)arm EP4
}
}
}
|
Firmware for EZ-USB FX3: ucecho-fx3.c
Also note that the Cypress SDK contains a very similar example (cyfxisolpmaninout) which is more than 1000 long. This demonstrates the efficiency
of the ZTEX SDK.
#include "cyu3system.h"
#include "cyu3os.h"
#include "cyu3dma.h"
// loads default configuration macros
#include "ztex-conf.c"
CyU3PDmaChannel dma_out_handle, dma_in_handle;
/* Define endpoints 2 and 4. Both belong to interface 0 (in/out are seen from the host)
* Burst size is 1 and DMA size is 2x1K. */
#undef EP_SETUP
#define EP_SETUP \
INTERFACE(0, \
EP_BULK(4, OUT, 1, /* direction as seen from the host */ \
DMA(dma_in_handle, CY_U3P_DMA_TYPE_MANUAL_IN, 1, 2, CY_U3P_CPU_SOCKET_CONS, \
CB(0,0) \
) \
) \
EP_BULK(2, IN, 1, \
DMA(dma_out_handle, CY_U3P_DMA_TYPE_MANUAL_OUT, 1, 2, CY_U3P_CPU_SOCKET_PROD, ) \
) \
)
#undef ZTEX_PRODUCT_STRING
#define ZTEX_PRODUCT_STRING "ucecho for EZ-USB FX3"
#include "ztex.c"
void usb_start() {
// start USB transfers as soon cable is connected
ZTEX_REC(CyU3PDmaChannelSetXfer (&dma_in_handle, 0));
ZTEX_REC(CyU3PDmaChannelSetXfer (&dma_out_handle, 0));
}
void usb_stop() {
// nothing required here
}
void run () {
CyU3PDmaBuffer_t inbuf, outbuf;
CyU3PReturnStatus_t status;
uint32_t i;
ztex_log ( "ucecho for EZ-USB devices" );
while (1) {
if (ztex_usb_is_connected) {
/* Wait for receiving a buffer from the producer socket (OUT endpoint). The call
* will fail if there was an error or if the USB connection was reset / disconnected.
* In case of error invoke the error handler and in case of reset / disconnection,
* ztex_usb_is_connected will be 0; continue to beginning of the loop. */
status = CyU3PDmaChannelGetBuffer (&dma_in_handle, &inbuf, CYU3P_WAIT_FOREVER);
// ZTEX_LOG("EC=%d, Read %d bytes", status, inbuf.count);
if (!ztex_usb_is_connected || status==CY_U3P_ERROR_TIMEOUT) continue;
ZTEX_REC_CONT(status);
/* Wait for a free buffer to transmit the received data.
* The failure cases are same as above. */
status = CyU3PDmaChannelGetBuffer (&dma_out_handle, &outbuf, CYU3P_WAIT_FOREVER);
if (!ztex_usb_is_connected || status==CY_U3P_ERROR_TIMEOUT) continue;
ZTEX_REC(status);
/* Convert the data from the producer channel to the consumer channel.
* The inbuf.count holds the amount of valid data received. */
CyU3PMemCopy (outbuf.buffer, inbuf.buffer, inbuf.count);
for (i=0; i<inbuf.count; i++ )
outbuf.buffer[i] = inbuf.buffer[i]>='a' && inbuf.buffer[i]<='z' ?
inbuf.buffer[i] - 32 : inbuf.buffer[i];
/* Now discard the data from the producer channel so that the buffer is made
* available to receive more data. */
status = CyU3PDmaChannelDiscardBuffer (&dma_in_handle);
if (!ztex_usb_is_connected) continue;
ZTEX_REC(status);
/* Commit the received data to the consumer pipe so that the data can be
* transmitted back to the USB host. Since the same data is sent back, the
* count shall be same as received and the status field of the call shall
* be 0 for default use case. */
status = CyU3PDmaChannelCommitBuffer (&dma_out_handle, inbuf.count, 0);
// ZTEX_LOG("EC=%d, Sent %d bytes", status, outbuf.status);
if (!ztex_usb_is_connected) continue;
ZTEX_REC(status);
}
else {
/* No active data transfer. Sleep for a small amount of time. */
CyU3PThreadSleep (100);
}
}
}
/*
* Main function
*/
int main (void)
{
// global configuration
ztex_app_thread_run = run;
ztex_usb_start = usb_start;
ztex_usb_stop = usb_stop;
ztex_main(); // starts the OS and never returns
return 0; // makes the compiler happy
}
|
Host Software: UCEcho.java
The Java host software writes strings entered by user to endpoint 4 and outputs the result read from endpoint 2.
If no or incorrect firmware is installed, the EZ-USB variant is determined and the correct firmware image is uploaded automatically
import java.io.*;
import java.util.*;
import java.nio.*;
import org.usb4java.*;
import ztex.*;
// *****************************************************************************
// ******* ParameterException **************************************************
// *****************************************************************************
// Exception the prints a help message
class ParameterException extends Exception {
public final static String helpMsg = new String (
"Parameters:\n"+
" -d <number> Device Number (default: 0)\n" +
" -f Force uploads\n" +
" -p Print bus info\n" +
" -h This help" );
public ParameterException (String msg) {
super( msg + "\n" + helpMsg );
}
}
// *****************************************************************************
// ******* UCEcho *************************************************************
// *****************************************************************************
class UCEcho extends Ztex1v1 {
// ******* Debug ***************************************************************
// constructor
public UCEcho ( ZtexDevice1 pDev ) throws UsbException {
super ( pDev );
}
// ******* echo ****************************************************************
// writes a string to Endpoint 4, reads it back from Endpoint 2 and outputs the result
public void echo ( String input ) throws UsbException {
int i = bulkWrite(0x04, allocateByteBuffer(input.getBytes()) , 1000);
if ( i<0 ) throw new UsbException("Error sending data: " + LibUsb.strError(i));
System.out.println("Send "+i+" bytes: `"+input+"'" );
try { Thread.sleep( 10 ); } catch ( InterruptedException e ) { }
ByteBuffer buffer = BufferUtils.allocateByteBuffer(1024);
i = bulkRead(0x82, buffer, 1000);
if ( i<0 ) throw new UsbException("Error receiving data: " + LibUsb.strError(i));
else if (i==0) System.out.println("Read "+0+" bytes" );
else {
byte[] buf = new byte[i];
buffer.get(buf);
System.out.println("Read "+i+" bytes: `"+new String(buf,0,i)+"'" );
}
}
// ******* main ****************************************************************
public static void main (String args[]) {
int devNum = 0;
boolean force = false;
try {
// Scan the USB. This also creates and initializes a new USB context.
ZtexScanBus1 bus = new ZtexScanBus1( ZtexDevice1.ztexVendorId,
ZtexDevice1.ztexProductId, true, false, 1);
if ( bus.numberOfDevices() <= 0) {
System.err.println("No devices found");
System.exit(0);
}
// scan the command line arguments
for (int i=0; i<args.length; i++ ) {
if ( args[i].equals("-d") ) {
i++;
try {
if (i>=args.length) throw new Exception();
devNum = Integer.parseInt( args[i] );
}
catch (Exception e) {
throw new ParameterException("Device number expected after -d");
}
}
else if ( args[i].equals("-f") ) {
force = true;
}
else if ( args[i].equals("-p") ) {
bus.printBus(System.out);
System.exit(0);
}
else if ( args[i].equals("-h") ) {
System.err.println(ParameterException.helpMsg);
System.exit(0);
}
else throw new ParameterException("Invalid Parameter: "+args[i]);
}
// create the main class
UCEcho ztex = new UCEcho ( bus.device(devNum) );
bus.unref();
// upload the firmware if necessary
if ( force || ! ztex.valid() ||
! ztex.dev().productString().equals("ucecho for EZ-USB devices") ) {
String imgfn = "ucecho-fx2.ihx";
if ( ztex.dev().fx3() ) {
System.out.println( "Trying to overwrite firmware in RAM. This only " +
"works if a board specific firmware with reset\n" +
"support is running. If uploading firmware fails "+
" please restart board with disabled firmware." );
imgfn = "ucecho-fx3.img";
}
System.out.println( "Firmware upload time: " +
ztex.uploadFirmware( imgfn, force ) + " ms");
}
// claim interface 0
ztex.trySetConfiguration ( 1 );
ztex.claimInterface ( 0 );
// print board log
ztex.debug2PrintNextLogMessages(System.out);
// read string from stdin and write it to USB device
try {
String str = "";
BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
while ( ! str.equals("quit") ) {
System.out.print("Enter a string or `quit' to exit the program: ");
str = reader.readLine();
if ( ! str.equals("") ) ztex.echo(str);
System.out.println("");
ztex.debug2PrintNextLogMessages(System.out);
}
}
catch ( Exception e ) {
System.out.println("ucecho test failed: " + e.getLocalizedMessage() );
}
ztex.debug2PrintNextLogMessages(System.out);
ztex.dispose(); // this also releases claimed interfaces
}
catch (Exception e) {
System.out.println("Error: "+e.getLocalizedMessage() );
}
}
}
|
Example call
An example call with output including FX3 log messages can be found below.
stefan@ws2:/drv_s2/usb-fpga/ucecho$ java -cp UCEcho.jar UCEcho
Trying to overwrite firmware in RAM. This only works if a board specific firmware with reset
support is running. If uploading firmware fails please restart board with disabled firmware.
Firmware upload time: 144 ms
Info: Found 128 MBit SPI Flash
ucecho for EZ-USB devices
Info: USB setup finished: super speed
Info: USB disconnected.
Info: USB setup finished: super speed
Enter a string or `quit' to exit the program: hello world!
Send 12 bytes: `hello world!'
Read 12 bytes: `HELLO WORLD!'
Enter a string or `quit' to exit the program: quit
Send 4 bytes: `quit'
Read 4 bytes: `QUIT'
|
|