]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blobdiff - pmsm-control/rpi_pmsm_control.vhdl
Correct typo in rpi-mc-1 mapping to Ti AM437x based RICO board.
[fpga/rpi-motor-control.git] / pmsm-control / rpi_pmsm_control.vhdl
index 3f8619423f93ac241749c098b19ee693babccc5a..e900e8de60cc7a8df12c0dc0f9e2d21cac982305 100644 (file)
@@ -1,13 +1,22 @@
 --
--- * LXPWR slave part *
---  common sioreg & common counter for several ADC&PWM blocks
+-- * Raspberry Pi BLDC/PMSM motor control design for RPi-MI-1 board *
+-- The toplevel component file
 --
--- part of LXPWR motion control board (c) PiKRON Ltd
--- idea by Pavel Pisa PiKRON Ltd <pisa@cmp.felk.cvut.cz>
--- code by Marek Peca <mp@duch.cz>
--- 01/2013
+-- (c) 2015 Martin Prudek <prudemar@fel.cvut.cz>
+-- Czech Technical University in Prague
 --
--- license: GNU GPLv3
+-- Project supervision and original project idea
+-- idea by Pavel Pisa <pisa@cmp.felk.cvut.cz>
+--
+-- Related RPi-MI-1 hardware is designed by Petr Porazil,
+-- PiKRON Ltd  <http://www.pikron.com>
+--
+-- VHDL design reuses some components and concepts from
+-- LXPWR motion power stage board and LX_RoCoN system
+-- developed at PiKRON Ltd with base code implemented
+-- by Marek Peca <hefaistos@gmail.com>
+--
+-- license: GNU LGPL and GPLv3+
 --
 
 library ieee;
