]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blobdiff - pmsm-control/rpi_pmsm_control.vhdl
Bug fix: unconsistent changes of match signal caused twitches im motor movement....
[fpga/rpi-motor-control.git] / pmsm-control / rpi_pmsm_control.vhdl
index 47fd12c8615e667018b2249a3439c9b9a8efa31f..beb4b9cfd2fa1fc291ec6681fad2264996f04961 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;
 --
 
 library ieee;
@@ -15,7 +24,7 @@ use ieee.std_logic_1164.all;
 use ieee.numeric_std.all;
 use work.util.all;
 
 use ieee.numeric_std.all;
 use work.util.all;
 
-entity rpi_mc_simple_dc is
+entity rpi_pmsm_control is
 generic(
        pwm_width : natural:=11
        );
 generic(
        pwm_width : natural:=11
        );
@@ -85,21 +94,22 @@ port (
        -- Unused terminal to keep design tools silent
        dummy_unused : out std_logic
 );
        -- Unused terminal to keep design tools silent
        dummy_unused : out std_logic
 );
-end rpi_mc_simple_dc;
+end rpi_pmsm_control;
 
 
 
 
-architecture behavioral of rpi_mc_simple_dc is
+architecture behavioral of rpi_pmsm_control is
        attribute syn_noprune :boolean;
        attribute syn_preserve :boolean;
        attribute syn_keep :boolean;
        attribute syn_hier :boolean;
        attribute syn_noprune :boolean;
        attribute syn_preserve :boolean;
        attribute syn_keep :boolean;
        attribute syn_hier :boolean;
+
        -- Actel lib
        -- Actel lib
-       -- component pll50to200
-       --   port (
-       --     powerdown, clka: in std_logic;
-       --     lock, gla: out std_logic
-       --   );
-       -- end component;
+       component pll50to200
+               port (
+                       powerdown, clka: in std_logic;
+                       lock, gla: out std_logic
+               );
+       end component;
        
        component CLKINT
                port (A: in std_logic; Y: out std_logic);
        
        component CLKINT
                port (A: in std_logic; Y: out std_logic);
@@ -133,17 +143,18 @@ architecture behavioral of rpi_mc_simple_dc is
        );
        end component;
        
        );
        end component;
        
-       component div8 is
+       --frequency division by 12
+       component divider is
        port (
        port (
-               --reset: in std_logic;
                clk_in: in std_logic;
                clk_in: in std_logic;
-               clk_out: out std_logic
+               div12: out std_logic
        );
        end component;
        
        component adc_reader is
        port (
                clk: in std_logic;                                      --input clk
        );
        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
                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,15 +167,26 @@ architecture behavioral of rpi_mc_simple_dc is
        end component;
        
        
        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);
        signal adc_channels: std_logic_vector(71 downto 0);
        signal adc_m_count: std_logic_vector(8 downto 0);
-       
+
+       --clock signals for logic and master fail monitoring
+       signal gpio_clk: std_logic;
+       signal pll_clkin, pll_clkout, pll_lock: std_logic;
+       signal clkmon_dly1, clkmon_dly2: std_logic;
+       signal clkmon_fail, clkmon_fail_next: std_logic;
+       signal clkmon_wdg: integer range 0 to 6;
+       signal reset_sync, reset_async: std_logic;
+       signal failsafe, next_failsafe: std_logic;
+
+       --RPi SPI interface signals named aliases
+       signal spi_clk, spi_ce, spi_mosi, spi_miso : std_logic;
        signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
        signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
+
        --signal pwm_in, pwm_dir_in: std_logic;
        --signal pwm_in, pwm_dir_in: std_logic;
-       signal gpio_clk: std_logic;
        signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
        signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
        signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
        signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
+       signal index_position: std_logic_vector(11 downto 0);           --pozice irc_i
        signal ce0_old: std_logic_vector(1 downto 0);
        
        --pwm signals
        signal ce0_old: std_logic_vector(1 downto 0);
        
        --pwm signals
@@ -175,6 +197,7 @@ architecture behavioral of rpi_mc_simple_dc 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_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_sync: std_logic;
        signal pwm_en_p: std_logic_vector(1 to 3);
        signal pwm_en_n: std_logic_vector(1 to 3);
