Electronic – Implementing the Digilent EPP

ccommunicationfpgatimingvhdl

I am trying to implement Digilent Parallel Interface from their SDK. You can specifically read up on the interface in this manual. I am using the Basys 2 250k board.

I am trying to figure out what I am I doing wrong which I think is just an issue with timing in my VHDL.

Here is a timing diagram to read data from the FPGA:
Digilent EPP Read Timing Diagram

The VHDL looks like:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity DeppSwitches is
    Port(
        mclk     : in std_logic;
        EppDB       : inout std_logic_vector(7 downto 0);
        EppAstb : in std_logic;
        EppDstb  : in std_logic;
        EppWR    : in std_logic;
        EppWait  : out std_logic;
        Led     : out std_logic_vector(7 downto 0);
        sw      : in std_logic_vector(7 downto 0);
        btn     : in std_logic_vector(4 downto 0);

        stepCurrOutDebug : out std_logic_vector(7 downto 0);
        stepNextOutDebug : out std_logic_vector(7 downto 0)
    );
end DeppSwitches;

architecture Behavioral of DeppSwitches is
    signal    busEppOut: std_logic_vector(7 downto 0); -- Channel to send bits to pc
    signal    busEppIn: std_logic_vector(7 downto 0); -- Address that the pc sends to fpga
    signal    busEppData: std_logic_vector(7 downto 0); -- Bits to send to PC

    signal peripheralWait: std_logic := '0';

    constant stepIdle: std_logic_vector(7 downto 0) := "0001" & "0000";
    constant stepRead: std_logic_vector(7 downto 0) := "0010" & "0000"; -- PC Read from FPGA
    constant stepRead2: std_logic_vector(7 downto 0) := "0100" & "0000"; -- PC Read from FPGA

    signal stepCurr: std_logic_vector(7 downto 0) := stepIdle;
    signal stepNext: std_logic_vector(7 downto 0);
begin
    Led <= sw;

    -- Handshake signal used to indicate when the peripheral is ready to accept data or has data available.
    EppWait <= peripheralWait;

    -- Data bus direction control. The internal input data bus always
    -- gets the port data bus. The port data bus drives the internal
    -- output data bus onto the pins when the interface says we are doing
    -- a read cycle and we are in one of the read cycles states in the
    -- state machine.
    busEppIn <= EppDB;
    EppDB <= busEppOut;

    -- Hook the data bits to the switches
    busEppData <= sw;

    -- We need this to see the state when debugging
    stepCurrOutDebug <= stepCurr;
    stepNextOutDebug <= stepNext;

    -- Advance the state machine
    process(mclk)
    begin
        if rising_edge(mclk) then
            stepCurr <= stepNext;
        end if;
    end process;

    process(mclk)
    begin
        if rising_edge(mclk) then
            case stepCurr is
                when stepIdle =>
                    peripheralWait <= '0';
                    busEppOut <= "ZZZZZZZZ";

                    if EppWR = '1' then
                        stepNext <= stepRead;
                    else
                        stepNext <= stepIdle;
                    end if;

                when stepRead =>
                    if EppDstb = '0' then
                        busEppOut <= busEppData;
                        peripheralWait <= '1';

                        stepNext <= stepRead2;
                    end if;

                when stepRead2 =>
                    if EppDstb = '1' then
                        busEppOut <= "ZZZZZZZZ";

                        stepNext <= stepIdle;
                    else 
                        stepNext <= stepRead2;
                    end if;

                when others => stepNext <= stepIdle;
            end case;
        end if;
    end process;

end Behavioral;

After simulation with this test bench stimulus I get these results:

-- insert stimulus here 
EppWR <= '1';
EppDstb <= '1';
sw <= "00001111";

wait for 4 ns;
EppDstb <= '0';
wait for 50 ns;
EppDstb <= '1';

Timing Simulation


My C++ project compiles just fine and I used Hamsters EPP Performace project as my base (which I got working just fine) and then went into the demo file of the SDK download and grabbed the DoGetReg() function to start reading bytes.

Whenever I run the program I get…

Opening
Enabling
Getting
DeppGetReg failed

Here is the code:

// DeppSwitches.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "dpcdecl.h"
#include "depp.h"
#include "dmgr.h"

static HIF hif = hifInvalid;

void ErrorExit();
void DoGetReg();

int main(int cszArg, char * rgszArg[]) 
{
    fprintf(stderr,"Opening\n");
    if(!DmgrOpen(&hif, "Basys2")) // Change to Basys2 for the other board.
    {  
        printf("DmgrOpen failed (check the device name you provided)\n");
        return 0;
    }

    fprintf(stderr,"Enabling\n");
    if(!DeppEnable(hif)) 
    {
        printf("DeppEnable failed\n");
        return 0;
    }

    fprintf(stderr,"Getting\n");
    DoGetReg();

    if( hif != hifInvalid ) 
    {
        DeppDisable(hif);
        DmgrClose(hif);
    }
    return 0;
}

