use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
+library unisim;
+use unisim.vcomponents.all;
+
--------------------------------------------------------------------------------
entity msp_motion is
architecture rtl of msp_motion is
+ signal reset_p : std_logic;
+
+ ------------------------------------------------------------------------------
-- OpenMSP430 softcore MCU module
- signal mclk : std_logic;
- signal puc : std_logic;
+ ------------------------------------------------------------------------------
+ signal mclk : std_logic;
+ signal puc : std_logic;
+ -- External data bus
+ signal dmem_addr : std_logic_vector (11 downto 0);
+ signal dmem_ce : std_logic;
+ signal dmem_we : std_logic;
+ signal dmem_din : std_logic_vector (15 downto 0);
+ signal dmem_dout : std_logic_vector (15 downto 0);
+ -- Peripheral bus
+ signal per_din : std_logic_vector (15 downto 0);
+ signal per_dout : std_logic_Vector (15 downto 0);
+ signal per_wen : std_logic_vector (1 downto 0);
+ signal per_wen16 : std_logic;
+ signal per_en : std_logic;
+ signal per_addr : std_logic_vector (7 downto 0);
+ -- Interrupt
+ --signal irq : std_logic_vector (13 downto 0) := (others => '0');
+ signal irq : std_logic_vector (13 downto 0);
+ signal irq_acc : std_logic_vector (13 downto 0);
+
+ ------------------------------------------------------------------------------
+ -- MCU peripherals
+ ------------------------------------------------------------------------------
+ -- GPIO
+ signal GPIO_IN : std_logic_vector (15 downto 0);
+ signal GPIO_OUT : std_logic_vector (15 downto 0);
+ signal GPIO_DAT_O : std_logic_vector (15 downto 0);
+ signal GPIO_SEL : std_logic;
+ -- Qcounter MCU interface
+ signal QCNT_DAT_O : std_logic_vector (15 downto 0);
+ signal QCNT_SEL : std_logic;
+ -- Motor feedback IRQ generator
+ signal MOTOR_IRQ : std_logic;
+
+ ------------------------------------------------------------------------------
+ -- Dual-port shared memory
+ ------------------------------------------------------------------------------
+ -- These signals of A-port (MCU) enables creation of external data encoder and
+ -- multiplexer in a case of multiple devices connected to the external data
+ -- bus. Otherwise useless.
+ signal DPA_DAT_O : std_logic_vector (15 downto 0);
+ signal DPA_SEL : std_logic;
+ signal DPA_STB : std_logic;
+ -- Auxiliary register used to generate IRF_ACK
+ signal IRF_ACK_REG : std_logic := '0';
+ -- Auxiliary signal used to form B-port address
+ signal DPB_ADR : std_logic_vector (9 downto 0);
+
+ ------------------------------------------------------------------------------
+ -- Motion Control Chain
+ ------------------------------------------------------------------------------
+ -- Constants
+ constant PWM_W : integer := 10;
+ constant LUT_ADR_W : integer := 11;
+ constant LUT_INIT : string := "sin1000.lut";
+
+ -- Bus interface to the shared memory
+ signal IRF_ACK : std_logic;
+ signal IRF_ADR : std_logic_vector (4 downto 0);
+ signal IRF_DAT_I : std_logic_vector (15 downto 0);
+ signal IRF_DAT_O : std_logic_vector (15 downto 0);
+ signal IRF_STB : std_logic;
+ signal IRF_WE : std_logic;
+ -- Wave look-up table
+ signal LUT_ADR : std_logic_vector (LUT_ADR_W-1 downto 0);
+ signal LUT_DAT_O : std_logic_vector (PWM_W-1 downto 0);
+ signal LUT_STB : std_logic;
+ -- MCC execution control
+ signal MCC_ACK : std_logic;
+ signal MCC_STB : std_logic;
+
+ ------------------------------------------------------------------------------
+ -- PWM and IRC
+ ------------------------------------------------------------------------------
+ signal PWM_CNT : std_logic_vector (PWM_W-1 downto 0);
+ signal PWM_OW : std_logic; -- PWM counter overflow
+ -- PWM interface to the MCC
+ signal PWM_DAT : std_logic_vector (PWM_W-1 downto 0);
+ signal PWM1_STB : std_logic;
+ signal PWM2_STB : std_logic;
+ signal PWM3_STB : std_logic;
+ -- PWM outputs
+ signal PWM1_OUT : std_logic;
+ signal PWM2_OUT : std_logic;
+ signal PWM3_OUT : std_logic;
+ -- IRC value
+ signal QCNT : std_logic_vector (31 downto 0);
--------------------------------------------------------------------------------
port map (
dco_clk => CLK_24MHz,
lfxt_clk => '0',
- reset_n => RESET,
+ reset_n => '1',
rxd => RXD,
txd => TXD,
- per_addr => open,
- per_din => open,
- per_dout => (others => '0'),
- per_wen => open,
- per_en => open,
+ per_addr => per_addr,
+ per_din => per_din,
+ per_dout => per_dout,
+ per_wen => per_wen,
+ per_en => per_en,
nmi => '0',
- irq => (others => '0'),
- irq_acc => open,
+ irq => irq,
+ irq_acc => irq_acc,
aclk_en => open,
smclk_en => open,
mclk => mclk,
- puc => puc,
- dmem_addr => open,
- dmem_ce => open,
- dmem_we => open,
- dmem_din => open,
- dmem_dout => (others => '0'));
+ puc => open,
+ dmem_addr => dmem_addr,
+ dmem_ce => dmem_ce,
+ dmem_we => dmem_we,
+ dmem_din => dmem_din,
+ dmem_dout => dmem_dout);
+
+ puc <= '0';
+ reset_p <= not RESET;
+
+ STARTUP_VIRTEX2_inst : STARTUP_VIRTEX2
+ port map (
+ CLK => open,
+ -- Clock input for start-up sequence
+ GSR => reset_p, -- Global Set/Reset input (GSR cannot be used for the port name)
+ GTS => open); -- Global 3-state input (GTS cannot be used for the port name)
+
+
+ -- External data bus address decoder and data multiplexer.
+ ------------------------------------------------------------------------------
+ -- When connection more memories, be aware that 'dmem_dout' can vary only when
+ -- reading cycle is performed. I.e. mux variable must be registered.
+ dmem_dout <= DPA_DAT_O;
+
+ DPA_SEL <= '1' when dmem_addr (11 downto 10) = "00" else '0';
+ DPA_STB <= dmem_ce and DPA_SEL;
+
+ -- Peripheral bus address decoder and data multiplexer.
+ ------------------------------------------------------------------------------
+ per_dout <= GPIO_DAT_O when GPIO_SEL = '1' else
+ QCNT_DAT_O when QCNT_SEL = '1' else
+ (others => '0'); -- MUST be 0 when nothing is addressed
+
+ GPIO_SEL <= '1' when per_addr(7 downto 2) = 16#0140#/2/4 else '0';
+ QCNT_SEL <= '1' when per_addr(7 downto 1) = 16#0148#/2/2 else '0';
+
+ -- Interrupt signals
+ ------------------------------------------------------------------------------
+ irq (13 downto 1) <= (others => '0');
+
+ motor_irq_ff : process (mclk, puc) is
+ begin
+ if rising_edge (mclk) then
+ if puc = '1' or irq_acc (0) = '1' then
+ irq (0) <= '0';
+ elsif MOTOR_IRQ = '1' then
+ irq (0) <= '1';
+ end if;
+ end if;
+ end process;
+
+
+ ------------------------------------------------------------------------------
+ -- MCU peripherals
+ ------------------------------------------------------------------------------
+ GPIO_IN(0) <= HAL0;
+ GPIO_IN(1) <= HAL1;
+ GPIO_IN(2) <= HAL2;
+ GPIO_IN(3) <= IRC_INDEX;
+
+ gpio_0 : entity work.gpio
+ generic map (
+ W => 16)
+ port map (
+ ACK_O => open,
+ ADR_I => per_addr (1 downto 0),
+ CLK_I => mclk,
+ DAT_I => per_din,
+ DAT_O => GPIO_DAT_O,
+ RST_I => puc,
+ SEL_I => GPIO_SEL,
+ STB_I => per_en,
+ WE_I => per_wen16,
+ GPIO_I => GPIO_IN,
+ GPIO_O => GPIO_OUT);
+
+ qcounter_mcu16_0 : entity work.qcounter_mcu16
+ port map (
+ ACK_O => open,
+ ADR_I => per_addr (0),
+ CLK_I => mclk,
+ DAT_O => QCNT_DAT_O,
+ SEL_I => QCNT_SEL,
+ STB_I => per_en,
+ QCOUNT => QCNT);
+
+ -- Motor feedback IRQ generator
+ -- f_motor_irq approx. 1 kHz
+ mcc_irq_counter_1 : entity work.counter
+ generic map (
+ WIDTH => 5,
+ MAX => 22)
+ port map (
+ clk => mclk,
+ clk_en => PWM_OW,
+ reset => puc,
+ count => open,
+ event_ow => MOTOR_IRQ);
+
+
+ ------------------------------------------------------------------------------
+ -- Dual-port shared memory
+ ------------------------------------------------------------------------------
+ -- Shared memory between MCU and MCC (size: 16+2 bits x 1k).
+ -- Port A (MCU side) has a priority of writing.
+ shared_mem : RAMB16_S18_S18
+ generic map (
+ WRITE_MODE_A => "READ_FIRST",
+ WRITE_MODE_B => "WRITE_FIRST")
+ port map (
+ -- A-Port (MCU)
+ ADDRA => dmem_addr (9 downto 0),
+ CLKA => mclk,
+ DIA => dmem_din,
+ DIPA => "00",
+ DOA => DPA_DAT_O,
+ DOPA => open,
+ ENA => DPA_STB,
+ SSRA => '0',
+ WEA => dmem_we,
+ -- B-Port (MCC)
+ ADDRB => DPB_ADR,
+ CLKB => mclk,
+ DIB => IRF_DAT_I,
+ DIPB => "00",
+ DOB => IRF_DAT_O,
+ DOPB => open,
+ ENB => IRF_STB,
+ SSRB => '0',
+ WEB => IRF_WE);
+
+ -- B-Port address (10 bits) constructed from IRF_ADR (5 bits). Upper addr bits
+ -- are forced to '0', but in a case of several axes these can be used to
+ -- address memory space of the appropriate one.
+ DPB_ADR (9 downto 5) <= (others => '0');
+ DPB_ADR (4 downto 0) <= IRF_ADR;
+
+ -- Generation of IRF acknowledge signal for MCC.
+ IRF_ACK <= IRF_STB and (IRF_WE or IRF_ACK_REG);
+
+ -- IRF_ACK_REG signalizes that data is present on IRF_DAT_O when reading.
+ irf_read : process (mclk, puc) is
+ begin
+ if rising_edge(mclk) then
+ if puc = '1' then
+ IRF_ACK_REG <= '0';
+ else
+ IRF_ACK_REG <= IRF_STB and not IRF_WE;
+ end if;
+ end if;
+ end process;
+
+
+ ------------------------------------------------------------------------------
+ -- Motion Control Chain
+ ------------------------------------------------------------------------------
+ mcc_exec_1 : entity work.mcc_exec
+ port map (
+ CLK_I => mclk,
+ RST_I => puc,
+ MCC_EN_I => '1',
+ MCC_EXEC_I => PWM_OW,
+ MCC_ERR_O => open,
+ MCC_ACK_I => MCC_ACK,
+ MCC_STB_O => MCC_STB);
+
+ mcc_1 : entity work.mcc
+ generic map (
+ LUT_DAT_W => PWM_W,
+ LUT_ADR_W => LUT_ADR_W)
+ port map (
+ ACK_O => MCC_ACK,
+ CLK_I => mclk,
+ RST_I => puc,
+ STB_I => MCC_STB,
+ LUT_STB_O => LUT_STB,
+ LUT_ADR_O => LUT_ADR,
+ LUT_DAT_I => LUT_DAT_O,
+ IRC_DAT_I => QCNT (15 downto 0),
+ PWM_DAT_O => PWM_DAT,
+ PWM1_STB_O => PWM1_STB,
+ PWM2_STB_O => PWM2_STB,
+ PWM3_STB_O => PWM3_STB,
+ IRF_ACK_I => IRF_ACK,
+ IRF_ADR_O => IRF_ADR,
+ IRF_DAT_I => IRF_DAT_O,
+ IRF_DAT_O => IRF_DAT_I,
+ IRF_STB_O => IRF_STB,
+ IRF_WE_O => IRF_WE);
+
+ wave_table_1 : entity work.wave_table
+ generic map (
+ DAT_W => PWM_W,
+ ADR_W => LUT_ADR_W,
+ INIT_FILE => LUT_INIT)
+ port map (
+ ACK_O => open,
+ ADR_I => LUT_ADR,
+ CLK_I => mclk,
+ DAT_I => conv_std_logic_vector(0, PWM_W),
+ DAT_O => LUT_DAT_O,
+ STB_I => LUT_STB,
+ WE_I => '0');
+
+
+ ------------------------------------------------------------------------------
+ -- PWM and IRC
+ ------------------------------------------------------------------------------
+ -- PWM counter is shared by all PWM generators. Generator contains only
+ -- comparator and desired value.
+ counter_1 : entity work.counter
+ generic map (
+ WIDTH => PWM_W,
+ MAX => 2**PWM_W - 2)
+ port map (
+ clk => mclk,
+ clk_en => '1',
+ reset => puc,
+ count => PWM_CNT,
+ event_ow => PWM_OW);
+
+ pwm_1 : entity work.pwm
+ generic map (
+ PWM_WIDTH => PWM_W)
+ port map (
+ clk => mclk,
+ reset => puc,
+ din => PWM_DAT,
+ we => PWM1_STB,
+ pwm_cnt => PWM_CNT,
+ pwm_cyc => PWM_OW,
+ pwm => PWM1_OUT);
+
+ pwm_2 : entity work.pwm
+ generic map (
+ PWM_WIDTH => PWM_W)
+ port map (
+ clk => mclk,
+ reset => puc,
+ din => PWM_DAT,
+ we => PWM2_STB,
+ pwm_cnt => PWM_CNT,
+ pwm_cyc => PWM_OW,
+ pwm => PWM2_OUT);
+
+ pwm_3 : entity work.pwm
+ generic map (
+ PWM_WIDTH => PWM_W)
+ port map (
+ clk => mclk,
+ reset => puc,
+ din => PWM_DAT,
+ we => PWM3_STB,
+ pwm_cnt => PWM_CNT,
+ pwm_cyc => PWM_OW,
+ pwm => PWM3_OUT);
+
+ -- PWM signals mapped to FPGA outputs, EN forced to '1'
+ PWM0 <= PWM1_OUT;
+ PWM0_EN <= '1';
+ PWM1 <= PWM2_OUT;
+ PWM1_EN <= '1';
+ PWM2 <= PWM3_OUT;
+ PWM2_EN <= '1';
+ -- PWM is signalized on LEDs
+ LED0 <= PWM1_OUT;
+ LED1 <= PWM2_OUT;
+ LED2 <= PWM3_OUT;
+
+ qcounter_1 : entity work.qcounter
+ port map (
+ clock => mclk,
+ reset => puc,
+ a0 => IRC_A,
+ b0 => IRC_B,
+ qcount => QCNT,
+ a_rise => open,
+ a_fall => open,
+ b_rise => open,
+ b_fall => open,
+ ab_event => open,
+ ab_error => open);
+
end rtl;