]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blob - pmsm-control/rpi_pmsm_control.vhdl
4829bebb6b40e8ec6ba7a1b14754352d528de7c1
[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         -- Actel lib
97         -- component pll50to200
98         --   port (
99         --     powerdown, clka: in std_logic;
100         --     lock, gla: out std_logic
101         --   );
102         -- end component;
103         
104         component CLKINT
105                 port (A: in std_logic; Y: out std_logic);
106         end component;
107         
108         component qcounter
109         port (
110                 clock: in std_logic;
111                 reset: in std_logic;
112                 a0, b0: in std_logic;
113                 qcount: out std_logic_vector (31 downto 0);
114                 a_rise, a_fall, b_rise, b_fall, ab_event: out std_logic;
115                 ab_error: out std_logic
116         );
117         end component;
118
119         component mcpwm is
120         generic (
121                 pwm_width: natural
122         );
123         port (
124                 clock: in std_logic;
125                 sync: in std_logic;                             --flag that counter "restarts-overflows"
126                 data_valid:in std_logic;                        --indicates data is consistent
127                 failsafe: in std_logic;                         --turn off both transistors
128                 en_p, en_n: in std_logic;                       --enable positive & enable shutdown
129                 match: in std_logic_vector (pwm_width-1 downto 0); --posion of counter when we swap output logic
130                 count: in std_logic_vector (pwm_width-1 downto 0); --we use an external counter
131                 out_p, out_n: out std_logic                     --pwm outputs: positive & shutdown
132                 --TODO add the rest of pwm signals, swap match to pwm_word
133         );
134         end component;
135         
136         --frequency division by 12
137         component divider is
138         port (
139                 clk_in: in std_logic;
140                 div12: out std_logic
141         );
142         end component;
143         
144         component adc_reader is
145         port (
146                 clk: in std_logic;                                      --input clk
147                 adc_reset: in std_logic;
148                 adc_miso: in std_logic;                                 --spi master in slave out
149                 adc_channels: out std_logic_vector (35 downto 0);       --consistent data of 3 channels
150                 adc_sclk: out std_logic;                                --spi clk
151                 adc_scs: out std_logic;                                 --spi slave select
152                 adc_mosi: out std_logic;                                --spi master out slave in
153                 measur_count: out std_logic_vector(8 downto 0)          --number of accumulated measurments
154         
155         );
156         end component;
157         
158         
159         signal adc_reset : std_logic;
160         signal adc_channels: std_logic_vector(71 downto 0);
161         signal adc_m_count: std_logic_vector(8 downto 0);
162         
163         signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
164         --signal pwm_in, pwm_dir_in: std_logic;
165         signal gpio_clk: std_logic;
166         signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
167         signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
168         signal index_position: std_logic_vector(11 downto 0);           --pozice irc_i
169         signal ce0_old: std_logic_vector(1 downto 0);
170         
171         --pwm signals
172         constant pwm_n: natural := 3;                                   --number of pwm outputs
173         --number of ticks per pwm cycle, 2^11=2048
174         constant pwm_period : std_logic_vector (pwm_width-1 downto 0) := (others=>'1'); 
175         type pwm_res_type is array(1 to 3) of std_logic_vector (pwm_width-1 downto 0);
176         
177         signal pwm_match: pwm_res_type;                                 --point of reversion of pwm output, 0 to 2047
178         signal pwm_count: std_logic_vector (pwm_width-1 downto 0);      --counter, 0 to 2047
179         signal pwm_sync: std_logic;
180         signal pwm_en_p: std_logic_vector(1 to 3);
181         signal pwm_en_n: std_logic_vector(1 to 3);
182         signal pwm_sig: std_logic_vector(1 to 3);
183         
184         signal income_data_valid: std_logic;
185         
186         signal clk_4M17: std_logic;
187         
188         
189         
190         --  attribute syn_noprune of gpio2 : signal is true;
191         --  attribute syn_preserve of gpio2 : signal is true;
192         --  attribute syn_keep of gpio2 : signal is true;
193         --  attribute syn_hier of gpio2 : signal is true;
194
195 begin
196         -- PLL as a reset generator
197         
198         --zesileni signalu GPIO CLK
199         copyclk2: CLKINT
200         port map (
201                 a => gpio4,
202                 y => gpio_clk
203         );
204         
205         
206         qcount: qcounter
207         port map (
208                 clock => gpio_clk,
209                 reset => '0',
210                 a0 => irc_a,
211                 b0 => irc_b,
212                 qcount => position,
213                 a_rise => open,
214                 a_fall => open,
215                 b_rise => open,
216                 b_fall => open,
217                 ab_event => open,
218                 ab_error => open
219         );
220         
221         pwm_block: for i in pwm_n downto 1 generate
222                 pwm_map: mcpwm
223                 generic map (
224                         pwm_width => pwm_width
225                 )
226                 port map (
227                         clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
228                         sync => pwm_sync,                               --counter restarts
229                         data_valid => income_data_valid,                        
230                         failsafe => '0',
231                         --
232                         -- pwm config bits & match word
233                         --
234                         en_n => pwm_en_n(i),                            --enable positive pwm
235                         en_p => pwm_en_p(i),                            --enable "negative" ->activate shutdown
236                         match => pwm_match(i),
237                         count => pwm_count,
238                         -- outputs
239                         out_p => pwm_sig(i),                            --positive signal
240                         out_n => shdn(i)                                --reverse signal is in shutdown mode
241                 );
242         end generate;
243         
244         
245         div12_map: divider
246         port map(
247                 --reset => income_data_valid,
248                 clk_in => gpio_clk,
249                 div12 => clk_4M17
250         );
251         
252         -- ADC needs 3.2 MHz clk when powered from +5V Vcc
253         --           2.0 MHz clk when +2.7V Vcc
254         -- on the input is 4.17Mhz,but this frequency is divided inside adc_reader by 2 to 2.08 Mhz,
255         --        while we use +3.3V Vcc     
256         adc_reader_map: adc_reader 
257         port map(
258                 clk =>clk_4M17,
259                 adc_reset => adc_reset,
260                 adc_miso => adc_miso,
261                 adc_channels => adc_channels,
262                 adc_sclk => adc_sclk,
263                 adc_scs => adc_scs,
264                 adc_mosi => adc_mosi,
265                 measur_count => adc_m_count
266                 
267         );
268
269         
270         
271         --   pll: pll50to200
272         --     port map (
273         --       powerdown => '1',
274         --       clka => pll_clkin,
275         --       gla => pll_clkout,
276         --       lock => pll_lock);
277         -- --  reset <= not pll_lock;
278         --   reset <= '0';                         -- TODO: apply reset for good failsafe
279                                            -- upon power-on
280         --   clock <= clkm;
281
282         dummy_unused <= gpio2 and gpio3  and gpio4 and
283                 gpio5 and gpio6 and
284                 gpio12 and gpio13 and gpio14 and
285                 gpio15 and gpio16 and gpio19 and
286                 gpio20 and gpio21 and gpio26 and
287                 stat(1) and stat(2) and stat(3) and
288                 hal_in(1) and hal_in(2) and hal_in(3) and
289                 irc_i and power_stat and 
290                 adc_miso and 
291                 rs485_rxd and
292                 can_rx and can_tx and
293                 dip_sw(1) and dip_sw(2) and dip_sw(3) and
294                 irc_a and irc_b and
295                 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
296                 gpio8  and gpio11 and gpio7 and gpio10 and
297                 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
298                         
299         rs485_txd <= '1';
300         rs485_dir <= '0';
301
302
303         pwm(1) <= pwm_sig(1) and dip_sw(1);
304         pwm(2) <= pwm_sig(2) and dip_sw(2);
305         pwm(3) <= pwm_sig(3) and dip_sw(3);
306         
307                 
308         process
309         begin
310                 wait until (irc_i'event and irc_i='1');
311                 index_position(11 downto 0)<=position(11 downto 0);
312         end process;
313         
314         process
315         begin
316                 wait until (gpio_clk'event and gpio_clk='1');
317                 IF(pwm_count = pwm_period) THEN                         
318                 --end of period reached
319                         pwm_count <= (others=>'0');      --reset counter
320                         pwm_sync <= '1';                                -- inform PWM logic about new period start
321                 ELSE                                                    --end of period not reached
322                         pwm_count <= std_logic_vector(unsigned(pwm_count)+1);           --increment counter
323                         pwm_sync <= '0';
324                 END IF;
325         end process;
326         
327         process
328         begin
329                 --position is obtained on rising edge -> we should write it on next cycle
330                 wait until (gpio_clk'event and gpio_clk='1');
331                 
332                 --SCLK edge detection
333                 spiclk_old(0)<=gpio11;
334                 spiclk_old(1)<=spiclk_old(0);
335                 
336                 --SS edge detection
337                 ce0_old(0)<=gpio7;
338                 ce0_old(1)<=ce0_old(0);
339                 
340                 if (spiclk_old="01") then --rising edge, faze cteni
341                         if (gpio7 = '0') then             -- SPI CS must be selected
342                                 -- shift serial data into dat_reg on each rising edge
343                                 -- of SCK, MSB first
344                                 dat_reg(127 downto 0) <= dat_reg(126 downto 0) & gpio10;
345                                 end if;
346                 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
347                         if (gpio7 = '0') then
348                                 gpio9 <= dat_reg(127); --zapisujeme nejdriv MSB
349                         end if;
350                 end if;
351                 
352                         
353                 --sestupna hrana SS, pripravime data pro prenos
354                 if (ce0_old = "10" ) then 
355                         income_data_valid<='0';
356                         dat_reg(127 downto 96) <= position(31 downto 0); --pozice
357                         dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
358                         dat_reg(92 downto 81) <= index_position(11 downto 0);   --position of irc_i
359                         dat_reg(80 downto 72) <=adc_m_count(8 downto 0);        --count of measurments
360                         --data order schould be: ch2 downto ch0 downto ch1
361                         dat_reg(71 downto 0) <= adc_channels(71 downto 0);      --current mesurments
362                         adc_reset<='0'; --remove reset flag, and wait on its rising edge
363                 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
364                         adc_reset<='1';
365                         pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
366                         pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
367                         --11 bit pwm TODO: make it generic
368                         pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(66 downto 56);
369                         pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(55 downto 45);
370                         -- 12 + 11 Unused
371                         pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(42 downto 32);
372                         income_data_valid<='1';
373                 end if;
374         end process;
375                         
376 end behavioral;
377