]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blob - pmsm-control/rpi_pmsm_control.vhdl
Remove unused package and swap DIP switch order to match board.
[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         --resetovatelna delicka
185         component div128 is
186         port (
187                 clk_in: in std_logic;
188                 rst: in std_logic;
189                 fail_safe: out std_logic
190         );
191         end component;
192         
193         component div256 is
194         port (
195                 clk_in: in std_logic;
196                 div256: out std_logic
197         );
198         end component;
199         
200         
201         signal adc_channels: std_logic_vector(71 downto 0);
202         signal adc_m_count: std_logic_vector(8 downto 0);
203
204         --clock signals for logic and master fail monitoring
205         signal gpio_clk: std_logic;
206         signal pll_clkin, pll_clkout, pll_lock: std_logic;
207         signal clkmon_dly1, clkmon_dly2: std_logic;
208         signal clkmon_fail, clkmon_fail_next: std_logic;
209         signal clkmon_wdg: integer range 0 to 6;
210         signal reset_sync, reset_async: std_logic;
211         signal failsafe, next_failsafe: std_logic;
212
213         --RPi SPI interface signals named aliases
214         signal spi_clk, spi_ce, spi_mosi, spi_miso : std_logic;
215         signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
216
217         --signal pwm_in, pwm_dir_in: std_logic;
218         signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
219         signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
220         signal index_position: std_logic_vector(11 downto 0);           --pozice irc_i
221         signal ce0_old: std_logic_vector(1 downto 0);
222         
223         --pwm signals
224         constant pwm_n: natural := 3;                                   --number of pwm outputs
225         --number of ticks per pwm cycle, 2^11=2048
226         constant pwm_period : std_logic_vector (pwm_width-1 downto 0) := (others=>'1'); 
227         type pwm_res_type is array(1 to 3) of std_logic_vector (pwm_width-1 downto 0);
228         
229         signal pwm_match: pwm_res_type;                                 --point of reversion of pwm output, 0 to 2047
230         signal pwm_count: std_logic_vector (pwm_width-1 downto 0);      --counter, 0 to 2047
231         signal pwm_sync_at_next: std_logic;
232         signal pwm_sync: std_logic;
233         signal pwm_en_p: std_logic_vector(1 to 3);
234         signal pwm_en_n: std_logic_vector(1 to 3);
235         signal pwm_sig: std_logic_vector(1 to 3);
236         
237         signal income_data_valid: std_logic;
238         
239         signal clk_4M17: std_logic;
240
241         -- irc signals processing
242         signal irc_i_prev: std_logic;
243         
244         --filetered irc signals
245         signal irc_a_dff3: std_logic;
246         signal irc_b_dff3: std_logic;
247         
248         --16k3 clk signal
249         signal clk_16k3: std_logic;
250         --detekce prichazejicich prikazu po SPI
251         signal spi_command_lost: std_logic;
252         
253         --  attribute syn_noprune of gpio2 : signal is true;
254         --  attribute syn_preserve of gpio2 : signal is true;
255         --  attribute syn_keep of gpio2 : signal is true;
256         --  attribute syn_hier of gpio2 : signal is true;
257
258 begin
259         -- PLL as a reset generator
260         
261         --zesileni signalu GPIO CLK
262         copyclk2: CLKINT
263         port map (
264                 a => gpio4,
265                 y => gpio_clk
266         );
267         
268         pll: pll50to200
269         port map (
270                 powerdown => '1',
271                 clka => pll_clkin,
272                 gla => pll_clkout,
273                 lock => pll_lock);
274
275         -- the failasfe signal from communication block if CRC is used
276         next_failsafe <= '0';
277
278         reset_async <= not pll_lock or clkmon_fail;
279
280         pll_clkin <= gpio_clk;
281         
282         qcount: qcounter
283         port map (
284                 clock => gpio_clk,
285                 reset => '0',
286                 a0 => irc_a_dff3,
287                 b0 => irc_b_dff3,
288                 qcount => position,
289                 a_rise => open,
290                 a_fall => open,
291                 b_rise => open,
292                 b_fall => open,
293                 ab_event => open,
294                 ab_error => open
295         );
296         
297         pwm_block: for i in pwm_n downto 1 generate
298                 pwm_map: mcpwm
299                 generic map (
300                         pwm_width => pwm_width
301                 )
302                 port map (
303                         clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
304                         sync => pwm_sync,                               --counter restarts
305                         data_valid => pwm_sync_at_next,                 
306                         failsafe => failsafe,
307                         --
308                         -- pwm config bits & match word
309                         --
310                         en_n => pwm_en_n(i),                            --enable positive pwm
311                         en_p => pwm_en_p(i),                            --enable "negative" ->activate shutdown
312                         match => pwm_match(i),
313                         count => pwm_count,
314                         -- outputs
315                         out_p => pwm_sig(i),                            --positive signal
316                         out_n => shdn(i)                                --reverse signal is in shutdown mode
317                 );
318         end generate;
319         
320         
321         div12_map: cnt_div
322         port map(
323                 clk_i  => gpio_clk,
324                 en_i   =>'1',
325                 reset_i   =>'0',
326                 ratio_i   =>"1101", --POZN.: counter detekuje cnt<=1
327                 q_out_o   =>clk_4M17
328         );
329         
330         div256_map: div256 
331         port map(
332                 clk_in => clk_4M17,
333                 div256 => clk_16k3
334         );
335         
336         div128_map: div128 
337         port map(
338                 clk_in => clk_16k3,
339                 rst => income_data_valid,
340                 fail_safe => spi_command_lost
341 );
342
343         -- ADC needs 3.2 MHz clk when powered from +5V Vcc
344         --           2.0 MHz clk when +2.7V Vcc
345         -- on the input is 4.17Mhz,but this frequency is divided inside adc_reader by 2 to 2.08 Mhz,
346         --        while we use +3.3V Vcc     
347         adc_reader_map: adc_reader 
348         port map(
349                 clk => gpio_clk,
350                 divided_clk => clk_4M17,
351                 adc_reset => income_data_valid, --reset at each SPI cycle,TODO: replace with PLL reset
352                 adc_miso => adc_miso,
353                 adc_channels => adc_channels,
354                 adc_sclk => adc_sclk,
355                 adc_scs => adc_scs,
356                 adc_mosi => adc_mosi,
357                 measur_count => adc_m_count
358                 
359         );
360         
361         dff3_a: dff3
362         port map(       
363                 clk_i => gpio_clk,
364                 d_i   => irc_a,
365                 q_o   => irc_a_dff3 
366         );
367         
368         dff3_b: dff3
369         port map(       
370                 clk_i => gpio_clk,
371                 d_i   => irc_b,
372                 q_o   => irc_b_dff3 
373         );
374
375         dummy_unused <= gpio2 and gpio3 and
376                 gpio5 and gpio6 and
377                 gpio12 and gpio13 and gpio14 and
378                 gpio15 and gpio16 and gpio19 and
379                 gpio20 and gpio21 and gpio26 and
380                 stat(1) and stat(2) and stat(3) and
381                 hal_in(1) and hal_in(2) and hal_in(3) and
382                 irc_i and power_stat and 
383                 adc_miso and 
384                 rs485_rxd and
385                 can_rx and can_tx and
386                 dip_sw(1) and dip_sw(2) and dip_sw(3) and
387                 irc_a and irc_b and
388                 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
389                 gpio8  and
390                 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
391                         
392         rs485_txd <= '1';
393         rs485_dir <= '0';
394
395         spi_clk <= gpio11;
396         spi_ce <= gpio7;
397         spi_mosi <= gpio10;
398         gpio9 <= spi_miso;
399
400         pwm(1) <= pwm_sig(1) and dip_sw(1) and not spi_command_lost;
401         pwm(2) <= pwm_sig(2) and dip_sw(2) and not spi_command_lost;
402         pwm(3) <= pwm_sig(3) and dip_sw(3) and not spi_command_lost;
403         
404                 
405         process
406         begin
407                 wait until (gpio_clk'event and gpio_clk='1');
408                 if irc_i_prev = '0' and irc_i = '1' then
409                         index_position(11 downto 0)<=position(11 downto 0);
410                 end if;
411                 irc_i_prev<=irc_i;
412         end process;
413         
414         process
415         begin
416                 wait until (gpio_clk'event and gpio_clk='1');
417                 IF pwm_count = std_logic_vector(unsigned(pwm_period) - 1) THEN                          
418                         --end of period nearly reached
419                         --fetch new pwm match data
420                         pwm_sync_at_next <= '1';
421                 else
422                         pwm_sync_at_next <= '0';
423                 end if;
424                 
425                 if pwm_sync_at_next='1' then
426                         --end of period reached
427                         pwm_count <= (others=>'0');      --reset counter
428                         pwm_sync <= '1';                                -- inform PWM logic about new period start
429                 ELSE                                                    --end of period not reached
430                         pwm_count <= std_logic_vector(unsigned(pwm_count)+1);           --increment counter
431                         pwm_sync <= '0';
432                 END IF;
433         end process;
434         
435         process
436         begin
437                 --position is obtained on rising edge -> we should write it on next cycle
438                 wait until (gpio_clk'event and gpio_clk='1');
439                 
440                 --SCLK edge detection
441                 spiclk_old(0)<=spi_clk;
442                 spiclk_old(1)<=spiclk_old(0);
443                 
444                 --SS edge detection
445                 ce0_old(0)<=spi_ce;
446                 ce0_old(1)<=ce0_old(0);
447                 
448                 if (spiclk_old="01") then --rising edge, faze cteni
449                         if (spi_ce = '0') then             -- SPI CS must be selected
450                                 -- shift serial data into dat_reg on each rising edge
451                                 -- of SCK, MSB first
452                                 dat_reg(127 downto 0) <= dat_reg(126 downto 0) & spi_mosi;
453                                 end if;
454                 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
455                         if (spi_ce = '0') then
456                                 spi_miso <= dat_reg(127); --zapisujeme nejdriv MSB
457                         end if;
458                 end if;
459                 
460                         
461                 --sestupna hrana SS, pripravime data pro prenos
462                 if (ce0_old = "10" ) then 
463                         income_data_valid<='0';
464                         dat_reg(127 downto 96) <= position(31 downto 0); --pozice
465                         dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
466                         dat_reg(92 downto 81) <= index_position(11 downto 0);   --position of irc_i
467                         dat_reg(80 downto 72) <=adc_m_count(8 downto 0);        --count of measurments
468                         --data order schould be: ch2 downto ch0 downto ch1
469                         dat_reg(71 downto 0) <= adc_channels(71 downto 0);      --current mesurments
470                         spi_miso <= position(31);               --prepare the first bit on SE activation
471                 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
472                         pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
473                         pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
474                         --usable for up to 16-bit PWM duty cycle resolution (pwm_width):
475                         pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(pwm_width+31 downto 32);
476                         pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(pwm_width+15 downto 16);
477                         pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(pwm_width-1 downto 0);
478                         income_data_valid<='1';
479                 end if;
480         end process;
481
482         clock_monitor: process (pll_clkout, gpio_clk, clkmon_dly1, clkmon_wdg, clkmon_fail_next)
483         begin
484                 if pll_clkout'event and pll_clkout = '1' then
485                         clkmon_dly1 <= gpio_clk;
486                         clkmon_dly2 <= clkmon_dly1;
487                         if clkmon_dly1 = '0' and clkmon_dly2 = '1' then
488                                 clkmon_wdg <= 6;
489                                 clkmon_fail_next <= '0';
490                         elsif clkmon_wdg > 0 then
491                                 clkmon_wdg <= clkmon_wdg - 1;
492                                 clkmon_fail_next <= '0';
493                         else
494                                 clkmon_wdg <= 0;
495                                 clkmon_fail_next <= '1';
496                         end if;
497                         clkmon_fail <= clkmon_fail_next;
498                 end if;
499         end process;
500
501         async_rst: process (gpio_clk, reset_async, reset_sync)
502         begin
503                 if reset_async = '1' then
504                         failsafe <= '1';
505                 elsif gpio_clk'event and gpio_clk = '1' then
506                         failsafe <= next_failsafe or reset_sync;
507                 end if;
508         end process;
509
510         sync_rst: process (gpio_clk, reset_async)
511         begin
512                 if gpio_clk'event and gpio_clk = '1' then
513                         reset_sync <= reset_async;
514                 end if;
515         end process;
516
517 end behavioral;
518