void DoGetReg() 
{
    BYTE    idReg;
    BYTE    idData;

    idReg = (BYTE)0;

    // DEPP API Call: DeppGetReg
    if(!DeppGetReg(hif, idReg, &idData, fFalse)) { 
        printf("DeppGetReg failed\n");
        ErrorExit();
    }

    printf("Complete. Recieved data %d\n", idData);

    return;
}


/* ------------------------------------------------------------ */
/***    ErrorExit
**
**  Parameters:
**      none
**
**  Return Value:
**      none
**
**  Errors:
**      none
**
**  Description:
**      Disables DEPP, closes the device, close any open files, and exits the program
*/
void ErrorExit() {
    if( hif != hifInvalid ) {
        // DEPP API Call: DeppDisable
        DeppDisable(hif);

        // DMGR API Call: DmgrClose
        DmgrClose(hif);
    }

    exit(1);
}

Best Answer

Thanks to some help from Hamster I managed to get it working.

My code had many problems but the main thing I was doing wrong was not supporting write commands.

Here is my VHDL:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity DeppSwitches is
    Port(
        mclk     : in std_logic;
        EppDB       : inout std_logic_vector(7 downto 0);
        EppAstb : in std_logic;
        EppDstb  : in std_logic;
        EppWR    : in std_logic;
        EppWait  : out std_logic;
        Led     : out std_logic_vector(7 downto 0);
        sw      : in std_logic_vector(7 downto 0);
        btn     : in std_logic_vector(4 downto 0);

        stepCurrOutDebug : out std_logic_vector(7 downto 0);
        stepNextOutDebug : out std_logic_vector(7 downto 0)
    );
end DeppSwitches;

architecture Behavioral of DeppSwitches is
    signal    busEppOut: std_logic_vector(7 downto 0); -- Channel to send bits to pc
    signal    busEppIn: std_logic_vector(7 downto 0); -- Address that the pc sends to fpga
    signal    busEppData: std_logic_vector(7 downto 0); -- Bits to send to PC

    signal peripheralWait: std_logic := '0';

    constant stepIdle: std_logic_vector(7 downto 0)     := "0000" & "0000";
    constant stepReadA: std_logic_vector(7 downto 0)    := "0001" & "0000"; -- PC Read from FPGA Address
    constant stepReadD: std_logic_vector(7 downto 0)    := "0010" & "0000"; -- PC Read from FPGA Data
    constant stepWriteA: std_logic_vector(7 downto 0)   := "0100" & "0000"; -- PC Write to FPGA Address
    constant stepWriteD: std_logic_vector(7 downto 0)   := "1000" & "0000"; -- PC Write to FPGA Data

    signal stepCurr: std_logic_vector(7 downto 0) := stepIdle;
    signal stepNext: std_logic_vector(7 downto 0);
begin
    Led <= sw;

    -- Handshake signal used to indicate when the peripheral is ready to accept data or has data available.
    EppWait <= peripheralWait;

    -- Data bus direction control. The internal input data bus always
    -- gets the port data bus. The port data bus drives the internal
    -- output data bus onto the pins when the interface says we are doing
    -- a read cycle and we are in one of the read cycles states in the
    -- state machine.
    busEppIn <= EppDB;
    EppDB <= busEppOut;

    -- Hook the data bits to the switches
    busEppData <= sw;

    -- We need this to see the state when debugging
    stepCurrOutDebug <= stepCurr;
    stepNextOutDebug <= stepNext;

    -- Advance the state machine
    process(mclk)
    begin
        if rising_edge(mclk) then
            stepCurr <= stepNext;
        end if;
    end process;

    process(mclk)
    begin
        if rising_edge(mclk) then
            case stepCurr is                    
                when stepIdle =>
                    peripheralWait <= '0';
                    busEppOut <= "ZZZZZZZZ";

                    if EppDstb = '0' then 
                        if EppWr = '0' then
                            stepNext <= stepWriteD; -- PC Write to FPGA Data
                        else
                            stepNext <= stepReadD; -- PC Read from FPGA Data
                        end if;
                    end if;

                    if EppAstb = '0' then 
                        if EppWr = '0' then
                            stepNext <= stepWriteA; -- PC Write to FPGA Address
                        else
                            stepNext <= stepReadA; -- PC Read from FPGA Address
                        end if;
                    end if;
                -------------------------------------------------

                when stepReadD | stepReadA =>
                    busEppOut <= busEppData;
                    peripheralWait <= '1';

                    if EppDstb = '1' then
                        stepNext <= stepIdle;
                    end if;
                -------------------------------------------------

                when stepWriteD | stepWriteA =>
                    peripheralWait <= '1';
                    if EppDstb = '1' then
                        stepNext <= stepIdle;
                    end if;

                when others => stepNext <= stepIdle;
            end case;
        end if;
    end process;

end Behavioral;

My C++ program was just fine. You can see the code in the main post.