Bar
SpaceWire UK
Specialist providers of VHDL Intellectual Property & Design Services
BarBarBarBar
Tutorial
Missing Image!
Part 17 - Update website to allow access to Programmable Logic address space

Introduction

This tutorial details the steps required to add form elements to the existing website such that the Programmable Logic address space can be accessed from a webpage.

Aims

The aims of this tutorial are as follows :-
  1. Setup environment
  2. Change present working directory
  3. Add form elements to website
  4. Add extra Javascript functions
  5. Build, package & deploy on Zedboard
  6. Check everything is working

1. Setup environment

Setup Xilinx design environment for the 2020.2 toolset.
steve@Linux-Steve:/home/steve$ source xilinx.sh
Xilinx tools available tools at /opt/Xilinx :-
1) 2020.2 - Vivado - SDK - Vitis - PetaLinux
0) Exit
Please select tools required or exit : 1

Tools are as follows :-
vivado @ /opt/Xilinx/Vivado/2020.2/bin/vivado
vitis @ /opt/Xilinx/Vitis/2020.2/bin/vitis
petalinux-build @ /opt/Xilinx/PetaLinux/2020.2/tool/tools/common/petalinux/bin/petalinux-build

2. Change present working directory

Change the present working directory to be the project directory.
steve@Linux-Steve:/home/steve$ cd /home/steve/projects/petalinux/avnet-digilent-zedboard-2020.2

3. Add form elements to website

Edit the existing dynamic webpage file to add read & write register functionality using HTML forms linked to Javascript functions. Lines 59-77 show the additions.
steve@Linux-Steve:/home/steve/projects/petalinux/avnet-digilent-zedboard-2020.2$ subl project-spec/meta-user/recipes-apps/website/files/cgi-bin/index.cgi

