library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.MATH_REAL.ALL; -- -- Copyright (C) 2009, Peter C. Wallace, Mesa Electronics -- Copyright (C) 2020, Curtis E Dutton, Dutton Industrial -- http://www.mesanet.com -- -- This program is is licensed under a disjunctive dual license giving you -- the choice of one of the two following sets of free software/open source -- licensing terms: -- -- * GNU General Public License (GPL), version 2.0 or later -- * 3-clause BSD License -- -- -- The GNU GPL License: -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program 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 General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- -- -- The 3-clause BSD License: -- -- 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. -- -- * Neither the name of Mesa Electronics nor the names of its -- contributors may be used to endorse or promote products -- derived from this software without specific prior written -- permission. -- -- -- Disclaimer: -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- "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 THE -- COPYRIGHT OWNER OR CONTRIBUTORS 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. -- --from idromconst --sanmotionenc - Interfaces with Sanyo Denki encoders -- constant sanmotionencControlAddr : std_logic_vector(7 downto 0) := x"E0"; -- constant sanmotionencRx0Addr : std_logic_vector(7 downto 0) := X"E1"; -- constant sanmotionencRx1Addr : std_logic_vector(7 downto 0) := X"E2"; -- constant sanmotionencStatusAddr : std_logic_vector(7 downto 0) := X"E3"; -- constant sanmotionencNumRegs : std_logic_vector(7 downto 0) := x"04"; -- constant sanmotionencMPBitMask : std_logic_vector(31 downto 0) := x"0000001F"; -- constant sanmotionencTag : std_logic_vector(7 downto 0) := x"1F"; -- constant sanmotionencTxdataPin : std_logic_vector(7 downto 0) := x"81"; -- constant sanmotionencRxdataPin : std_logic_vector(7 downto 0) := x"02"; -- constant sanmotionencTxenPin : std_logic_vector(7 downto 0) := x"83"; Is this correct, or 82? --from idromtools -- if(tag = sanmotionencTag) then return "sanmotionenc"; end if; -- elsif(tag = sanmotionencTag) then --if(pin = sanmotionencTxdataPin) then return "Sanmotion Encoder Txdata"; --elsif(pin = sanmotionencRxdataPin) then return "Sanmotion Encoder Rxdata"; --elsif(pin = sanmotionencTxenPin) then return "Sanmotion Encoder Tx Enable"; --The sanmotionenc component transmits --16bit of data then listens for a response of three frames (16bit) from a Sanyo Denki encoders --Half-duplex serial communication, NRZ code, asynchronous --Command data, 1-frame, 18bits/ frame, 3bit CRC --Encoder data, 1-frame, 3-4 fields/frame, 18bits/ field, 8bit CRC, position data binary ST17bit, MT16bit entity sanmotionenc is generic ( buswidth : integer ); Port ( clkmed : in std_logic; clklow : in std_logic; ibus : in std_logic_vector(buswidth-1 downto 0); --host bus data in obus : out std_logic_vector(buswidth-1 downto 0); --host bus data outa timers : in std_logic_vector(4 downto 0); --dpll timers bus_load_control : in std_logic; --load transmit from control register bus_store_rx0 : in std_logic; bus_store_rx1 : in std_logic; --bus_store_rx2 : in std_logic; --not needed with ST-request bus_store_status : in std_logic; txdata : out std_logic; --transmit data txen : out std_logic; --transmit enable rxdata : in std_logic --receive data ); end sanmotionenc; architecture Behavioral of sanmotionenc is constant bitrate : std_logic_vector(7 downto 0) := x"14"; --50MHz/2.5Mbps = 20 signal enable : std_logic; --when true transmit cycle is enabled signal transmitting : std_logic; --controls transmit recieve cycle signal transmit : std_logic; --start a transmit cycle signal transmit_prev : std_logic; signal rx_ok : std_logic; signal busy : std_logic; signal rx_clk : std_logic; signal rx_bit : std_logic; signal rx_timer : std_logic_vector(17 downto 0); signal any_data_received : std_logic; --number of bits receive signal rx_data : std_logic; signal rx_data_prev : std_logic; signal rx_count : std_logic_vector(7 downto 0); --number of bits to receive signal rx_register : std_logic_vector(53 downto 0); --RX register size 3*18bits=54 --number of bits to send signal tx_data : std_logic_vector(17 downto 0); signal tx_count : std_logic_vector(5 downto 0); --number of bits to transmit, 010010= 18bits signal tx_en_counter : std_logic_vector(7 downto 0); --used to time enable signal setup signal tx_interval_counter : std_logic_vector(7 downto 0); --counts from N to 0. Used to control bit rate output signal timer_enable : std_logic; signal timer_sel : std_logic_vector(2 downto 0); signal timer : std_logic; signal timer_prev : std_logic; --(val >> 1) function one_half(val : in std_logic_vector(7 downto 0)) return std_logic_vector is begin return ('0' & val(7 downto 1)); end function; --(val >> 1) + val function three_half(val : in std_logic_vector(7 downto 0)) return std_logic_vector is begin return ('0' & val(7 downto 1)) + val; end function; --(val >> 1) + (val << 1) function five_half(val : in std_logic_vector(7 downto 0)) return std_logic_vector is begin return ('0' & val(7 downto 1)) + (val(6 downto 0) & '0'); end function; begin mantrx : process(clkmed) begin if rising_edge(clkmed) then timer_prev <= timer; transmit_prev <= transmit; case timer_sel is when "000" => timer <= timers(0); when "001" => timer <= timers(1); when "010" => timer <= timers(2); when "011" => timer <= timers(3); when "100" => timer <= timers(4); when others => timer <= timers(0); end case; end if; end process; --copies data into rx_register rx_sanmotion : process(clkmed) begin if rising_edge(clkmed) then rx_data_prev <= rx_data; rx_data <= rxdata; if transmitting = '1' then --reset receive data rx_timer <= (others=>'0'); rx_clk <= '0'; rx_bit <= '0'; busy <= '1'; else if rx_data /= rx_data_prev then rx_timer <= (others=>'0'); if rx_timer > one_half(bitrate) then if rx_timer < three_half(bitrate) then rx_clk <= '1'; rx_bit <= rx_data; else if rx_timer < five_half(bitrate) then rx_clk <= '1'; rx_bit <= rx_data; else rx_clk <= '0'; rx_timer <= rx_timer + 1; end if; end if; else if rx_timer = five_half(bitrate) then --after no more data comes in tack on an additional 0 bit rx_clk <= '1'; rx_bit <= '0'; busy <= '0'; rx_timer <= rx_timer + 1; else rx_clk <= '0'; rx_timer <= rx_timer + 1; end if; end if; else rx_clk <= '0'; rx_timer <= rx_timer + 1; end if; end if; end if; end process; --transmits data over tx tx_sanmotion : process(clkmed) begin if rising_edge(clkmed) then if enable = '1' and ((transmit /= transmit_prev) or (timer_enable = '1' and timer_prev = '0' and timer = '1')) then transmitting <= '1'; end if; if transmitting = '0' then --during receive we can prepare for a tx tx_en_counter <= (others=>'0'); tx_interval_counter <= (others=>'0'); tx_data <= "001000000100000011"; -- 18 bits to transmit tx_count <= "010010"; txen <= '0'; else --assert txenable txen <= '1'; --transmits data in tx_data register --transmits from LSB to MSB if tx_count /= 0 then if tx_en_counter < bitrate then --make sure that txen is asserted --prior to sending data tx_en_counter <= tx_en_counter + 1; else -- transmit LSB first txdata <= tx_data(tx_data'RIGHT); tx_data <= '0' & tx_data(tx_data'LEFT-1 downto 0); tx_count <= tx_count - 1; tx_interval_counter <= bitrate; end if; else if tx_en_counter /= 0 then --make sure txen is asserted for one bitperiod --after data is sent tx_en_counter <= tx_en_counter - 1; else transmitting <= '0'; end if; end if; end if; end if; end process; load : process(clklow) begin if rising_edge(clklow) then if bus_load_control = '1' then enable <= ibus(0); transmit <= ibus(1); timer_enable <= ibus(2); timer_sel <= ibus(10 downto 8); end if; end if; end process; store : process(clklow) begin if falling_edge(clklow) then obus<= (others=>'Z'); if bus_store_rx0 = '1' then obus <= rx_register(rx_register'LEFT downto rx_register'LEFT-31); end if; if bus_store_rx1 = '1' then obus <= rx_register(rx_register'LEFT-32 downto rx_register'LEFT-53); end if; -- if bus_store_rx2 = '1' then -- obus <= rx_register(rx_register'LEFT-64 downto rx_register'LEFT-95); -- end if; if bus_store_status = '1' then obus <= (0=>enable, 1=>transmit, 2=>timer_enable, 3=>rx_ok, 4=>busy, 5=>any_data_received, others =>'0'); obus(10 downto 8) <= timer_sel; obus(31 downto 16) <= (others =>'0'); end if; end if; end process; end Behavioral;