]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blob - pmsm-control/rpi_mc_simple_dc.vhdl
GPCLK frequency from RPi increased from 2Mhz to 50Mhz. To keep clk frequency for...
[fpga/rpi-motor-control.git] / pmsm-control / rpi_mc_simple_dc.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         
145         type state_type is (f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,f15,r15,reset,rst_wait);
146         signal state : state_type;
147         
148         type channel_type is (ch0, ch1, ch2);
149         
150         signal adc_data: std_logic_vector(11 downto 0); --ADC income data
151         signal adc_reset : std_logic;
152         signal adc_rst_old : std_logic_vector(1 downto 0);
153         signal adc_address: std_logic_vector(8 downto 0);
154         signal adc_channels: std_logic_vector(35 downto 0);
155         
156         signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
157         --signal pwm_in, pwm_dir_in: std_logic;
158         signal gpio_clk: std_logic;
159         signal dat_reg : STD_LOGIC_VECTOR (95 downto 0); --shift register for spi
160         signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
161         signal ce0_old: std_logic_vector(1 downto 0);
162         
163         --pwm signals
164         constant pwm_n: natural := 3;                                   --number of pwm outputs
165         --number of ticks per pwm cycle, 2^11=2048
166         constant pwm_period : std_logic_vector (pwm_width-1 downto 0) := (others=>'1'); 
167         type pwm_res_type is array(1 to 3) of std_logic_vector (pwm_width-1 downto 0);
168         
169         signal pwm_match: pwm_res_type;                                 --point of reversion of pwm output, 0 to 2047
170         signal pwm_count: std_logic_vector (pwm_width-1 downto 0);      --counter, 0 to 2047
171         signal pwm_sync: std_logic;
172         signal pwm_en_p: std_logic_vector(1 to 3);
173         signal pwm_en_n: std_logic_vector(1 to 3);
174         
175         signal income_data_valid: std_logic;
176         
177         signal clk_3M1: std_logic;
178         
179         
180         --  attribute syn_noprune of gpio2 : signal is true;
181         --  attribute syn_preserve of gpio2 : signal is true;
182         --  attribute syn_keep of gpio2 : signal is true;
183         --  attribute syn_hier of gpio2 : signal is true;
184
185 begin
186         -- PLL as a reset generator
187         
188         --zesileni signalu GPIO CLK
189         copyclk2: CLKINT
190         port map (
191                 a => gpio4,
192                 y => gpio_clk
193         );
194         
195         
196         qcount: qcounter
197         port map (
198                 clock => gpio_clk,
199                 reset => '0',
200                 a0 => irc_a,
201                 b0 => irc_b,
202                 qcount => position,
203                 a_rise => open,
204                 a_fall => open,
205                 b_rise => open,
206                 b_fall => open,
207                 ab_event => open,
208                 ab_error => open
209         );
210         
211         pwm_block: for i in pwm_n downto 1 generate
212                 pwm_map: mcpwm
213                 generic map (
214                         pwm_width => pwm_width
215                 )
216                 port map (
217                         clock => gpio_clk,                              --50 Mhz clk from gpclk on raspberry
218                         sync => pwm_sync,                               --counter restarts
219                         data_valid => income_data_valid,                        
220                         failsafe => '0',
221                         --
222                         -- pwm config bits & match word
223                         --
224                         en_n => pwm_en_n(i),                            --enable positive pwm
225                         en_p => pwm_en_p(i),                            --enable "negative" ->activate shutdown
226                         match => pwm_match(i),
227                         count => pwm_count,
228                         -- outputs
229                         out_p => pwm(i),                                --positive signal
230                         out_n => shdn(i)                                --reverse signal is in shutdown mode
231                 );
232         end generate;
233         
234         
235         div8_map: div8 
236         port map(
237                 --reset => income_data_valid,
238                 clk_in => gpio_clk,
239                 clk_out => clk_3M1
240         );
241
242         
243         
244         --   pll: pll50to200
245         --     port map (
246         --       powerdown => '1',
247         --       clka => pll_clkin,
248         --       gla => pll_clkout,
249         --       lock => pll_lock);
250         -- --  reset <= not pll_lock;
251         --   reset <= '0';                         -- TODO: apply reset for good failsafe
252                                            -- upon power-on
253         --   clock <= clkm;
254
255         dummy_unused <= gpio2 and gpio3  and gpio4 and
256                 gpio5 and gpio6 and
257                 gpio12 and gpio13 and gpio14 and
258                 gpio15 and gpio16 and gpio19 and
259                 gpio20 and gpio21 and gpio26 and
260                 stat(1) and stat(2) and stat(3) and
261                 hal_in(1) and hal_in(2) and hal_in(3) and
262                 irc_i and power_stat and 
263                 adc_miso and 
264                 rs485_rxd and
265                 can_rx and can_tx and
266                 dip_sw(1) and dip_sw(2) and dip_sw(3) and
267                 irc_a and irc_b and
268                 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
269                 gpio8  and gpio11 and gpio7 and gpio10 and
270                 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
271                         
272         rs485_txd <= '1';
273         rs485_dir <= '0';
274
275
276         --shdn(1) <= '0';
277         --shdn(2) <= '0';
278         --shdn(3) <= '1';
279
280         --pwm(1) <= '0';
281         --pwm(2) <= '0';
282         --pwm(3) <= '0';
283         
284         process
285         begin
286                 wait until (gpio_clk'event and gpio_clk='1');
287                 IF(pwm_count = pwm_period) THEN                         
288                 --end of period reached
289                         pwm_count <= (others=>'0');      --reset counter
290                         pwm_sync <= '1';                                -- inform PWM logic about new period start
291                 ELSE                                                    --end of period not reached
292                         pwm_count <= std_logic_vector(unsigned(pwm_count)+1);           --increment counter
293                         pwm_sync <= '0';
294                 END IF;
295         end process;
296         
297         process
298         begin
299                 --position is obtained on rising edge -> we should write it on next cycle
300                 wait until (gpio_clk'event and gpio_clk='1');
301                 
302                 --SCLK edge detection
303                 spiclk_old(0)<=gpio11;
304                 spiclk_old(1)<=spiclk_old(0);
305                 
306                 --SS edge detection
307                 ce0_old(0)<=gpio7;
308                 ce0_old(1)<=ce0_old(0);
309                 
310                 if (spiclk_old="01") then --rising edge, faze cteni
311                         if (gpio7 = '0') then             -- SPI CS must be selected
312                                 -- shift serial data into dat_reg on each rising edge
313                                 -- of SCK, MSB first
314                                 dat_reg(95 downto 0) <= dat_reg(94 downto 0) & gpio10;
315                                 end if;
316                 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
317                         if (gpio7 = '0') then
318                                 gpio9 <= dat_reg(95); --zapisujeme nejdriv MSB
319                         end if;
320                 end if;
321                 
322                         
323                 --sestupna hrana SS, pripravime data pro prenos
324                 if (ce0_old = "10" ) then 
325                         income_data_valid<='0';
326                         dat_reg(95 downto 64) <= position(31 downto 0); --pozice
327                         dat_reg(63 downto 61) <= hal_in(1 to 3); --halovy sondy
328                         dat_reg(60 downto 36) <= (others => '1'); --let the rest fill with ones
329                         dat_reg(35 downto 0) <= adc_channels(35 downto 0); --current mesurments
330                         adc_reset<='0'; --remove reset flag, and wait on its rising edge
331                 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
332                         adc_reset<=dat_reg(95);
333                         pwm_en_p(1 to 3)<=dat_reg(94 downto 92);
334                         pwm_en_n(1 to 3)<=dat_reg(91 downto 89);
335                         --11 bit pwm TODO: make it generic
336                         pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(34 downto 24);
337                         pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(22 downto 12);
338                         pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(10 downto 0);
339                         income_data_valid<='1';
340                 end if;
341         end process;
342         
343         process 
344                 variable data_ready : std_logic;
345                 variable channel: channel_type;
346                 variable reset_re: std_logic:='0';
347                 variable reset_count: integer:=0;
348         begin
349                 wait until (clk_3M1'event and clk_3M1='1');
350                 
351                 --reset rising edge detection
352                 adc_rst_old(0)<=adc_reset;
353                 adc_rst_old(1)<=adc_rst_old(0);
354                 
355                 if (adc_rst_old="01") then
356                         reset_re:='1';
357                 end if;
358                 
359                 case state is
360                         when reset=>
361                                 reset_re:='0'; --clear reset flag
362                                 adc_scs<='1'; --active-low SS
363                                 adc_sclk<='0'; --lower clock
364                                 data_ready:='0'; 
365                                 --addresse are CH(A2,A1,A0): CH0:(0,0,1),CH1:(1,0,1),CH2:(0,1,0)
366                                 adc_address<="001101010";
367                                 channel:=ch0;
368                                 adc_channels(35 downto 0)<=(others=>'1'); --for debug only - remove this line!
369                                 adc_data(11 downto 0)<=(others=>'1');
370                                 reset_count:=0;
371                                 state<=rst_wait;
372                         when rst_wait=>
373                                 if (reset_count<10) then
374                                         reset_count:=reset_count+1;
375                                         if (reset_count=7) then
376                                                 adc_scs<='0'; --give the adc some time to prepare before trensfer
377                                         end if;
378                                 else
379                                         state<=f1;
380                                 end if;
381                         when f1=> --1st 'fallin edge' - its not falling edge in any case-if rst clock is low before  
382                                 adc_sclk<='0'; --clk
383                                 adc_mosi<='1'; --start bit
384                                 state<=r1; --next state
385                         when r1=>       --1st rising edge (adc gets the start bit, we get date..)
386                                 adc_sclk<='1'; 
387                                 adc_data(5)<=adc_miso;
388                                 state<=f2;
389                         when f2=> --2nd falling edge
390                                 adc_sclk<='0';
391                                 adc_mosi<=adc_address(8); --A2 address
392                                 state<=r2;
393                         when r2=> --2nd rising edge (adc gets A2 address)
394                                 adc_sclk<='1';
395                                 adc_data(4)<=adc_miso;
396                                 state<=f3;
397                         when f3=> --3rd falling edge 
398                                 adc_sclk<='0';
399                                 adc_mosi<=adc_address(7); --A1 address
400                                 state<=r3;
401                         when r3=> --rising edge
402                                 adc_sclk<='1';
403                                 adc_data(3)<=adc_miso;
404                                 state<=f4;      
405                         when f4=> --4th falling edge
406                                 adc_sclk<='0';
407                                 adc_mosi<=adc_address(6); --A0 address
408                                 --shift the addresses
409                                 adc_address(8 downto 0)<=adc_address(5 downto 0) & adc_address(8 downto 6); 
410                                 state<=r4;
411                         when r4=> --rising edge
412                                 adc_sclk<='1';
413                                 adc_data(2)<=adc_miso;
414                                 state<=f5;      
415                         when f5=> --5th falling edge
416                                 adc_sclk<='0';
417                                 adc_mosi<='0'; --MODE (LOW -12bit)
418                                 state<=r5;
419                         when r5=> --rising edge
420                                 adc_sclk<='1';
421                                 adc_data(1)<=adc_miso;
422                                 state<=f6;      
423                         when f6=> --6th falling edge
424                                 adc_sclk<='0';
425                                 adc_mosi<='1'; --SGL/DIF (HIGH - SGL=Single Ended)
426                                 state<=r6;
427                         when r6=> --6th rising edge (we read last bit of conversion, adc gets SGL/DIF)
428                                 adc_sclk<='1';
429                                 adc_data(0)<=adc_miso;
430                                 state<=f7;              
431                         when f7=> -- 7th falling edge
432                                 adc_sclk<='0';
433                                 adc_mosi<='0'; --PD1 (power down - PD1=PD0=0 -> power down between conversion)
434                                 state<=r7;
435                         when r7=> --7th rising edge, data ready
436                                 adc_sclk<='1';
437                                 if (data_ready='1') then
438                                         case channel is
439                                                 when ch0=>
440                                                         adc_channels(35 downto 24)<=adc_data(11 downto 0);
441                                                         --adc_channels(35 downto 24)<=(others=>'0');
442                                                         channel:=ch1;
443                                                 when ch1=>
444                                                         adc_channels(23 downto 12)<=adc_data(11 downto 0);
445                                                         --adc_channels(23 downto 12)<=(others=>'1');
446                                                         channel:=ch2;
447                                                 when ch2=>
448                                                         adc_channels(11 downto 0)<=adc_data(11 downto 0);
449                                                         --adc_channels(11 downto 0)<=(others=>'0');
450                                                         channel:=ch0;
451                                         end case;
452                                 end if;
453                                 data_ready:='1';
454                                 state<=f8;      
455                         when f8=> --8th falling edge
456                                 adc_sclk<='0';
457                                 adc_mosi<='0'; --PD0
458                                 state<=r8;
459                         when r8=> --8th rising edge (adc gets PD0)
460                                 adc_sclk<='1';
461                                 state<=f9;
462                         when f9=> --9th falling edge busy state between conversion (we write nothing)
463                                 adc_sclk<='0';
464                                 state<=r9;
465                         when r9=>  --9th rising edge (we nor ads get nothing)
466                                 adc_sclk<='1';
467                                 state<=f10;
468                         when f10=> --10th falling edge
469                                 adc_sclk<='0';
470                                 state<=r10;
471                         when r10=>  --10th rising edge (we read 1. bit of conversion)
472                                 adc_sclk<='1';
473                                 adc_data(11)<=adc_miso;
474                                 state<=f11;
475                         when f11=>
476                                 adc_sclk<='0';
477                                 state<=r11;
478                         when r11=>  --11th rising edge
479                                 adc_sclk<='1';
480                                 adc_data(10)<=adc_miso;
481                                 state<=f12;
482                         when f12=>
483                                 adc_sclk<='0';
484                                 state<=r12;
485                         when r12=>  --12th rising edge
486                                 adc_sclk<='1';
487                                 adc_data(9)<=adc_miso;
488                                 state<=f13;
489                         when f13=>
490                                 adc_sclk<='0';
491                                 state<=r13;
492                         when r13=>  --13th rising edge
493                                 adc_sclk<='1';
494                                 adc_data(8)<=adc_miso;
495                                 state<=f14;
496                         when f14=>
497                                 adc_sclk<='0';
498                                 state<=r14;
499                         when r14=>  --14th rising edge
500                                 adc_sclk<='1';
501                                 adc_data(7)<=adc_miso;
502                                 state<=f15;
503                         when f15=>
504                                 adc_sclk<='0';
505                                 --for rising edge detection in next cycle
506                                 state<=r15;
507                         when r15=> --15th rising edge
508                                 adc_sclk<='1';
509                                 adc_data(6)<=adc_miso;
510                                 if (reset_re='1') then --we check rising edge of reset 
511                                         state<=reset;
512                                 else
513                                         state<=f1;
514                                 end if;
515                 end case;
516         end process;
517                         
518         
519                 
520 end behavioral;
521