This tutorial will demonstrate an HTTP web server running over Ethernet on Waxwing Spartan 6 FPGA Development board. A web server is a hardware or software that serves web pages requested by clients (such as web browsers) via HTTP protocol. The HTTP is a stateless, request-response based protocol that responds to client’s commands and submits requests to HTTP server. The communication over HTTP is a sequence of request and response transactions over TCP. The client establishes TCP connection with server by initiating a request to a particular port (typically port 80) on server. Once a connection is established, server listens to client’s request messages. Whenever a request is received, the server sends response with status and/or the requested data. This article will use Ethernet as its Link Layer protocol. The MAC layer (data link layer) layer running on FPGA is interfaced with external Ethernet PHY (Physical layer) using RMII (Reduced Media-Independent Interface). The MAC Layer converts the packets into stream of data while the physical layer converts the stream of data into electrical signals. FPGA will run the lwIP TCP/IP stack, on top of which HTTP server will be running. This example will demonstrate how users can toggle LEDs on Waxwing board using their web browsers.
- Waxwing Spartan 6 FPGA Development Board
- Xilinx Platform Cable USB II JTAG Debugger
- Ethernet cable
- Xilinx ISE Design Suite with EDK/XPS 14.7
Users are also expected to be familiar with Xilinx ISE Design Suite, Xilinx Platform Studio and Embedded Development Kit. Familiarity with lwIP will help in understanding the code easily.
Let’s Get Started!
XPS Base System Builder (BSB) is used to simplify creating new projects. To make the process easier, download BSB Wizard files from here and extract it to the folder “C:\Xilinx\xx.xx\ISE_DS\EDK\board”. Once extracted, the complete path to the file should look like C:\Xilinx\xx.xx\ISE_DS\EDK\board\NumatoLab\ipxact\WaxwingDevBoardLX45_V3\data”.
Open Xilinx Platform Studio from Start Menu. Go to ‘File’ and select ‘New BSB Project…’. It will open XPS new project wizard.
Browse to a convenient project location and enter a project name. Click OK. It will open ‘Base System Builder’ configuration window.
In ‘Board and System Selection’ page, select Board Vendor as ‘Numato Lab’ and Board Name as ‘Waxwing Dev Board LX45’. Click ‘Next’.
In ‘Processor, Cache and Peripheral Configuration’ page, select local memory size as 16 KB and include peripherals as shown below. Select ‘Use Interrupt’ for Ethernet_MAC and axi_timer IP cores and click Finish. It will create a new project with the selected settings.
Open the ‘<ProjectName>.ucf’ file from project files, delete all existing text and copy-paste the following constraints to the ucf file and save it.
NET CLK_100MHZ LOC = "V10" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_COL LOC = "U16" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_CRS LOC = "P17" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_MDC LOC = "T18" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_MDIO LOC = "V16" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_PHY_RST_N LOC = "P18" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_RXD LOC = "U17" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_RXD LOC = "U18" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_RXD LOC = "M18" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_RXD LOC = "M16" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_RX_CLK LOC = "T10" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_RX_DV LOC = "N14" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_RX_ER LOC = "P16" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_TXD LOC = "N16" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_TXD LOC = "N15" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_TXD LOC = "V12" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_TXD LOC = "T12" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_TX_CLK LOC = "R10" | IOSTANDARD = "LVCMOS33"; NET Ethernet_MAC_TX_EN LOC = "M14" | IOSTANDARD = "LVCMOS33"; NET LED LOC = "F9" | IOSTANDARD = "LVCMOS33"; NET LED LOC = "G9" | IOSTANDARD = "LVCMOS33"; NET LED LOC = "C15" | IOSTANDARD = "LVCMOS33"; NET LED LOC = "A15" | IOSTANDARD = "LVCMOS33"; NET LED LOC = "U5" | IOSTANDARD = "LVCMOS33"; NET LED LOC = "V5" | IOSTANDARD = "LVCMOS33"; NET LED LOC = "V7" | IOSTANDARD = "LVCMOS33"; NET LED LOC = "U7" | IOSTANDARD = "LVCMOS33"; NET uart1_sin LOC = "N11" | IOSTANDARD = "LVCMOS33"; NET uart1_sout LOC = "M11" | IOSTANDARD = "LVCMOS33"; NET "CLK_100MHZ" TNM_NET = sys_clk_pin; TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 100000 kHz; NET "RESET" LOC = "B6" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLDOWN = TRUE;
From the Navigator, click “Generate Bitstream” and wait for the process to get completed. Next, click “Export Design” and select “Export and Launch SDK”. Click ‘OK’. This should launch the Xilinx SDK window.
In Xilinx SDK, select File -> New -> Application Project.
Enter project name as ‘web_server’ and click ‘Next’. It will open ‘Templates’ page. Select ‘lwIP Echo Server’ as template and click ‘Finish’.
In the previous step, the Xilinx SDK created a sample TCP Echo Server using lightweight IP (lwIP) open-source TCP/IP stack. lwIP supports both BSD-style Socket API as well as RAW API using callbacks. The sample echo server created by Xilinx SDK uses RAW API. Readers are encouraged to take a look at the code to understand its working because the same lwIP stack will be used to implement HTTP web server also.
This article follows the Xilinx Application Note 1026 titled “LightWeight IP Application Examples”. In the following paragraph, a short description of the workflow of the code is explained.
Code execution starts from the main() function where ‘lwip’ and ‘platforms’ are initialized, after which
start_web_application() is called. In this function, a TCP PCB (Protocol Control Block) structure is created and the TCP PCB is bound to port number 80. After binding, the port starts listening for connections. When client (web browser) makes an HTTP request, the TCP connection state changes from LISTEN to ESTABLISHED. The connection is then established with client. After this, the code checks for any incoming packets in an infinite while loop. In case of packet reception, the packet is stored in
pbuf (packet buffer) and its payload is extracted.
The whole application works with 3 important callback functions:
http_accept_callback: This function is called by
tcp_accept(), which is called when the listening connection changes to established state, i.e, client is now connected.
http_recv_callback: This function is called by
tcp_recv(), which is called whenever any TCP packet is received. The
pbufis passed to
http_recv_callback(), the data is parsed as per HTTP protocol specification and response is generated accordingly.
http_sent_callback: This function is called by
tcp_sent(), which is called when a TCP packet has been sent successfully, it will check if there is any more data to be sent and sends the remaining data (if any).
The graphical flow of the code is illustrated below:
Download the source code for this project from here. Go to web_server -> src, remove all files except ‘lscript.ld’ and and add the downloaded source files to the project.
In ‘Project Explorer’, right-click on ‘web_server_bsp’ and select ‘Board Support Package Settings’. From the supported libraries list, select ‘lwip140’ and ‘xilmfs’.
Open ‘lwip140’ library configuration window, under ‘temac_adapter_options’ select phy_link_speed as ‘CONFIG_LINKSPEED100’.
Open ‘xilmfs’ library configuration, and change the settings as shown below, ‘numbytes’ is the size of MFS image in bytes. Click ‘OK’ and build the project in case it is not built automatically.
Note: The base address of LPDDR is ‘0xA4000000’, where the code will be located. So ‘base_address’ for MFS image is configured to 0xA5000000 to avoid overwriting the code area.
Creating MFS Image:
Once the design is ready, MFS (Memory File System) image needs to be written to memory for testing the web server. The MFS image contains the index.html file which is opened and read when the web server receives
GET command i.e. when a client requests a web page.
copy the following code in text editor and save it as ‘index.html’ in the project directory ‘/SDK/web_server/Debug’.
In Xilinx SDK, go to Xilinx Tools -> Launch Shell.
In command shell, go to the directory where ‘index.html’ is saved, and give the following command to create ‘image.mfs’ file
mfsgen -cvbf image.mfs 400 index.html
Running the Design on Hardware:
Set up the hardware by connecting JTAG, power supply and Ethernet cable.
In Windows, go to Control Panel -> Network and Internet -> Network and Sharing Centre. Double-click on ‘Ethernet’ adapter, click on ‘Properties’, select IPv4 properties and change the IP address, Subnet mask and Default gateway as shown below. If you use any other host operating system, configure the network interface as applicable.
Open the serial port of Waxwing in any serial terminal application (such as PuTTY) with the Baud-rate set as 9600.
In SDK, go to Xilinx Tools -> Program FPGA and click ‘Program’.
Go to Xilinx Tools -> XMD Console. Enter the following commands in XMD console
connect mb mdm cd SDK/web_server/Debug dow -data image.mfs 0xA5000000 dow web_server.elf con
Open any web browser and enter the following url
It will open the ‘index.html’ file that was stored in MFS image. Click on ‘Toggle LEDs’, to turn on/off LEDs on Waxwing Board and notice the LEDs toggling their state on the Waxwing board.
The serial terminal will show important debug and status information.
That was it! A simple web server running on Waxwing Spartan 6 Development board. You are encouraged to check out the source code and try to improvise it and add additional capabilities to this example design.