ZTEX uses the FX3S on its FPGA Boards. These boards have native SD card support (including SDIO).
On FX2 based based Series 2 FPGA Boards there is no SD socket. Users that miss it (e.g. because they previously used Series 1 Boards) can easily add a (micro)SD socket to their application circuit.
This page described how this is done and how firmware support is activated. This is explained best by an example:
A SD card is connected to an USB-FPGA Module 2.01 as follows
External I/O | FX2 I/O | ||||
---|---|---|---|---|---|
Signal | pin | FPGA pin | direction | pin | FPGA pin |
CS | B13 | K15 | ← (in) | PC1 | N12 |
DI | B14 | J13 | ← (in) | PC2 | P12 |
CLK | B18 | J14 | ← (in) | PC3 | N5 |
DO | B19 | H15 | → (out) | PA2 | H15 |
The HDL code for routing the signals is:
# ... NET "pa2" LOC = "B10" | IOSTANDARD = LVCMOS33 ; # PA2 NET "pc1" LOC = "N12" | IOSTANDARD = LVCMOS33 ; # PC1/GPIFADR1 NET "pc2" LOC = "P12" | IOSTANDARD = LVCMOS33 ; # PC2/GPIFADR2 NET "pc3" LOC = "N5" | IOSTANDARD = LVCMOS33 ; # PC3/GPIFADR3 NET "b13" LOC = "K15" | IOSTANDARD = LVCMOS33 ; NET "b14" LOC = "J13" | IOSTANDARD = LVCMOS33 ; NET "b18" LOC = "J14" | IOSTANDARD = LVCMOS33 ; NET "b19" LOC = "H15" | IOSTANDARD = LVCMOS33 ; # ...
(.ucf constraints file) and
// ... module top ( // ... input pc1,pc2,pc3, b19, output b13,b14,b18, pa2 ); // ... assign b13 = pc1; assign b14 = pc2; assign b18 = pc3; assign pa2 = b19; // ... endmodule
(verilog HDL file).
In order to enable firmware support the following lines have to be inserted between #include[ztex-conf.h]
and #include[ztex.h]
ENABLE_FLASH2; // enables SD support as secondary Flash #define[MMC_PORT][C] // Port for input signals, valid values: A..D #define[MMC__PORT_DO][A] // Port for output signals (valid values: A..D, // can be omitted if equal to input port) #define[MMC_BIT_CS][1] // Pin number for CS signal, i.e. PC1 #define[MMC_BIT_DI][2] // Pin number for DI signal, i.e. PC2 #define[MMC_BIT_DO][2] // Pin number for DO signal, i.e. PA2 #define[MMC_BIT_CLK][3] // Pin number for CLK signal, i.e. PC3
From the firmware the SD card now can be accessed using the functions flash2_read_init
, flash2_read
, flash2_read_finish
,flash2_write_init
, flash2_write
, flash2_write_finish
. The syntax is is the same as of flash_read_*
and flash_write_*
functions.
From host software the SD card can be accessed using then functions flash2* (which are equivalent to the functions for primary flash).
Their usage can be explained with flashdemo
example ported to secondary flash. The firmware code is:
#include[ztex-conf.h] // Loads the configuration macros, see ztex-conf.h for the available macros #include[ztex-utils.h] // include basic functions and variables // select ZTEX USB FPGA Module 2.01 as target (required for FPGA configuration) IDENTITY_UFM_2_01(10.18.0.0,0); // enable Flash support ENABLE_FLASH; ENABLE_FLASH_BITSTREAM; ENABLE_FLASH2; // enables SD support as secondary Flash #define[MMC_PORT][C] // Port for input signals, valid values: A..D #define[MMC__PORT_DO][A] // Port for output signals (valid values: A..D, // can be omitted if equal to input port) #define[MMC_BIT_CS][1] // Pin number for CS signal, i.e. PC1 #define[MMC_BIT_DI][2] // Pin number for DI signal, i.e. PC2 #define[MMC_BIT_DO][2] // Pin number for DO signal, i.e. PA2 #define[MMC_BIT_CLK][3] // Pin number for CLK signal, i.e. PC3 // this product string is also used for identification by the host software #define[PRODUCT_STRING]["Flash2 demo for UFM 2.01"] __code char flash2_string[] = "Hello World!"; // include the main part of the firmware kit, define the descriptors, ... #include[ztex.h] void main(void) { __xdata DWORD sector; init_USB(); // init everything if ( flash2_enabled ) { flash2_read_init( 0 ); // prepare reading sector 0 flash2_read((__xdata BYTE*) §or, 4); // read the number of last sector flash2_read_finish(flash2_sector_size - 4); // dummy-read the rest of the sector + finish read operation sector++; if ( sector > flash2_sectors || sector == 0 ) { sector = 1; } flash2_write_init( 0 ); // prepare writing sector 0 flash2_write((__xdata BYTE*) §or, 4); // write the current sector number flash2_write_finish_sector(flash2_sector_size - 4); // dummy-write the rest of the sector + CRC flash2_write_finish(); // finish write operation flash2_write_init( sector ); // prepare writing sector sector flash2_write((__xdata BYTE*) flash2_string, sizeof(flash2_string)); // write the string flash2_write_finish_sector(flash2_sector_size - sizeof(flash2_string)); // dummy-write the rest of the sector + CRC flash2_write_finish(); // finish write operation } while (1) { } // twiddle thumbs }
and the host software is defined by
import java.io.*; import java.util.*; import ch.ntb.usb.*; 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" + " -ue Upload Firmware to EEPROM\n" + " -re Reset EEPROM Firmware\n" + " -w Enable certain workarounds\n" + " -h This help" ); public ParameterException (String msg) { super( msg + "\n" + helpMsg ); } } // ***************************************************************************** // ******* Test0 *************************************************************** // ***************************************************************************** class FlashDemo extends Ztex1v1 { // ******* FlashDemo *********************************************************** // constructor public FlashDemo ( ZtexDevice1 pDev ) throws UsbException { super ( pDev ); } // ******* main **************************************************************** public static void main (String args[]) { int devNum = 0; boolean force = false; boolean workarounds = false; try { // init USB stuff LibusbJava.usb_init(); // scan the USB bus 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("-w") ) { workarounds = true; } else if ( args[i].equals("-h") ) { System.err.println(ParameterException.helpMsg); System.exit(0); } else if ( !args[i].equals("-re") && !args[i].equals("-ue") ) throw new ParameterException("Invalid Parameter: "+args[i]); } // create the main class FlashDemo ztex = new FlashDemo ( bus.device(devNum) ); ztex.certainWorkarounds = workarounds; // upload the firmware if necessary if ( force || ! ztex.valid() || ! ztex.dev().productString().equals("Flash2 demo for UFM 2.01") ) { System.out.println("Firmware upload time: " + ztex.uploadFirmware( "flashdemo.ihx", force ) + " ms"); } for (int i=0; i<args.length; i++ ) { if ( args[i].equals("-re") ) { ztex.eepromDisable(); } else if ( args[i].equals("-ue") ) { System.out.println("Firmware to EEPROM upload time: " + ztex.eepromUpload( "flashdemo.ihx", force ) + " ms"); } } // print some information System.out.println("Capabilities: " + ztex.capabilityInfo(", ")); System.out.println("Enabled: " + ztex.flash2Enabled()); System.out.println("Size: " + ztex.flash2Size()); ztex.printMmc2State(); if ( ztex.getFlash2EC() == ztex.FLASH_EC_PENDING ) { System.out.print("Another operation is pending. Waiting .."); int i = 20; do { System.out.print("."); try { Thread.sleep( 1000 ); } catch ( InterruptedException e) { } i--; } while ( ztex.getFlash2EC()==ztex.FLASH_EC_PENDING && i>0 ); System.out.println(); } byte[] buf = new byte[ztex.flash2SectorSize()]; ztex.flash2ReadSector(0,buf); // read out the last sector; int sector = (buf[0] & 255) | ((buf[1] & 255) << 8) | ((buf[1] & 255) << 16) | ((buf[1] & 255) << 24); System.out.println("Last sector: "+sector); ztex.flash2ReadSector(sector,buf); // read out the string int i=0; while ( buf[i] != '\0'&& i < ztex.flash2SectorSize() ) i++; System.out.println("The string: `" + new String(buf,0,i)+ "'"); } catch (Exception e) { System.out.println("Error: "+e.getLocalizedMessage() ); } } }