URL
https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk
Subversion Repositories open8_urisc
[/] [open8_urisc/] [trunk/] [VHDL/] [adc128s022.vhd] - Rev 329
Go to most recent revision | Compare with Previous | Blame | View Log
-- Copyright (c)2023 Jeremy Seth Henry -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- * Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- * Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution, -- where applicable (as part of a user interface, debugging port, etc.) -- -- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY -- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- -- VHDL units : adc12s022 -- Description: Provides higher-level control of a single ADC128S022 12-bit ADC -- Note that the base part has a maximum Fsclk of 3.2MHz. Note that to simplify -- downstream logic, the data is expanded to a 16-bit bus. -- -- Revision History -- Author Date Change ------------------ -------- --------------------------------------------------- -- Seth Henry 05/18/23 Initial Upload library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; use ieee.std_logic_misc.all; entity adc12s022 is generic( Clock_Frequency : real; Reset_Level : std_logic := '1' ); port( Clock : in std_logic; Reset : in std_logic; -- Reinit : in std_logic := '0'; -- Optional sync reset -- RAW_Channel : out std_logic_vector(2 downto 0); RAW_Data : out std_logic_vector(15 downto 0); RAW_Valid : out std_logic; -- Busy_In : in std_logic; -- SDO : in std_logic; SDI : out std_logic; SCLK : out std_logic; CSn : out std_logic ); end entity; architecture behave of adc12s022 is -- The ceil_log2 function returns the minimum register width required to -- hold the supplied integer. function ceil_log2 (x : in natural) return natural is variable retval : natural; begin retval := 1; while ((2**retval) - 1) < x loop retval := retval + 1; end loop; return retval; end function; -- Per the datasheet, the _022 part has a Fsmax of 3.2MHz, which results in -- a maximum single-channel conversion rate of 200ksps, or maximum -- multiplexed rate of 25ksps. constant ADS128S022_FSCLK : real := 3200000.0; constant Clock_Ratio : real := ((Clock_Frequency + (0.5*ADS128S022_FSCLK)) / ADS128S022_FSCLK); constant Half_Period_Clks : integer := integer(Clock_Ratio * 0.5); type ADC_STATES is ( INIT, IDLE, REQ_SP, SP_WAIT, INC_CH ); signal ADC_State : ADC_STATES := INIT; signal Channel : std_logic_vector(2 downto 0) := "000"; signal Conv_Start : std_logic := '0'; signal Data_Out : std_logic_vector(11 downto 0) := (others => '0'); signal Valid : std_logic := '0'; constant Clk_Div_i : integer := Half_Period_Clks - 1; constant Clk_Div_Bits : integer := ceil_log2(Clk_Div_i); constant CLK_DIV_VAL : std_logic_vector(Clk_Div_Bits - 1 downto 0) := conv_std_logic_vector(Clk_Div_i,Clk_Div_Bits); signal HT_Cntr : std_logic_vector(Clk_Div_Bits - 1 downto 0); signal HT_Tick : std_logic := '0'; type SPI_STATES is ( IDLE, ALIGN, CSn_START, CLK_SETUP, CLK_HOLD, CSn_END ); signal spi_state : SPI_STATES; signal spi_wr_buffer : std_logic_vector(15 downto 0) := x"0000"; signal spi_rd_buffer : std_logic_vector(15 downto 0) := x"0000"; signal bit_cntr : std_logic_vector(3 downto 0) := x"0"; begin ADC_Control_FSM_proc: process( Clock, Reset ) begin if( Reset = Reset_Level )then ADC_State <= INIT; Channel <= (others => '0'); Conv_Start <= '0'; RAW_Channel <= (others => '0'); RAW_Data <= (others => '0'); RAW_Valid <= '0'; elsif( rising_edge(Clock) )then Conv_Start <= '0'; RAW_Channel <= (others => '0'); RAW_Data <= (others => '0'); RAW_Valid <= '0'; case ADC_State is when INIT => Channel <= (others => '0'); ADC_State <= IDLE; when IDLE => if( Reinit = '1' )then ADC_State <= INIT; elsif( Busy_In = '0' )then ADC_State <= REQ_SP; end if; when REQ_SP => Conv_Start <= '1'; ADC_State <= SP_WAIT; when SP_WAIT => if( Valid = '1' )then RAW_Channel <= Channel - 1; RAW_Data <= "0000" & Data_Out; RAW_Valid <= '1'; ADC_State <= INC_CH; end if; when INC_CH => Channel <= Channel + 1; ADC_State <= IDLE; when others => null; end case; end if; end process; SPI_IO_FSM: process( Clock, Reset ) begin if( Reset = Reset_Level )then spi_state <= IDLE; spi_wr_buffer <= (others => '0'); spi_rd_buffer <= (others => '0'); bit_cntr <= (others => '0'); HT_Cntr <= (others => '0'); HT_Tick <= '0'; SDI <= '0'; SCLK <= '0'; CSn <= '1'; Data_Out <= (others => '0'); Valid <= '0'; elsif( rising_edge(Clock) )then HT_Cntr <= HT_Cntr - 1; HT_Tick <= '0'; if( HT_Cntr = 0 )then HT_Cntr <= CLK_DIV_VAL; HT_Tick <= '1'; end if; SCLK <= '1'; SDI <= '1'; Valid <= '0'; case( spi_state )is when IDLE => CSn <= '1'; bit_cntr <= x"F"; if( Conv_Start = '1' )then spi_wr_buffer <= "00" & Channel & "00000000000"; spi_state <= ALIGN; end if; when ALIGN => if( HT_Tick = '1' )then spi_state <= CSn_START; end if; when CSn_START => CSn <= '0'; if( HT_Tick = '1' )then spi_state <= CLK_SETUP; end if; when CLK_SETUP => SCLK <= '0'; SDI <= spi_wr_buffer(conv_integer(bit_cntr)); CSn <= '0'; if( HT_Tick = '1' )then spi_rd_buffer <= spi_rd_buffer(14 downto 0) & SDO; spi_state <= CLK_HOLD; end if; when CLK_HOLD => SDI <= spi_wr_buffer(conv_integer(bit_cntr)); if( HT_Tick = '1' )then bit_cntr <= bit_cntr - 1; spi_state <= CLK_SETUP; if( bit_cntr = 0 )then spi_state <= CSn_END; end if; end if; when CSn_END => if( HT_Tick = '1' )then Data_Out <= spi_rd_buffer(11 downto 0); Valid <= '1'; spi_state <= IDLE; end if; when others => null; end case; end if; end process; end architecture;
Go to most recent revision | Compare with Previous | Blame | View Log