2 -- * LXPWR slave part *
3 -- common sioreg & common counter for several ADC&PWM blocks
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>
14 use ieee.std_logic_1164.all;
15 use ieee.numeric_std.all;
18 entity rpi_mc_simple_dc is
20 pwm_width : natural:=11
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
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);
57 hal_in: in std_logic_vector (1 to 3);
63 power_stat: in std_logic;
65 adc_miso: in std_logic;
66 adc_mosi: out std_logic;
67 adc_sclk: out std_logic;
68 adc_scs: out std_logic;
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;
77 rs485_rxd: in std_logic;
78 rs485_txd: out std_logic;
79 rs485_dir: out std_logic;
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
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;
97 -- component pll50to200
99 -- powerdown, clka: in std_logic;
100 -- lock, gla: out std_logic
105 port (A: in std_logic; Y: out 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
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
138 --reset: in std_logic;
139 clk_in: in std_logic;
140 clk_out: out std_logic
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;
148 type channel_type is (ch0, ch1, ch2);
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);
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);
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);
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);
175 signal income_data_valid: std_logic;
177 signal clk_3M1: std_logic;
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;
186 -- PLL as a reset generator
188 --zesileni signalu GPIO CLK
211 pwm_block: for i in pwm_n downto 1 generate
214 pwm_width => pwm_width
217 clock => gpio_clk, --50 Mhz clk from gpclk on raspberry
218 sync => pwm_sync, --counter restarts
219 data_valid => income_data_valid,
222 -- pwm config bits & match word
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),
229 out_p => pwm(i), --positive signal
230 out_n => shdn(i) --reverse signal is in shutdown mode
237 --reset => income_data_valid,
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
255 dummy_unused <= gpio2 and gpio3 and gpio4 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
265 can_rx and can_tx and
266 dip_sw(1) and dip_sw(2) and dip_sw(3) 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;
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
299 --position is obtained on rising edge -> we should write it on next cycle
300 wait until (gpio_clk'event and gpio_clk='1');
302 --SCLK edge detection
303 spiclk_old(0)<=gpio11;
304 spiclk_old(1)<=spiclk_old(0);
308 ce0_old(1)<=ce0_old(0);
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
314 dat_reg(95 downto 0) <= dat_reg(94 downto 0) & gpio10;
316 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
317 if (gpio7 = '0') then
318 gpio9 <= dat_reg(95); --zapisujeme nejdriv MSB
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';
344 variable data_ready : std_logic;
345 variable channel: channel_type;
346 variable reset_re: std_logic:='0';
347 variable reset_count: integer:=0;
349 wait until (clk_3M1'event and clk_3M1='1');
351 --reset rising edge detection
352 adc_rst_old(0)<=adc_reset;
353 adc_rst_old(1)<=adc_rst_old(0);
355 if (adc_rst_old="01") then
361 reset_re:='0'; --clear reset flag
362 adc_scs<='1'; --active-low SS
363 adc_sclk<='0'; --lower clock
365 --addresse are CH(A2,A1,A0): CH0:(0,0,1),CH1:(1,0,1),CH2:(0,1,0)
366 adc_address<="001101010";
368 adc_channels(35 downto 0)<=(others=>'1'); --for debug only - remove this line!
369 adc_data(11 downto 0)<=(others=>'1');
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
381 when f1=> --1st 'fallin edge' - its not falling edge in any case-if rst clock is low before
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..)
387 adc_data(5)<=adc_miso;
389 when f2=> --2nd falling edge
391 adc_mosi<=adc_address(8); --A2 address
393 when r2=> --2nd rising edge (adc gets A2 address)
395 adc_data(4)<=adc_miso;
397 when f3=> --3rd falling edge
399 adc_mosi<=adc_address(7); --A1 address
401 when r3=> --rising edge
403 adc_data(3)<=adc_miso;
405 when f4=> --4th falling edge
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);
411 when r4=> --rising edge
413 adc_data(2)<=adc_miso;
415 when f5=> --5th falling edge
417 adc_mosi<='0'; --MODE (LOW -12bit)
419 when r5=> --rising edge
421 adc_data(1)<=adc_miso;
423 when f6=> --6th falling edge
425 adc_mosi<='1'; --SGL/DIF (HIGH - SGL=Single Ended)
427 when r6=> --6th rising edge (we read last bit of conversion, adc gets SGL/DIF)
429 adc_data(0)<=adc_miso;
431 when f7=> -- 7th falling edge
433 adc_mosi<='0'; --PD1 (power down - PD1=PD0=0 -> power down between conversion)
435 when r7=> --7th rising edge, data ready
437 if (data_ready='1') then
440 adc_channels(35 downto 24)<=adc_data(11 downto 0);
441 --adc_channels(35 downto 24)<=(others=>'0');
444 adc_channels(23 downto 12)<=adc_data(11 downto 0);
445 --adc_channels(23 downto 12)<=(others=>'1');
448 adc_channels(11 downto 0)<=adc_data(11 downto 0);
449 --adc_channels(11 downto 0)<=(others=>'0');
455 when f8=> --8th falling edge
459 when r8=> --8th rising edge (adc gets PD0)
462 when f9=> --9th falling edge busy state between conversion (we write nothing)
465 when r9=> --9th rising edge (we nor ads get nothing)
468 when f10=> --10th falling edge
471 when r10=> --10th rising edge (we read 1. bit of conversion)
473 adc_data(11)<=adc_miso;
478 when r11=> --11th rising edge
480 adc_data(10)<=adc_miso;
485 when r12=> --12th rising edge
487 adc_data(9)<=adc_miso;
492 when r13=> --13th rising edge
494 adc_data(8)<=adc_miso;
499 when r14=> --14th rising edge
501 adc_data(7)<=adc_miso;
505 --for rising edge detection in next cycle
507 when r15=> --15th rising edge
509 adc_data(6)<=adc_miso;
510 if (reset_re='1') then --we check rising edge of reset