Adapting Wishbone Cores For Use With The Papilio And DesignLab

After a hiatus of about a year I’ve pulled out my Papilio One FPGA board and started working on my VHDL programming skills again. The majority of my previous efforts involved putting together Wishbone cores for the ZPUino softcore and I thought I’d pick up where I left off. However, since I last spent any time with the Papilio toolset the community has moved on to the DesignLab IDE.

DesignLab is a great piece of software, allowing for the graphical design of FPGAs using chips from the included library of circuits. It even allows you to create projects based upon the ZPUino and AVR8 softcores.

But what about all those cores I designed using the old toolset? After studying tutorials on the GadgetFactory site and considering the problem, I came up with a workflow that allows me to adapt my existing WishBone cores for use in DesignLab and thought I’d share it for anyone else who might want to do something similar.

In The Beginning…

For this example, I’ll update a basic WishBone core for use as a DesignLab library. The VHDL code is listed below. All it does is write a value to a register and read it back out.

--
--  Basic Wishbone Core
-- 
--  Version: 1.0
--
--  Copyright 2014 J. Consugar
-- 
--  This code is in the public domain.
--  
--  This core does nothing but write a value to a register and allow
--  it to be read back.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.ALL;
use ieee.std_logic_misc.ALL;
use std.textio.all;

library work;
use work.zpu_config.all;
use work.zpupkg.all;
use work.zpuinopkg.all;

entity basic_wishbone is
  port (
    -- Wishbone signals.
    -- ZPUino has a 32 bit word size.
    wb_clk_i: in std_logic;     -- FPGA clock signal
    wb_rst_i: in std_logic;     -- reset signal
    wb_dat_o: out std_logic_vector(wordSize-1 downto 0);      -- data out signal
    wb_dat_i: in std_logic_vector(wordSize-1 downto 0);       -- data in signal
    wb_adr_i: in std_logic_vector(maxIObit downto minIObit);  -- read/write address
    wb_we_i:  in std_logic;     -- write enable
    wb_cyc_i: in std_logic;
    wb_stb_i: in std_logic;
    wb_ack_o: out std_logic;
    wb_inta_o:out std_logic;
  );
end entity basic_wishbone;

architecture behave of basic_wishbone is

  -- Register to hold value
  signal regigster0 : std_logic_vector(31 downto 0);

begin
  --
  -- Acknowledge all tranfers per the wishbone spec.
  --
  wb_ack_o <= wb_stb_i and wb_cyc_i; 
  
  -- 
  -- Tie interrupt to '0', we never interrupt. 
  --
  wb_inta_o <= '0';
  
  --
  -- Write data processing block.
  --
  process(wb_clk_i, wb_rst_i)
  begin
    if (wb_rst_i = '1') then
      --
      -- Reset signal.
      --
      register0 <= (others => '0');
    elsif (rising_edge(wb_clk_i)) then
      --
      -- On the rising edge of the clock...
      --
      if (wb_cyc_i='1' and wb_stb_i='1' and wb_we_i='1') then
        case wb_adr_i(4 downto 2) is
          when "000" =>
            -- 
            -- Store the value.
            --
            register0 <= wb_dat_i;
          when others =>
            --
            -- No-op.
            --
        end case;
      end if;
    end if;
  end process;
  
  --
  -- Load the output data when address is read.
  --
  process(wb_adr_i, register0)
  begin
    case wb_adr_i(4 downto 2) is
      when "000" =>
        -- 
        -- Store the value to be returned.
        --
        wb_dat_o(31 downto 0) <= (others => '0');
        wb_dat_o(31 downto 0) <= register0;
      when others =>
        wb_dat_o(31 downto 0) <= (others => '0');
    end case;
  end process; 
  
end behave;

Creating The Project

To start, open DesignLab and select Papilio : New DesignLab Library – Wishbone VHDL to create the project. Change the name to BasicWishbone and click OK to save it.

edit_library - Papilio DesignLab

In the edit_library tab, click sketchdir://Chip_Designer.xise to open the project in the Xilinx ISE Project Navigator.

ISE Project Navigator

Updating The VHDL

Once the ISE Project Navigator is open, expand Edit_Your_Chip_Design in the Hierarchy tree and double-click the BasicWishbone entry to view the created VHDL code.

