Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC DEL 1ns 2cha
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
9
Issues
9
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
FMC DEL 1ns 2cha
Commits
475932c2
Commit
475932c2
authored
Aug 18, 2016
by
Jan Pospisil
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added entity for automatic control of AD9512 divider + testbench
parent
bb9540eb
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
436 additions
and
0 deletions
+436
-0
Ad9512Control.vhd
hdl/ffpg/rtl/Ad9512Control.vhd
+363
-0
Ad9512Control_tb.vhd
hdl/ffpg/rtl/Ad9512Control_tb.vhd
+73
-0
No files found.
hdl/ffpg/rtl/Ad9512Control.vhd
0 → 100644
View file @
475932c2
------------------------------------------------------------------------
-- Title : AD9512 Control
-- Project : http://www.ohwr.org/projects/fmc-del-1ns-2cha/
------------------------------------------------------------------------
-- File : Ad9512Control.vhd
-- Author : T. Levens, J. Pospisil
-- Company : CERN BE-BI-QP
-- Created : 2015-08-17
-- Last update: 2016-08-18
-- Platform : FPGA-generic
-- Standard : VHDL
------------------------------------------------------------------------
-- Description:
--
-- AD9512 control using OpenCores SPI master.
--
-- Based on https://gitlab.cern.ch/bi/mim/blob/master/hdl/rtl/PllControl.v
------------------------------------------------------------------------
library
ieee
;
use
ieee
.
std_logic_1164
.
all
;
use
ieee
.
numeric_std
.
all
;
entity
Ad9512Control
is
generic
(
g_ClkFrequency
:
positive
-- input clock frequency in Hz
);
port
(
Clk_ik
:
in
std_logic
;
Rst_ir
:
in
std_logic
;
Cfg_i
:
in
std_logic
;
Busy_o
:
out
std_logic
;
ClockSelection_i
:
in
std_logic
;
-- 0 - CLK1, 1 - CLK2
ClockRatioMinus1_ib
:
in
unsigned
(
4
downto
0
);
SpiAd9512Sclk_o
:
out
std_logic
;
SpiAd9512Mosi_o
:
out
std_logic
;
SpiAd9512Miso_i
:
in
std_logic
;
SpiAd9512Cs_on
:
out
std_logic
);
end
entity
;
architecture
syn
of
Ad9512Control
is
--! computes least possible width of the vector to store value X
-- http://stackoverflow.com/a/12751341/615627
function
f_log2
(
x
:
natural
)
return
natural
is
variable
i
:
natural
;
begin
i
:
=
0
;
while
(
2
**
i
<
x
)
loop
i
:
=
i
+
1
;
end
loop
;
return
i
;
end
function
;
function
if_slv
(
condition
:
boolean
;
pos
:
std_logic_vector
;
neg
:
std_logic_vector
)
return
std_logic_vector
is
begin
if
condition
then
return
pos
;
else
return
neg
;
end
if
;
end
function
;
------------------------------------------------------------------------
-- Input registers for config
------------------------------------------------------------------------
signal
ClockSelection
:
std_logic
:
=
'0'
;
signal
ClockRatioMinus1_b
:
unsigned
(
ClockRatioMinus1_ib
'range
)
:
=
to_unsigned
(
2-1
,
ClockRatioMinus1_ib
'length
);
------------------------------------------------------------------------
-- AD9512 config registers
------------------------------------------------------------------------
type
t_Ad9512Register
is
record
Address
:
std_logic_vector
(
7
downto
0
);
Data
:
std_logic_vector
(
7
downto
0
);
end
record
;
function
f_Ad9512Register2WriteInstruction
(
Reg
:
t_Ad9512Register
)
return
std_logic_vector
is
variable
ZerosToPad
:
integer
:
=
32
-
Reg
.
Address
'length
-
Reg
.
Data
'length
;
begin
return
std_logic_vector
(
to_unsigned
(
0
,
ZerosToPad
))
&
Reg
.
Address
&
Reg
.
Data
;
end
function
;
constant
c_Ad9512RegisterCount
:
positive
:
=
14
;
type
t_Ad9512RegisterFiled
is
array
(
integer
range
<>
)
of
t_Ad9512Register
;
signal
c_Ad9512Registers
:
t_Ad9512RegisterFiled
(
0
to
c_Ad9512RegisterCount
-1
);
-- calculate cycles according to provided ratio
function
f_CreateDivideReg1
(
ClockRatioMinus1_b
:
unsigned
)
return
std_logic_vector
is
variable
LowCycles
,
HighCycles
:
unsigned
(
3
downto
0
);
begin
HighCycles
:
=
ClockRatioMinus1_b
(
4
downto
1
);
if
ClockRatioMinus1_b
(
0
)
=
'1'
then
LowCycles
:
=
HighCycles
;
else
LowCycles
:
=
HighCycles
-1
;
end
if
;
if
ClockRatioMinus1_b
=
"00000"
then
return
"00000000"
;
else
return
std_logic_vector
(
LowCycles
&
HighCycles
);
end
if
;
end
function
;
-- divider bypass, phase, ...
function
f_CreateDivideReg2
(
ClockRatioMinus1_b
:
unsigned
)
return
std_logic_vector
is
variable
PhaseOffset
:
std_logic_vector
(
3
downto
0
)
:
=
"0000"
;
variable
StartHL
:
std_logic
:
=
'0'
;
variable
ForceState
:
std_logic
:
=
'0'
;
variable
NoSync
:
std_logic
:
=
'0'
;
variable
Bypass
:
std_logic
;
begin
if
ClockRatioMinus1_b
=
"00000"
then
Bypass
:
=
'1'
;
else
Bypass
:
=
'0'
;
end
if
;
return
Bypass
&
NoSync
&
ForceState
&
StartHL
&
PhaseOffset
;
end
function
;
------------------------------------------------------------------------
-- SPI core config
------------------------------------------------------------------------
function
f_SpiCalcDivider
(
WbFreq
,
SpiMaxFreq
:
positive
)
return
integer
is
begin
if
WbFreq
<
2
*
SpiMaxFreq
then
return
0
;
else
return
(
WbFreq
/
(
SpiMaxFreq
*
2
));
end
if
;
end
function
;
constant
c_SpiMaxFrequency
:
positive
:
=
25
e6
;
-- in Hz
-- ---------------------- ASS
-- / ------------------- IE
-- / / ---------------- LSB
-- / / / ------------- Tx_NEG
-- / / / / ---------- Rx_NEG
-- / / / / / ------- GO_BSY
-- / / / / / /
-- / / / / / / --- CHAR_LEN
-- / / / / / / /
constant
c_SpiCtrlReg_b32
:
-- | | | | | | |
std_logic_vector
(
13
downto
0
)
:
=
(
"1"
&
"1"
&
"0"
&
"1"
&
"1"
&
"0"
&
X"18"
);
constant
c_SpiGo_b32
:
-- | | | | | | |
std_logic_vector
(
13
downto
0
)
:
=
(
"0"
&
"0"
&
"0"
&
"0"
&
"0"
&
"1"
&
X"00"
);
constant
c_SpiSs
:
std_logic_vector
(
31
downto
0
)
:
=
X"00000001"
;
constant
c_SpiDivider
:
std_logic_vector
(
31
downto
0
)
:
=
std_logic_vector
(
to_unsigned
(
f_SpiCalcDivider
(
g_ClkFrequency
,
c_SpiMaxFrequency
),
32
));
-- WB control signals
signal
WbAdr_b5
:
std_logic_vector
(
4
downto
0
);
signal
WbDatIn_b32
:
std_logic_vector
(
31
downto
0
);
signal
WbDatOut_b32
:
std_logic_vector
(
31
downto
0
);
signal
WbStb
:
std_logic
;
signal
WbWe
:
std_logic
;
signal
WbAck
:
std_logic
;
signal
WbInt
:
std_logic
;
-- FSM
type
t_State
is
(
S_INIT
,
S_DIVIDER
,
S_SS
,
S_CTRL
,
S_IDLE
,
S_WR_DATA
,
S_WR_CTRL
,
S_WAIT
,
S_COUNT_DEC
);
constant
c_ResetState
:
t_State
:
=
S_INIT
;
signal
SeqCurrentState
:
t_State
:
=
c_ResetState
;
-- Write counter
signal
SeqCnt
:
unsigned
(
3
downto
0
)
:
=
(
others
=>
'0'
);
signal
SeqCntEnable
,
SeqCntReset
:
std_logic
:
=
'0'
;
signal
SeqCntOverflow
:
std_logic
;
signal
SpiAd9512Cs_n
:
std_logic_vector
(
0
downto
0
);
begin
cConfigInputRegisters
:
process
(
Clk_ik
)
is
begin
if
rising_edge
(
Clk_ik
)
then
if
Cfg_i
=
'1'
then
ClockSelection
<=
ClockSelection_i
;
ClockRatioMinus1_b
<=
ClockRatioMinus1_ib
;
end
if
;
end
if
;
end
process
;
c_Ad9512Registers
<=
(
-- power down unused output (OUT2)
(
X"3f"
,
X"03"
),
-- select CLK1 input, power down CLK2 input
(
X"45"
,
if_slv
(
ClockSelection
=
'0'
,
X"05"
,
X"02"
)),
-- output frequency 200 MHz (divide by 2)
(
X"4a"
,
f_CreateDivideReg1
(
ClockRatioMinus1_b
)),
-- OUT0
(
X"4c"
,
f_CreateDivideReg1
(
ClockRatioMinus1_b
)),
-- OUT1
(
X"4e"
,
f_CreateDivideReg1
(
ClockRatioMinus1_b
)),
-- OUT2
(
X"50"
,
f_CreateDivideReg1
(
ClockRatioMinus1_b
)),
-- OUT3
(
X"52"
,
f_CreateDivideReg1
(
ClockRatioMinus1_b
)),
-- OUT4
-- phase 0
(
X"4b"
,
f_CreateDivideReg2
(
ClockRatioMinus1_b
)),
-- OUT0
(
X"4d"
,
f_CreateDivideReg2
(
ClockRatioMinus1_b
)),
-- OUT1
(
X"4f"
,
f_CreateDivideReg2
(
ClockRatioMinus1_b
)),
-- OUT2
(
X"51"
,
f_CreateDivideReg2
(
ClockRatioMinus1_b
)),
-- OUT3
(
X"53"
,
f_CreateDivideReg2
(
ClockRatioMinus1_b
)),
-- OUT4
-- function pin as sync
(
X"58"
,
X"20"
),
-- confirm write
(
X"5a"
,
X"01"
)
);
cRegisterCounter
:
entity
work
.
Counter
(
syn
)
generic
map
(
g_Width
=>
f_log2
(
c_Ad9512RegisterCount
),
g_Limit
=>
c_Ad9512RegisterCount
)
port
map
(
Clk_ik
=>
Clk_ik
,
Reset_ir
=>
SeqCntReset
,
Enable_i
=>
SeqCntEnable
,
Set_i
=>
'0'
,
SetValue_ib
=>
(
others
=>
'0'
),
Overflow_o
=>
SeqCntOverflow
,
Value_ob
=>
SeqCnt
);
pFsmTransitions
:
process
(
Clk_ik
)
is
begin
if
rising_edge
(
Clk_ik
)
then
if
Rst_ir
=
'1'
then
SeqCurrentState
<=
c_ResetState
;
else
SeqCurrentState
<=
SeqCurrentState
;
case
SeqCurrentState
is
when
S_INIT
=>
SeqCurrentState
<=
S_DIVIDER
;
when
S_DIVIDER
=>
if
WbAck
=
'1'
then
SeqCurrentState
<=
S_CTRL
;
end
if
;
when
S_CTRL
=>
if
WbAck
=
'1'
then
SeqCurrentState
<=
S_SS
;
end
if
;
when
S_SS
=>
if
WbAck
=
'1'
then
SeqCurrentState
<=
S_WR_DATA
;
end
if
;
when
S_IDLE
=>
if
Cfg_i
=
'1'
then
SeqCurrentState
<=
S_WR_DATA
;
end
if
;
when
S_WR_DATA
=>
if
WbAck
=
'1'
then
SeqCurrentState
<=
S_WR_CTRL
;
end
if
;
when
S_WR_CTRL
=>
if
WbAck
=
'1'
then
SeqCurrentState
<=
S_WAIT
;
end
if
;
when
S_WAIT
=>
if
(
WbInt
=
'1'
)
and
(
SeqCntOverflow
=
'1'
)
then
SeqCurrentState
<=
S_IDLE
;
elsif
WbInt
=
'1'
then
SeqCurrentState
<=
S_COUNT_DEC
;
end
if
;
when
S_COUNT_DEC
=>
SeqCurrentState
<=
S_WR_DATA
;
end
case
;
end
if
;
end
if
;
end
process
;
pFsmOutputs
:
process
(
SeqCurrentState
,
SeqCnt
)
is
begin
WbAdr_b5
<=
(
others
=>
'0'
);
WbDatIn_b32
<=
(
others
=>
'0'
);
WbStb
<=
'0'
;
WbWe
<=
'0'
;
Busy_o
<=
'1'
;
SeqCntReset
<=
'0'
;
SeqCntEnable
<=
'0'
;
case
SeqCurrentState
is
when
S_INIT
=>
-- Do nothing
null
;
when
S_DIVIDER
=>
WbAdr_b5
<=
std_logic_vector
(
to_unsigned
(
16
#
14
#
,
5
));
WbDatIn_b32
<=
c_SpiDivider
;
WbStb
<=
'1'
;
WbWe
<=
'1'
;
when
S_CTRL
=>
WbAdr_b5
<=
std_logic_vector
(
to_unsigned
(
16
#
10
#
,
5
));
WbDatIn_b32
(
13
downto
0
)
<=
c_SpiCtrlReg_b32
;
WbStb
<=
'1'
;
WbWe
<=
'1'
;
when
S_SS
=>
WbAdr_b5
<=
std_logic_vector
(
to_unsigned
(
16
#
18
#
,
5
));
WbDatIn_b32
<=
c_SpiSs
;
WbStb
<=
'1'
;
WbWe
<=
'1'
;
SeqCntReset
<=
'1'
;
when
S_IDLE
=>
Busy_o
<=
'0'
;
SeqCntReset
<=
'1'
;
when
S_WR_DATA
=>
WbAdr_b5
<=
std_logic_vector
(
to_unsigned
(
16
#
00
#
,
5
));
WbDatIn_b32
<=
f_Ad9512Register2WriteInstruction
(
c_Ad9512Registers
(
to_integer
(
SeqCnt
)));
WbStb
<=
'1'
;
WbWe
<=
'1'
;
when
S_WR_CTRL
=>
WbAdr_b5
<=
std_logic_vector
(
to_unsigned
(
16
#
10
#
,
5
));
WbDatIn_b32
(
13
downto
0
)
<=
c_SpiCtrlReg_b32
or
c_SpiGo_b32
;
WbStb
<=
'1'
;
WbWe
<=
'1'
;
when
S_WAIT
=>
-- do nothing
null
;
when
S_COUNT_DEC
=>
SeqCntEnable
<=
'1'
;
end
case
;
end
process
;
------------------------------------------------------------------------
-- Wishbone SPI master
------------------------------------------------------------------------
i_spi_top
:
entity
work
.
spi_top
generic
map
(
SPI_SS_NB
=>
1
)
port
map
(
wb_clk_i
=>
Clk_ik
,
wb_rst_i
=>
Rst_ir
,
wb_adr_i
=>
WbAdr_b5
,
wb_dat_i
=>
WbDatIn_b32
,
wb_dat_o
=>
WbDatOut_b32
,
wb_sel_i
=>
(
others
=>
'1'
),
wb_we_i
=>
WbWe
,
wb_stb_i
=>
WbStb
,
wb_cyc_i
=>
WbStb
,
wb_ack_o
=>
WbAck
,
wb_err_o
=>
open
,
wb_int_o
=>
WbInt
,
ss_pad_o
=>
SpiAd9512Cs_n
,
sclk_pad_o
=>
SpiAd9512Sclk_o
,
mosi_pad_o
=>
SpiAd9512Mosi_o
,
miso_pad_i
=>
SpiAd9512Miso_i
);
SpiAd9512Cs_on
<=
SpiAd9512Cs_n
(
0
);
end
architecture
;
\ No newline at end of file
hdl/ffpg/rtl/Ad9512Control_tb.vhd
0 → 100644
View file @
475932c2
library
ieee
;
use
ieee
.
std_logic_1164
.
all
;
use
ieee
.
numeric_std
.
all
;
entity
Ad9512Control_tb
is
end
entity
;
architecture
testbench
of
Ad9512Control_tb
is
constant
c_ClkFrequency
:
positive
:
=
100
_
000
_
000
;
constant
c_ClkPeriod
:
time
:
=
(
1
sec
)
/
real
(
c_ClkFrequency
);
signal
Clk_ik
,
Rst_ir
,
Cfg_i
,
Busy_o
:
std_logic
:
=
'0'
;
signal
ClockSelection_i
:
std_logic
:
=
'0'
;
signal
ClockRatioMinus1_ib
:
unsigned
(
4
downto
0
)
:
=
to_unsigned
(
2-1
,
5
);
signal
SpiAd9512Sclk_o
,
SpiAd9512Mosi_o
,
SpiAd9512Miso_i
,
SpiAd9512Cs_on
:
std_logic
:
=
'0'
;
subtype
t_Ratio
is
Integer
range
1
to
32
;
procedure
f_Tick
(
ticks
:
in
natural
)
is
begin
wait
for
ticks
*
c_ClkPeriod
;
end
procedure
;
begin
cDUT
:
entity
work
.
Ad9512Control
(
syn
)
generic
map
(
g_ClkFrequency
=>
c_ClkFrequency
)
port
map
(
Clk_ik
=>
Clk_ik
,
Rst_ir
=>
Rst_ir
,
Cfg_i
=>
Cfg_i
,
Busy_o
=>
Busy_o
,
ClockSelection_i
=>
ClockSelection_i
,
ClockRatioMinus1_ib
=>
ClockRatioMinus1_ib
,
SpiAd9512Sclk_o
=>
SpiAd9512Sclk_o
,
SpiAd9512Mosi_o
=>
SpiAd9512Mosi_o
,
SpiAd9512Miso_i
=>
SpiAd9512Miso_i
,
SpiAd9512Cs_on
=>
SpiAd9512Cs_on
);
pClk
:
process
is
begin
Clk_ik
<=
'0'
;
wait
for
c_ClkPeriod
/
2
;
Clk_ik
<=
'1'
;
wait
for
c_ClkPeriod
/
2
;
end
process
;
pTest
:
process
is
variable
Ratio
:
t_Ratio
;
begin
Rst_ir
<=
'1'
;
f_Tick
(
5
);
Rst_ir
<=
'0'
;
f_Tick
(
2300
);
ClockSelection_i
<=
'1'
;
Ratio
:
=
23
;
ClockRatioMinus1_ib
<=
to_unsigned
(
Ratio
-1
,
ClockRatioMinus1_ib
'length
);
Cfg_i
<=
'1'
;
f_Tick
(
1
);
ClockSelection_i
<=
'0'
;
Ratio
:
=
10
;
ClockRatioMinus1_ib
<=
to_unsigned
(
Ratio
-1
,
ClockRatioMinus1_ib
'length
);
Cfg_i
<=
'0'
;
f_Tick
(
2300
);
assert
false
report
"NONE. End of simulation."
severity
failure
;
wait
;
end
process
;
end
architecture
;
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment