Академический Документы
Профессиональный Документы
Культура Документы
Outline
Project Overview
Transfer sampled ADC data over USB to
PC Application
Run ADC at 1 million samples per second
USB transfer must be at least 2MB/s
USB communication using Nexys2 Board
and Cypress chip
PC Application written in C# using Digilent
communication driver
Hardware
Windows PC
Digilent Nexys2 Board
Cypress CY7C68013A High-Speed USB
Peripheral Controller
USB_RdWr
USB_Wait
RdWr
Wait
USB_CLK
USB_Dstb
Dstb
USB_Data
ADC_CNV
ADC_CLK
MUX_SEL
LEDs
USB_Astb
FPGA
LED_Status
ADC_SDO
50MHz
Crystal
3
/
Out
VIN
ADC
CLK
SCK
Astb
Sel
Data
In0
In1
In2
In3
In4
In5
In6
In7
CNV
SDO
USB
D+
D-
USB Subsystem
SYS_CLK
USB_RdWr
USB_Wait
RdWr
Wait
USB_CLK
USB_Dstb
Dstb
USB_Data
ADC_CNV
ADC_CLK
MUX_SEL
LEDs
USB_Astb
FPGA
LED_Status
ADC_SDO
50MHz
Crystal
3
/
Out
VIN
ADC
CLK
SCK
Astb
Sel
Data
In0
In1
In2
In3
In4
In5
In6
In7
CNV
SDO
USB
D+
D-
CY7C68013A Capabilities
Slave FIFO
Endpoint FIFOs are controlled by an external
master
Cypress CY7C68013A
Clock Pin
Other miscellaneous Cypress Pins
Address Read
Address Write
Data Read
Data Write
Address Read
(FPGA->PC)
Data Read
(FPGA->PC)
LEDs (0x00)
Switches (0x01) (read-only)
Buttons (0x02) (read-only)
SSD (0xFF:0xFE)
Ready
0
Dstb = 0
Pwr = 1
Dstb = 0
Pwr = 0
Astb = 0
Pwr = 1
Astb = 0
Pwr = 0
DrdA
Dir
DwrA
0
AwrA
0
ArdA
Dir
DrdB
Dir
DwrB
Dwr
AwrB
Awr
ArdB
Dir
Dstb = 1
Dstb = 1
DrdC
Dir
Wait
Dstb = 0
Data Read
(FPGA -> USB)
Astb = 1
Astb = 1
DwrC
Wait
AwrC
Wait
ArdC
Dir
Wait
Dstb = 0
Astb = 0
Astb = 0
Data Write
(USB -> FPGA)
Address Write
(USB -> FPGA)
Address Read
(FPGA -> USB)
stEppReady
stEppAwrA
stEppAwrB
stEppAwrC
stEppArdA
stEppArdB
stEppArdC
stEppDwrA
stEppDwrB
stEppDwrC
stEppDrdA
stEppDrdB
stEppDrdC
:
:
:
:
:
:
:
:
:
:
:
:
:
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
std_logic_vector(7
downto
downto
downto
downto
downto
downto
downto
downto
downto
downto
downto
downto
downto
0)
0)
0)
0)
0)
0)
0)
0)
0)
0)
0)
0)
0)
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
:=
"0000"
"0001"
"0010"
"0011"
"0100"
"0101"
"0110"
"0111"
"1000"
"1001"
"1010"
"1011"
"1100"
&
&
&
&
&
&
&
&
&
&
&
&
&
"0000";
"0000";
"0100";
"0001";
"0010";
"0010";
"0011";
"0000";
"1000";
"0001";
"0010";
"0010";
"0011";
when
when
when
when
when
regEppAdr
regEppAdr
regEppAdr
regEppAdr
regEppAdr
=
=
=
=
=
x"00"
x"01"
x"02"
x"FE"
x"FF"
else
else
else
else
else
dataStrobePin = 1
addressStrobePin = 1
addressStrobePin = 1
S0_Ready
0
dataStrobePin = 0
fpga2UsbPin = 1
S1_Fpga2UsbData
OutputEnable
AddressDataMux
RamReadEnable
Wait
dataStrobePin = 0
fpga2UsbPin = 0
addressStrobePin = 1
fpga2UsbPin = 0
S1_Usb2FpgaData
AddressDataMux
RamWriteEnable
Wait
addressStrobePin = 1
fpga2UsbPin = 1
S1_Usb2FpgaAddress
AddressUpdateEnable
Wait
S1_Fpga2UsbAddress
OutputEnable
Wait
S2_Usb2FpgaAddress
Wait
S2_Fpga2UsbAddress
OutputEnable
Wait
dataStrobePin = 1
dataStrobePin = 1
S2_Fpga2UsbData
OutputEnable
AddressDataMux
Wait
S2_Usb2FpgaData
AddressDataMux
Wait
dataStrobePin = 0
dataStrobePin = 0
addressStrobePin = 0
addressStrobePin = 0
Data Read
(FPGA -> USB)
Data Write
(USB -> FPGA)
Address Write
(USB -> FPGA)
Address Read
(FPGA -> USB)
fsm_encoding : string;
fsm_encoding of currentState : signal is "auto";
safe_implementation: string;
safe_implementation of currentState : signal is "yes";
USB_RdWr
USB_Wait
RdWr
Wait
USB_CLK
USB_Dstb
Dstb
USB_Data
ADC_CNV
ADC_CLK
MUX_SEL
LEDs
USB_Astb
FPGA
LED_Status
ADC_SDO
50MHz
Crystal
3
/
Out
VIN
ADC
CLK
SCK
Astb
Sel
Data
In0
In1
In2
In3
In4
In5
In6
In7
CNV
SDO
USB
D+
D-
+
-
+
-
X8
In0
In1
In2
In3
In4
In5
In6
In7
SCK
Out
VIN
ADC
CNV
SDO
Sel
Description:
A rising edge on CNV initiates a conversion and forces SDO to
high impedance.
CNV should remain high until the maximum conversion time
elapses.
When the conversion is complete, the AD7980 enters the
acquisition phase and powers down.
When CNV goes low, the MSB is output onto SDO. The
remaining data bits are then clocked by subsequent SCK falling
edges.
After the 16th SCK falling edge or when CNV goes high,
whichever is earlier, SDO returns to high impedance.
Timing Specifications
Timing Specifications
FPGA Logic
SYS_CLK
USB_RdWr
USB_Wait
RdWr
Wait
USB_CLK
USB_Dstb
Dstb
USB_Data
ADC_CNV
ADC_CLK
MUX_SEL
LEDs
USB_Astb
FPGA
LED_Status
ADC_SDO
50MHz
Crystal
3
/
Out
VIN
ADC
CLK
SCK
Astb
Sel
Data
In0
In1
In2
In3
In4
In5
In6
In7
CNV
SDO
USB
D+
D-
CLKFX
DCM
Status Read_CLK
Reset
CLKFX180
LEDS
Write_Error
Read_Error
CLK
HEX
ADC Driver
SEG
Block FIFO
ADC_CLK
CLK180
ADC_CNV
CLK
Write_Error
Read_Error
Write_CLK
Read_CLK
16
ADC_SDO
AN
SSD Driver
Sample
USB I/O
16
Write_Data
Read_Data
SampleValid
Write_Enable
Reset
Write_Ready
FIFO_ReadData
USB_CLK
Read_Next
FIFO_ReadNext
USB_AddrStrobe
Read_Valid
FIFO_ReadValid
USB_DataStrobe
MUX_SEL
Reset
MUX_Channel
USB_ReadWrite
MUX_Override
USB_Wait
ADC_Enable
3
3
S
USB_DataBus
ADC Driver
A custom VHDL entity was created to control the
ADC and analog multiplexer.
Clock frequency and desired sample rate can be
specified using generics.
A simple linear state machine controls the
conversion / acquisition process.
Each state lasts a fixed number of clock cycles.
The number of clock cycles for each state are
determined at compile time
STARTUP
TimerPulse = 0 /
Convert = 0,
ClockEnable = 1,
SampleValid = 0,
IncrementMux = 0
TimerPulse = 1 /
Convert = 0,
ClockEnable = 1,
SampleValid = 0,
IncrementMux = 1
CONV_WAIT
TimerPulse = 0 /
Convert = 1,
ClockEnable = 0,
SampleValid = 0,
IncrementMux = 0
ACQ_SHIFT
TimerPulse = 1 /
Convert = 1,
ClockEnable = 0,
SampleValid = 1,
IncrementMux = 0
TimerPulse = 0 /
Convert = 0,
ClockEnable = 1,
SampleValid = 0,
IncrementMux = 0
State Machine
CurrentState
State
Value
TimerPulse
A
Up Counter
Clock
EQ
Convert
ADC_CNV
ClockEnable
ClockEnable
Clock
SampleValid
SampleValid
Reset
IncrementMux
Count
Clear
Up Counter
Enable
CLK
Clock
RST
Clear
Count
MUX_SEL
Clock
Shift Register
ADC_SDO
SerialData
ParallelData
Sample
CLKFX
DCM
Status Read_CLK
Reset
CLKFX180
LEDS
Write_Error
Read_Error
CLK
HEX
ADC Driver
SEG
Block FIFO
ADC_CLK
CLK180
ADC_CNV
CLK
Write_Error
Read_Error
Write_CLK
Read_CLK
16
ADC_SDO
AN
SSD Driver
Sample
USB I/O
16
Write_Data
Read_Data
SampleValid
Write_Enable
Reset
Write_Ready
FIFO_ReadData
USB_CLK
Read_Next
FIFO_ReadNext
USB_AddrStrobe
Read_Valid
FIFO_ReadValid
USB_DataStrobe
MUX_SEL
Reset
MUX_Channel
USB_ReadWrite
MUX_Override
USB_Wait
ADC_Enable
3
3
S
USB_DataBus
ADC_CLK
ClockEnable
Spartan 3E IOB
Block FIFO
This method can be extended by utilizing multiple blocks
of memory.
Read/Write status signals exist for each block of memory.
When one block of memory is filled, the write domain sets the
appropriate status bit and moves on to the next block.
Similarly, the read domain empties a block at a time, and
acknowledges each complete read.
This creates a multi-block FIFO structure similar to the one in the
Cypress USB chip.
Block FIFO
2
Write_CLK
CLKIN
CLKFX
DCM
Status Read_CLK
Reset
CLKFX180
LEDS
Write_Error
Read_Error
CLK
HEX
ADC Driver
SEG
Block FIFO
ADC_CLK
CLK180
ADC_CNV
CLK
Write_Error
Read_Error
Write_CLK
Read_CLK
16
ADC_SDO
AN
SSD Driver
Sample
USB I/O
16
Write_Data
Read_Data
SampleValid
Write_Enable
Reset
Write_Ready
FIFO_ReadData
USB_CLK
Read_Next
FIFO_ReadNext
USB_AddrStrobe
Read_Valid
FIFO_ReadValid
USB_DataStrobe
MUX_SEL
Reset
MUX_Channel
USB_ReadWrite
MUX_Override
USB_Wait
ADC_Enable
3
3
S
USB_DataBus
Block FIFO
Read Signals
ReadCLK: Clock signal used to control the data read
logic.
ReadNext: Read next signal. The read pointer is
incremented and the next unit of data will be output
on the rising edge of ReadCLK. One unit of data can
be removed from the FIFO every clock cycle if this
signal is connected to ReadDataValid.
ReadDataValid: Status signal; if this signal is high,
ReadData contains valid data to be read.
ReadError: Status signal; if this signal is high, a read
was attempted on an empty FIFO.
ReadData: Data output signal. 16 bits wide.
Block FIFO
Write Signals
WriteCLK: Clock signal used to control the data write
logic.
WriteEnable: Write enable signal. One unit of data
can be added to the FIFO on every rising edge of
WriteCLK that this signal is high.
WriteReady: Status signal; if this signal is high, there
is free space in the FIFO to store data.
WriteError: Status signal; if this signal is high, a write
was attempted when the FIFO was full.
WriteData: Data input signal. 16 bits wide.
USB I/O
2
Write_CLK
CLKIN
CLKFX
DCM
Status Read_CLK
Reset
CLKFX180
LEDS
Write_Error
Read_Error
CLK
HEX
ADC Driver
SEG
Block FIFO
ADC_CLK
CLK180
ADC_CNV
CLK
Write_Error
Read_Error
Write_CLK
Read_CLK
16
ADC_SDO
AN
SSD Driver
Sample
USB I/O
16
Write_Data
Read_Data
SampleValid
Write_Enable
Reset
Write_Ready
FIFO_ReadData
USB_CLK
Read_Next
FIFO_ReadNext
USB_AddrStrobe
Read_Valid
FIFO_ReadValid
USB_DataStrobe
MUX_SEL
Reset
MUX_Channel
USB_ReadWrite
MUX_Override
USB_Wait
ADC_Enable
3
3
S
USB_DataBus
USB_AddrStrobe = 1
USB_DataStrobe = 1
USB_DataStrobe = 1
S0_Idle
USB_DataStrobe = 0
USB_Direction = 0
USB_AddrStrobe = 0
USB_Direction = 1
USB_AddrStrobe = 0
USB_Direction = 0
S1_Usb2Fpga_DummyData
WaitOutput = 0
USB_DataStrobe = 0
USB_Direction = 1
ADC_GettingData = 1
ReadingDataMSB = 0
FIFO_ReadDataValid = 1
USB_AddrStrobe = 1
S1_Usb2Fpga_Command
WaitOutput = 1
CommandUpdate = 1
USB_DataStrobe = 0
USB_Direction = 1
ADC_GettingData = 1
ReadingDataMSB = 1
USB_DataStrobe = 1
S1_Fpga2Usb_DataMSB
OutputEnable = 1
WaitOutput = 1
OutputDataMux = 1
ReadDataMSB = 1
S1_Fpga2Usb_DummyData
OutputEnable = 1
WaitOutput = 1
S1_Fpga2Usb_DataLSB
OutputEnable = 1
WaitOutput = 1
OutputDataMux = 1
ReadDataLSB = 1
USB_AddrStrobe = 0
or
USB_DataStrobe = 0
USB_DataStrobe = 0
S2_Usb2Fpga_Command
WaitOutput = 1
USB_AddrStrobe = 0
S2_Fpga2Usb_Data
OutputEnable = 1
WaitOutput = 1
OutputDataMux = 1
USB_DataStrobe = 0
USB Commands
The following commands were implemented:
CMD_StopADC: Disables the ADC and Block FIFO
by holding the Reset signal high.
CMD_StartADC: Enables the ADC and Block FIFO
by bringing the Reset signal low.
CMD_GetSamples: Specifies that subsequent read
data operations will return ADC samples from the
FIFO.
CMD_SetChannel: Can be used to override the
analog multiplexer channel used. The selected
channel and override flag are stored in the upper
nibble of the command byte.
CLKFX
DCM
Status Read_CLK
Reset
CLKFX180
LEDS
Write_Error
Read_Error
CLK
HEX
ADC Driver
SEG
Block FIFO
ADC_CLK
CLK180
ADC_CNV
CLK
Write_Error
Read_Error
Write_CLK
Read_CLK
16
ADC_SDO
AN
SSD Driver
Sample
USB I/O
16
Write_Data
Read_Data
SampleValid
Write_Enable
Reset
Write_Ready
FIFO_ReadData
USB_CLK
Read_Next
FIFO_ReadNext
USB_AddrStrobe
Read_Valid
FIFO_ReadValid
USB_DataStrobe
MUX_SEL
Reset
MUX_Channel
USB_ReadWrite
MUX_Override
USB_Wait
ADC_Enable
3
3
S
USB_DataBus
ERC *perc)
// DPC Stuff
[DllImport("dpcutil.dll")]
public static extern bool DpcInit( out int ErrorCode );
[DllImport("dpcutil.dll")]
public static extern void DpcTerm();
[DllImport("dpcutil.dll")]
public static extern bool DpcGetDpcVersion( StringBuilder VersionString, out int ErrorCode );
[DllImport("dpcutil.dll")]
public static extern bool DpcStartNotify( IntPtr hwndTemp, ushort idNotifyTemp, out int ErrorCode );
[DllImport("dpcutil.dll")]
public static extern bool DpcEndNotify( IntPtr hwndTemp, out int ErrorCode );
[DllImport("dpcutil.dll")]
public static extern bool DpcGetVersion( IntPtr InterfaceHandle, byte[] rgbVersion, int cbVersion, out
int ErrorCode, UIntPtr TransactionID );
[DllImport("dpcutil.dll")]
public static extern int DpcGetFirstError( IntPtr InterfaceHandle );
DPC Wrapper
Initialization/Termination
private bool DPC_Init()
{
int ErrorCode;
int DeviceID;
if ( !DPCUtil.DpcInit(out ErrorCode) )
{
return false;
}
DeviceID = DPCUtil.DvmgGetDefaultDev(out ErrorCode);
if ( DeviceID == -1 )
{
return false;
}
else
{
DPCUtil.DvmgGetDevName(DeviceID, DefaultDeviceName, out ErrorCode);
return true;
}
}
private void MainForm_FormClosed( object sender, FormClosedEventArgs e )
{
DPCUtil.DpcTerm();
}
Read a Register
public bool DPC_GetReg( byte RegisterAddress, ref byte RegisterData )
{
int ErrorCode;
IntPtr InterfaceHandle;
bool Success = true;
if ( !DPCUtil.DpcOpenData(out InterfaceHandle, DefaultDeviceName, out
ErrorCode, UIntPtr.Zero) )
return false;
if ( !DPCUtil.DpcGetReg(InterfaceHandle, RegisterAddress, out RegisterData,
out ErrorCode, UIntPtr.Zero) )
Success = false;
Write a Register
public bool DPC_PutReg( byte RegisterAddress, byte RegisterData )
{
int ErrorCode;
IntPtr InterfaceHandle;
bool Success = true;
if ( !DPCUtil.DpcOpenData(out InterfaceHandle, DefaultDeviceName, out
ErrorCode, UIntPtr.Zero) )
return false;
if ( !DPCUtil.DpcPutReg(InterfaceHandle, RegisterAddress, RegisterData, out
ErrorCode, UIntPtr.Zero) )
Success = false;
Conclusion
We successfully implemented a PC-controlled
ADC reader
The original Digilent FPGA USB protocol was
modified and improved
We are able to continuously read at 16Mbit/s
with no data corruption
Speeds up to 50Mbit/s should be possible with
the improved Digilent protocol
Even greater speeds can be achieved with new
firmware on the Cypress chip
Sources
Questions?