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
144 component adc_reader is
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
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);
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);
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);
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);
184 signal income_data_valid: std_logic;
186 signal clk_3M1: std_logic;
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;
196 -- PLL as a reset generator
198 --zesileni signalu GPIO CLK
221 pwm_block: for i in pwm_n downto 1 generate
224 pwm_width => pwm_width
227 clock => gpio_clk, --50 Mhz clk from gpclk on raspberry
228 sync => pwm_sync, --counter restarts
229 data_valid => income_data_valid,
232 -- pwm config bits & match word
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),
239 out_p => pwm_sig(i), --positive signal
240 out_n => shdn(i) --reverse signal is in shutdown mode
247 --reset => income_data_valid,
252 adc_reader_map: adc_reader
255 adc_reset => adc_reset,
256 adc_miso => adc_miso,
257 adc_channels => adc_channels,
258 adc_sclk => adc_sclk,
260 adc_mosi => adc_mosi,
261 measur_count => adc_m_count
270 -- clka => pll_clkin,
271 -- gla => pll_clkout,
272 -- lock => pll_lock);
273 -- -- reset <= not pll_lock;
274 -- reset <= '0'; -- TODO: apply reset for good failsafe
278 dummy_unused <= gpio2 and gpio3 and gpio4 and
280 gpio12 and gpio13 and gpio14 and
281 gpio15 and gpio16 and gpio19 and
282 gpio20 and gpio21 and gpio26 and
283 stat(1) and stat(2) and stat(3) and
284 hal_in(1) and hal_in(2) and hal_in(3) and
285 irc_i and power_stat and
288 can_rx and can_tx and
289 dip_sw(1) and dip_sw(2) and dip_sw(3) and
291 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
292 gpio8 and gpio11 and gpio7 and gpio10 and
293 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
299 pwm(1) <= pwm_sig(1) and dip_sw(1);
300 pwm(2) <= pwm_sig(2) and dip_sw(2);
301 pwm(3) <= pwm_sig(3) and dip_sw(3);
306 wait until (irc_i'event and irc_i='1');
307 index_position(11 downto 0)<=position(11 downto 0);
312 wait until (gpio_clk'event and gpio_clk='1');
313 IF(pwm_count = pwm_period) THEN
314 --end of period reached
315 pwm_count <= (others=>'0'); --reset counter
316 pwm_sync <= '1'; -- inform PWM logic about new period start
317 ELSE --end of period not reached
318 pwm_count <= std_logic_vector(unsigned(pwm_count)+1); --increment counter
325 --position is obtained on rising edge -> we should write it on next cycle
326 wait until (gpio_clk'event and gpio_clk='1');
328 --SCLK edge detection
329 spiclk_old(0)<=gpio11;
330 spiclk_old(1)<=spiclk_old(0);
334 ce0_old(1)<=ce0_old(0);
336 if (spiclk_old="01") then --rising edge, faze cteni
337 if (gpio7 = '0') then -- SPI CS must be selected
338 -- shift serial data into dat_reg on each rising edge
340 dat_reg(127 downto 0) <= dat_reg(126 downto 0) & gpio10;
342 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
343 if (gpio7 = '0') then
344 gpio9 <= dat_reg(127); --zapisujeme nejdriv MSB
349 --sestupna hrana SS, pripravime data pro prenos
350 if (ce0_old = "10" ) then
351 income_data_valid<='0';
352 dat_reg(127 downto 96) <= position(31 downto 0); --pozice
353 dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
354 dat_reg(92 downto 81) <= index_position(11 downto 0); --position of irc_i
355 dat_reg(80 downto 72) <=adc_m_count(8 downto 0); --count of measurments
356 --data order schould be: ch2 downto ch0 downto ch1
357 dat_reg(71 downto 0) <= adc_channels(71 downto 0); --current mesurments
358 adc_reset<='0'; --remove reset flag, and wait on its rising edge
359 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
361 pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
362 pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
363 --11 bit pwm TODO: make it generic
364 pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(66 downto 56);
365 pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(55 downto 45);
367 pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(42 downto 32);
368 income_data_valid<='1';