]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blob - pmsm-control/rpi_pmsm_control.vhdl
Current measurment bits transferring via SPI from FPGA to RPi extended from 12 to...
[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_mc_simple_dc 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_mc_simple_dc;
89
90
91 architecture behavioral of rpi_mc_simple_dc 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         component div8 is
137         port (
138                 --reset: in std_logic;
139                 clk_in: in std_logic;
140                 clk_out: 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         
154         );
155         end component;
156         
157         
158         signal adc_reset : std_logic;
159         signal adc_channels: std_logic_vector(35 downto 0);
160         
161         signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
162         --signal pwm_in, pwm_dir_in: std_logic;
163         signal gpio_clk: std_logic;
164         signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
165         signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
166         signal ce0_old: std_logic_vector(1 downto 0);
167         
168         --pwm signals
169         constant pwm_n: natural := 3;                                   --number of pwm outputs
170         --number of ticks per pwm cycle, 2^11=2048
171         constant pwm_period : std_logic_vector (pwm_width-1 downto 0) := (others=>'1'); 
172         type pwm_res_type is array(1 to 3) of std_logic_vector (pwm_width-1 downto 0);
173         
174         signal pwm_match: pwm_res_type;                                 --point of reversion of pwm output, 0 to 2047
175         signal pwm_count: std_logic_vector (pwm_width-1 downto 0);      --counter, 0 to 2047
176         signal pwm_sync: std_logic;
177         signal pwm_en_p: std_logic_vector(1 to 3);
178         signal pwm_en_n: std_logic_vector(1 to 3);
179         
180         signal income_data_valid: std_logic;
181         
182         signal clk_3M1: std_logic;
183         
184         
185         
186         --  attribute syn_noprune of gpio2 : signal is true;
187         --  attribute syn_preserve of gpio2 : signal is true;
188         --  attribute syn_keep of gpio2 : signal is true;
189         --  attribute syn_hier of gpio2 : signal is true;
190
191 begin
192         -- PLL as a reset generator
193         
194         --zesileni signalu GPIO CLK
195         copyclk2: CLKINT
196         port map (
197                 a => gpio4,
198                 y => gpio_clk
199         );
200         
201         
202         qcount: qcounter
203         port map (
204                 clock => gpio_clk,
205                 reset => '0',
206                 a0 => irc_a,
207                 b0 => irc_b,
208                 qcount => position,
209                 a_rise => open,
210                 a_fall => open,
211                 b_rise => open,
212                 b_fall => open,
213                 ab_event => open,
214                 ab_error => open
215         );
216         
217         pwm_block: for i in pwm_n downto 1 generate
218                 pwm_map: mcpwm
219                 generic map (
220                         pwm_width => pwm_width
221                 )
222                 port map (
223                         clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
224                         sync => pwm_sync,                               --counter restarts
225                         data_valid => income_data_valid,                        
226                         failsafe => '0',
227                         --
228                         -- pwm config bits & match word
229                         --
230                         en_n => pwm_en_n(i),                            --enable positive pwm
231                         en_p => pwm_en_p(i),                            --enable "negative" ->activate shutdown
232                         match => pwm_match(i),
233                         count => pwm_count,
234                         -- outputs
235                         out_p => open,--pwm(i),                         --positive signal
236                         out_n => shdn(i)                                --reverse signal is in shutdown mode
237                 );
238         end generate;
239         
240         
241         div8_map: div8 
242         port map(
243                 --reset => income_data_valid,
244                 clk_in => gpio_clk,
245                 clk_out => clk_3M1
246         );
247         
248         adc_reader_map: adc_reader 
249         port map(
250                 clk =>clk_3M1,
251                 adc_reset => adc_reset,
252                 adc_miso => adc_miso,
253                 adc_channels => adc_channels,
254                 adc_sclk => adc_sclk,
255                 adc_scs => adc_scs,
256                 adc_mosi => adc_mosi
257                 
258         );
259
260         
261         
262         --   pll: pll50to200
263         --     port map (
264         --       powerdown => '1',
265         --       clka => pll_clkin,
266         --       gla => pll_clkout,
267         --       lock => pll_lock);
268         -- --  reset <= not pll_lock;
269         --   reset <= '0';                         -- TODO: apply reset for good failsafe
270                                            -- upon power-on
271         --   clock <= clkm;
272
273         dummy_unused <= gpio2 and gpio3  and gpio4 and
274                 gpio5 and gpio6 and
275                 gpio12 and gpio13 and gpio14 and
276                 gpio15 and gpio16 and gpio19 and
277                 gpio20 and gpio21 and gpio26 and
278                 stat(1) and stat(2) and stat(3) and
279                 hal_in(1) and hal_in(2) and hal_in(3) and
280                 irc_i and power_stat and 
281                 adc_miso and 
282                 rs485_rxd and
283                 can_rx and can_tx and
284                 dip_sw(1) and dip_sw(2) and dip_sw(3) and
285                 irc_a and irc_b and
286                 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
287                 gpio8  and gpio11 and gpio7 and gpio10 and
288                 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
289                         
290         rs485_txd <= '1';
291         rs485_dir <= '0';
292
293
294         --shdn(1) <= '0';
295         --shdn(2) <= '1';
296         --shdn(3) <= '0';
297
298         --pwm(1) <= '0';
299         --pwm(2) <= '0';
300         --pwm(3) <= '0';
301         
302                 
303         
304         process
305         begin
306                 wait until (gpio_clk'event and gpio_clk='1');
307                 IF(pwm_count = pwm_period) THEN                         
308                 --end of period reached
309                         pwm_count <= (others=>'0');      --reset counter
310                         pwm_sync <= '1';                                -- inform PWM logic about new period start
311                 ELSE                                                    --end of period not reached
312                         pwm_count <= std_logic_vector(unsigned(pwm_count)+1);           --increment counter
313                         pwm_sync <= '0';
314                 END IF;
315         end process;
316         
317         process
318         begin
319                 --position is obtained on rising edge -> we should write it on next cycle
320                 wait until (gpio_clk'event and gpio_clk='1');
321                 
322                 --SCLK edge detection
323                 spiclk_old(0)<=gpio11;
324                 spiclk_old(1)<=spiclk_old(0);
325                 
326                 --SS edge detection
327                 ce0_old(0)<=gpio7;
328                 ce0_old(1)<=ce0_old(0);
329                 
330                 if (spiclk_old="01") then --rising edge, faze cteni
331                         if (gpio7 = '0') then             -- SPI CS must be selected
332                                 -- shift serial data into dat_reg on each rising edge
333                                 -- of SCK, MSB first
334                                 dat_reg(127 downto 0) <= dat_reg(126 downto 0) & gpio10;
335                                 end if;
336                 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
337                         if (gpio7 = '0') then
338                                 gpio9 <= dat_reg(127); --zapisujeme nejdriv MSB
339                         end if;
340                 end if;
341                 
342                         
343                 --sestupna hrana SS, pripravime data pro prenos
344                 if (ce0_old = "10" ) then 
345                         income_data_valid<='0';
346                         dat_reg(127 downto 96) <= position(31 downto 0); --pozice
347                         dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
348                         dat_reg(92 downto 90) <= pwm_en_p(1 to 3); --enable positive
349                         dat_reg(89 downto 87) <= pwm_en_n(1 to 3); --shutdown
350                         dat_reg(86 downto 81) <= (others=>'0');--pwm_match(1)(10 downto 5); --6 MSb of PWM1
351                         dat_reg(80 downto 74) <= (others=>'0');--pwm_match(2)(10 downto 4); --7 MSb of PWM2
352                         dat_reg(73 downto 68) <= (others=>'0');--pwm_match(3)(10 downto 5); --6 MSb of PWM3
353                         dat_reg(71 downto 60)<=(others=>'0');
354                         dat_reg(59 downto 48) <= adc_channels(35 downto 24); --current mesurments
355                         dat_reg(47 downto 36)<=(others=>'0');
356                         dat_reg(35 downto 24) <= adc_channels(23 downto 12); --current mesurments
357                         dat_reg(23 downto 12)<=(others=>'0');
358                         dat_reg(11 downto 0) <= adc_channels(11 downto 0); --current mesurments
359                         adc_reset<='0'; --remove reset flag, and wait on its rising edge
360                 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
361                         adc_reset<='1';
362                         pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
363                         pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
364                         --11 bit pwm TODO: make it generic
365                         pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(66 downto 56);
366                         pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(55 downto 45);
367                         -- 12 + 11 Unused
368                         pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(42 downto 32);
369                         income_data_valid<='1';
370                 end if;
371         end process;
372                         
373 end behavioral;
374