@@ -22,28 +31,28 @@ generic(
 port (
        gpio2: in std_logic; -- SDA
        gpio3: in std_logic; -- SCL
-       gpio4: in std_logic; -- CLK
+       gpio4: in std_logic; -- CLK           (gpio_clk)
        gpio14: in std_logic; -- Tx
        gpio15: in std_logic; -- Rx
-       gpio17: in std_logic; -- RTS
-       gpio18: in std_logic; -- PWM0/PCMCLK
-       gpio27: in std_logic; -- SD1DAT3
-       gpio22: in std_logic; -- SD1CLK
-       gpio23: in std_logic; -- SD1CMD
-       gpio24: in std_logic; -- SD1DAT0
-       gpio10: in std_logic; -- SPI0MOSI
-       gpio9: out std_logic; -- SPI0MISO
-       gpio25: in std_logic; -- SD1DAT1
-       gpio11: in std_logic; -- SPI0SCLK
+       gpio17: inout std_logic; -- RTS       (irc_i)
+       gpio18: in std_logic; -- PWM0/PCMCLK  (pwm_in/pwm1)
+       gpio27: inout std_logic; -- SD1DAT3   (irc_b)
+       gpio22: in std_logic; -- SD1CLK       (pwm_dir_in/pwm1_en)
+       gpio23: inout std_logic; -- SD1CMD    (irc_a)
+       gpio24: inout std_logic; -- SD1DAT0   (irc_a)
+       gpio10: in std_logic; -- SPI0MOSI     (spi_mosi)
+       gpio9: out std_logic; -- SPI0MISO     (spi_miso)
+       gpio25: inout std_logic; -- SD1DAT1   (irc_b)
+       gpio11: in std_logic; -- SPI0SCLK     (spi_clk)
        gpio8: in std_logic; -- SPI0CE0
-       gpio7: in std_logic; -- SPI0CE1
+       gpio7: in std_logic; -- SPI0CE1       (spi_ce)
        gpio5: in std_logic; -- GPCLK1
        gpio6: in std_logic; -- GPCLK2
-       gpio12: in std_logic; -- PWM0
-       gpio13: in std_logic; -- PWM1
-       gpio19: in std_logic; -- PWM1/SPI1MISO/PCMFS
+       gpio12: in std_logic; -- PWM0         (pwm3)
+       gpio13: in std_logic; -- PWM1         (pwm2)
+       gpio19: in std_logic; -- PWM1/SPI1MISO/PCMFS (pwm2_en)
        gpio16: in std_logic; -- SPI1CE2
-       gpio26: in std_logic; -- SD1DAT2
+       gpio26: in std_logic; -- SD1DAT2      (pwm3_en)
        gpio20: in std_logic; -- SPI1MOSI/PCMDIN/GPCLK0
        gpio21: in std_logic; -- SPI1SCLK/PCMDOUT/GPCLK1
        --
@@ -135,16 +144,24 @@ architecture behavioral of rpi_pmsm_control is
        end component;
        
        --frequency division by 12
-       component divider is
-       port (
-               clk_in: in std_logic;
-               div12: out std_logic
+       component cnt_div is
+       generic (
+               cnt_width_g : natural := 4
+       );
+       port
+       (
+               clk_i     : in std_logic;                               --clk to divide
+               en_i      : in std_logic;                               --enable bit?
+               reset_i   : in std_logic;                               --asynch. reset
+               ratio_i   : in std_logic_vector(cnt_width_g-1 downto 0);--initial value
+               q_out_o   : out std_logic                               --generates puls when counter underflows
        );
        end component;
        
        component adc_reader is
        port (
                clk: in std_logic;                                      --input clk
+               divided_clk : in std_logic;                             --divided clk - value suitable to sourcing voltage
                adc_reset: in std_logic;
                adc_miso: in std_logic;                                 --spi master in slave out
                adc_channels: out std_logic_vector (35 downto 0);       --consistent data of 3 channels
@@ -156,8 +173,31 @@ architecture behavioral of rpi_pmsm_control is
        );
        end component;
        
+       component dff3 is
+       port(
+               clk_i   : in std_logic;
+               d_i     : in std_logic;
+               q_o     : out std_logic
+       );
+       end component;
+       
+       --resetovatelna delicka
+       component div128 is
+       port (
+               clk_in: in std_logic;
+               rst: in std_logic;
+               fail_safe: out std_logic
+       );
+       end component;
+       
+       component div256 is
+       port (
+               clk_in: in std_logic;
+               div256: out std_logic
+       );
+       end component;
+       
        
-       signal adc_reset : std_logic;
        signal adc_channels: std_logic_vector(71 downto 0);
        signal adc_m_count: std_logic_vector(8 downto 0);
 
@@ -188,18 +228,37 @@ architecture behavioral of rpi_pmsm_control is
        
        signal pwm_match: pwm_res_type;                                 --point of reversion of pwm output, 0 to 2047
        signal pwm_count: std_logic_vector (pwm_width-1 downto 0);      --counter, 0 to 2047
+       signal pwm_sync_at_next: std_logic;
        signal pwm_sync: std_logic;
        signal pwm_en_p: std_logic_vector(1 to 3);
        signal pwm_en_n: std_logic_vector(1 to 3);
        signal pwm_sig: std_logic_vector(1 to 3);
+       signal shdn_sig: std_logic_vector (1 to 3);
        
        signal income_data_valid: std_logic;
+       signal spi_timout_pulse: std_logic;
        
        signal clk_4M17: std_logic;
 
        -- irc signals processing
        signal irc_i_prev: std_logic;
+
+       -- function configuration options
+       -- direct IRC channel A, B and I output to RPi/SoC
+       signal fnccfg_direct_irc: std_logic;
+       -- direct 3 phase PWM output
+       signal fnccfg_direct_3ph_pwm: std_logic;
+       -- PWM1 and PWM2 controlled by PWM input and direction
+       signal fnccfg_pwm12_by_pwm_and_dir: std_logic;
+       
+       --filetered irc signals
+       signal irc_a_dff3: std_logic;
+       signal irc_b_dff3: std_logic;
        
+       --16k3 clk signal
+       signal clk_16k3: std_logic;
+       --detekce prichazejicich prikazu po SPI
+
        --  attribute syn_noprune of gpio2 : signal is true;
        --  attribute syn_preserve of gpio2 : signal is true;
        --  attribute syn_keep of gpio2 : signal is true;
@@ -222,9 +281,6 @@ begin
                gla => pll_clkout,
                lock => pll_lock);
 
-       -- the failasfe signal from communication block if CRC is used
-       next_failsafe <= '0';
-
        reset_async <= not pll_lock or clkmon_fail;
 
        pll_clkin <= gpio_clk;
@@ -233,8 +289,8 @@ begin
        port map (
                clock => gpio_clk,
                reset => '0',
-               a0 => irc_a,
-               b0 => irc_b,
+               a0 => irc_a_dff3,
+               b0 => irc_b_dff3,
                qcount => position,
                a_rise => open,
                a_fall => open,
@@ -252,7 +308,7 @@ begin
                port map (
                        clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
                        sync => pwm_sync,                               --counter restarts
-                       data_valid => income_data_valid,                        
+                       data_valid => pwm_sync_at_next,                 
                        failsafe => failsafe,
                        --
                        -- pwm config bits & match word
@@ -263,26 +319,56 @@ begin
                        count => pwm_count,
                        -- outputs
                        out_p => pwm_sig(i),                            --positive signal
-                       out_n => shdn(i)                                --reverse signal is in shutdown mode
+                       out_n => shdn_sig(i)                            --reverse signal is in shutdown mode
                );
        end generate;
        
        
-       div12_map: divider
+       div12_map: cnt_div
+       generic map (
+               cnt_width_g => 4
+       )
        port map(
-               --reset => income_data_valid,
-               clk_in => gpio_clk,
-               div12 => clk_4M17
+               clk_i  => gpio_clk,
+               en_i   =>'1',
+               reset_i   =>'0',
+               ratio_i   =>"1101", --POZN.: counter detekuje cnt<=1
+               q_out_o   =>clk_4M17
        );
-       
+
+       clk_16k3_div: cnt_div
+       generic map (
+               cnt_width_g => 8
+       )
+       port map(
+               clk_i  => gpio_clk,
+               en_i   => clk_4M17,
+               reset_i   => '0',
+               ratio_i   => "11111111",
+               q_out_o   => clk_16k3
+       );
+
+       spi_timeout_div : cnt_div
+       generic map (
+               cnt_width_g => 7
+       )
+       port map(
+               clk_i  => gpio_clk,
+               en_i   => clk_16k3,
+               reset_i   => income_data_valid,
+               ratio_i   => "1111111",
+               q_out_o   => spi_timout_pulse
+       );
+
        -- ADC needs 3.2 MHz clk when powered from +5V Vcc
        --           2.0 MHz clk when +2.7V Vcc
        -- on the input is 4.17Mhz,but this frequency is divided inside adc_reader by 2 to 2.08 Mhz,
-       --        while we use +3.3V Vcc     
-       adc_reader_map: adc_reader 
+       --        while we use +3.3V Vcc
+       adc_reader_map: adc_reader
        port map(
-               clk =>clk_4M17,
-               adc_reset => adc_reset,
+               clk => gpio_clk,
+               divided_clk => clk_4M17,
+               adc_reset => income_data_valid, --reset at each SPI cycle,TODO: replace with PLL reset
                adc_miso => adc_miso,
                adc_channels => adc_channels,
                adc_sclk => adc_sclk,
@@ -291,6 +377,20 @@ begin
                measur_count => adc_m_count
                
        );
+       
+       dff3_a: dff3
+       port map(       
+               clk_i => gpio_clk,
+               d_i   => irc_a,
+               q_o   => irc_a_dff3
+       );
+       
+       dff3_b: dff3
+       port map(       
+               clk_i => gpio_clk,
+               d_i   => irc_b,
+               q_o   => irc_b_dff3
+       );
 
        dummy_unused <= gpio2 and gpio3 and
                gpio5 and gpio6 and
@@ -299,15 +399,18 @@ begin
                gpio20 and gpio21 and gpio26 and
                stat(1) and stat(2) and stat(3) and
                hal_in(1) and hal_in(2) and hal_in(3) and
-               irc_i and power_stat and 
-               adc_miso and 
+               irc_i and power_stat and
+               adc_miso and
                rs485_rxd and
                can_rx and can_tx and
-               dip_sw(1) and dip_sw(2) and dip_sw(3) and
                irc_a and irc_b and
                gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
                gpio8  and
                ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
+
+       fnccfg_direct_irc <= not dip_sw(1);
+       fnccfg_direct_3ph_pwm <= not dip_sw(2) and dip_sw(3);
+       fnccfg_pwm12_by_pwm_and_dir <= not dip_sw(2) and not dip_sw(3);
                        
        rs485_txd <= '1';
        rs485_dir <= '0';
@@ -317,11 +420,50 @@ begin
        spi_mosi <= gpio10;
        gpio9 <= spi_miso;
 
-       pwm(1) <= pwm_sig(1) and dip_sw(1);
-       pwm(2) <= pwm_sig(2) and dip_sw(2);
-       pwm(3) <= pwm_sig(3) and dip_sw(3);
-       
-               
+       irc_direct_output_selection: process(fnccfg_direct_irc, irc_a, irc_b, irc_i)
+       begin
+               if fnccfg_direct_irc = '1' then
+                       gpio23 <= irc_a;
+                       gpio24 <= irc_a;
+                       gpio27 <= irc_b;
+                       gpio25 <= irc_b;
+                       gpio17 <= irc_i;
+               else
+                       gpio23 <= 'Z';
+                       gpio24 <= 'Z';
+                       gpio27 <= 'Z';
+                       gpio25 <= 'Z';
+                       gpio17 <= 'Z';
+               end if;
+       end process;
+
+       pwm_output_selection: process(pwm_sig, shdn_sig,
+               fnccfg_direct_3ph_pwm, fnccfg_pwm12_by_pwm_and_dir,
+               fnccfg_pwm12_by_pwm_and_dir, gpio12, gpio13, gpio18, gpio19,
+               gpio22, gpio26)
+       begin
+               if fnccfg_direct_3ph_pwm = '1' then
+                       pwm(1) <= gpio18;
+                       pwm(2) <= gpio13;
+                       pwm(3) <= gpio12;
+                       shdn(1) <= not gpio22;
+                       shdn(2) <= not gpio19;
+                       shdn(3) <= not gpio26;
+               elsif fnccfg_pwm12_by_pwm_and_dir = '1' then
+                       -- pwm(1) <= pwm_in and not pwm_dir_in;
+                       pwm(1) <= gpio18 and not gpio22;
+                       -- pwm(2) <= pwm_in and pwm_dir_in;;
+                       pwm(2) <= gpio18 and gpio22;
+                       pwm(3) <= '0';
+                       shdn(1) <= '0';
+                       shdn(2) <= '0';
+                       shdn(3) <= '1';
+               else
+                       pwm <= pwm_sig;
+                       shdn <= shdn_sig;
+               end if;
+       end process;
+
        process
        begin
                wait until (gpio_clk'event and gpio_clk='1');
@@ -334,8 +476,16 @@ begin
        process
        begin
                wait until (gpio_clk'event and gpio_clk='1');
-               IF(pwm_count = pwm_period) THEN                         
-               --end of period reached
+               IF pwm_count = std_logic_vector(unsigned(pwm_period) - 1) THEN                          
+                       --end of period nearly reached
+                       --fetch new pwm match data
+                       pwm_sync_at_next <= '1';
+               else
+                       pwm_sync_at_next <= '0';
+               end if;
+               
+               if pwm_sync_at_next='1' then
+                       --end of period reached
                        pwm_count <= (others=>'0');      --reset counter
                        pwm_sync <= '1';                                -- inform PWM logic about new period start
                ELSE                                                    --end of period not reached
@@ -369,27 +519,29 @@ begin
                        end if;
                end if;
                
-                       
+
+               if (ce0_old = "10" ) then
+                       income_data_valid <= '1';
+               else
+                       income_data_valid <= '0';
+               end if;
+
                --sestupna hrana SS, pripravime data pro prenos
-               if (ce0_old = "10" ) then 
-                       income_data_valid<='0';
+               if (ce0_old = "10" ) then
                        dat_reg(127 downto 96) <= position(31 downto 0); --pozice
                        dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
                        dat_reg(92 downto 81) <= index_position(11 downto 0);   --position of irc_i
                        dat_reg(80 downto 72) <=adc_m_count(8 downto 0);        --count of measurments
                        --data order schould be: ch2 downto ch0 downto ch1
                        dat_reg(71 downto 0) <= adc_channels(71 downto 0);      --current mesurments
-                       adc_reset<='0'; --remove reset flag, and wait on its rising edge
+                       spi_miso <= position(31);               --prepare the first bit on SE activation
                elsif (ce0_old = "01") then --rising edge of SS, we should read the data
-                       adc_reset<='1';
                        pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
                        pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
-                       --11 bit pwm TODO: make it generic
-                       pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(66 downto 56);
-                       pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(55 downto 45);
-                       -- 12 + 11 Unused
-                       pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(42 downto 32);
-                       income_data_valid<='1';
+                       --usable for up to 16-bit PWM duty cycle resolution (pwm_width):
+                       pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(pwm_width+31 downto 32);
+                       pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(pwm_width+15 downto 16);
+                       pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(pwm_width-1 downto 0);
                end if;
        end process;
 
@@ -412,6 +564,19 @@ begin
                end if;
        end process;
 
+       failsafe_spi_monitor: process (failsafe, spi_timout_pulse, income_data_valid)
+       begin
+               -- the failasfe signal from communication block if CRC is used
+               -- or simple watchdog for SPI communication
+               if income_data_valid = '1' then
+                       next_failsafe <= '0';
+               elsif spi_timout_pulse = '1' then
+                       next_failsafe <= '1';
+               else
+                       next_failsafe <= failsafe;
+               end if;
+       end process;
+
        async_rst: process (gpio_clk, reset_async, reset_sync)
        begin
                if reset_async = '1' then