Basic WishBone VHDL

In the VHDL entity block, remove the leds and buttons connections. In the architecture block remove the Wishbone_to_Registers component and all associated signals and registers. Once you’re done, the code will look like this:

--------------------------------------------------------------------------------
-- Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved.
--------------------------------------------------------------------------------
--   ____  ____ 
--  /   /\/   / 
-- /___/  \  /    Vendor: Xilinx 
-- \   \   \/     Version : 14.7
--  \   \         Application : 
--  /   /         Filename : xil_12112_30
-- /___/   /\     Timestamp : 09/23/2014 15:24:59
-- \   \  /  \ 
--  \___\/\___\ 
--
--Command: 
--Design Name: 
--

library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.ALL;
library UNISIM;
use UNISIM.Vcomponents.ALL;

library DesignLab;
use DesignLab.ALL;

entity BasicWishbone is
  port ( 
    wishbone_in  : in    std_logic_vector (100 downto 0); 
    wishbone_out : out   std_logic_vector (100 downto 0);
			 
		--Put your external connections here
  );
end BasicWishbone;

architecture BEHAVIORAL of BasicWishbone is
	
	--Put your unique register names here

begin

end BEHAVIORAL;

The DesignLab WishBone interface passes all signals into and out of the core via arrays. To make the code easier to read, add the aliases defined below to the top of the architecture block so the slices of interest can be accessed using their original names.

  --
  -- Rather than deal with slices out of the wishbone arrays we'll define some
  -- aliases here that allow use of the original names.
  --
  alias wb_clk_i: std_logic is wishbone_in(61);     -- FPGA clock signal
  alias wb_rst_i: std_logic is wishbone_in(60);     -- reset signal
  alias wb_dat_i: std_logic_vector(31 downto 0) is wishbone_in(59 downto 28); -- data in signal
  alias wb_adr_i: std_logic_vector(26 downto 2) is wishbone_in(27 downto 3);  -- read/write address
  alias wb_we_i : std_logic is wishbone_in(2);      -- write enable
  alias wb_cyc_i: std_logic is wishbone_in(1);
  alias wb_stb_i: std_logic is wishbone_in(0);

  alias wb_dat_o: std_logic_vector(31 downto 0) is wishbone_out(33 downto 2); -- data out signal
  alias wb_ack_o: std_logic is wishbone_out(1);
  alias wb_inta_o:std_logic is wishbone_out(0);

Now it’s time to copy the WishBone code from the original core. For each block in the original core, copy the VHDL code to the Xilinx ISE project code. For this example, the result will look like the code below.

--------------------------------------------------------------------------------
-- Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved.
--------------------------------------------------------------------------------
--   ____  ____ 
--  /   /\/   / 
-- /___/  \  /    Vendor: Xilinx 
-- \   \   \/     Version : 14.7
--  \   \         Application : 
--  /   /         Filename : xil_12112_30
-- /___/   /\     Timestamp : 09/23/2014 15:24:59
-- \   \  /  \ 
--  \___\/\___\ 
--
--Command: 
--Design Name: 
--

library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.ALL;
library UNISIM;
use UNISIM.Vcomponents.ALL;

library DesignLab;
use DesignLab.ALL;

entity BasicWishbone is
  port ( 
    wishbone_in  : in    std_logic_vector (100 downto 0); 
    wishbone_out : out   std_logic_vector (100 downto 0)
			 
    -- Put your external connections here
  );
end BasicWishbone;

architecture BEHAVIORAL of BasicWishbone is
	
  -- Put your unique register names here
  --
  -- Rather than deal with slices out of the wishbone arrays we'll define some
  -- aliases here that allow use of the original names.
  --
  alias wb_clk_i: std_logic is wishbone_in(61);     -- FPGA clock signal
  alias wb_rst_i: std_logic is wishbone_in(60);     -- reset signal
  alias wb_dat_i: std_logic_vector(31 downto 0) is wishbone_in(59 downto 28); -- data in signal
  alias wb_adr_i: std_logic_vector(26 downto 2) is wishbone_in(27 downto 3);  -- read/write address
  alias wb_we_i : std_logic is wishbone_in(2);      -- write enable
  alias wb_cyc_i: std_logic is wishbone_in(1);
  alias wb_stb_i: std_logic is wishbone_in(0);

  alias wb_dat_o: std_logic_vector(31 downto 0) is wishbone_out(33 downto 2); -- data out signal
  alias wb_ack_o: std_logic is wishbone_out(1);
  alias wb_inta_o:std_logic is wishbone_out(0);
  
  --
  -- Simple register to hold contents of a Wishbone read/write.
  --
  signal register0: std_logic_vector(31 downto 0);
