OpenCores
URL https://opencores.org/ocsvn/simpcon/simpcon/trunk

Subversion Repositories simpcon

[/] [simpcon/] [trunk/] [vhdl/] [sc_lego.vhd] - Rev 20

Go to most recent revision | Compare with Previous | Blame | View Log

--
--      sc_lego.vhd
--
--      Motor and sensor interface for LEGO MindStorms
--      
--      Original author: Martin Schoeberl       martin@jopdesign.com
--      Author: Peter Hilber                    peter.hilber@student.tuwien.ac.at
--
--      address map:
--		see read and write processes
--
--
--      2005-12-22      adapted for SimpCon interface
--      2007-03-13      extended for Lego PCB
--
--      todo:
--
--
 
 
--
--	lego io
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.lego_pld_pack.all;
use work.lego_pack.all;
 
entity sc_lego is
    generic (addr_bits : integer;
             clk_freq : integer);
 
    port (
        clk		: in std_logic;
        reset	: in std_logic;
 
        -- SimpCon interface
 
        address		: in std_logic_vector(addr_bits-1 downto 0);
        wr_data		: in std_logic_vector(31 downto 0);
        rd, wr		: in std_logic;
        rd_data		: out std_logic_vector(31 downto 0);
        rdy_cnt		: out unsigned(1 downto 0);
 
		-- speaker
 
		speaker : out std_logic;
 
        -- motor stuff
 
        m0en : out std_logic;
        m0dir : out std_logic;
        m0break : out std_logic;
        m0dia : in std_logic;
        m0doa : out std_logic;
        m0dib : in std_logic;
        m0dob : out std_logic;
 
        m1en : out std_logic;
        m1dir : out std_logic;
        m1break : out std_logic;
        m1dia : in std_logic;
        m1doa : out std_logic;
        m1dib : in std_logic;
        m1dob : out std_logic;
 
        m2en : out std_logic;
        m2dir : out std_logic;
        m2break : out std_logic;
 
        -- sensor stuff
 
        s0di : in std_logic;
        s0do : out std_logic;
        s0pi : out std_logic;
        s1di : in std_logic;
        s1do : out std_logic;
        s1pi : out std_logic;
        s2di : in std_logic;
        s2do : out std_logic;
        s2pi : out std_logic;
 
        mic1do : out std_logic;
        mic1 : in std_logic;
 
 
		-- pld
		pld_strobe 		: out std_logic;
		pld_data		: inout std_logic;
		pld_clk			: out std_logic
 
        );
end sc_lego;
 
architecture rtl of sc_lego is
    -- settings for components
    constant adc_width               : integer := 9;
 
    -- settings for motor
    constant motor_dout_width : integer := 9;    
    constant duty_cycle_width        : integer := 14;
 
    constant ld_ratio_measure_to_pwm : integer := 4;   -- ld(bit width time/bit width time spent measuring)
    constant clkint_prescaler_width  : integer := 18;	
    constant counter_width           : integer := clkint_prescaler_width + ld_ratio_measure_to_pwm + 1;
    constant clksd_prescaler_width   : integer := clkint_prescaler_width - motor_dout_width;
 
 
	constant audio_input_width : integer := 8;
 
 
	-- pld	
 
    signal pld_out_pins : FORWARDED_PINS;
    signal pld_in_pins  : FORWARDED_PINS;
 
	-- signals
 
	signal sensor0_dout: std_logic_vector(adc_width-1 downto 0);
	signal sensor1_dout: std_logic_vector(adc_width-1 downto 0);
	signal sensor2_dout: std_logic_vector(adc_width-1 downto 0);
 
	-- motors
 
    signal motor0_state: 		lego_motor_state;
    signal motor0_duty_cycle: 	unsigned(duty_cycle_width-1 downto 0);
    signal motor0_measure:      std_logic;
 
	signal motor0_dout1: 	std_logic_vector(motor_dout_width-1 downto 0);
	signal motor0_dout2: 	std_logic_vector(motor_dout_width-1 downto 0);
 
	signal motor1_state: 		lego_motor_state;
    signal motor1_duty_cycle: 	unsigned(duty_cycle_width-1 downto 0);
    signal motor1_measure:      std_logic;
 
	signal motor1_dout1: 	std_logic_vector(motor_dout_width-1 downto 0);
	signal motor1_dout2: 	std_logic_vector(motor_dout_width-1 downto 0);
 
	signal motor2_state: 		lego_motor_state;
    signal motor2_duty_cycle: 	unsigned(duty_cycle_width-1 downto 0);
    signal motor2_measure:      std_logic;
 
	signal motor1_buf_bemf: 	std_logic_vector(motor_dout_width*2-1 downto 0);
 
	-- microphone
 
	signal micro_dout:			std_logic_vector(adc_width-1 downto 0);
 
	signal cmp_micro_counter: unsigned(clkint_prescaler_width-1 downto 0);
	signal cmp_micro_clksd: std_logic;
	signal cmp_micro_clkint: std_logic;
 
	-- speaker
 
	signal audio_input:			std_logic_vector(audio_input_width-1 downto 0);
