Digilent Nexys

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

FPGA-Board, verfügbar mit Xilinx Spartan 3-200, -400 und -1000, Speedgrade 4.

Nexys mit Erweiterungsboard FX2-BB


Dokumentation

RAM

Das RAM ist ein MT45W8MW16 PSRAM (pseudo-statisches RAM) von Micron. Im einfachsten Fall kann es wie ein (mit 70 ns leider ziemlich langsames) SRAM angesteuert werden (Beispiel unter T51-Core). Schneller geht es mit dem synchronen Burst-Mode, der auch nicht besonders schwierig zu implementieren sein sollte.

Beispieldesigns

Cypress FX2-Firmware

Die USB-Verbindung wird durch einen Cypress FX2-Mikrocontroller realisiert.

Die vorinstallierte Firmware ermöglicht rudimentäre Verbindungen zu der auf der Digilent Webseite bereitgestellten Adept-Software. Das ebenfalls bereitgestellte "dpimref.vhd"-Modul kann für einen Datentransfer zwischen PC und FPGA benutzt werden. Ein Mapping der dort verwendeten Signale auf die USB-Signale innerhalb des Schematics ist dabei folgendermaßen (funktioniert so auch für das Basys Board und vermutlich allen anderen FX2 basierten Digilent Produkten):

ASTRB <-> U-FLAGA
DSTRB <-> U-FLAGB
WAIT <-> U-SLRD
WRITE <-> U-FLAGC
DATA(7:0) <-> U-FD7 bis U-FD0

FX2-Firmware Hacking

Wie man die Firmware durch seine eigene ersetzen kann wird hier erklärt: http://www.hackdaworld.org/cgi-bin/awki.cgi/NexysFPGA

FX2-Firmware von ixo.de

Es ist auch möglich, die Firmware des Projektes "usb_jtag" von http://www.ixo.de/ leicht anzupassen, um dann mittels UrJtag auf den FPGA zuzugreifen. Dabei geht man wie folgt vor:

Zunächst muß man wie unter http://www.hackdaworld.org/cgi-bin/awki.cgi/NexysFPGA beschrieben, die SDA-Leitung am FX2-Mikrocontroller durchtrennen.

Danach kann man direkt die FX2-Firmware und die JTAG-Software installieren:

Firmware

 # wget "http://www.ixo.de/info/usb_jtag/usb_jtag-20080705-1200.zip"
 # unzip usb_jtag-20080705-1200.zip
 # cd usb_jtag/device/c51
 # cat hw_nexys.c # folgende C-Datei aus dem Wiki mit Copy und Paste in den Ordner kopieren:

usb_jtag/device/c51/hw_nexys.c:

<c> /*-----------------------------------------------------------------------------

* Hardware-dependent code for usb_jtag
*-----------------------------------------------------------------------------
* Copyright (C) 2007 Kolja Waschk, ixo.de
*-----------------------------------------------------------------------------
* This code is part of usbjtag. usbjtag is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version. usbjtag is distributed in the hope
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.  You should have received a
* copy of the GNU General Public License along with this program in the file
* COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin
* St, Fifth Floor, Boston, MA  02110-1301  USA
*-----------------------------------------------------------------------------
*/
  1. include <fx2regs.h>
  2. include "hardware.h"
  3. include "delay.h"

//-----------------------------------------------------------------------------

/* JTAG TCK, AS/PS DCLK */

sbit at 0xB4 TCK;

  1. define bmTCKOE bmBIT4
  2. define SetTCK(x) do{TCK=(x);}while(0)

/* JTAG TDI, AS ASDI, PS DATA0 */

sbit at 0xB2 TDI;

  1. define bmTDIOE bmBIT2
  2. define SetTDI(x) do{TDI=(x);}while(0)

/* JTAG TMS, AS/PS nCONFIG */ sbit at 0xB3 TMS;

  1. define bmTMSOE bmBIT3
  2. define SetTMS(x) do{TMS=(x);}while(0)

/* JTAG TDO, AS/PS CONF_DONE */

sbit at 0xB0 TDO;

  1. define bmTDOOE bmBIT0
  2. define GetTDO(x) TDO

//-----------------------------------------------------------------------------

  1. define bmPROGOUTOE (bmTCKOE|bmTDIOE|bmTMSOE)
  2. define bmPROGINOE (bmTDOOE)

//-----------------------------------------------------------------------------

void ProgIO_Poll(void) {} // These aren't called anywhere in usbjtag.c, but I plan to do so... void ProgIO_Enable(void) {} void ProgIO_Disable(void) {} void ProgIO_Deinit(void) {}


