Instead of having to look up the specifics of the USB chip on the board, the Adept SDK provides APIs to interact with the board. In this post, I'll cover just 2 of the libraries: the device access management library (DMGR) and the asynchronous parallel port library (DEPP). Note that DEPP is so named for the similarity to the Enhanced Parallel Port (EPP) protocol used by parallel ports.
The Adept SDK provides code samples for each of the libraries. For the DMGR library, there are 2 examples: EnumDemo and GetInfoDemo. To get started, download the Adept SDK and Adept Runtime from Digilent. Install the runtime, and decompress the SDK somewhere you can find it. The SDK contains:
- Documentation: PDF files describing how to use the libraries in the doc folder
- Header Files: The include folder contains header files
- Static Libraries: The APIs are provided as precompiled libraries
- Code Samples: Example code for each library is included in the samples folders
After downloading the SDK for Windows, I set about to compiling some of the samples. There are introductions on how to do this in the samples directory, but they are specific to Visual Studio. In my case, I am using MinGW's toolchain. The linkers in the two toolchains expect library files to be named differently. Visual Studio expects a library file named <library name>.lib, and this is how the libraries are provided by Digilent. MinGW's linker, ld, only accepts library files in the format lib<library name>.a. Similarly, ld running under Linux expects a file lib<library name>.so. So, in order to use the Windows libraries provided by Digilent, I had to rename all of the files. dmgr.lib had to be renamed libdmgr.a, for example. The Windows version of the SDK contains the libraries in the lib or lib64 directories. The Linux version installs the libraries with the runtime.
In order to get g++ to compile the examples, I had to specify the include directory using -I, specify the library directory using -L, and specify which libraries to use AFTER the filename. For example, a project that uses only the DMGR library would have -ldmgr after the file name.
I compiled and executed the DMGR examples EnumDemo and GetInfoDemo. These confirmed that there was in fact a Basys2 attached to my system, and that it supported the DEPP library. I then instantiated a DEPP interface on the FPGA that included 2 operand registers and a result register. The operand registers can be written by the PC, and the result register can be read. Actually creating those structures on the FPGA will be covered in another post, but project files can be found here.
I wanted to write some code to write values to the operand registers, then read the result out. Here's what it looks like (full file here):
#if defined(WIN32)
/* Include Windows specific headers here.*/
#include <windows.h>
#endif
This makes the necessary types available on a Windows.
When it was all said and done, the output looked like this:
Successfully opened a handle to Basys2
Successfully enabled Port 0
0x00 + 0x00 = 0x00
0x01 + 0x00 = 0x01
0x01 + 0x01 = 0x02
0xA5 + 0x5A = 0xFF
0xFF + 0x01 = 0x00
Successfully disabled DEPP port
Successfully closed device handle
And so, I successfully moved raw data to the device, and read a result. While an unsigned 8-bit adder is trivial, this gives me all of the building blocks to do something more interesting, like cryptographic work.
#include <stdio.h>All of the header files needed for this project.
#include "dpcdecl.h"
#include "dmgr.h"
#include "depp.h"
#define OP1ADDR 0x00I chose to use text substitutions to define the register locations, to make my code easier to read. And then we start with main():
#define OP2ADDR 0x01
#define RESADDR 0x00
int main()The type HIF is defined in dpcdecl.h, and is a structure that holds a handle to a device. This handle is used to interact with the Basys2. The status variable will be used for error detection/error handling. The device name is the UserName of the device. I found the UserName using EnumDemo. result will hold the result of the arithmetic that we read back from the device.
{
HIF deviceHandle;
int status = fTrue;
char deviceName[32] = "Basys2";
unsigned char result;
//Open a handle to the deviceThe first step in interacting with the device is to open a handle to it. Note that the API functions return FALSE if there is an error, and TRUE if they are successful.
status = DmgrOpen(&deviceHandle,deviceName);
if (status)
printf("Successfully opened a handle to %s\n", deviceName);
else
{
status = DmgrGetLastError();
printf("Error code: %d\n", status);
}
//Enable the default port (Port 0) on the deviceThe EPP port must be enabled before reading or writing.
status = DeppEnable(deviceHandle);
if (status)
printf("Successfully enabled Port 0\n");
else
{
status = DmgrGetLastError();
printf("Error code: %d\n", status);
}
//Do some mathHere's where I actually transfer some data to and from the device. I write to the operand registers using DeppPutReg(), and then read the result register using DeppGetReg(). I ran through several scenarios to make sure that the adder was working properly.
DeppPutReg(deviceHandle, OP1ADDR, 0x00, fFalse);
DeppPutReg(deviceHandle, OP2ADDR, 0x00, fFalse);
DeppGetReg(deviceHandle, RESADDR, &result, fFalse);
printf("0x00 + 0x00 = 0x%02X\n", result);
//...
DeppPutReg(deviceHandle, OP1ADDR, 0xFF, fFalse);
DeppPutReg(deviceHandle, OP2ADDR, 0x01, fFalse);
DeppGetReg(deviceHandle, RESADDR, &result, fFalse);
printf("0xFF + 0x01 = 0x%02X\n", result);
//Disable the active port on the deviceThis is all cleanup to make sure that I gracefully release the device.
status = DeppDisable(deviceHandle);
if (status)
printf("Successfully disabled DEPP port\n");
else
{
status = DmgrGetLastError();
printf("Error code: %d\n", status);
}
//Close our handle to the devicestatus = DmgrClose(deviceHandle);
if (status)
printf("Successfully closed device handle\n");
else
{
status = DmgrGetLastError();
printf("Error code: %d\n", status);
}
When it was all said and done, the output looked like this:
Successfully opened a handle to Basys2
Successfully enabled Port 0
0x00 + 0x00 = 0x00
0x01 + 0x00 = 0x01
0x01 + 0x01 = 0x02
0xA5 + 0x5A = 0xFF
0xFF + 0x01 = 0x00
Successfully disabled DEPP port
Successfully closed device handle
And so, I successfully moved raw data to the device, and read a result. While an unsigned 8-bit adder is trivial, this gives me all of the building blocks to do something more interesting, like cryptographic work.
Hello, Camdon!
ReplyDeleteYou did a great job here!I want to ask if it's possible to extend a litle bit the discussion about the gcc compiler. I have a Windows XP x86 machine and I want to compile the Adept sources with g++!I renamed all the libraries as you suggested but I have a lot of errors telling me that some headers couldn't be found. Can you share the steps to follow in order to compile Adept sources with g++?Hope I'm not disturbing you but I see that you worked with this stuff and maybe you can give some hint!Thank you!
Angela, what sorts of errors are you seeing? Could you be a bit more specific, maybe include a brief dump? It sounds like you're likely missing some path info for the -L and/or -I options of gcc. Perhaps you need to find the directory which has the .h files which are "missing" and include the -I "c:\whatever_the_path_is" in the command line. Similarly the -L option should have the path to the lib directories. For the -L option it may be necessary that it come *after* any .c files are specified for compiling.
DeleteIf you don't mind I'm adding your on Google+ as well in case you'd like to do a "hangout" for any further assistance in solving your issues - please let us know if you figure it out what the solution was! [Edits: because I'm not feeling well and I thought my original reply didn't make much sense.]
Angela,
DeleteCan you post the specific text of some of the errors (starting with the first one)?
I agree with Ken that it is probably a path issue. Are you using Cygwin, MinGW, or something else?
Thank you both for responding...Ken was right, it was a mistake in the command line!
ReplyDeleteI figure out what I was doing wrong, so practically, it was the way the included directory and library directory were specified.I was calling them before the .cpp filename(a generic example of command line, which works is: g++ -o test test.cpp -I /../../../include -L /../../../lib -ldepp -ldmgr).
Hi!
ReplyDeleteThank you for this tutorial! I am curious about how you handle all this on the FPGA side. Care to show some VHDL? Thank you.
Part 1:
Deletehttp://sadgeeksinsnow.blogspot.com/2012/09/implementing-depp-interface-on-basys2.html
Part 2:
http://sadgeeksinsnow.blogspot.com/2012/09/implementing-depp-interface-on-basys2_12.html
Cheers
Thank you!
DeleteNo problem! Enjoy!
DeleteGood day, I was trying your design on my Basys 2 and, so far, it doesn't seem to work for me.
ReplyDeleteI created an Adder8Bit module and simulated the behavior of the whole design, checking it works. However, I cannot modify the registers using the C++ program you provided.
Jack, as you may be able to tell we like to help as much as possible. I appreciate you going through the process of putting this together (I know it is no simple task!) And with that said, I hope we can get you up and working ASAP.
DeleteBy chance do you have any error messages that may be of use? I believe we have some full source files around here somewhere... lemme dig them up so you can compare/contrast what Camdon did. Additionally, I'll ensure he is informed he's kinda my FGPA whiz kid ^_^.
So yeah, maybe a copy of your terminal output when running the C program?
Thanks!
Following up, here are all of the files we used. Additionally there is a zip - it's just the other files (but just 1 download).
Deletehttps://drive.google.com/folderview?id=0ByjYpdaRCAj-SUlVYjJ5TG13c2c&usp=sharing
For your compare/contrast, if you wanted to see what's different.
Hi Ken,
DeleteI appreciate your quick response and I do apologize if my first post sounded brash and vague.
I assembled your files and added a makeshift Adder8Bit module to add the values of both operand registers and send the result to the third register. The problem seems to be that no matter what value I send to the registers, they seem to have a will of its own.
I have tested this in three different boxes (all 32 bit), with Ubuntu 12.04, Fedora 18 and Windows 7. Only Win7 gives me the correct output, while the other two output something similar to this:
Successfully opened a handle to Basys2
Successfully enabled port 0
0xAF + 0x04 = 0x08
0xAF + 0x04 = 0x08
0xAF + 0x04 = 0x08
0xAF + 0x04 = 0x08
0xAF + 0x04 = 0x08
Successfully disabled DEPP port
Successfully closed device handle
I am beginning to think that this is a problem with the Linux ports of the SDK. Have installed all required libraries (libusb-1.0+ and ftdi driver) and even checked the shared libraries that the program uses with the ldd command, all seems normal.
It does sound like a problem of some sort with the drivers. A couple questions:
Delete1. Are you re-programming the FPGA each time you connect to a different system, or do you write the bitstream to the flash and load it from there?
2. Assuming that you are programming the FPGA each time, have you written some bitstream that you know works to the device? Something like setting the LEDs so a specific configuration so you know the bitstream took?
3. Have you checked the jumper that controls where the FPGA gets the bitstream from? Having that jumper in the wrong position essentially leads to undefined behavior, and I wouldn't be surprised if the behavior varied from system to system.
4. Are any of the systems you are using virtual machines, not running directly on the hardware? (Using VMWare, VirtualBox, QEMU, etc)
1.- Yes, I do re-program the FPGA each time.
Delete2.- Yes, I did. A small 2 bit adder with led output using the switches, and it works mint.
3.- No, I haven't checked this one yet. I'll keep you posted.
4.- No, installed and running navitely on each box.
Jack, yeah when I first did this #3 bit me too! The jumper next to the VGA port, labeled JP3, Mode, PC | ROM.
DeleteSet it so it's on the PC side if you're loading the bit stream to the FPGA directly (e.g. the "Device 0: XC3S250E")
Otherwise, if you're loading to the ROM be sure you've set the jumper.
Let us know the results!
I suppose we can take that the silence on the wire means the solution was achieved? Opa!
Delete