@@ -182,9 +205,10 @@ architecture behavioral of rpi_mc_simple_dc is
        
        signal income_data_valid: std_logic;
        
        
        signal income_data_valid: std_logic;
        
-       signal clk_3M1: std_logic;
-       
-       
+       signal clk_4M17: std_logic;
+
+       -- irc signals processing
+       signal irc_i_prev: std_logic;
        
        --  attribute syn_noprune of gpio2 : signal is true;
        --  attribute syn_preserve of gpio2 : signal is true;
        
        --  attribute syn_noprune of gpio2 : signal is true;
        --  attribute syn_preserve of gpio2 : signal is true;
@@ -201,6 +225,19 @@ begin
                y => gpio_clk
        );
        
                y => gpio_clk
        );
        
+       pll: pll50to200
+       port map (
+               powerdown => '1',
+               clka => pll_clkin,
+               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;
        
        qcount: qcounter
        port map (
        
        qcount: qcounter
        port map (
@@ -225,8 +262,8 @@ begin
                port map (
                        clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
                        sync => pwm_sync,                               --counter restarts
                port map (
                        clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
                        sync => pwm_sync,                               --counter restarts
-                       data_valid => income_data_valid,                        
-                       failsafe => '0',
+                       data_valid => pwm_sync_at_next,                 
+                       failsafe => failsafe,
                        --
                        -- pwm config bits & match word
                        --
                        --
                        -- pwm config bits & match word
                        --
@@ -241,17 +278,22 @@ begin
        end generate;
        
        
        end generate;
        
        
-       div8_map: div8 
+       div12_map: divider
        port map(
                --reset => income_data_valid,
                clk_in => gpio_clk,
        port map(
                --reset => income_data_valid,
                clk_in => gpio_clk,
-               clk_out => clk_3M1
+               div12 => clk_4M17
        );
        
        );
        
+       -- 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 
        port map(
        adc_reader_map: adc_reader 
        port map(
-               clk =>clk_3M1,
-               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,
                adc_miso => adc_miso,
                adc_channels => adc_channels,
                adc_sclk => adc_sclk,
@@ -261,20 +303,7 @@ begin
                
        );
 
                
        );
 
-       
-       
-       --   pll: pll50to200
-       --     port map (
-       --       powerdown => '1',
-       --       clka => pll_clkin,
-       --       gla => pll_clkout,
-       --       lock => pll_lock);
-       -- --  reset <= not pll_lock;
-       --   reset <= '0';                         -- TODO: apply reset for good failsafe
-                                           -- upon power-on
-       --   clock <= clkm;
-
-       dummy_unused <= gpio2 and gpio3  and gpio4 and
+       dummy_unused <= gpio2 and gpio3 and
                gpio5 and gpio6 and
                gpio12 and gpio13 and gpio14 and
                gpio15 and gpio16 and gpio19 and
                gpio5 and gpio6 and
                gpio12 and gpio13 and gpio14 and
                gpio15 and gpio16 and gpio19 and
@@ -288,24 +317,44 @@ begin
                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
                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 gpio11 and gpio7 and gpio10 and
+               gpio8  and
                ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
                        
        rs485_txd <= '1';
        rs485_dir <= '0';
 
                ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
                        
        rs485_txd <= '1';
        rs485_dir <= '0';
 
+       spi_clk <= gpio11;
+       spi_ce <= gpio7;
+       spi_mosi <= gpio10;
+       gpio9 <= spi_miso;
 
        pwm(1) <= pwm_sig(1) and dip_sw(1);
 
        pwm(1) <= pwm_sig(1) and dip_sw(1);
-       pwm(2) <= pwm_sig(2) and dip_sw(1);
-       pwm(3) <= pwm_sig(3) and dip_sw(1);
+       pwm(2) <= pwm_sig(2) and dip_sw(2);
+       pwm(3) <= pwm_sig(3) and dip_sw(3);
        
                
        
                
+       process
+       begin
+               wait until (gpio_clk'event and gpio_clk='1');
+               if irc_i_prev = '0' and irc_i = '1' then
+                       index_position(11 downto 0)<=position(11 downto 0);
+               end if;
+               irc_i_prev<=irc_i;
+       end process;
        
        process
        begin
                wait until (gpio_clk'event and gpio_clk='1');
        
        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
                        pwm_count <= (others=>'0');      --reset counter
                        pwm_sync <= '1';                                -- inform PWM logic about new period start
                ELSE                                                    --end of period not reached
@@ -320,22 +369,22 @@ begin
                wait until (gpio_clk'event and gpio_clk='1');
                
                --SCLK edge detection
                wait until (gpio_clk'event and gpio_clk='1');
                
                --SCLK edge detection
-               spiclk_old(0)<=gpio11;
+               spiclk_old(0)<=spi_clk;
                spiclk_old(1)<=spiclk_old(0);
                
                --SS edge detection
                spiclk_old(1)<=spiclk_old(0);
                
                --SS edge detection
-               ce0_old(0)<=gpio7;
+               ce0_old(0)<=spi_ce;
                ce0_old(1)<=ce0_old(0);
                
                if (spiclk_old="01") then --rising edge, faze cteni
                ce0_old(1)<=ce0_old(0);
                
                if (spiclk_old="01") then --rising edge, faze cteni
-                       if (gpio7 = '0') then             -- SPI CS must be selected
+                       if (spi_ce = '0') then             -- SPI CS must be selected
                                -- shift serial data into dat_reg on each rising edge
                                -- of SCK, MSB first
                                -- shift serial data into dat_reg on each rising edge
                                -- of SCK, MSB first
-                               dat_reg(127 downto 0) <= dat_reg(126 downto 0) & gpio10;
+                               dat_reg(127 downto 0) <= dat_reg(126 downto 0) & spi_mosi;
                                end if;
                elsif (spiclk_old="10" ) then --falling edge, faze zapisu
                                end if;
                elsif (spiclk_old="10" ) then --falling edge, faze zapisu
-                       if (gpio7 = '0') then
-                               gpio9 <= dat_reg(127); --zapisujeme nejdriv MSB
+                       if (spi_ce = '0') then
+                               spi_miso <= dat_reg(127); --zapisujeme nejdriv MSB
                        end if;
                end if;
                
                        end if;
                end if;
                
@@ -345,24 +394,56 @@ begin
                        income_data_valid<='0';
                        dat_reg(127 downto 96) <= position(31 downto 0); --pozice
                        dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
                        income_data_valid<='0';
                        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 90) <= pwm_en_p(1 to 3); --enable positive
-                       dat_reg(89 downto 87) <= pwm_en_n(1 to 3); --shutdown
-                       dat_reg(86 downto 81) <= (others=>'0');--pwm_match(1)(10 downto 5); --6 MSb of PWM1
+                       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
                        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
                        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
                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);
                        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);
+                       --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);
                        income_data_valid<='1';
                end if;
        end process;
                        income_data_valid<='1';
                end if;
        end process;
-                       
+
+       clock_monitor: process (pll_clkout, gpio_clk, clkmon_dly1, clkmon_wdg, clkmon_fail_next)
+       begin
+               if pll_clkout'event and pll_clkout = '1' then
+                       clkmon_dly1 <= gpio_clk;
+                       clkmon_dly2 <= clkmon_dly1;
+                       if clkmon_dly1 = '0' and clkmon_dly2 = '1' then
+                               clkmon_wdg <= 6;
+                               clkmon_fail_next <= '0';
+                       elsif clkmon_wdg > 0 then
+                               clkmon_wdg <= clkmon_wdg - 1;
+                               clkmon_fail_next <= '0';
+                       else
+                               clkmon_wdg <= 0;
+                               clkmon_fail_next <= '1';
+                       end if;
+                       clkmon_fail <= clkmon_fail_next;
+               end if;
+       end process;
+
+       async_rst: process (gpio_clk, reset_async, reset_sync)
+       begin
+               if reset_async = '1' then
+                       failsafe <= '1';
+               elsif gpio_clk'event and gpio_clk = '1' then
+                       failsafe <= next_failsafe or reset_sync;
+               end if;
+       end process;
+
+       sync_rst: process (gpio_clk, reset_async)
+       begin
+               if gpio_clk'event and gpio_clk = '1' then
+                       reset_sync <= reset_async;
+               end if;
+       end process;
+
 end behavioral;
 
 end behavioral;