]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blob - pmsm-control/rpi_pmsm_control.vhdl
3f8619423f93ac241749c098b19ee693babccc5a
[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         --RPi SPI interface signals named aliases
174         signal spi_clk, spi_ce, spi_mosi, spi_miso : std_logic;
175         signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
176
177         --signal pwm_in, pwm_dir_in: std_logic;
178         signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
179         signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
180         signal index_position: std_logic_vector(11 downto 0);           --pozice irc_i
181         signal ce0_old: std_logic_vector(1 downto 0);
182         
183         --pwm signals
184         constant pwm_n: natural := 3;                                   --number of pwm outputs
185         --number of ticks per pwm cycle, 2^11=2048
186         constant pwm_period : std_logic_vector (pwm_width-1 downto 0) := (others=>'1'); 
187         type pwm_res_type is array(1 to 3) of std_logic_vector (pwm_width-1 downto 0);
188         
189         signal pwm_match: pwm_res_type;                                 --point of reversion of pwm output, 0 to 2047
190         signal pwm_count: std_logic_vector (pwm_width-1 downto 0);      --counter, 0 to 2047
191         signal pwm_sync: std_logic;
192         signal pwm_en_p: std_logic_vector(1 to 3);
193         signal pwm_en_n: std_logic_vector(1 to 3);
194         signal pwm_sig: std_logic_vector(1 to 3);
195         
196         signal income_data_valid: std_logic;
197         
198         signal clk_4M17: std_logic;
199
200         -- irc signals processing
201         signal irc_i_prev: std_logic;
202         
203         --  attribute syn_noprune of gpio2 : signal is true;
204         --  attribute syn_preserve of gpio2 : signal is true;
205         --  attribute syn_keep of gpio2 : signal is true;
206         --  attribute syn_hier of gpio2 : signal is true;
207
208 begin
209         -- PLL as a reset generator
210         
211         --zesileni signalu GPIO CLK
212         copyclk2: CLKINT
213         port map (
214                 a => gpio4,
215                 y => gpio_clk
216         );
217         
218         pll: pll50to200
219         port map (
220                 powerdown => '1',
221                 clka => pll_clkin,
222                 gla => pll_clkout,
223                 lock => pll_lock);
224
225         -- the failasfe signal from communication block if CRC is used
226         next_failsafe <= '0';
227
228         reset_async <= not pll_lock or clkmon_fail;
229
230         pll_clkin <= gpio_clk;
231         
232         qcount: qcounter
233         port map (
234                 clock => gpio_clk,
235                 reset => '0',
236                 a0 => irc_a,
237                 b0 => irc_b,
238                 qcount => position,
239                 a_rise => open,
240                 a_fall => open,
241                 b_rise => open,
242                 b_fall => open,
243                 ab_event => open,
244                 ab_error => open
245         );
246         
247         pwm_block: for i in pwm_n downto 1 generate
248                 pwm_map: mcpwm
249                 generic map (
250                         pwm_width => pwm_width
251                 )
252                 port map (
253                         clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
254                         sync => pwm_sync,                               --counter restarts
255                         data_valid => income_data_valid,                        
256                         failsafe => failsafe,
257                         --
258                         -- pwm config bits & match word
259                         --
260                         en_n => pwm_en_n(i),                            --enable positive pwm
261                         en_p => pwm_en_p(i),                            --enable "negative" ->activate shutdown
262                         match => pwm_match(i),
263                         count => pwm_count,
264                         -- outputs
265                         out_p => pwm_sig(i),                            --positive signal
266                         out_n => shdn(i)                                --reverse signal is in shutdown mode
267                 );
268         end generate;
269         
270         
271         div12_map: divider
272         port map(
273                 --reset => income_data_valid,
274                 clk_in => gpio_clk,
275                 div12 => clk_4M17
276         );
277         
278         -- ADC needs 3.2 MHz clk when powered from +5V Vcc
279         --           2.0 MHz clk when +2.7V Vcc
280         -- on the input is 4.17Mhz,but this frequency is divided inside adc_reader by 2 to 2.08 Mhz,
281         --        while we use +3.3V Vcc     
282         adc_reader_map: adc_reader 
283         port map(
284                 clk =>clk_4M17,
285                 adc_reset => adc_reset,
286                 adc_miso => adc_miso,
287                 adc_channels => adc_channels,
288                 adc_sclk => adc_sclk,
289                 adc_scs => adc_scs,
290                 adc_mosi => adc_mosi,
291                 measur_count => adc_m_count
292                 
293         );
294
295         dummy_unused <= gpio2 and gpio3 and
296                 gpio5 and gpio6 and
297                 gpio12 and gpio13 and gpio14 and
298                 gpio15 and gpio16 and gpio19 and
299                 gpio20 and gpio21 and gpio26 and
300                 stat(1) and stat(2) and stat(3) and
301                 hal_in(1) and hal_in(2) and hal_in(3) and
302                 irc_i and power_stat and 
303                 adc_miso and 
304                 rs485_rxd and
305                 can_rx and can_tx and
306                 dip_sw(1) and dip_sw(2) and dip_sw(3) and
307                 irc_a and irc_b and
308                 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
309                 gpio8  and
310                 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
311                         
312         rs485_txd <= '1';
313         rs485_dir <= '0';
314
315         spi_clk <= gpio11;
316         spi_ce <= gpio7;
317         spi_mosi <= gpio10;
318         gpio9 <= spi_miso;
319
320         pwm(1) <= pwm_sig(1) and dip_sw(1);
321         pwm(2) <= pwm_sig(2) and dip_sw(2);
322         pwm(3) <= pwm_sig(3) and dip_sw(3);
323         
324                 
325         process
326         begin
327                 wait until (gpio_clk'event and gpio_clk='1');
328                 if irc_i_prev = '0' and irc_i = '1' then
329                         index_position(11 downto 0)<=position(11 downto 0);
330                 end if;
331                 irc_i_prev<=irc_i;
332         end process;
333         
334         process
335         begin
336                 wait until (gpio_clk'event and gpio_clk='1');
337                 IF(pwm_count = pwm_period) THEN                         
338                 --end of period reached
339                         pwm_count <= (others=>'0');      --reset counter
340                         pwm_sync <= '1';                                -- inform PWM logic about new period start
341                 ELSE                                                    --end of period not reached
342                         pwm_count <= std_logic_vector(unsigned(pwm_count)+1);           --increment counter
343                         pwm_sync <= '0';
344                 END IF;
345         end process;
346         
347         process
348         begin
349                 --position is obtained on rising edge -> we should write it on next cycle
350                 wait until (gpio_clk'event and gpio_clk='1');
351                 
352                 --SCLK edge detection
353                 spiclk_old(0)<=spi_clk;
354                 spiclk_old(1)<=spiclk_old(0);
355                 
356                 --SS edge detection
357                 ce0_old(0)<=spi_ce;
358                 ce0_old(1)<=ce0_old(0);
359                 
360                 if (spiclk_old="01") then --rising edge, faze cteni
361                         if (spi_ce = '0') then             -- SPI CS must be selected
362                                 -- shift serial data into dat_reg on each rising edge
363                                 -- of SCK, MSB first
364                                 dat_reg(127 downto 0) <= dat_reg(126 downto 0) & spi_mosi;
365                                 end if;
366                 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
367                         if (spi_ce = '0') then
368                                 spi_miso <= dat_reg(127); --zapisujeme nejdriv MSB
369                         end if;
370                 end if;
371                 
372                         
373                 --sestupna hrana SS, pripravime data pro prenos
374                 if (ce0_old = "10" ) then 
375                         income_data_valid<='0';
376                         dat_reg(127 downto 96) <= position(31 downto 0); --pozice
377                         dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
378                         dat_reg(92 downto 81) <= index_position(11 downto 0);   --position of irc_i
379                         dat_reg(80 downto 72) <=adc_m_count(8 downto 0);        --count of measurments
380                         --data order schould be: ch2 downto ch0 downto ch1
381                         dat_reg(71 downto 0) <= adc_channels(71 downto 0);      --current mesurments
382                         adc_reset<='0'; --remove reset flag, and wait on its rising edge
383                 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
384                         adc_reset<='1';
385                         pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
386                         pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
387                         --11 bit pwm TODO: make it generic
388                         pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(66 downto 56);
389                         pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(55 downto 45);
390                         -- 12 + 11 Unused
391                         pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(42 downto 32);
392                         income_data_valid<='1';
393                 end if;
394         end process;
395
396         clock_monitor: process (pll_clkout, gpio_clk, clkmon_dly1, clkmon_wdg, clkmon_fail_next)
397         begin
398                 if pll_clkout'event and pll_clkout = '1' then
399                         clkmon_dly1 <= gpio_clk;
400                         clkmon_dly2 <= clkmon_dly1;
401                         if clkmon_dly1 = '0' and clkmon_dly2 = '1' then
402                                 clkmon_wdg <= 6;
403                                 clkmon_fail_next <= '0';
404                         elsif clkmon_wdg > 0 then
405                                 clkmon_wdg <= clkmon_wdg - 1;
406                                 clkmon_fail_next <= '0';
407                         else
408                                 clkmon_wdg <= 0;
409                                 clkmon_fail_next <= '1';
410                         end if;
411                         clkmon_fail <= clkmon_fail_next;
412                 end if;
413         end process;
414
415         async_rst: process (gpio_clk, reset_async, reset_sync)
416         begin
417                 if reset_async = '1' then
418                         failsafe <= '1';
419                 elsif gpio_clk'event and gpio_clk = '1' then
420                         failsafe <= next_failsafe or reset_sync;
421                 end if;
422         end process;
423
424         sync_rst: process (gpio_clk, reset_async)
425         begin
426                 if gpio_clk'event and gpio_clk = '1' then
427                         reset_sync <= reset_async;
428                 end if;
429         end process;
430
431 end behavioral;
432