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_pmsm_control 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_pmsm_control is
92 attribute syn_noprune :boolean;
93 attribute syn_preserve :boolean;
94 attribute syn_keep :boolean;
95 attribute syn_hier :boolean;
100 powerdown, clka: in std_logic;
101 lock, gla: out std_logic
106 port (A: in std_logic; Y: out std_logic);
113 a0, b0: in std_logic;
114 qcount: out std_logic_vector (31 downto 0);
115 a_rise, a_fall, b_rise, b_fall, ab_event: out std_logic;
116 ab_error: out std_logic
126 sync: in std_logic; --flag that counter "restarts-overflows"
127 data_valid:in std_logic; --indicates data is consistent
128 failsafe: in std_logic; --turn off both transistors
129 en_p, en_n: in std_logic; --enable positive & enable shutdown
130 match: in std_logic_vector (pwm_width-1 downto 0); --posion of counter when we swap output logic
131 count: in std_logic_vector (pwm_width-1 downto 0); --we use an external counter
132 out_p, out_n: out std_logic --pwm outputs: positive & shutdown
133 --TODO add the rest of pwm signals, swap match to pwm_word
137 --frequency division by 12
140 clk_in: in std_logic;
145 component adc_reader is
147 clk: in std_logic; --input clk
148 adc_reset: in std_logic;
149 adc_miso: in std_logic; --spi master in slave out
150 adc_channels: out std_logic_vector (35 downto 0); --consistent data of 3 channels
151 adc_sclk: out std_logic; --spi clk
152 adc_scs: out std_logic; --spi slave select
153 adc_mosi: out std_logic; --spi master out slave in
154 measur_count: out std_logic_vector(8 downto 0) --number of accumulated measurments
160 signal adc_reset : std_logic;
161 signal adc_channels: std_logic_vector(71 downto 0);
162 signal adc_m_count: std_logic_vector(8 downto 0);
164 --clock signals for logic and master fail monitoring
165 signal gpio_clk: std_logic;
166 signal pll_clkin, pll_clkout, pll_lock: std_logic;
167 signal clkmon_dly1, clkmon_dly2: std_logic;
168 signal clkmon_fail, clkmon_fail_next: std_logic;
169 signal clkmon_wdg: integer range 0 to 6;
170 signal reset_sync, reset_async: std_logic;
171 signal failsafe, next_failsafe: std_logic;
173 --RPi SPI interface signals named aliases
174 signal spi_clk, spi_ce, spi_mosi, spi_miso : std_logic;
175 signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
177 --signal pwm_in, pwm_dir_in: std_logic;
178 signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
179 signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
180 signal index_position: std_logic_vector(11 downto 0); --pozice irc_i
181 signal ce0_old: std_logic_vector(1 downto 0);
184 constant pwm_n: natural := 3; --number of pwm outputs
185 --number of ticks per pwm cycle, 2^11=2048
186 constant pwm_period : std_logic_vector (pwm_width-1 downto 0) := (others=>'1');
187 type pwm_res_type is array(1 to 3) of std_logic_vector (pwm_width-1 downto 0);
189 signal pwm_match: pwm_res_type; --point of reversion of pwm output, 0 to 2047
190 signal pwm_count: std_logic_vector (pwm_width-1 downto 0); --counter, 0 to 2047
191 signal pwm_sync: std_logic;
192 signal pwm_en_p: std_logic_vector(1 to 3);
193 signal pwm_en_n: std_logic_vector(1 to 3);
194 signal pwm_sig: std_logic_vector(1 to 3);
196 signal income_data_valid: std_logic;
198 signal clk_4M17: std_logic;
200 -- irc signals processing
201 signal irc_i_prev: std_logic;
203 -- attribute syn_noprune of gpio2 : signal is true;
204 -- attribute syn_preserve of gpio2 : signal is true;
205 -- attribute syn_keep of gpio2 : signal is true;
206 -- attribute syn_hier of gpio2 : signal is true;
209 -- PLL as a reset generator
211 --zesileni signalu GPIO CLK
225 -- the failasfe signal from communication block if CRC is used
226 next_failsafe <= '0';
228 reset_async <= not pll_lock or clkmon_fail;
230 pll_clkin <= gpio_clk;
247 pwm_block: for i in pwm_n downto 1 generate
250 pwm_width => pwm_width
253 clock => gpio_clk, --50 Mhz clk from gpclk on raspberry
254 sync => pwm_sync, --counter restarts
255 data_valid => income_data_valid,
256 failsafe => failsafe,
258 -- pwm config bits & match word
260 en_n => pwm_en_n(i), --enable positive pwm
261 en_p => pwm_en_p(i), --enable "negative" ->activate shutdown
262 match => pwm_match(i),
265 out_p => pwm_sig(i), --positive signal
266 out_n => shdn(i) --reverse signal is in shutdown mode
273 --reset => income_data_valid,
278 -- ADC needs 3.2 MHz clk when powered from +5V Vcc
279 -- 2.0 MHz clk when +2.7V Vcc
280 -- on the input is 4.17Mhz,but this frequency is divided inside adc_reader by 2 to 2.08 Mhz,
281 -- while we use +3.3V Vcc
282 adc_reader_map: adc_reader
285 adc_reset => adc_reset,
286 adc_miso => adc_miso,
287 adc_channels => adc_channels,
288 adc_sclk => adc_sclk,
290 adc_mosi => adc_mosi,
291 measur_count => adc_m_count
295 dummy_unused <= gpio2 and gpio3 and
297 gpio12 and gpio13 and gpio14 and
298 gpio15 and gpio16 and gpio19 and
299 gpio20 and gpio21 and gpio26 and
300 stat(1) and stat(2) and stat(3) and
301 hal_in(1) and hal_in(2) and hal_in(3) and
302 irc_i and power_stat and
305 can_rx and can_tx and
306 dip_sw(1) and dip_sw(2) and dip_sw(3) and
308 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
310 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
320 pwm(1) <= pwm_sig(1) and dip_sw(1);
321 pwm(2) <= pwm_sig(2) and dip_sw(2);
322 pwm(3) <= pwm_sig(3) and dip_sw(3);
327 wait until (gpio_clk'event and gpio_clk='1');
328 if irc_i_prev = '0' and irc_i = '1' then
329 index_position(11 downto 0)<=position(11 downto 0);
336 wait until (gpio_clk'event and gpio_clk='1');
337 IF(pwm_count = pwm_period) THEN
338 --end of period reached
339 pwm_count <= (others=>'0'); --reset counter
340 pwm_sync <= '1'; -- inform PWM logic about new period start
341 ELSE --end of period not reached
342 pwm_count <= std_logic_vector(unsigned(pwm_count)+1); --increment counter
349 --position is obtained on rising edge -> we should write it on next cycle
350 wait until (gpio_clk'event and gpio_clk='1');
352 --SCLK edge detection
353 spiclk_old(0)<=spi_clk;
354 spiclk_old(1)<=spiclk_old(0);
358 ce0_old(1)<=ce0_old(0);
360 if (spiclk_old="01") then --rising edge, faze cteni
361 if (spi_ce = '0') then -- SPI CS must be selected
362 -- shift serial data into dat_reg on each rising edge
364 dat_reg(127 downto 0) <= dat_reg(126 downto 0) & spi_mosi;
366 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
367 if (spi_ce = '0') then
368 spi_miso <= dat_reg(127); --zapisujeme nejdriv MSB
373 --sestupna hrana SS, pripravime data pro prenos
374 if (ce0_old = "10" ) then
375 income_data_valid<='0';
376 dat_reg(127 downto 96) <= position(31 downto 0); --pozice
377 dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
378 dat_reg(92 downto 81) <= index_position(11 downto 0); --position of irc_i
379 dat_reg(80 downto 72) <=adc_m_count(8 downto 0); --count of measurments
380 --data order schould be: ch2 downto ch0 downto ch1
381 dat_reg(71 downto 0) <= adc_channels(71 downto 0); --current mesurments
382 adc_reset<='0'; --remove reset flag, and wait on its rising edge
383 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
385 pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
386 pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
387 --11 bit pwm TODO: make it generic
388 pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(66 downto 56);
389 pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(55 downto 45);
391 pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(42 downto 32);
392 income_data_valid<='1';
396 clock_monitor: process (pll_clkout, gpio_clk, clkmon_dly1, clkmon_wdg, clkmon_fail_next)
398 if pll_clkout'event and pll_clkout = '1' then
399 clkmon_dly1 <= gpio_clk;
400 clkmon_dly2 <= clkmon_dly1;
401 if clkmon_dly1 = '0' and clkmon_dly2 = '1' then
403 clkmon_fail_next <= '0';
404 elsif clkmon_wdg > 0 then
405 clkmon_wdg <= clkmon_wdg - 1;
406 clkmon_fail_next <= '0';
409 clkmon_fail_next <= '1';
411 clkmon_fail <= clkmon_fail_next;
415 async_rst: process (gpio_clk, reset_async, reset_sync)
417 if reset_async = '1' then
419 elsif gpio_clk'event and gpio_clk = '1' then
420 failsafe <= next_failsafe or reset_sync;
424 sync_rst: process (gpio_clk, reset_async)
426 if gpio_clk'event and gpio_clk = '1' then
427 reset_sync <= reset_async;