begin
 
    rdy_cnt <= "00";	-- no wait states
 
--
--	The registered MUX is all we need for a SimpCon read.
--	The read data is stored in registered rd_data.
--
    read: process(clk, reset)
    begin
 
        if (reset='1') then
            rd_data <= (others => '0');
        elsif rising_edge(clk) then
 
            if rd='1' then
				rd_data <= (others => '0');
                -- that's our very simple address decoder
                case address(3 downto 0) is
					-- sensors
					when "0000" => 
						rd_data(adc_width*3-1 downto 0) <= sensor2_dout & sensor1_dout & sensor0_dout;
					-- microphone
					when "0001" =>
						rd_data(adc_width-1 downto 0) <= micro_dout;
					-- motor 0 back-emf
					when "0010" =>
						rd_data(motor_dout_width*2-1 downto 0) <= motor0_dout2 & motor0_dout1;
					-- motor 1 back-emf
					when "0011" =>
						rd_data(motor_dout_width*2-1 downto 0) <= motor1_dout2 & motor1_dout1;
					-- buttons
					when "0100" =>
						rd_data(3 downto 0) <= pld_in_pins(btn3) & pld_in_pins(btn2) & pld_in_pins(btn1) & pld_in_pins(btn0);
					-- digital inputs
					when "0101" =>
						rd_data(2 downto 0) <= pld_in_pins(i2) & pld_in_pins(i1) & pld_in_pins(i0);
					-- for future use
					when "0110" =>
						rd_data(9 downto 0) <= pld_in_pins(unused9) & pld_in_pins(unused8) & pld_in_pins(unused7) & 
												pld_in_pins(unused6) & pld_in_pins(unused5) & pld_in_pins(unused4) & 
												pld_in_pins(unused3) & pld_in_pins(unused2) & pld_in_pins(unused1) & 
												pld_in_pins(unused0);
					-- pld raw input
					when "0111" =>
						rd_data(20 downto 0) <= pld_in_pins;
					-- motor 0 back-emf
					when "1000" =>
						rd_data(motor_dout_width*2-1 downto 0) <= motor0_dout2 & motor0_dout1;
						motor1_buf_bemf <= motor1_dout2 & motor1_dout1;
					-- motor 1 back-emf
					when "1001" =>
						rd_data(motor_dout_width*2-1 downto 0) <= motor1_buf_bemf;
                	when others => 
                end case;
            end if;
        end if;
 
    end process;
 
 