index.cgi

  1. #!/bin/sh

  2. # Output Header
  3. printf "Content-type: text/html\r\n\r\n"

  4. # Get information
  5. sys_host=$(hostname)
  6. sys_time=$(date)
  7. sys_load=$(awk '{print $1}' /proc/loadavg)
  8. sys_up=$(awk '{print $1}' /proc/uptime)
  9. cpu_model=$(grep model /proc/cpuinfo | cut -d : -f2 | tail -1 | sed 's/\s//')
  10. cpu_cores=$(grep -c ^processor /proc/cpuinfo)
  11. mem_total=$(free -m | awk 'NR==2{print $2}')
  12. mem_used=$(free -m | awk 'NR==2{print $3}')
  13. mem_free=$(free -m | awk 'NR==2{print $4}')
  14. net_mac=$(cat /sys/class/net/eth0/address)
  15. net_ip_loc=$(ip a | grep inet | grep -vw lo | grep -v inet6 | cut -d \/ -f1 | sed 's/[^0-9\.]*//g')
  16. net_ip_ext=$(wget -q -O- http://ipecho.net/plain)

  17. # Output HTML
  18. printf '<!DOCTYPE html>'
  19. printf '<html lang="en">'
  20. printf '<head>'
  21. printf '<meta http-equiv="content-type" content="text/html; charset=UTF-8">'
  22. printf '<script src="../uptime.js"></script>';
  23. printf '<title>Zedboard webserver</title>'
  24. printf '</head>'
  25. printf '<body>'
  26. printf 'Hello from your Zedboard webserver...'
  27. printf '<br>'
  28. printf '<img src="../zedboard.png" alt="Missing Image!">'

  29. printf '<br>System<br>'
  30. printf 'Honstname: %s<br>' "${sys_host}"
  31. printf 'Time: %s<br>' "${sys_time}"
  32. printf 'Uptime: <span id="uptime_text">%.2f</span> seconds ' ${sys_up}
  33. printf '​<button onclick="GetUpTime()">Refresh</button>'
  34. printf '​ Auto : <select onchange="SetTimeout(this)">'
  35. printf '​<option value="0">Off</option>'
  36. printf '​<option value="1">1s</option>'
  37. printf '​<option value="5">5s</option>'
  38. printf '​</select><br>'

  39. printf '<br>CPU<br>'
  40. printf 'Model: %s<br>' "${cpu_model}"
  41. printf 'Cores: %d<br>' ${cpu_cores}
  42. printf 'Load: %.2f<br>' ${sys_load}

  43. printf '<br>Memory<br>'
  44. printf 'Total: %d Mb<br>' ${mem_total}
  45. printf 'Used: %d Mb<br>' ${mem_used}
  46. printf 'Free: %d Mb<br>' ${mem_free}

  47. printf '<br>Network<br>'
  48. printf 'MAC Address: %s<br>' "${net_mac}"
  49. printf 'Local IP: %s<br>' "${net_ip_loc}"
  50. printf 'External IP: %s<br>' "${net_ip_ext}"

  51. printf '<br>';
  52. printf '<form onsubmit="return false;">'
  53. printf ' <label for="waddr">Write : address</label>'
  54. printf ' <input type="text" id="waddr" name="waddr" value="0x41200000" size="10">'
  55. printf ' <label for="wdata">data </label>'
  56. printf ' <input type="text" id="wdata" name="wdata" value="0x00000000" size="10">'
  57. printf ' <input type="submit" value="Write" onclick="WebWrite(this.form)">'
  58. printf ' Status : <span id="wstatus">None</span>';
  59. printf '</form>';

  60. printf '<br>';
  61. printf '<form onsubmit="return false;">'
  62. printf ' <label for="raddr">Read : address</label>'
  63. printf ' <input type="text" id="raddr" name="raddr" value="0x41200000" size="10">'
  64. printf ' <label for="rdata">data</label>'
  65. printf ' <input type="text" id="rdata" name="rdata" value="0x00000000"  size="10" readonly>'
  66. printf ' <input type="submit" value="Read" onclick="WebRead(this.form)">'
  67. printf ' Status : <span id="rstatus">None</span>';
  68. printf '</form>';

  69. printf '</body>'
  70. printf '</html>'

4. Add extra Javascript functions

Edit the existing Javascript file to add read and write register requests that call the peek & poke CGI scripts and update the webpage accordingly. Lines 37-80 show the additions.
steve@Linux-Steve:/home/steve/projects/petalinux/avnet-digilent-zedboard-2020.2$ subl project-spec/meta-user/recipes-apps/website/files/uptime.js

uptime.js

  1. // Requests
  2. var uptime_req;
  3. var timer_req;
  4. var write_req;
  5. var read_req;

  6. // Receive data & update webpage accordingly
  7. function GotUptime() {
  8.   if (uptime_req.readyState == 4 && uptime_req.status == 200) {
  9.     txtObj = document.getElementById("uptime_text");
  10.     if (txtObj !== null) {
  11.       txtObj.innerHTML = uptime_req.responseText;
  12.     }
  13.   }
  14. }

  15. // Setup request and ask for data return
  16. function GetUpTime() {
  17.   if (window.XMLHttpRequest) {
  18.     uptime_req = new XMLHttpRequest();
  19.     uptime_req.abort();
  20.     uptime_req.onreadystatechange = GotUptime;
  21.     uptime_req.open("POST", "/cgi-bin/uptime.cgi", true);
  22.     uptime_req.send(null);
  23.   }
  24. }

  25. // Setup/Cancel timer request
  26. function SetTimeout(obj) {
  27.   clearInterval(timer_req);
  28.   var interval = obj.value;
  29.   if (interval > 0) {
  30.     timer_req = setInterval("GetUpTime()", 1000 * interval);
  31.   }
  32. }

  33. // Receive data & update webpage accordingly
  34. function GotWrite() {
  35.   if (write_req.readyState == 4 && write_req.status == 200) {
  36.     if (write_req.responseText === "failed") {
  37.       document.getElementById("wstatus").innerHTML = "Failed";
  38.     } else {
  39.       document.getElementById("wstatus").innerHTML = "Success";
  40.     }
  41.   }
  42. }

  43. // Setup request and ask for data return
  44. function WebWrite(form) {
  45.   if (window.XMLHttpRequest) {
  46.     write_req = new XMLHttpRequest();
  47.     write_req.abort();
  48.     write_req.onreadystatechange = GotWrite;
  49.     write_req.open("POST", "/cgi-bin/poke.sh?addr=" + form.waddr.value + "&val=" + form.wdata.value, true);
  50.     write_req.send(null);
  51.   }
  52. }

  53. // Receive data & update webpage accordingly
  54. function GotRead() {
  55.   if (read_req.readyState == 4 && read_req.status == 200) {
  56.     if (read_req.responseText === "failed") {
  57.       document.getElementById("rstatus").innerHTML = "Failed";
  58.     } else {
  59.       document.getElementById("rstatus").innerHTML = "Success";
  60.       document.getElementById("rdata").value = read_req.responseText.toUpperCase();
  61.     }
  62.   }
  63. }

  64. // Setup request and ask for data return
  65. function WebRead(form) {
  66.   if (window.XMLHttpRequest) {
  67.     read_req = new XMLHttpRequest();
  68.     read_req.abort();
  69.     read_req.onreadystatechange = GotRead;
  70.     read_req.open("POST", "/cgi-bin/peek.sh?addr=" + form.raddr.value, true);
  71.     read_req.send(null);
  72.   }
  73. }

5. Build, package & deploy on Zedboard

Rebuild the project to include the updated files, package it up ready for deployment, power cycle the Zedboard and deploy via JTAG.
steve@Linux-Steve:/home/steve/projects/petalinux/avnet-digilent-zedboard-2020.2$ petalinux-build
steve@Linux-Steve:/home/steve/projects/petalinux/avnet-digilent-zedboard-2020.2$ petalinux-package --prebuilt --force
steve@Linux-Steve:/home/steve/projects/petalinux/avnet-digilent-zedboard-2020.2$ petalinux-boot --jtag --prebuilt 3

6. Check everything is working

Access the webserver running on the Zedboard using a browser pointing at the Zedboard's IP address. All being well something akin to the following webpage should be displayed. Missing Image! Registers within the Programmable Logic can now be accessed directly using the Read & Write forms at the bottom of the webpage. To write a register set the write address, write data and press the Write button. Likewise to read a register set the read address and press the Read button. As before the LED register is located at 0x41200000 and the slide switch register at 0x41200008. The status of the executed request is shown next the the Status text. Note the Javascript functions do not contain any timeout functionality so if the CGI scripts do not respond with anything then no error status will be reported.