begin
  -- Begin the architecture code.
  --
  -- Acknowledge all tranfers per the wishbone spec.
  --
  wb_ack_o <= wb_stb_i and wb_cyc_i; 
  
  -- 
  -- Tie interrupt to '0', we never interrupt 
  --
  wb_inta_o <= '0';
    
  --
  -- Write register processing loop.
  --
  process(wb_clk_i, wb_rst_i)
  begin
    if (wb_rst_i = '1') then
      --
      -- Circuit reset.
      -- 
      register0 <= (others => '0');   -- Initialize register to all '0'
      
    elsif (rising_edge(wb_clk_i)) then
      --
      -- On the rising edge of the clock...
      --
      if (wb_cyc_i='1' and wb_stb_i='1' and wb_we_i='1') then
        -- 
        -- Decoded as a write signal.
        --
        case wb_adr_i(4 downto 2) is
          when "000" =>
            --
            -- Accessing register 000
            -- Save the written value.
            --
            register0 <= wb_dat_i;
          when others =>
        end case;
      end if;
    end if;
  end process;
  
  --
  -- Load the output data when address is read.
  --
  process(wb_adr_i, register0)
  begin
    case wb_adr_i(4 downto 2) is
      when "000" =>
        -- 
        -- Store the value to be returned.
        --
        wb_dat_o(31 downto 0) <= (others => '0');
        wb_dat_o(31 downto 0) <= register0;
      when others =>
        wb_dat_o(31 downto 0) <= (others => '0');
    end case;
  end process;  
end BEHAVIORAL;

Creating The Schematic Symbol

To create the schematic symbol, expand Edit_Your_Chip_Design in the Hierarchy tree, right-click on the BasicWishbone entry, and select Source Properties. When the Source Properties form is displayed, change the Source Library to work and click OK.

Source Properties Form

Expand the Design Utilities in the Processes tree, and double-click Create Schematic Symbol. The process will run for a bit and if all is successful you’ll get a green check.

Create Schematic Symbol - Green Check

To confirm the schematic symbol has been created properly, double-click Edit_Your_Chip_Design in the Hierarchy tree. When you get the Open Schematic File Errors form, select Ignore The Error as the Action, click Update Instances, and OK to close the form.

Open Schematic File Errors

The updated schematic symbol should be shown on the display. You can now go back to the DesignLab IDE and perform the remaining steps to finish putting together your library.

Compiling WSPR For The pcDuino

I was working my way through my pile of development boards looking for project ideas when I ran across my pcDuino. I originally bought it to put together a small Linux SDR system but set it aside since the kernel at that time didn’t contain support for my USB sound card. Since then there have been a number of updates to the kernel so I decided to have another go at it.

We all have to start somewhere and I decided to start with the WSPR software. Using the instructions provided on George Smart’s Compiling WSPR page, it was only a few hours before I had a working system.

Base System

I started with the pcDuino base Lubuntu installation on a bootable SD card. The SD card is required since the pcDuino has only 2 GB of flash memory on board, which isn’t enough to hold all the tools needed to build WSPR. Mine was a 16 GB card but I think you could do it with 8 GB.

A network connection to load the necessary tools is also necessary.

Required Software

To build WSPR the following software from the repositories is needed:

  • subversion
  • python3-dev
  • python3-numpy
  • libportaudio2
  • libportaudio-dev
  • libsamplerate0-dev
  • gfortran
  • portaudio19-dev
  • cl-fftw3
  • tk8.5-dev
  • tcl8.5-dev
  • python3-tk
  • python3-setuptools

These can all be installed using apt-get.

    sudo apt-get install < package >

The pcDuino’s version of autoconf isn’t recent enough to use with the WSPR source so it will need to be updated. However, before that, the M4 macro preprocessor needs to be installed.

To do so, download the file m4-1.4.17.tar.gz from the site ftp://ftp.gnu.org/gnu/m4 and untar it to a convenient location.

    tar -xvf m4-1.4.17.tar.gz