void ProgIO_Init(void) {

 /* The following code depends on your actual circuit design.
    Make required changes _before_ you try the code! */
 // set the CPU clock to 48MHz, enable clock output to FPGA
 CPUCS = bmCLKOE | bmCLKSPD1;
 // Use external clock, use "Slave FIFO" mode for all pins
 //IFCONFIG = bmIFCFG1 | bmIFCFG0;
 //IFCONFIG = bmIFCFG0;
 //IFCONFIG = 0xcb;
 // pin 7 of port d enables fpga power supply
 OED |= (1<<7);
 IOD |= (1<<7);
 mdelay(500);
 /* p. 180: must be set to 1 */
 REVCTL=0;//((1<<0)|(1<<1));
 // TDO input, others output
 OED=(OED&~bmPROGINOE) | bmPROGOUTOE;
 OED |= bmPROGOUTOE;
 OED &= ~bmPROGINOE;
 IOD &= ~(bmPROGOUTOE);
 // pin 5 of port d disables tdi -> tdo forward
 OED|=(1<<5);
 IOD|=(1<<5);

}

void ProgIO_Set_State(unsigned char d) {

 /* Set state of output pins:
  *
  * d.0 => TCK
  * d.1 => TMS
  * d.2 => nCE (only #ifdef HAVE_AS_MODE)
  * d.3 => nCS (only #ifdef HAVE_AS_MODE)
  * d.4 => TDI
  * d.6 => LED / Output Enable
  */
 SetTCK((d & bmBIT0) ? 1 : 0);
 SetTMS((d & bmBIT1) ? 1 : 0);
 SetTDI((d & bmBIT4) ? 1 : 0);

}

unsigned char ProgIO_Set_Get_State(unsigned char d) {

 /* Set state of output pins (s.a.)
  * then read state of input pins:
  *
  * TDO => d.0
  * DATAOUT => d.1 (only #ifdef HAVE_AS_MODE)
  */
 ProgIO_Set_State(d);
 return 2|GetTDO(); /* DATAOUT assumed high, no AS mode */

}

//-----------------------------------------------------------------------------

void ProgIO_ShiftOut(unsigned char c) {

 /* Shift out byte C:
  *
  * 8x {
  *   Output least significant bit on TDI
  *   Raise TCK
  *   Shift c right
  *   Lower TCK
  * }
  */
 (void)c; /* argument passed in DPL */
 _asm
       MOV  A,DPL
       ;; Bit0
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       ;; Bit1
       RRC  A
       CLR  _TCK
       MOV  _TDI,C
       SETB _TCK
       ;; Bit2
       RRC  A
       CLR  _TCK
       MOV  _TDI,C
       SETB _TCK
       ;; Bit3
       RRC  A
       CLR  _TCK
       MOV  _TDI,C
       SETB _TCK
       ;; Bit4
       RRC  A
       CLR  _TCK
       MOV  _TDI,C
       SETB _TCK
       ;; Bit5
       RRC  A
       CLR  _TCK
       MOV  _TDI,C
       SETB _TCK
       ;; Bit6
       RRC  A
       CLR  _TCK
       MOV  _TDI,C
       SETB _TCK
       ;; Bit7
       RRC  A
       CLR  _TCK
       MOV  _TDI,C
       SETB _TCK
       NOP
       CLR  _TCK
       ret
 _endasm;

}

/*

For ShiftInOut, the timing is a little more
critical because we have to read _TDO/shift/set _TDI
when _TCK is low. But 20% duty cycle at 48/4/5 MHz
is just like 50% at 6 Mhz, and that's still acceptable
  • /

unsigned char ProgIO_ShiftInOut(unsigned char c) {

 /* Shift out byte C, shift in from TDO:
  *
  * 8x {
 *   Read carry from TDO
  *   Output least significant bit on TDI
  *   Raise TCK
  *   Shift c right, append carry (TDO) at left
  *   Lower TCK
  * }
  * Return c.
  */
  (void)c; /* argument passed in DPL */
 _asm
       MOV  A,DPL
       ;; Bit0
       MOV  C,_TDO
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       CLR  _TCK
       ;; Bit1
       MOV  C,_TDO
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       CLR  _TCK
       ;; Bit2
       MOV  C,_TDO
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       CLR  _TCK
       ;; Bit3
       MOV  C,_TDO
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       CLR  _TCK
       ;; Bit4
      MOV  C,_TDO
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       CLR  _TCK
       ;; Bit5
       MOV  C,_TDO
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       CLR  _TCK
       ;; Bit6
       MOV  C,_TDO
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       CLR  _TCK
       ;; Bit7
       MOV  C,_TDO
       RRC  A
       MOV  _TDI,C
       SETB _TCK
       CLR  _TCK
       MOV  DPL,A
       ret
 _endasm;
 /* return value in DPL */
 return c;

} </c>

