Thursday 15 December 2016

fpga - Implementing the Digilent EPP


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

#include
#include
#include
#include

#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);
}

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.


No comments:

Post a Comment

arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...