Change to the created directory and build using the standard commands:

    cd m4-1.4.17
    ./configure
    make
    sudo make install

Once that’s done repeat the process for autoconf. Download the file autoconf-2.69.tar.gz from the site ftp.gnu.org/gnu/autoconf, untar it, and build.

    tar xvf autoconf-2.69.tar.gz
    cd autoconf-2.69
    ./configure
    make
    sudo make install

You’ll also need Pillow (a fork of the Python Imaging Library) from the python repositories:

    sudo easy_install3 pip
    sudo pip install -I --no-cache-dir pillow

Configuring The Source Code

On my system a link to the f2py utility didn’t exist so I had to create it:

    sudo ln -s /usr/bin/f2py3.2 /usr/bin/f2py

Once that’s done, check the WSPR source code out of the repository:

    svn checkout svn://svn.code.sf.net/p/wsjt/wsjt/branches/wspr wspr

and configure the Makefile:

    cd wspr
    ./autogen.sh

Building The Software

When I first tried to build the software I had problems with the man pages. Since I didn’t anticipate a need for them I updated the Makefile to remove references to them. Change the line:

    all:  libwspr.a WsprMod/w.so fmtest fmtave fcal fmeasure 
          wsprcode wspr0 manp user-guide

to remove references to manp and user-guide so the line reads:

    all:  libwspr.a WsprMod/w.so fmtest fmtave fcal fmeasure 
          wsprcode wspr0

Once this is done, save the updated Makefile and perform the build.

    make

Assuming everything completes without error, you can run the software with the command:

    python3 ./wspr.py

The picture below shows the WSPR software running on the pcDuino. I like the idea of having a small, low power system running my SDR software so I think I’ll try a few more packages. I don’t think there’s enough power here to run something like gnuradio but rtlsdr and perhaps HDSDR are definite possibilities.

WSPR on the pcDuino

USB Power For Your 12V Circuits

If your desk is anything like mine you have a pile of USB cables and chargers squirrelled away in a drawer. These are great for powering 5V or 3.3V circuits, especially when paired with one of the USB power sticks that have become so popular. But what about circuits that require a little more voltage?

I run into this problem occasionally and the solution I had in mind was a small step-up regulator that could be paired with the appropriate connector to create a voltage converter that could be plugged directly into a USB port. After looking around for a while I found just the thing I needed being offered by Pololu; a series of step-up regulators with a wide variety of input voltages, output voltages, and current capabilities. I bought a few of the 12V variety to try them out.

The specific one I used was the UV312F12 and the circuit couldn’t be simpler. A type A USB connector at one end supplying 5V from the USB port and a dual pin connector at the other for the 12V output. Two prototypes I put together are shown below. For the first I used an old USB cable from which I removed the plug and attached the 5V and GND lines to the regulator input. As an alternative you could replace the cable with a mini/micro-USB connector and use a USB wall charger.

Voltage Converter Prototype 1

For the second I mounted a type A connector directly to a piece of stripboard with the regulator.

In both cases when I plugged them into a USB port the measured output voltage was exactly 12V. I’ve been using the first to power my WSPR receiver for the last few days with no problems.

One limit of which you need to be aware. The Polulo site lists the regulator’s maximum input current. The available output current will depend on the voltage conversion ratio and conversion losses. So for example, with a USB port providing 100mA at 5V I wouldn’t expect more than about 40mA after converting it to 12V. If you use a USB power stick you’ll probably have more power available. The one I use can supply 5V at up to 2.1A, which is actually more current than the input specification for the regulator I used. With the appropriate regulator you could probably get enough power out for a small QRP transmitter.

rtl-sdr.com

A blog about RTL-SDR (RTL2832) and cheap software defined radio

DuWayne's Place

Computers, Electronics, and Amateur Radio from KC3XM

QRP HomeBuilder - QRPHB

Computers, Electronics, and Amateur Radio from KC3XM

Open Emitter

Computers, Electronics, and Amateur Radio from KC3XM

Ripples in the Ether

Emanations from Amateur Radio Station NT7S

m0xpd's 'Shack Nasties'

Computers, Electronics, and Amateur Radio from KC3XM

Follow

Get every new post delivered to your Inbox.