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