Commit e197b6c2 authored by Peter Jansweijer's avatar Peter Jansweijer

add sit5359 interface files

parent 7655749b
......@@ -9,6 +9,7 @@ modules = {
"wr_pps_gen",
"wr_dacs",
"wr_si57x_interface",
"wr_sit5359_interface",
"wr_eca",
"wr_tlu",
"wrc_core",
......
files = ["sit5359_regs_pkg.vhd",
"sit5359_if_wb.vhd",
"wr_sit5359_interface.vhd",
"xwr_sit5359_interface.vhd"]
#!/bin/bash
mkdir -p doc
wbgen2.exe -D ./doc/sit5359_id_wb.html -C sit5359_regs.h -p sit5359_regs_pkg.vhd -H record -V sit5359_if_wb.vhd --cstyle defines --lang vhdl sit5359_if_wb.wb
\ No newline at end of file
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for SiTime 5359 interface
---------------------------------------------------------------------------------------
-- File : sit5359_if_wb.vhd
-- Author : auto-generated by wbgen2 from sit5359_if_wb.wb
-- Created : 01/11/22 17:31:58
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE sit5359_if_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.sit5359_wbgen2_pkg.all;
entity sit5359_if_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(1 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
regs_i : in t_sit5359_in_registers;
regs_o : out t_sit5359_out_registers
);
end sit5359_if_wb;
architecture syn of sit5359_if_wb is
signal sit5359_cr_i2c_addr_int : std_logic_vector(7 downto 0);
signal sit5359_cr_clk_div_int : std_logic_vector(7 downto 0);
signal sit5359_cr_spll_en_int : std_logic ;
signal sit5359_cr_osc_oe_int : std_logic ;
signal sit5359_gpcr_scl_dly0 : std_logic ;
signal sit5359_gpcr_scl_int : std_logic ;
signal sit5359_gpcr_sda_dly0 : std_logic ;
signal sit5359_gpcr_sda_int : std_logic ;
signal ack_sreg : std_logic_vector(9 downto 0);
signal rddata_reg : std_logic_vector(31 downto 0);
signal wrdata_reg : std_logic_vector(31 downto 0);
signal bwsel_reg : std_logic_vector(3 downto 0);
signal rwaddr_reg : std_logic_vector(1 downto 0);
signal ack_in_progress : std_logic ;
signal wr_int : std_logic ;
signal rd_int : std_logic ;
signal allones : std_logic_vector(31 downto 0);
signal allzeros : std_logic_vector(31 downto 0);
begin
-- Some internal signals assignments. For (foreseen) compatibility with other bus standards.
wrdata_reg <= wb_dat_i;
bwsel_reg <= wb_sel_i;
rd_int <= wb_cyc_i and (wb_stb_i and (not wb_we_i));
wr_int <= wb_cyc_i and (wb_stb_i and wb_we_i);
allones <= (others => '1');
allzeros <= (others => '0');
--
-- Main register bank access process.
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
ack_sreg <= "0000000000";
ack_in_progress <= '0';
rddata_reg <= "00000000000000000000000000000000";
sit5359_cr_i2c_addr_int <= "00000000";
sit5359_cr_clk_div_int <= "00000000";
sit5359_cr_spll_en_int <= '0';
sit5359_cr_osc_oe_int <= '0';
regs_o.gpsr_scl_load_o <= '0';
regs_o.gpsr_sda_load_o <= '0';
sit5359_gpcr_scl_int <= '0';
sit5359_gpcr_sda_int <= '0';
elsif rising_edge(clk_sys_i) then
-- advance the ACK generator shift register
ack_sreg(8 downto 0) <= ack_sreg(9 downto 1);
ack_sreg(9) <= '0';
if (ack_in_progress = '1') then
if (ack_sreg(0) = '1') then
regs_o.gpsr_scl_load_o <= '0';
regs_o.gpsr_sda_load_o <= '0';
sit5359_gpcr_scl_int <= '0';
sit5359_gpcr_sda_int <= '0';
ack_in_progress <= '0';
else
regs_o.gpsr_scl_load_o <= '0';
regs_o.gpsr_sda_load_o <= '0';
end if;
else
if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then
case rwaddr_reg(1 downto 0) is
when "00" =>
if (wb_we_i = '1') then
sit5359_cr_i2c_addr_int <= wrdata_reg(7 downto 0);
sit5359_cr_clk_div_int <= wrdata_reg(15 downto 8);
sit5359_cr_spll_en_int <= wrdata_reg(16);
sit5359_cr_osc_oe_int <= wrdata_reg(17);
end if;
rddata_reg(7 downto 0) <= sit5359_cr_i2c_addr_int;
rddata_reg(15 downto 8) <= sit5359_cr_clk_div_int;
rddata_reg(16) <= sit5359_cr_spll_en_int;
rddata_reg(17) <= sit5359_cr_osc_oe_int;
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01" =>
if (wb_we_i = '1') then
regs_o.gpsr_scl_load_o <= '1';
regs_o.gpsr_sda_load_o <= '1';
end if;
rddata_reg(0) <= regs_i.gpsr_scl_i;
rddata_reg(1) <= regs_i.gpsr_sda_i;
rddata_reg(2) <= 'X';
rddata_reg(3) <= 'X';
rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(7) <= 'X';
rddata_reg(8) <= 'X';
rddata_reg(9) <= 'X';
rddata_reg(10) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "10" =>
if (wb_we_i = '1') then
sit5359_gpcr_scl_int <= wrdata_reg(0);
sit5359_gpcr_sda_int <= wrdata_reg(1);
end if;
rddata_reg(0) <= '0';
rddata_reg(1) <= '0';
rddata_reg(0) <= 'X';
rddata_reg(1) <= 'X';
rddata_reg(2) <= 'X';
rddata_reg(3) <= 'X';
rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(7) <= 'X';
rddata_reg(8) <= 'X';
rddata_reg(9) <= 'X';
rddata_reg(10) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(2) <= '1';
ack_in_progress <= '1';
when others =>
-- prevent the slave from hanging the bus on invalid address
ack_in_progress <= '1';
ack_sreg(0) <= '1';
end case;
end if;
end if;
end if;
end process;
-- Drive the data output bus
wb_dat_o <= rddata_reg;
-- Sit5359 I2C Address
regs_o.cr_i2c_addr_o <= sit5359_cr_i2c_addr_int;
-- I2C Clock Divider (1 I2C bit = 4*(CLK_DIV+1)*clk_sys-period)
regs_o.cr_clk_div_o <= sit5359_cr_clk_div_int;
-- Sit5359 SPLL input enable
regs_o.cr_spll_en_o <= sit5359_cr_spll_en_int;
-- Sit5359 Oscillator Output Enable
regs_o.cr_osc_oe_o <= sit5359_cr_osc_oe_int;
-- Sit5359 I2C bitbanged SCL
regs_o.gpsr_scl_o <= wrdata_reg(0);
-- Sit5359 I2C bitbanged SDA
regs_o.gpsr_sda_o <= wrdata_reg(1);
-- Sit5359 I2C bitbanged SCL
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
sit5359_gpcr_scl_dly0 <= '0';
regs_o.gpcr_scl_o <= '0';
elsif rising_edge(clk_sys_i) then
sit5359_gpcr_scl_dly0 <= sit5359_gpcr_scl_int;
regs_o.gpcr_scl_o <= sit5359_gpcr_scl_int and (not sit5359_gpcr_scl_dly0);
end if;
end process;
-- Sit5359 I2C bitbanged SDA
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
sit5359_gpcr_sda_dly0 <= '0';
regs_o.gpcr_sda_o <= '0';
elsif rising_edge(clk_sys_i) then
sit5359_gpcr_sda_dly0 <= sit5359_gpcr_sda_int;
regs_o.gpcr_sda_o <= sit5359_gpcr_sda_int and (not sit5359_gpcr_sda_dly0);
end if;
end process;
rwaddr_reg <= wb_adr_i;
wb_stall_o <= (not ack_sreg(0)) and (wb_stb_i and wb_cyc_i);
-- ACK signal generation. Just pass the LSB of ACK counter.
wb_ack_o <= ack_sreg(0);
end syn;
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral {
name = "SiTime 5359 interface";
hdl_entity = "sit5359_if_wb";
prefix = "sit5359";
reg {
name = "Control Register";
prefix = "CR";
field {
name = "Sit5359 I2C Address";
size = 8;
type = SLV;
prefix = "I2C_ADDR";
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "I2C Clock Divider (1 I2C bit = 4*(CLK_DIV+1)*clk_sys-period)";
prefix = "CLK_DIV";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Sit5359 SPLL input enable";
prefix = "SPLL_EN";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Sit5359 Oscillator Output Enable";
prefix = "OSC_OE";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "GPIO Set/Readback Register";
prefix = "GPSR";
field {
name = "Sit5359 I2C bitbanged SCL";
prefix = "scl";
description = "write 1: Set FMC SCL line to 1 (pullup)\
read : returns the current status of the SCL line.";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
name = "Sit5359 I2C bitbanged SDA";
prefix = "sda";
description = "write 1: Set FMC SDA line to 1 (pullup)\
read : returns the current status of the SCL line.";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
};
reg {
name = "GPIO Clear Register";
prefix = "GPCR";
field {
name = "Sit5359 I2C bitbanged SCL";
prefix = "scl";
description = "write 1: Set SCL line to 0\
read : returns the current status of the SCL line.";
type = MONOSTABLE;
};
field {
name = "Sit5359 I2C bitbanged SDA";
prefix = "sda";
description = "write 1: Set SDA line to 0\
read : returns the current status of the SCL line.";
type = MONOSTABLE;
};
};
};
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for SiTime 5359 interface
---------------------------------------------------------------------------------------
-- File : sit5359_regs_pkg.vhd
-- Author : auto-generated by wbgen2 from sit5359_if_wb.wb
-- Created : 01/11/22 17:31:58
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE sit5359_if_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package sit5359_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_sit5359_in_registers is record
gpsr_scl_i : std_logic;
gpsr_sda_i : std_logic;
end record;
constant c_sit5359_in_registers_init_value: t_sit5359_in_registers := (
gpsr_scl_i => '0',
gpsr_sda_i => '0'
);
-- Output registers (WB slave -> user design)
type t_sit5359_out_registers is record
cr_i2c_addr_o : std_logic_vector(7 downto 0);
cr_clk_div_o : std_logic_vector(7 downto 0);
cr_spll_en_o : std_logic;
cr_osc_oe_o : std_logic;
gpsr_scl_o : std_logic;
gpsr_scl_load_o : std_logic;
gpsr_sda_o : std_logic;
gpsr_sda_load_o : std_logic;
gpcr_scl_o : std_logic;
gpcr_sda_o : std_logic;
end record;
constant c_sit5359_out_registers_init_value: t_sit5359_out_registers := (
cr_i2c_addr_o => (others => '0'),
cr_clk_div_o => (others => '0'),
cr_spll_en_o => '0',
cr_osc_oe_o => '0',
gpsr_scl_o => '0',
gpsr_scl_load_o => '0',
gpsr_sda_o => '0',
gpsr_sda_load_o => '0',
gpcr_scl_o => '0',
gpcr_sda_o => '0'
);
function "or" (left, right: t_sit5359_in_registers) return t_sit5359_in_registers;
function f_x_to_zero (x:std_logic) return std_logic;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector;
end package;
package body sit5359_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if x = '1' then
return '1';
else
return '0';
end if;
end function;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector is
variable tmp: std_logic_vector(x'length-1 downto 0);
begin
for i in 0 to x'length-1 loop
if(x(i) = 'X' or x(i) = 'U') then
tmp(i):= '0';
else
tmp(i):=x(i);
end if;
end loop;
return tmp;
end function;
function "or" (left, right: t_sit5359_in_registers) return t_sit5359_in_registers is
variable tmp: t_sit5359_in_registers;
begin
tmp.gpsr_scl_i := f_x_to_zero(left.gpsr_scl_i) or f_x_to_zero(right.gpsr_scl_i);
tmp.gpsr_sda_i := f_x_to_zero(left.gpsr_sda_i) or f_x_to_zero(right.gpsr_sda_i);
return tmp;
end function;
end package body;
-------------------------------------------------------------------------------
-- Title : SiTime Sit5359 oscillator I2C controller
-- Project : White Rabbit
-------------------------------------------------------------------------------
-- File : wr_sit5359_interface.vhd
-- Author : Peter Jansweijer (inspired by Tomasz Wlostowski)
-- Company : Nikhef/CERN BE-Co-HT
-- Created : 2022-01-10
-- Last update: 2022-01-10
-- Platform : FPGA-generic
-- Standard : VHDL '93
-------------------------------------------------------------------------------
-- Description: SiTime Sit5359 MEMS- oscillator hardware interface for the WR
-- Core SoftPLL, allowing it to discipline Sit5359 oscillators to WR clock.
-- The core performs two tasks:
-- - allows the WR core to access I2C registers of attached Sit5359 oscillator
-- through bit-banging (e.g. to set base frequency)
-- - controls the Sit5359 PLL tuning in atomic (HW-only) way via tm_dac_value port.
-- The tuning value is added to pre-programmed RFREQ bias value set via
-- Wishbone.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2013 CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.sit5359_wbgen2_pkg.all;
entity wr_sit5359_interface is
generic (
g_simulation : integer := 0;
g_sys_clock_freq : integer := 62500000;
g_i2c_freq : integer := 400000
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- WR Core timing interface: aux clock tune port
tm_dac_value_i : in std_logic_vector(15 downto 0) := (others => '0');
tm_dac_value_wr_i : in std_logic := '0';
-- I2C bus: output enable (active low)
scl_pad_oen_o : out std_logic;
sda_pad_oen_o : out std_logic;
-- I2C bus: input pads
scl_pad_i : in std_logic;
sda_pad_i : in std_logic;
-- Wishbone
wb_adr_i : in std_logic_vector(c_wishbone_address_width-1 downto 0) := (others => '0');
wb_dat_i : in std_logic_vector(c_wishbone_data_width-1 downto 0) := (others => '0');
wb_dat_o : out std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_sel_i : in std_logic_vector(c_wishbone_address_width/8-1 downto 0) := (others => '0');
wb_we_i : in std_logic := '0';
wb_cyc_i : in std_logic := '0';
wb_stb_i : in std_logic := '0';
wb_ack_o : out std_logic;
wb_err_o : out std_logic;
wb_stall_o : out std_logic
);
end wr_sit5359_interface;
architecture rtl of wr_sit5359_interface is
component sit5359_if_wb
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(1 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
regs_i : in t_sit5359_in_registers;
regs_o : out t_sit5359_out_registers);
end component;
signal regs_in : t_sit5359_in_registers;
signal regs_out : t_sit5359_out_registers;
signal rfreq_new_p : std_logic;
signal rfreq_current, rfreq_new : unsigned(31 downto 0);
signal tm_dac_value_wr_d : std_logic;
signal tm_dac_value_wr_d1 : std_logic;
signal tm_dac_value : std_logic_vector(15 downto 0);
signal i2c_tick : std_logic;
signal i2c_divider : unsigned(7 downto 0);
signal scl_int : std_logic;
signal sda_int : std_logic;
signal seq_count : unsigned(8 downto 0);
type t_i2c_transaction is (START, STOP, SEND_BYTE);
type t_state is (IDLE, SI_START0, SI_ADDR0, SI_REG0, SI_RF0, SI_RF1, SI_RF2, SI_RF3, SI_STOP0);
signal state : t_state;
signal scl_out_host, scl_out_fsm : std_logic;
signal sda_out_host, sda_out_fsm : std_logic;
procedure f_i2c_iterate(tick : std_logic; signal counter : inout unsigned; value : std_logic_vector(7 downto 0); trans_type : t_i2c_transaction; signal scl : out std_logic; signal sda : out std_logic; signal state_var : out t_state; next_state : t_state) is
variable last : boolean;
begin
last := false;
if(tick = '0') then
return;
end if;
case trans_type is
when START =>
case counter(1 downto 0) is
-- states 0..2: start condition
when "00" =>
scl <= '1';
sda <= '1';
when "01" =>
sda <= '0';
when "10" =>
scl <= '0';
last := true;
when others => null;
end case;
when STOP =>
case counter(1 downto 0) is
-- states 0..2: start condition
when "00" =>
sda <= '0';
when "01" =>
scl <= '1';
when "10" =>
sda <= '1';
last := true;
when others => null;
end case;
when SEND_BYTE =>
case counter(1 downto 0) is
when "00" =>
sda <= value(7-to_integer(counter(4 downto 2)));
when "01" =>
scl <= '1';
when "10" =>
scl <= '0';
if(counter(5) = '1') then
last := true;
end if;
when others => null;
end case;
end case;
if(last) then
state_var <= next_state;
counter <= "000000000";
else
counter <= counter + 1;
end if;
end f_i2c_iterate;
function f_sign_extend( x : signed; l : integer ) return unsigned is
variable rv : unsigned(l-1 downto 0);
begin
rv ( x'length-1 downto 0) := unsigned(x);
rv( l-1 downto x'length ) := (others => x(x'length-1));
return rv;
end f_sign_extend;
begin -- rtl
U_WB_Slave : sit5359_if_wb
port map (
rst_n_i => rst_n_i,
clk_sys_i => clk_sys_i,
wb_adr_i => wb_adr_i(3 downto 2),
wb_dat_i => wb_dat_i,
wb_dat_o => wb_dat_o,
wb_cyc_i => wb_cyc_i,
wb_sel_i => wb_sel_i,
wb_stb_i => wb_stb_i,
wb_we_i => wb_we_i,
wb_ack_o => wb_ack_o,
wb_stall_o => wb_stall_o,
regs_i => regs_in,
regs_o => regs_out);
p_rfreq : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
rfreq_new_p <= '0';
rfreq_new <= (others => '0');
tm_dac_value_wr_d <= '0';
tm_dac_value_wr_d1 <= '0';
else
tm_dac_value_wr_d <= tm_dac_value_wr_i;
tm_dac_value_wr_d1 <= tm_dac_value_wr_d;
-- latch on rising edge tm_dac_value_wr_i
if(tm_dac_value_wr_i = '1' and tm_dac_value_wr_d = '0') then
tm_dac_value <= tm_dac_value_i;
end if;
-- next pipeline stage, create fromatted frequency tune word
if(tm_dac_value_wr_d = '1' and tm_dac_value_wr_d1 = '0') then
-- Sit5359 Freqency Control Word is 26 bits signed
-- Convert 16 bit unsigned DAC value to 17 bit signed and
-- shift DAC bits to MSB bits of 26 bit Freqency Control Word.
rfreq_new <= "00000" & regs_out.cr_osc_oe_o & unsigned((signed('0' & tm_dac_value(15 downto 0)) - to_signed(32768, 17)) & "000000000");
end if;
rfreq_new_p <= tm_dac_value_wr_d and not tm_dac_value_wr_d1 and regs_out.cr_spll_en_o;
end if;
end if;
end process;
p_i2c_divider : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
i2c_divider <= (others => '0');
i2c_tick <= '0';
else
if(i2c_divider = unsigned(regs_out.cr_clk_div_o)) then
i2c_tick <= '1';
i2c_divider <= (others => '0');
else
i2c_tick <= '0';
i2c_divider <= i2c_divider + 1;
end if;
end if;
end if;
end process;
p_i2c_fsm : process(clk_sys_i)
variable i2c_last : boolean;
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= IDLE;
seq_count <= (others => '0');
scl_out_fsm <= '1';
sda_out_fsm <= '1';
else
case state is
when IDLE =>
if(rfreq_new_p = '1') then
state <= SI_START0;
rfreq_current <= rfreq_new;
end if;
when SI_START0 =>
f_i2c_iterate(i2c_tick, seq_count, x"00", START, scl_out_fsm, sda_out_fsm, state, SI_ADDR0);
when SI_ADDR0 =>
f_i2c_iterate(i2c_tick, seq_count, regs_out.cr_i2c_addr_o, SEND_BYTE, scl_out_fsm, sda_out_fsm, state, SI_REG0);
when SI_REG0 =>
f_i2c_iterate(i2c_tick, seq_count, x"00", SEND_BYTE, scl_out_fsm, sda_out_fsm, state, SI_RF0);
when SI_RF0 =>
f_i2c_iterate(i2c_tick, seq_count, std_logic_vector(rfreq_current(15 downto 8)), SEND_BYTE, scl_out_fsm, sda_out_fsm, state, SI_RF1);
when SI_RF1 =>
f_i2c_iterate(i2c_tick, seq_count, std_logic_vector(rfreq_current(7 downto 0)), SEND_BYTE, scl_out_fsm, sda_out_fsm, state, SI_RF2);
when SI_RF2 =>
f_i2c_iterate(i2c_tick, seq_count, std_logic_vector(rfreq_current(31 downto 24)), SEND_BYTE, scl_out_fsm, sda_out_fsm, state, SI_RF3);
when SI_RF3 =>
f_i2c_iterate(i2c_tick, seq_count, std_logic_vector(rfreq_current(23 downto 16)), SEND_BYTE, scl_out_fsm, sda_out_fsm, state, SI_STOP0);
when SI_STOP0 =>
f_i2c_iterate(i2c_tick, seq_count, x"00", STOP, scl_out_fsm, sda_out_fsm, state, IDLE);
when others => null;
end case;
end if;
end if;
end process;
regs_in.gpsr_scl_i <= scl_pad_i;
regs_in.gpsr_sda_i <= sda_pad_i;
p_host_i2c : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if(rst_n_i = '0') then
scl_out_host <= '1';
sda_out_host <= '1';
else
if(regs_out.gpsr_scl_load_o = '1' and regs_out.gpsr_scl_o = '1') then
scl_out_host <= '1';
end if;
if(regs_out.gpsr_sda_load_o = '1' and regs_out.gpsr_sda_o = '1') then
sda_out_host <= '1';
end if;
if(regs_out.gpcr_scl_o = '1') then
scl_out_host <= '0';
end if;
if(regs_out.gpcr_sda_o = '1') then
sda_out_host <= '0';
end if;
end if;
end if;
end process;
p_mux_i2c : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if(state = IDLE) then
scl_pad_oen_o <= scl_out_host;
sda_pad_oen_o <= sda_out_host;
else
scl_pad_oen_o <= scl_out_fsm;
sda_pad_oen_o <= sda_out_fsm;
end if;
end if;
end process;
wb_err_o <= '0';
end rtl;
-------------------------------------------------------------------------------
-- Title : SiTime Sit5359 oscillator I2C controller
-- Project : White Rabbit
-------------------------------------------------------------------------------
-- File : xwr_sit5359_interface.vhd
-- Author : Peter Jansweijer (inspired by Tomasz Wlostowski)
-- Company : Nikhef/CERN BE-Co-HT
-- Created : 2022-01-10
-- Last update: 2022-01-10
-- Platform : FPGA-generic
-- Standard : VHDL '93
-------------------------------------------------------------------------------
-- Description: Wrapper for wr_sit5359_interface using Wishbone records in
-- entity interface. See wr_sit5359_interface.vhd for description.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2013 CERN
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.wishbone_pkg.all;
entity xwr_sit5359_interface is
generic (
g_simulation : integer := 0);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
tm_dac_value_i : in std_logic_vector(15 downto 0) := (others => '0');
tm_dac_value_wr_i : in std_logic := '0';
scl_pad_oen_o : out std_logic;
sda_pad_oen_o : out std_logic;
scl_pad_i : in std_logic;
sda_pad_i : in std_logic;
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out
);
end xwr_sit5359_interface;
architecture wrapper of xwr_sit5359_interface is
component wr_sit5359_interface
generic (
g_simulation : integer);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
tm_dac_value_i : in std_logic_vector(15 downto 0) := (others => '0');
tm_dac_value_wr_i : in std_logic := '0';
scl_pad_oen_o : out std_logic;
sda_pad_oen_o : out std_logic;
scl_pad_i : in std_logic;
sda_pad_i : in std_logic;
wb_adr_i : in std_logic_vector(c_wishbone_address_width-1 downto 0) := (others => '0');
wb_dat_i : in std_logic_vector(c_wishbone_data_width-1 downto 0) := (others => '0');
wb_dat_o : out std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_sel_i : in std_logic_vector(c_wishbone_address_width/8-1 downto 0) := (others => '0');
wb_we_i : in std_logic := '0';
wb_cyc_i : in std_logic := '0';
wb_stb_i : in std_logic := '0';
wb_ack_o : out std_logic;
wb_err_o : out std_logic;
wb_stall_o : out std_logic);
end component;
begin -- wrapper
U_Wrapped_sit5359 : wr_sit5359_interface
generic map (
g_simulation => g_simulation)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
tm_dac_value_i => tm_dac_value_i,
tm_dac_value_wr_i => tm_dac_value_wr_i,
scl_pad_oen_o => scl_pad_oen_o,
sda_pad_oen_o => sda_pad_oen_o,
scl_pad_i => scl_pad_i,
sda_pad_i => sda_pad_i,
wb_adr_i => slave_i.adr,
wb_dat_i => slave_i.dat,
wb_dat_o => slave_o.dat,
wb_sel_i => slave_i.sel,
wb_we_i => slave_i.we,
wb_cyc_i => slave_i.cyc,
wb_stb_i => slave_i.stb,
wb_ack_o => slave_o.ack,
wb_err_o => slave_o.err,
wb_stall_o => slave_o.stall);
end wrapper;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment