Beginning FPGA Programming - Partie67

Download as pdf or txt
Download as pdf or txt
You are on page 1of 5

Chapter 14 ■ How Fast Can You Run? Ask the Accelerometer!

data_clk <= '1';


end if;
else
spi_sclk <= cpol;
data_clk <= '0';
end if;
end if;
end process;

running_p : process (clk, reset_n)


begin
if (reset_n = '0') then
bit_count <= (others => '0');
running <= '0';
elsif(rising_edge(clk)) then
if(running = '1') then -- Clear when running
ena_dly <= '0';
elsif(ena = '1') then
ena_dly <= '1';
end if;
if(ena_dly = '1' and count = clk_div2-1) then -- wait for the right
-- start time
running <= '1';
else
if(bit_count = 8) then -- stop running after 8 bit send out
running <= '0';
end if;
end if;

if(running = '1' and count = clk_div2-1) then


if (bit_count < 8) then
bit_count <= bit_count + 1;
else
bit_count <= (others => '0');
end if;
else
if(bit_count = 8) then
bit_count <= (others => '0');
end if;
end if;
end if;
end process;

cs_p : process (clk, reset_n)


begin
if (reset_n = '0') then
spi_cs <= '1';
elsif(rising_edge(clk)) then
if(running = '0' and bit_count = 0 and last_byte = '1' and ena = '0' and ena_dly =
'0') then
spi_cs <= not cspol; -- chip select is not active after the
-- last byte send/receive

328
Chapter 14 ■ How Fast Can You Run? Ask the Accelerometer!

elsif(ena = '1') then --Chip select is active when start to


--send/ receive data
spi_cs <= cspol;
end if;
end if;
end process;

-----------------------------------------------------------------------------
-- Data sending out to the MOSI is using shift register
-----------------------------------------------------------------------------
data_out_p : process (clk, reset_n)
begin
if (reset_n = '0') then
reg_shift_out <= (others => '0');
elsif(rising_edge(clk)) then
if(ena = '1') then
reg_shift_out <= '0'& write_byte;
else
if(running = '1' and count = 0) then
reg_shift_out <= reg_shift_out(7 downto 0)& '0';
end if;
end if;
end if;

end process;

-------------------------------------------------------------------------------
-- Data receiving from SPI slave is shifted into shift register
-------------------------------------------------------------------------------
data_in_p : process (clk, reset_n)
begin
if (reset_n = '0') then
data_clk_dly <= '0';
reg_shift_in <= (others => '0');
elsif(rising_edge(clk)) then
data_clk_dly <= data_clk;
if(ena = '1') then
reg_shift_in <= (others => '0');
else
if(running = '1' and data_clk_dly = '0' and data_clk = '1') then
-- only shift when SPI clock is rising edge
reg_shift_in <= reg_shift_in(6 downto 0)& spi_miso;
end if;
end if;
end if;

end process;

spi_mosi <= reg_shift_out(8);


read_byte <= reg_shift_in;
done <= not running;

end rtl;
329
Chapter 14 ■ How Fast Can You Run? Ask the Accelerometer!

14.3.3.2 uartTOi2cspi.vhd code
This module is copied from Chapter 13's uartTOi2c.vhd file with modifications to support the SPI master. It
added some commands and status registers which are described in the section “Add New Command and Status
Registers.” This new updated uartTOi2cspi code in Listing 14-2 also includes the new spi_master.vhd file

Listing 14-2.  uartTOi2cspi.vhd vhdl


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity uartTOi2cspi is
port(
clk_uart_29MHz_i : in std_logic;
uart_rst_i : in std_logic;
uart_leds_o : out std_logic_vector(7 downto 0);
clk_uart_monitor_o : out std_logic;
------------UART TX & RX---------------------------
uart_dout_o : out std_logic;
uart_din_i : in std_logic;
-----------I2C interface---------------------------
i2c_scl : inout std_logic; -- serial clock
i2c_dat : inout std_logic; -- serial data
-----------SPI Master interface--------------------
spi_sclk : out std_logic;
spi_csn : out std_logic;
spi_mosi : out std_logic;
spi_miso : in std_logic;
spi_int1 : in std_logic;
spi_int2 : in std_logic
);
end uartTOi2cspi;

architecture rtl of uartTOi2cspi is


--
-- Internal signal declaration
--
signal s_rst : std_logic; -- main reset
signal s_clk_uart : std_logic; -- slow (29 MHz) clock

-- uart control signals


signal s_uart_br_clk : std_logic; -- unused clock monitor
signal s_uart_rx_add : std_logic_vector (15 downto 0);
signal s_uart_rx_data : std_logic_vector (31 downto 0);
signal s_uart_rx_rdy : std_logic;
signal s_uart_rx_stb_read_data : std_logic;
signal s_update : std_logic;
signal s_uart_tx_add : std_logic_vector (15 downto 0);
signal s_uart_tx_data : std_logic_vector (31 downto 0);
signal s_uart_tx_data_rdy : std_logic;
signal s_uart_tx_req : std_logic;

