The Digilent Atlys is a pretty good board! It has a nice, high speed VHDCI connector, gigabit Ethernet, HDMI, and DDR2 memory. Unfortunately it suffers from a manual with some glaring errors (including a misspelling of 'FPGA'), an Ethernet chip with an impossible-to-obtain datasheet, and a reference design that was created using the SDK. For those of us using ISE, read on!
I wanted to use the Gigabit Ethernet interface to send data (ideally in UDP packets) to a host computer at high speed. Most HDL experts say that this should be possible without using a microcontroller. They're right, but it's a big pain for several reasons.
Xilinx supplies a triple-speed Ethernet MAC core, TEMAC, but it requires a license, and if you had the money for one of those you could be using a Microblaze soft core and thus Digilent's reference implementation. Opencores.org has a gigabit MAC but I couldn't make much sense of it, which I find is pretty typical of my experience with the site.
Turning to a physically realised design that uses Gigabit, I delved into the USRP2 software defined radio's HDL and firmware. It uses a different chip, but contains a working GPL licensed gigabit-only MAC and MDIO interface. After many hours of studying this in an attempt to figure out how it works, pulling apart the Digilent reference design to figure out which registers I needed to set on the PHY, and then writing a state machine-based driver for the Wishbone bus, I came up with a working implementation, which I present to you here:
License is GPLv2, but parts written for the USRP2 are currently not attributed properly
It generates a hard-coded UDP packet (the size of the payload is controlled by the SPST switches) without checksums when the 'reset' button is pressed and works pretty well. The PHY is re-initialised when BTNU is pressed. Receiving is not implemented in the top-level test application (though it is included in the MAC implementation and I have no reason to think it wouldn't work). If you generate packets larger than 1500 bytes, you will need to increase your NIC's MTU (9000 should do it). Otherwise, large packets *will* mysteriously disappear.
The 88E1111's datasheet is only available under NDA (and in my experience the manufacturer will ignore your requests to obtain an NDA) but some clues are available in XAPP1042 and the reference designs in particular (e.g. XAPP1042_PPC405).
arp -s 169.254.77.1 0037ffff3737
The IP address doesn't actually matter (packet_receiver.v doesn't check it) but it will need to be on the same subnet as your computer. I used the auto-configuration range so your computer may (if it's Windows or OS X at least) eventually give up on DHCP and assign something in the 169.254/16 subnet. You can set a static address of anything, e.g. 192.168.0.1 and add the ARP entry for 192.168.0.2.
netcat -u 169.254.77.1 1234
They should be displayed on the serial port.
Use Wireshark or similar to see the packets, which are sent whenever btn is pressed. You should see the TX LED flash.
btn will re-initialise the PHY, which will cause all of the LEDs to flash a bit.
Note that there may be some clock domain crossing issues involving resets in this example that I haven't had a chance to fix. These don't affect operation.
Unfortunately the state machine approach is quite annoying and cumbersome, even for just sending a single packet. I would therefore like to design a similar aemb based soft core controller along with a tutorial on how to actually go about using aemb (once I figure it out myself), since one is sorely lacking. I may never bother with this, since I've lost all interest in using aemb for now.
I use a PLL to generate 90 and 270 degree clocks for the ODDR that drives the TX clock at 125 MHz. This is poor design - it's safe to use the ODDR's built-in clock inverter (and by some accounts much better). It should also be possible to avoid the extra PLL trickery and just clock TX at 180 degrees out of phase from the GMII signals. The 90 degree phase is just a leftover from when I was troubleshooting the design.
If you change the IP header (MAC and IP addresses), you will need to calculate a new header checksum, or your PC will drop the packets (and they won't be visible to Wireshark etc.).
These issues will be fixed at some point in the distant future when I feel inspired, but let me know if you need any help in the meantime.
I have written some extensive notes on using the MIG with the Atlys.
When building a board-to-board interface using the VHDCI connector, your options for male connectors are:
The final option is to use a female VHDCI connector (which are much more common than the male) and a VHDCI cable. Digilent sell these, and they're fairly common on eBay. I don't really like the idea of long, thick cables connecting to my tiny, fragile interface board though!
The reference manual states a few untruths about the HDMI interface. The Digilent test application uses an EDK-ed version of the XAPP495 code, and not the xps_tft core. XAPP495 does not provide an implementation of HDMI's EDID, so the dvi_demo may not work if you connect it to a source (such as some PC graphics cards) that require EDID. There are a couple of different solutions: setting the jumpers to allow for SCL/SDA pass-through (but this has some other caveats), using a DVI splitter cable to attach an extra monitor to the HDMI source, or implementing an EDID ROM. Please see my Improved XAPP495 design below.
Note that HDMI input J1 is disabled by default unless you install JP5, which is connected to the TMDS141 chip's output enable. This is not documented anywhere!
If you're new to ISE, here are the steps you'll need to take to try out XAPP495, or see below where you can download an
The vtc_demo should cause you no woe, but dvi_demo will probably require some reconfiguration of jumpers on the Atlys for it to work:
There's a more thorough analysis of the Atlys HDMI situation on the timvideos wiki.
An explanation of the DDC control signals, which are used for EDID. Looking at the schematics, the PMODA HDMI connector (an output - the unlabelled one on the bottom of the board) has its SDA/SCL connected to JA-SCL/JA-SDA and, if you fit JP2, which is labelled as "SDA" and "SCL" on the PCB, PMOD-SCL/PMOD-SDA.
JA-SCL/JA-SDA go to C13 and A13 (on the FPGA). PMOD-SCL/PMOD-SDA go through the HDMI buffer and to HDMI input J1. This means that the DDC for input 1 is either left floating (if JP2 isn't fitted) or is connected to some FPGA pins and output PMODA.
HDMI OUT J2 has its DDC connected to TMDS-TX-SCL/TMDS-TX-SCL (D9 and C9). If you fit JP6 and JP7, these are connected directly to HDMI IN J3's DDC
As a result, switching options are limited! HDMI sources (inputs) must be connected directly to one of the outputs, or not at all, and the connections are fixed. However it would be possible to work around this by connecting the four appropriate pins on JP2, JP6 and JP7 to spare inputs (e.g. on the PMOD connector JB).
Note that if you are using HDMI DDC pass-through, you will need to set the corresponding FPGA pins (C13 and A13, D9 and C9) to high impedance in your constraints file or else they will load the bus.
The XAPP495 examples were written for ISE12.x and are not compatibile with later versions - you will get the error "BUFIO2 has an invalid setting of DIVIDE by 2. This setting is not supported."
Xilinx forum user yetanotherid has provided a solution. Rather than using BUFIO2 to divide the 100 MHz system clock by 2, we now use a DCM (Digital Clock Manager) to generate the 50 MHz signal.
// In vtc_demo.v, replace this code: BUFIO2 #(.DIVIDE_BYPASS("FALSE"), .DIVIDE(2)) sysclk_div (.DIVCLK(clk50m), .IOCLK(), .SERDESSTROBE(), .I(sysclk)); // With this code: wire clkfb; DCM_SP #( .CLKDV_DIVIDE(2.0), .CLKFX_DIVIDE(1), .CLKFX_MULTIPLY(4), .CLKIN_DIVIDE_BY_2("TRUE"), .CLKIN_PERIOD(10.0), .CLKOUT_PHASE_SHIFT("NONE"), .CLK_FEEDBACK("1X"), .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), .DFS_FREQUENCY_MODE("LOW"), .DLL_FREQUENCY_MODE("LOW"), .DSS_MODE("NONE"), .DUTY_CYCLE_CORRECTION("TRUE"), .FACTORY_JF(16'hc080), .PHASE_SHIFT(0), .STARTUP_WAIT("FALSE") ) DCM_SP_inst ( .CLK0(clk50m), .CLK180(), .CLK270(), .CLK2X(), .CLK2X180(), .CLK90(), .CLKDV(), .CLKFX(), .CLKFX180(), .LOCKED(), .PSDONE(), .STATUS(), .CLKFB(clkfb), .CLKIN(sysclk), .DSSEN(1'b0), .PSCLK(1'b0), .PSEN(1'b0), .PSINCDEC(1'b0), .RST(1'b0) ); BUFIO2FB #( .DIVIDE_BYPASS("TRUE") ) BUFIO2FB_inst ( .O(clkfb), .I(clk50m) );
The XAPP495 design does the bare minimum to demonstrate the HDMI receiver / transmitter concept. It fails to work for most people due to EDID issues, and is not completely compatible with modern versions of Xilinx ISE. I have fixed a couple of problems in the design:
You can download it from here:
Some jumper setting is required:
I've had reports that this worked, but I'm not able to confirm it myself as I no longer have my Atlys!
The manual and a close look at the board indicates that the USB host is controlled by a PIC24FJ192, while the schematic says it's a PIC32MX440F256H-40I/MR!
The PIC will load a bit file placed on a USB drive formatted with a FAT file system if jumper JP11 is closed. Note that it takes about 26 seconds for the load process to complete! LED7 will be stuck on while JP11 is closed, but the jumper can be removed once the FPGA has been initialised.
Some fine investigative work by Stromeko has revealed that only USB devices advertising a current consumption of 100 mA (or less) will work. If your device isn't working, check the USB descriptor on a computer.
The PS/2 interface provided by the PIC uses open drain ports, so it's necessary to provide pull-up constraints. Note that the manual is wrong - the PS/2 mouse clock and data pins are swapped. The following constraints are correct:
Net "PS2DATA" LOC = N18 | IOSTANDARD = LVCMOS33 | PULLUP; Net "PS2CLOCK" LOC = P18 | IOSTANDARD = LVCMOS33 | PULLUP;
The Atlys has a USB-serial device, which works fine, but for higher speeds consider using MakeStuff FPGALink. It is a library and firmware for the Cypress FX2LP USB controller (the "PROG" interface) that replaces Digilent Adept and provides an open source, cross platform bitstream upload facility and a high speed (40 MB/s) data transfer facility.
There's now a version of the PicoBlaze soft processor for the Spartan-6, but it didn't originally include the UART peripheral that came with the Spartan-3 core. I've fixed the UART so that it synthesises and runs on the Atlys and have written a small demo/framework design based on the old alarm clock demo. It's intended as a nice starting point for new designs that require PicoBlaze.
Note that a new version of KCPSM6 has since been released, complete with UART, so you should drop the new files into this demo until I get around to updating it.
Predictably, the manual again has some grievous errors. The references to the 1/8" audio ports (J15-J18) are wrong (should be J4-J8), as is the codec (IC19 should be IC3). The FPGA pin assignments given in the diagram on page 14 are correct (N16, L13, T18, U17, T17), but those in the table on page 15 are wrong. This was probably copied and pasted from another board's manual and not corrected.
Digilent's built-in self test application has plenty of code for decoding and encoding AC'97 frames (ac97_if), and comprehensive example MicroBlaze C code for initialising and playing with the codec (ac97_if_00.c).
Digilent have now released a MicroBlaze design demonstrating just AC'97.
Jose Juan Garcia-Hernandez from Cinvestav Tamaulipas has written a VHDL implementation of AC'97 for the Atlys. It includes a demo that passes audio from line in to line out, and allows volume and channel to be controlled. He has kindly released it without restriction but asks for a citation if you use it.
It's impossible to tell because the Spartan-6 chip on the Atlys has a heatsink attached, but according to mrflibble, Digilent report that it's a -2. The BSB files that Digilent supply claims that it's a -3.
Stromeko has some interesting notes about the Atlys, including errata.
BASTLI has created an expansion board and turned the Atlys into a logic analyser called BitHound based on SUMP.