Nach dem Anlegen der Datei "hw_nexys.c" kann die Firmware mittels:

 # make HARDWARE=hw_nexys

übersetzt werden. Mittels dem Tools "fxload" kann die Firmware dann temporär auf den FX2-Mikrocontroller geladen werden (vgl. [1]):

 # cd ~/bin; wget http://www.erazor-zone.de/ez/projects/linux/getdevpath
 # chmod +x ~/bin/getdevpath
 # fxload -t fx2 -D $(getdevpath -v 04b4 -p 8613) -I std.hex

Der "nackte" FX2 hat, wenn man (wie in der hackdaworld.org-Anleitung oben nachliest) die SDA-Datenleitung zum Flash durchtrennt laut "lsusb" folgende ID, über die man ihn im Pfad im /dev-Dateisystem findet:

 # lsusb
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 008: ID 04b4:8613 Cypress Semiconductor Corp. CY7C68013 EZ-USB FX2 USB 2.0 Development Kit
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Ist die FX2-Firmware geladen, sollten auf dem Nexys-Board die acht LEDs (stärker) leuchten (- ohne geladene FX2-Firmware sind die LEDs leicht gedimmt), und der FX2-Mikrocontroller sich mittels "lsusb" nun als "VOTI" melden:

 # lsusb 
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 009: ID 16c0:06ad VOTI
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

JTAG-Software

Nimmt man nun ein aktuelles Release von URJtag (hier: svn Version 1356), kann man nach dem "./configure; make && make install" sofort loslegen (vgl. [2]).

Man muß lediglich beachten, daß man die richtigen BSDL-Dateien aus dem Xilinx-Ordner in das Verzeichnis /usr/local/share/urjtag/bsdl/ kopiert (die BSDL-Dateien heißen in der Xilinx-Installation "*.bsd"), damit URJtag beim "detect" die Chips richtig erkennt.

mobil11:~/.svn/fpga/Nexys_demo_simple# jtag

UrJTAG 0.8 #1356
Copyright (C) 2002, 2003 ETC s.r.o.
Copyright (C) 2007, 2008 Kolja Waschk and the respective authors

UrJTAG is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
There is absolutely no warranty for UrJTAG.

WARNING: UrJTAG may damage your hardware!
Type "quit" to exit, "help" for help.

jtag> bsdl path /usr/local/share/urjtag/bsdl
jtag> cable UsbBlaster ftdi 16c0:06ad
Connected to libftdi driver.
jtag> detect
IR length: 14
Chain length: 2
Device Id: 11110101000001000110000010010011 (0x00000000F5046093)
  Filename:     /usr/local/share/urjtag/bsdl/xcf04s.bsd
Device Id: 00010001010000101000000010010011 (0x0000000011428093)
  Filename:     /usr/local/share/urjtag/bsdl/xc3s1000l.bsd
jtag> print chain
 No. Manufacturer              Part                 Stepping Instruction          Register
-------------------------------------------------------------------------------------------------------------------
   0                           XCF04S                        BYPASS               BYPASS
   1                           XC3S1000L_BARE                BYPASS               BYPASS
jtag> part 1
jtag> svf Nexysdemo.svf
Warning: USB-Blaster frequency is fixed to 12000000 Hz
Warning svf: command TIR not implemented
Warning svf: command TDR not implemented
Warning svf: command TIR not implemented
Warning svf: command TDR not implemented
Warning svf: command HIR not implemented
Warning svf: command HDR not implemented
Warning svf: command TIR not implemented
Warning svf: command TDR not implemented
Error svf: SIR command length inconsistent.
 in input file between line 6623 col 1 and line 6623 col 33
Error occured for SVF command SIR.
jtag> quit
mobil11:~/.svn/fpga/Nexys_demo_simple#

Die usb_jtag-Firmware wird in URJtag als "Altera USB-Blaster" erkannt. Wichtig beim "cable"-Kommando ist die Angabe der USB-ID "16c0:06ad".

Beim Erzeugen der SVF-Datei im Impact muß man darauf achten, daß alle Geräte des JTAG-Chains des Nexys-Boards in der Datei enthalten sind.

Anregungen bitte via Jabber an koppi@jabber.ccc.de