330
Chapter 14 ■ How Fast Can You Run? Ask the Accelerometer!

signal s_uart_tx_stb_acq : std_logic;


signal s_tx_complete : std_logic;

-- address decoder signals


signal r_config_addr_uart : std_logic_vector (1 downto 0);
signal r_leds : std_logic_vector (7 downto 0); -- 0x0000
signal reg01 : std_logic_vector (31 downto 0); -- 0x0010
signal reg02 : std_logic_vector (31 downto 0); -- 0x0001
signal reg_spi_control : std_logic_vector (31 downto 0); -- 0x0100
signal reg_spi_write : std_logic_vector (31 downto 0); -- 0x0101
signal reg_spi_read : std_logic_vector (31 downto 0); -- 0x0110
----------------------------------
-- singals for i2c Master block --
----------------------------------
signal s_rst_n : std_logic;
signal i2c_busy : std_logic;
signal i2c_busy_dly : std_logic;
signal i2c_busy_01 : std_logic; -- rising edge of i2c_busy
signal i2cByte1 : std_logic;
signal i2c_2bytes : std_logic;
signal data_wr : std_logic_vector(7 downto 0);
signal data_rd : std_logic_vector(7 downto 0);

----------------------------------
-- signals for SPI Master block --
----------------------------------
signal spi_done : std_logic;
signal spi_done_dly : std_logic;
signal spi_firstbyte : std_logic;
signal spi_read : std_logic_vector(7 downto 0);
--------------------------
-- State Machine states --
--------------------------
type t_tx_reg_map is (IDLE, WAIT_A_BYTE, LATCH, TRANSMIT);
signal s_tx_fsm : t_tx_reg_map;

begin

s_rst <= not uart_rst_i; -- Change to active high reset


s_rst_n <= uart_rst_i; -- active low reset

uart_leds_o <= not r_leds; -- Output LED with '1' mean on

s_clk_uart <= clk_uart_29MHz_i; -- UART system clock 29.4912 MHz


clk_uart_monitor_o <= s_uart_br_clk;

i2c_busy_01 <= i2c_busy and not i2c_busy_dly;


i2c_2bytes <= reg01(30); -- This i2c command has 2 bytes

-- Data write to the I2C Master depends on # of bytes operations


data_wr <= reg01(7 downto 0) when i2cByte1 = '0' else reg01(15 downto 8);

331
Chapter 14 ■ How Fast Can You Run? Ask the Accelerometer!

-- UART simple register map : UART to BeMicro MAX10


register_map : process (s_rst, s_clk_uart)
begin
if s_rst = '1' then -- reset all registers here
s_uart_rx_stb_read_data <= '0';
s_update <= '0';
r_leds <= (others => '0');
r_config_addr_uart <= "10";
reg01 <= (others => '0');
i2c_busy_dly <= '0';
i2cByte1 <= '0';
reg_spi_control <= x"00000040";
reg_spi_write <= (others => '0');
elsif rising_edge(s_clk_uart) then
r_leds(1) <= spi_int2;
r_leds(0) <= spi_int1; -- LED0 will up when the motion detected

i2c_busy_dly <= i2c_busy;


if s_uart_rx_rdy = '1' then
case (s_uart_rx_add) is
-- Address 0x00 0x00 -- Removed the lower two bit for spi int
when X"0000" => r_leds(7 downto 2) <= s_uart_rx_data(7 downto 2);
-- Address 0x00 0x10
when X"0010" => reg01 <= s_uart_rx_data;
-- Address 0x00 0x100
when X"0100" => reg_spi_control <= s_uart_rx_data;
-- Address 0x00 0x101
when X"0101" => reg_spi_write <= s_uart_rx_data;
-- Address 0x80 0x00
when X"8000" => s_update <= '1'; -- register update self clearing
when others => null;
end case;
s_uart_rx_stb_read_data <= '1';
else
s_uart_rx_stb_read_data <= '0';
s_update <= '0'; -- register update self clearing
-- Last byte send out to the i2C Master, then clean up data bits
if(i2c_busy_01 = '1' and i2cByte1 = '0' and i2c_2bytes = '0') then
reg01(29 downto 0) <= (others => '0');
end if;
-- After send the command to the I2C Master, then clean up command bits
if(i2c_busy_01 = '1' and (i2cByte1 = i2c_2bytes)) then -- 11 or 00 condition
reg01(31 downto 30) <= (others => '0');
end if;

if (s_uart_rx_stb_read_data = '1') then


i2cByte1 <= '0'; -- reset the condition after UART read request
elsif(i2c_2bytes = '1' and i2c_busy_01 = '1') then
-- Toggle every time i2C_busy change from low to high and two bytes operations
i2cByte1 <= not i2cByte1;
end if;

332

You might also like