]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blob - pmsm-control/rpi_pmsm_control.vhdl
Dff3 filter added to irc inputs.
[fpga/rpi-motor-control.git] / pmsm-control / rpi_pmsm_control.vhdl
1 --
2 -- * Raspberry Pi BLDC/PMSM motor control design for RPi-MI-1 board *
3 -- The toplevel component file
4 --
5 -- (c) 2015 Martin Prudek <prudemar@fel.cvut.cz>
6 -- Czech Technical University in Prague
7 --
8 -- Project supervision and original project idea
9 -- idea by Pavel Pisa <pisa@cmp.felk.cvut.cz>
10 --
11 -- Related RPi-MI-1 hardware is designed by Petr Porazil,
12 -- PiKRON Ltd  <http://www.pikron.com>
13 --
14 -- VHDL design reuses some components and concepts from
15 -- LXPWR motion power stage board and LX_RoCoN system
16 -- developed at PiKRON Ltd with base code implemented
17 -- by Marek Peca <hefaistos@gmail.com>
18 --
19 -- license: GNU LGPL and GPLv3+
20 --
21
22 library ieee;
23 use ieee.std_logic_1164.all;
24 use ieee.numeric_std.all;
25 use work.util.all;
26
27 entity rpi_pmsm_control is
28 generic(
29         pwm_width : natural:=11
30         );
31 port (
32         gpio2: in std_logic; -- SDA
33         gpio3: in std_logic; -- SCL
34         gpio4: in std_logic; -- CLK
35         gpio14: in std_logic; -- Tx
36         gpio15: in std_logic; -- Rx
37         gpio17: in std_logic; -- RTS
38         gpio18: in std_logic; -- PWM0/PCMCLK
39         gpio27: in std_logic; -- SD1DAT3
40         gpio22: in std_logic; -- SD1CLK
41         gpio23: in std_logic; -- SD1CMD
42         gpio24: in std_logic; -- SD1DAT0
43         gpio10: in std_logic; -- SPI0MOSI
44         gpio9: out std_logic; -- SPI0MISO
45         gpio25: in std_logic; -- SD1DAT1
46         gpio11: in std_logic; -- SPI0SCLK
47         gpio8: in std_logic; -- SPI0CE0
48         gpio7: in std_logic; -- SPI0CE1
49         gpio5: in std_logic; -- GPCLK1
50         gpio6: in std_logic; -- GPCLK2
51         gpio12: in std_logic; -- PWM0
52         gpio13: in std_logic; -- PWM1
53         gpio19: in std_logic; -- PWM1/SPI1MISO/PCMFS
54         gpio16: in std_logic; -- SPI1CE2
55         gpio26: in std_logic; -- SD1DAT2
56         gpio20: in std_logic; -- SPI1MOSI/PCMDIN/GPCLK0
57         gpio21: in std_logic; -- SPI1SCLK/PCMDOUT/GPCLK1
58         --
59         -- PWM
60         -- Each PWM signal has cooresponding shutdown
61         pwm: out std_logic_vector (1 to 3);
62         shdn: out std_logic_vector (1 to 3);
63         -- Fault/power stage status
64         stat: in std_logic_vector (1 to 3);
65         -- HAL inputs
66         hal_in: in std_logic_vector (1 to 3);
67         -- IRC inputs
68         irc_a: in std_logic;
69         irc_b: in std_logic;
70         irc_i: in std_logic;
71         -- Power status
72         power_stat: in std_logic;
73         -- ADC for current
74         adc_miso: in std_logic;
75         adc_mosi: out std_logic;
76         adc_sclk: out std_logic;
77         adc_scs: out std_logic;
78         -- Extarnal SPI
79         ext_miso: in std_logic; --master in slave out
80         ext_mosi: in std_logic; --master out slave in
81         ext_sclk: in std_logic;
82         ext_scs0: in std_logic;
83         ext_scs1: in std_logic;
84         ext_scs2: in std_logic;
85         -- RS-485 Transceiver
86         rs485_rxd: in std_logic;
87         rs485_txd: out std_logic;
88         rs485_dir: out std_logic;
89         -- CAN Transceiver
90         can_rx: in std_logic;
91         can_tx: in std_logic;
92         -- DIP switch
93         dip_sw: in std_logic_vector (1 to 3); --na desce je prohozene cislovanni
94         -- Unused terminal to keep design tools silent
95         dummy_unused : out std_logic
96 );
97 end rpi_pmsm_control;
98
99
100 architecture behavioral of rpi_pmsm_control is
101         attribute syn_noprune :boolean;
102         attribute syn_preserve :boolean;
103         attribute syn_keep :boolean;
104         attribute syn_hier :boolean;
105
106         -- Actel lib
107         component pll50to200
108                 port (
109                         powerdown, clka: in std_logic;
110                         lock, gla: out std_logic
111                 );
112         end component;
113         
114         component CLKINT
115                 port (A: in std_logic; Y: out std_logic);
116         end component;
117         
118         component qcounter
119         port (
120                 clock: in std_logic;
121                 reset: in std_logic;
122                 a0, b0: in std_logic;
123                 qcount: out std_logic_vector (31 downto 0);
124                 a_rise, a_fall, b_rise, b_fall, ab_event: out std_logic;
125                 ab_error: out std_logic
126         );
127         end component;
128
129         component mcpwm is
130         generic (
131                 pwm_width: natural
132         );
133         port (
134                 clock: in std_logic;
135                 sync: in std_logic;                             --flag that counter "restarts-overflows"
136                 data_valid:in std_logic;                        --indicates data is consistent
137                 failsafe: in std_logic;                         --turn off both transistors
138                 en_p, en_n: in std_logic;                       --enable positive & enable shutdown
139                 match: in std_logic_vector (pwm_width-1 downto 0); --posion of counter when we swap output logic
140                 count: in std_logic_vector (pwm_width-1 downto 0); --we use an external counter
141                 out_p, out_n: out std_logic                     --pwm outputs: positive & shutdown
142                 --TODO add the rest of pwm signals, swap match to pwm_word
143         );
144         end component;
145         
146         --frequency division by 12
147         component cnt_div is
148         generic (
149                 cnt_width_g : natural := 4
150         );
151         port
152         (
153                 clk_i     : in std_logic;                               --clk to divide
154                 en_i      : in std_logic;                               --enable bit?
155                 reset_i   : in std_logic;                               --asynch. reset
156                 ratio_i   : in std_logic_vector(cnt_width_g-1 downto 0);--initial value
157                 q_out_o   : out std_logic                               --generates puls when counter underflows
158         );
159         end component;
160         
161         component adc_reader is
162         port (
163                 clk: in std_logic;                                      --input clk
164                 divided_clk : in std_logic;                             --divided clk - value suitable to sourcing voltage
165                 adc_reset: in std_logic;
166                 adc_miso: in std_logic;                                 --spi master in slave out
167                 adc_channels: out std_logic_vector (35 downto 0);       --consistent data of 3 channels
168                 adc_sclk: out std_logic;                                --spi clk
169                 adc_scs: out std_logic;                                 --spi slave select
170                 adc_mosi: out std_logic;                                --spi master out slave in
171                 measur_count: out std_logic_vector(8 downto 0)          --number of accumulated measurments
172         
173         );
174         end component;
175         
176         component dff3 is
177         port(
178                 clk_i   : in std_logic;
179                 d_i     : in std_logic;
180                 q_o     : out std_logic
181         );
182         end component;
183         
184         
185         signal adc_channels: std_logic_vector(71 downto 0);
186         signal adc_m_count: std_logic_vector(8 downto 0);
187
188         --clock signals for logic and master fail monitoring
189         signal gpio_clk: std_logic;
190         signal pll_clkin, pll_clkout, pll_lock: std_logic;
191         signal clkmon_dly1, clkmon_dly2: std_logic;
192         signal clkmon_fail, clkmon_fail_next: std_logic;
193         signal clkmon_wdg: integer range 0 to 6;
194         signal reset_sync, reset_async: std_logic;
195         signal failsafe, next_failsafe: std_logic;
196
197         --RPi SPI interface signals named aliases
198         signal spi_clk, spi_ce, spi_mosi, spi_miso : std_logic;
199         signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
200
201         --signal pwm_in, pwm_dir_in: std_logic;
202         signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
203         signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
204         signal index_position: std_logic_vector(11 downto 0);           --pozice irc_i
205         signal ce0_old: std_logic_vector(1 downto 0);
206         
207         --pwm signals
208         constant pwm_n: natural := 3;                                   --number of pwm outputs
209         --number of ticks per pwm cycle, 2^11=2048
210         constant pwm_period : std_logic_vector (pwm_width-1 downto 0) := (others=>'1'); 
211         type pwm_res_type is array(1 to 3) of std_logic_vector (pwm_width-1 downto 0);
212         
213         signal pwm_match: pwm_res_type;                                 --point of reversion of pwm output, 0 to 2047
214         signal pwm_count: std_logic_vector (pwm_width-1 downto 0);      --counter, 0 to 2047
215         signal pwm_sync_at_next: std_logic;
216         signal pwm_sync: std_logic;
217         signal pwm_en_p: std_logic_vector(1 to 3);
218         signal pwm_en_n: std_logic_vector(1 to 3);
219         signal pwm_sig: std_logic_vector(1 to 3);
220         
221         signal income_data_valid: std_logic;
222         
223         signal clk_4M17: std_logic;
224
225         -- irc signals processing
226         signal irc_i_prev: std_logic;
227         
228         --filetered irc signals
229         signal irc_a_dff3: std_logic;
230         signal irc_b_dff3: std_logic;
231         
232         --  attribute syn_noprune of gpio2 : signal is true;
233         --  attribute syn_preserve of gpio2 : signal is true;
234         --  attribute syn_keep of gpio2 : signal is true;
235         --  attribute syn_hier of gpio2 : signal is true;
236
237 begin
238         -- PLL as a reset generator
239         
240         --zesileni signalu GPIO CLK
241         copyclk2: CLKINT
242         port map (
243                 a => gpio4,
244                 y => gpio_clk
245         );
246         
247         pll: pll50to200
248         port map (
249                 powerdown => '1',
250                 clka => pll_clkin,
251                 gla => pll_clkout,
252                 lock => pll_lock);
253
254         -- the failasfe signal from communication block if CRC is used
255         next_failsafe <= '0';
256
257         reset_async <= not pll_lock or clkmon_fail;
258
259         pll_clkin <= gpio_clk;
260         
261         qcount: qcounter
262         port map (
263                 clock => gpio_clk,
264                 reset => '0',
265                 a0 => irc_a_dff3,
266                 b0 => irc_b_dff3,
267                 qcount => position,
268                 a_rise => open,
269                 a_fall => open,
270                 b_rise => open,
271                 b_fall => open,
272                 ab_event => open,
273                 ab_error => open
274         );
275         
276         pwm_block: for i in pwm_n downto 1 generate
277                 pwm_map: mcpwm
278                 generic map (
279                         pwm_width => pwm_width
280                 )
281                 port map (
282                         clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
283                         sync => pwm_sync,                               --counter restarts
284                         data_valid => pwm_sync_at_next,                 
285                         failsafe => failsafe,
286                         --
287                         -- pwm config bits & match word
288                         --
289                         en_n => pwm_en_n(i),                            --enable positive pwm
290                         en_p => pwm_en_p(i),                            --enable "negative" ->activate shutdown
291                         match => pwm_match(i),
292                         count => pwm_count,
293                         -- outputs
294                         out_p => pwm_sig(i),                            --positive signal
295                         out_n => shdn(i)                                --reverse signal is in shutdown mode
296                 );
297         end generate;
298         
299         
300         div12_map: cnt_div
301         port map(
302                 clk_i  => gpio_clk,
303                 en_i   =>'1',
304                 reset_i   =>'0',
305                 ratio_i   =>"1101", --POZN.: counter detekuje cnt<=1
306                 q_out_o   =>clk_4M17
307         );
308         
309         -- ADC needs 3.2 MHz clk when powered from +5V Vcc
310         --           2.0 MHz clk when +2.7V Vcc
311         -- on the input is 4.17Mhz,but this frequency is divided inside adc_reader by 2 to 2.08 Mhz,
312         --        while we use +3.3V Vcc     
313         adc_reader_map: adc_reader 
314         port map(
315                 clk => gpio_clk,
316                 divided_clk => clk_4M17,
317                 adc_reset => income_data_valid, --reset at each SPI cycle,TODO: replace with PLL reset
318                 adc_miso => adc_miso,
319                 adc_channels => adc_channels,
320                 adc_sclk => adc_sclk,
321                 adc_scs => adc_scs,
322                 adc_mosi => adc_mosi,
323                 measur_count => adc_m_count
324                 
325         );
326         
327         dff3_a: dff3
328         port map(       
329                 clk_i => gpio_clk,
330                 d_i   => irc_a,
331                 q_o   => irc_a_dff3 
332         );
333         
334         dff3_b: dff3
335         port map(       
336                 clk_i => gpio_clk,
337                 d_i   => irc_b,
338                 q_o   => irc_b_dff3 
339         );
340
341         dummy_unused <= gpio2 and gpio3 and
342                 gpio5 and gpio6 and
343                 gpio12 and gpio13 and gpio14 and
344                 gpio15 and gpio16 and gpio19 and
345                 gpio20 and gpio21 and gpio26 and
346                 stat(1) and stat(2) and stat(3) and
347                 hal_in(1) and hal_in(2) and hal_in(3) and
348                 irc_i and power_stat and 
349                 adc_miso and 
350                 rs485_rxd and
351                 can_rx and can_tx and
352                 dip_sw(1) and dip_sw(2) and dip_sw(3) and
353                 irc_a and irc_b and
354                 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
355                 gpio8  and
356                 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
357                         
358         rs485_txd <= '1';
359         rs485_dir <= '0';
360
361         spi_clk <= gpio11;
362         spi_ce <= gpio7;
363         spi_mosi <= gpio10;
364         gpio9 <= spi_miso;
365
366         pwm(1) <= pwm_sig(1) and dip_sw(1);
367         pwm(2) <= pwm_sig(2) and dip_sw(2);
368         pwm(3) <= pwm_sig(3) and dip_sw(3);
369         
370                 
371         process
372         begin
373                 wait until (gpio_clk'event and gpio_clk='1');
374                 if irc_i_prev = '0' and irc_i = '1' then
375                         index_position(11 downto 0)<=position(11 downto 0);
376                 end if;
377                 irc_i_prev<=irc_i;
378         end process;
379         
380         process
381         begin
382                 wait until (gpio_clk'event and gpio_clk='1');
383                 IF pwm_count = std_logic_vector(unsigned(pwm_period) - 1) THEN                          
384                         --end of period nearly reached
385                         --fetch new pwm match data
386                         pwm_sync_at_next <= '1';
387                 else
388                         pwm_sync_at_next <= '0';
389                 end if;
390                 
391                 if pwm_sync_at_next='1' then
392                         --end of period reached
393                         pwm_count <= (others=>'0');      --reset counter
394                         pwm_sync <= '1';                                -- inform PWM logic about new period start
395                 ELSE                                                    --end of period not reached
396                         pwm_count <= std_logic_vector(unsigned(pwm_count)+1);           --increment counter
397                         pwm_sync <= '0';
398                 END IF;
399         end process;
400         
401         process
402         begin
403                 --position is obtained on rising edge -> we should write it on next cycle
404                 wait until (gpio_clk'event and gpio_clk='1');
405                 
406                 --SCLK edge detection
407                 spiclk_old(0)<=spi_clk;
408                 spiclk_old(1)<=spiclk_old(0);
409                 
410                 --SS edge detection
411                 ce0_old(0)<=spi_ce;
412                 ce0_old(1)<=ce0_old(0);
413                 
414                 if (spiclk_old="01") then --rising edge, faze cteni
415                         if (spi_ce = '0') then             -- SPI CS must be selected
416                                 -- shift serial data into dat_reg on each rising edge
417                                 -- of SCK, MSB first
418                                 dat_reg(127 downto 0) <= dat_reg(126 downto 0) & spi_mosi;
419                                 end if;
420                 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
421                         if (spi_ce = '0') then
422                                 spi_miso <= dat_reg(127); --zapisujeme nejdriv MSB
423                         end if;
424                 end if;
425                 
426                         
427                 --sestupna hrana SS, pripravime data pro prenos
428                 if (ce0_old = "10" ) then 
429                         income_data_valid<='0';
430                         dat_reg(127 downto 96) <= position(31 downto 0); --pozice
431                         dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
432                         dat_reg(92 downto 81) <= index_position(11 downto 0);   --position of irc_i
433                         dat_reg(80 downto 72) <=adc_m_count(8 downto 0);        --count of measurments
434                         --data order schould be: ch2 downto ch0 downto ch1
435                         dat_reg(71 downto 0) <= adc_channels(71 downto 0);      --current mesurments
436                         spi_miso <= position(31);               --prepare the first bit on SE activation
437                 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
438                         pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
439                         pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
440                         --usable for up to 16-bit PWM duty cycle resolution (pwm_width):
441                         pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(pwm_width+31 downto 32);
442                         pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(pwm_width+15 downto 16);
443                         pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(pwm_width-1 downto 0);
444                         income_data_valid<='1';
445                 end if;
446         end process;
447
448         clock_monitor: process (pll_clkout, gpio_clk, clkmon_dly1, clkmon_wdg, clkmon_fail_next)
449         begin
450                 if pll_clkout'event and pll_clkout = '1' then
451                         clkmon_dly1 <= gpio_clk;
452                         clkmon_dly2 <= clkmon_dly1;
453                         if clkmon_dly1 = '0' and clkmon_dly2 = '1' then
454                                 clkmon_wdg <= 6;
455                                 clkmon_fail_next <= '0';
456                         elsif clkmon_wdg > 0 then
457                                 clkmon_wdg <= clkmon_wdg - 1;
458                                 clkmon_fail_next <= '0';
459                         else
460                                 clkmon_wdg <= 0;
461                                 clkmon_fail_next <= '1';
462                         end if;
463                         clkmon_fail <= clkmon_fail_next;
464                 end if;
465         end process;
466
467         async_rst: process (gpio_clk, reset_async, reset_sync)
468         begin
469                 if reset_async = '1' then
470                         failsafe <= '1';
471                 elsif gpio_clk'event and gpio_clk = '1' then
472                         failsafe <= next_failsafe or reset_sync;
473                 end if;
474         end process;
475
476         sync_rst: process (gpio_clk, reset_async)
477         begin
478                 if gpio_clk'event and gpio_clk = '1' then
479                         reset_sync <= reset_async;
480                 end if;
481         end process;
482
483 end behavioral;
484