--
--	SimpCon write is very simple
--
    write: process(clk, reset)
 
    begin
 
        if (reset='1') then
			pld_out_pins <= (others => '0');
 
            motor0_state      <= LEGO_MOTOR_STATE_OFF;
            motor0_duty_cycle <= (others => '0');
            motor0_measure    <= '0';		
 
            motor1_state      <= LEGO_MOTOR_STATE_OFF;
            motor1_duty_cycle <= (others => '0');
            motor1_measure    <= '0';			
 
            motor2_state      <= LEGO_MOTOR_STATE_OFF;
            motor2_duty_cycle <= (others => '0');
			motor2_measure 	  <= '0';
 
        elsif rising_edge(clk) then
 
            if wr='1' then
 
				case address(2 downto 0) is
				    -- leds
					when "000" =>
						pld_out_pins(led0) <= wr_data(0);
						pld_out_pins(led1) <= wr_data(1);
						pld_out_pins(led2) <= wr_data(2);
						pld_out_pins(led3) <= wr_data(3);
					-- motor 0
					when "001" =>
						motor0_state <= lego_motor_state(wr_data(lego_motor_state'high downto 0));
						motor0_duty_cycle <= unsigned(wr_data(lego_motor_state'high+1+(duty_cycle_width-1) downto lego_motor_state'high+1));
						motor0_measure <= wr_data((duty_cycle_width-1)+lego_motor_state'high+2);
					-- motor 1
					when "010" =>
						motor1_state <= lego_motor_state(wr_data(lego_motor_state'high downto 0));
						motor1_duty_cycle <= unsigned(wr_data(lego_motor_state'high+1+(duty_cycle_width-1) downto lego_motor_state'high+1));
						motor1_measure <= wr_data((duty_cycle_width-1)+lego_motor_state'high+2);
					-- motor 2
					when "011" =>
						motor2_state <= lego_motor_state(wr_data(lego_motor_state'high downto 0));
						motor2_duty_cycle <= unsigned(wr_data(lego_motor_state'high+1+(duty_cycle_width-1) downto lego_motor_state'high+1));
						-- no actual back-emf measurement available
						motor2_measure <= wr_data((duty_cycle_width-1)+lego_motor_state'high+2);
					-- for future use
					when "110" =>
						pld_out_pins(unused9) <= wr_data(9);
						pld_out_pins(unused8) <= wr_data(8);
						pld_out_pins(unused7) <= wr_data(7);
						pld_out_pins(unused6) <= wr_data(6);
						pld_out_pins(unused5) <= wr_data(5);
						pld_out_pins(unused4) <= wr_data(4);
						pld_out_pins(unused3) <= wr_data(3);
						pld_out_pins(unused2) <= wr_data(2);
						pld_out_pins(unused1) <= wr_data(1);
						pld_out_pins(unused0) <= wr_data(0);
						pld_out_pins(10 downto 4) <= "0000000";
					when "111" =>
						audio_input <= wr_data(audio_input_width-1 downto 0);
					when others =>
						null;
				end case;
            end if;
 
        end if;
 
    end process;
 
 
    cmp_pld_interface: entity work.pld_interface
        port map(
            clk => clk,
            reset => reset,
            out_pins => pld_out_pins,
            in_pins => pld_in_pins,
            pld_strobe => pld_strobe,
            pld_clk => pld_clk,
            data => pld_data);
 
	cmp_sensor0: entity work.lesens generic map (
        clk_freq => clk_freq
        )
		port map(
			clk => clk,
        	reset => reset,
			dout => sensor0_dout,
			sp => s0pi,
        	sdi => s0di,
			sdo => s0do);
 
	cmp_sensor1: entity work.lesens generic map (
        clk_freq => clk_freq
        )
		port map(
			clk => clk,
        	reset => reset,
			dout => sensor1_dout,
			sp => s1pi,
        	sdi => s1di,
			sdo => s1do);
 
	cmp_sensor2: entity work.lesens generic map (
        clk_freq => clk_freq
        )
		port map(
			clk => clk,
        	reset => reset,
			dout => sensor2_dout,
			sp => s2pi,
        	sdi => s2di,
			sdo => s2do);
 
	cmp_motor0: entity work.lego_motor
        generic map (
            duty_cycle_width        => duty_cycle_width,
            counter_width           => counter_width,
            ld_ratio_measure_to_pwm => ld_ratio_measure_to_pwm,
            clksd_prescaler_width   => clksd_prescaler_width,
            clkint_prescaler_width  => clkint_prescaler_width,
            dout_width              => motor_dout_width)
        port map (
            clk                     => clk,
            reset                   => reset,
            state                   => motor0_state,
            duty_cycle              => motor0_duty_cycle,
            measure                 => motor0_measure,
            dout_1                  => motor0_dout1,
            dout_2					=> motor0_dout2,
            men                     => m0en,
			mdir					=> m0dir,
			mbreak					=> m0break,
            mdia                    => m0dia,
            mdoa                    => m0doa,
            mdib                    => m0dib,
            mdob                    => m0dob);
 
	cmp_motor1: entity work.lego_motor
        generic map (
            duty_cycle_width        => duty_cycle_width,
            counter_width           => counter_width,
            ld_ratio_measure_to_pwm => ld_ratio_measure_to_pwm,
            clksd_prescaler_width   => clksd_prescaler_width,
            clkint_prescaler_width  => clkint_prescaler_width,
            dout_width              => motor_dout_width)
        port map (
            clk                     => clk,
            reset                   => reset,
            state                   => motor1_state,
            duty_cycle              => motor1_duty_cycle,
            measure                 => motor1_measure,
            dout_1                  => motor1_dout1,
            dout_2					=> motor1_dout2,
            men                     => m1en,
			mdir					=> m1dir,
			mbreak					=> m1break,
            mdia                    => m1dia,
            mdoa                    => m1doa,
            mdib                    => m1dib,
            mdob                    => m1dob);
 
	-- no back-emf measurement available for this motor due to lack of pins :(
	cmp_motor2: entity work.lego_motor
        generic map (
            duty_cycle_width        => duty_cycle_width,
            counter_width           => counter_width,
            ld_ratio_measure_to_pwm => ld_ratio_measure_to_pwm,
            clksd_prescaler_width   => clksd_prescaler_width,
            clkint_prescaler_width  => clkint_prescaler_width,
            dout_width              => motor_dout_width)
        port map (
            clk                     => clk,
            reset                   => reset,
            state                   => motor2_state,
            duty_cycle              => motor2_duty_cycle,
            measure                 => motor2_measure,
            --dout_1                => motor2_dout1,
            --dout_2				=> motor2_dout2,
            men                     => m2en,
			mdir					=> m2dir,
			mbreak					=> m2break,
            mdia                  	=> '0',
            --mdoa                  => m2doa,
            mdib                  	=> '0'
            --mdob                  => m2dob
			);
 
	-- XXX
	cmp_micro_count: process(clk, reset)
  	begin
    	if reset = '1' then
      		cmp_micro_counter <= (others => '0');
    	elsif rising_edge(clk) then
      		cmp_micro_counter <= cmp_micro_counter + 1;
    	end if;
  	end process;
 
  	cmp_micro_clksd <= '1' when (cmp_micro_counter(clksd_prescaler_width-1 downto 0) = 0) else '0';
  	cmp_micro_clkint <= '1' when (cmp_micro_counter(clkint_prescaler_width-1 downto 0) = 0) else '0';	
 
	cmp_micro: entity work.sigma_delta
    generic map (
      dout_width => adc_width)
    port map (
      clk    => clk,
      reset  => reset,
      clksd  => cmp_micro_clksd,
      clkint => cmp_micro_clkint,
      dout   => micro_dout,
      sdi    => mic1,
      sdo    => mic1do);
 
	cmp_audio: entity work.audio
	generic map (
		input_width => audio_input_width)
	port map (
		clk => clk,
		reset => reset,
		input => audio_input,
		output => speaker);
 
end rtl;
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.