2 -- * Raspberry Pi BLDC/PMSM motor control design for RPi-MI-1 board *
3 -- The toplevel component file
5 -- (c) 2015 Martin Prudek <prudemar@fel.cvut.cz>
6 -- Czech Technical University in Prague
8 -- Project supervision and original project idea
9 -- idea by Pavel Pisa <pisa@cmp.felk.cvut.cz>
11 -- Related RPi-MI-1 hardware is designed by Petr Porazil,
12 -- PiKRON Ltd <http://www.pikron.com>
14 -- VHDL design reuses some components and concepts from
15 -- LXPWR motion power stage board and LX_RoCoN system
16 -- developed at PiKRON Ltd with base code implemented
17 -- by Marek Peca <hefaistos@gmail.com>
19 -- license: GNU LGPL and GPLv3+
23 use ieee.std_logic_1164.all;
24 use ieee.numeric_std.all;
27 entity rpi_pmsm_control is
29 pwm_width : natural:=11
32 gpio2: in std_logic; -- SDA
33 gpio3: in std_logic; -- SCL
34 gpio4: in std_logic; -- CLK
35 gpio14: in std_logic; -- Tx
36 gpio15: in std_logic; -- Rx
37 gpio17: in std_logic; -- RTS
38 gpio18: in std_logic; -- PWM0/PCMCLK
39 gpio27: in std_logic; -- SD1DAT3
40 gpio22: in std_logic; -- SD1CLK
41 gpio23: in std_logic; -- SD1CMD
42 gpio24: in std_logic; -- SD1DAT0
43 gpio10: in std_logic; -- SPI0MOSI
44 gpio9: out std_logic; -- SPI0MISO
45 gpio25: in std_logic; -- SD1DAT1
46 gpio11: in std_logic; -- SPI0SCLK
47 gpio8: in std_logic; -- SPI0CE0
48 gpio7: in std_logic; -- SPI0CE1
49 gpio5: in std_logic; -- GPCLK1
50 gpio6: in std_logic; -- GPCLK2
51 gpio12: in std_logic; -- PWM0
52 gpio13: in std_logic; -- PWM1
53 gpio19: in std_logic; -- PWM1/SPI1MISO/PCMFS
54 gpio16: in std_logic; -- SPI1CE2
55 gpio26: in std_logic; -- SD1DAT2
56 gpio20: in std_logic; -- SPI1MOSI/PCMDIN/GPCLK0
57 gpio21: in std_logic; -- SPI1SCLK/PCMDOUT/GPCLK1
60 -- Each PWM signal has cooresponding shutdown
61 pwm: out std_logic_vector (1 to 3);
62 shdn: out std_logic_vector (1 to 3);
63 -- Fault/power stage status
64 stat: in std_logic_vector (1 to 3);
66 hal_in: in std_logic_vector (1 to 3);
72 power_stat: in std_logic;
74 adc_miso: in std_logic;
75 adc_mosi: out std_logic;
76 adc_sclk: out std_logic;
77 adc_scs: out std_logic;
79 ext_miso: in std_logic; --master in slave out
80 ext_mosi: in std_logic; --master out slave in
81 ext_sclk: in std_logic;
82 ext_scs0: in std_logic;
83 ext_scs1: in std_logic;
84 ext_scs2: in std_logic;
86 rs485_rxd: in std_logic;
87 rs485_txd: out std_logic;
88 rs485_dir: out std_logic;
93 dip_sw: in std_logic_vector (1 to 3); --na desce je prohozene cislovanni
94 -- Unused terminal to keep design tools silent
95 dummy_unused : out std_logic
100 architecture behavioral of rpi_pmsm_control is
101 attribute syn_noprune :boolean;
102 attribute syn_preserve :boolean;
103 attribute syn_keep :boolean;
104 attribute syn_hier :boolean;
109 powerdown, clka: in std_logic;
110 lock, gla: out std_logic
115 port (A: in std_logic; Y: out std_logic);
122 a0, b0: in std_logic;
123 qcount: out std_logic_vector (31 downto 0);
124 a_rise, a_fall, b_rise, b_fall, ab_event: out std_logic;
125 ab_error: out std_logic
135 sync: in std_logic; --flag that counter "restarts-overflows"
136 data_valid:in std_logic; --indicates data is consistent
137 failsafe: in std_logic; --turn off both transistors
138 en_p, en_n: in std_logic; --enable positive & enable shutdown
139 match: in std_logic_vector (pwm_width-1 downto 0); --posion of counter when we swap output logic
140 count: in std_logic_vector (pwm_width-1 downto 0); --we use an external counter
141 out_p, out_n: out std_logic --pwm outputs: positive & shutdown
142 --TODO add the rest of pwm signals, swap match to pwm_word
146 --frequency division by 12
149 cnt_width_g : natural := 4
153 clk_i : in std_logic; --clk to divide
154 en_i : in std_logic; --enable bit?
155 reset_i : in std_logic; --asynch. reset
156 ratio_i : in std_logic_vector(cnt_width_g-1 downto 0);--initial value
157 q_out_o : out std_logic --generates puls when counter underflows
161 component adc_reader is
163 clk: in std_logic; --input clk
164 divided_clk : in std_logic; --divided clk - value suitable to sourcing voltage
165 adc_reset: in std_logic;
166 adc_miso: in std_logic; --spi master in slave out
167 adc_channels: out std_logic_vector (35 downto 0); --consistent data of 3 channels
168 adc_sclk: out std_logic; --spi clk
169 adc_scs: out std_logic; --spi slave select
170 adc_mosi: out std_logic; --spi master out slave in
171 measur_count: out std_logic_vector(8 downto 0) --number of accumulated measurments
178 clk_i : in std_logic;
185 signal adc_channels: std_logic_vector(71 downto 0);
186 signal adc_m_count: std_logic_vector(8 downto 0);
188 --clock signals for logic and master fail monitoring
189 signal gpio_clk: std_logic;
190 signal pll_clkin, pll_clkout, pll_lock: std_logic;
191 signal clkmon_dly1, clkmon_dly2: std_logic;
192 signal clkmon_fail, clkmon_fail_next: std_logic;
193 signal clkmon_wdg: integer range 0 to 6;
194 signal reset_sync, reset_async: std_logic;
195 signal failsafe, next_failsafe: std_logic;
197 --RPi SPI interface signals named aliases
198 signal spi_clk, spi_ce, spi_mosi, spi_miso : std_logic;
199 signal spiclk_old: std_logic_vector(1 downto 0); --pro detekci hrany SPI hodin
201 --signal pwm_in, pwm_dir_in: std_logic;
202 signal dat_reg : STD_LOGIC_VECTOR (127 downto 0); --shift register for spi
203 signal position: std_logic_vector(31 downto 0); --pozice z qcounteru
204 signal index_position: std_logic_vector(11 downto 0); --pozice irc_i
205 signal ce0_old: std_logic_vector(1 downto 0);
208 constant pwm_n: natural := 3; --number of pwm outputs
209 --number of ticks per pwm cycle, 2^11=2048
210 constant pwm_period : std_logic_vector (pwm_width-1 downto 0) := (others=>'1');
211 type pwm_res_type is array(1 to 3) of std_logic_vector (pwm_width-1 downto 0);
213 signal pwm_match: pwm_res_type; --point of reversion of pwm output, 0 to 2047
214 signal pwm_count: std_logic_vector (pwm_width-1 downto 0); --counter, 0 to 2047
215 signal pwm_sync_at_next: std_logic;
216 signal pwm_sync: std_logic;
217 signal pwm_en_p: std_logic_vector(1 to 3);
218 signal pwm_en_n: std_logic_vector(1 to 3);
219 signal pwm_sig: std_logic_vector(1 to 3);
221 signal income_data_valid: std_logic;
223 signal clk_4M17: std_logic;
225 -- irc signals processing
226 signal irc_i_prev: std_logic;
228 --filetered irc signals
229 signal irc_a_dff3: std_logic;
230 signal irc_b_dff3: std_logic;
232 -- attribute syn_noprune of gpio2 : signal is true;
233 -- attribute syn_preserve of gpio2 : signal is true;
234 -- attribute syn_keep of gpio2 : signal is true;
235 -- attribute syn_hier of gpio2 : signal is true;
238 -- PLL as a reset generator
240 --zesileni signalu GPIO CLK
254 -- the failasfe signal from communication block if CRC is used
255 next_failsafe <= '0';
257 reset_async <= not pll_lock or clkmon_fail;
259 pll_clkin <= gpio_clk;
276 pwm_block: for i in pwm_n downto 1 generate
279 pwm_width => pwm_width
282 clock => gpio_clk, --50 Mhz clk from gpclk on raspberry
283 sync => pwm_sync, --counter restarts
284 data_valid => pwm_sync_at_next,
285 failsafe => failsafe,
287 -- pwm config bits & match word
289 en_n => pwm_en_n(i), --enable positive pwm
290 en_p => pwm_en_p(i), --enable "negative" ->activate shutdown
291 match => pwm_match(i),
294 out_p => pwm_sig(i), --positive signal
295 out_n => shdn(i) --reverse signal is in shutdown mode
305 ratio_i =>"1101", --POZN.: counter detekuje cnt<=1
309 -- ADC needs 3.2 MHz clk when powered from +5V Vcc
310 -- 2.0 MHz clk when +2.7V Vcc
311 -- on the input is 4.17Mhz,but this frequency is divided inside adc_reader by 2 to 2.08 Mhz,
312 -- while we use +3.3V Vcc
313 adc_reader_map: adc_reader
316 divided_clk => clk_4M17,
317 adc_reset => income_data_valid, --reset at each SPI cycle,TODO: replace with PLL reset
318 adc_miso => adc_miso,
319 adc_channels => adc_channels,
320 adc_sclk => adc_sclk,
322 adc_mosi => adc_mosi,
323 measur_count => adc_m_count
341 dummy_unused <= gpio2 and gpio3 and
343 gpio12 and gpio13 and gpio14 and
344 gpio15 and gpio16 and gpio19 and
345 gpio20 and gpio21 and gpio26 and
346 stat(1) and stat(2) and stat(3) and
347 hal_in(1) and hal_in(2) and hal_in(3) and
348 irc_i and power_stat and
351 can_rx and can_tx and
352 dip_sw(1) and dip_sw(2) and dip_sw(3) and
354 gpio17 and gpio18 and gpio27 and gpio22 and gpio23 and gpio24 and gpio25 and
356 ext_scs1 and ext_scs2 and ext_miso and ext_mosi and ext_sclk and ext_scs0;
366 pwm(1) <= pwm_sig(1) and dip_sw(1);
367 pwm(2) <= pwm_sig(2) and dip_sw(2);
368 pwm(3) <= pwm_sig(3) and dip_sw(3);
373 wait until (gpio_clk'event and gpio_clk='1');
374 if irc_i_prev = '0' and irc_i = '1' then
375 index_position(11 downto 0)<=position(11 downto 0);
382 wait until (gpio_clk'event and gpio_clk='1');
383 IF pwm_count = std_logic_vector(unsigned(pwm_period) - 1) THEN
384 --end of period nearly reached
385 --fetch new pwm match data
386 pwm_sync_at_next <= '1';
388 pwm_sync_at_next <= '0';
391 if pwm_sync_at_next='1' then
392 --end of period reached
393 pwm_count <= (others=>'0'); --reset counter
394 pwm_sync <= '1'; -- inform PWM logic about new period start
395 ELSE --end of period not reached
396 pwm_count <= std_logic_vector(unsigned(pwm_count)+1); --increment counter
403 --position is obtained on rising edge -> we should write it on next cycle
404 wait until (gpio_clk'event and gpio_clk='1');
406 --SCLK edge detection
407 spiclk_old(0)<=spi_clk;
408 spiclk_old(1)<=spiclk_old(0);
412 ce0_old(1)<=ce0_old(0);
414 if (spiclk_old="01") then --rising edge, faze cteni
415 if (spi_ce = '0') then -- SPI CS must be selected
416 -- shift serial data into dat_reg on each rising edge
418 dat_reg(127 downto 0) <= dat_reg(126 downto 0) & spi_mosi;
420 elsif (spiclk_old="10" ) then --falling edge, faze zapisu
421 if (spi_ce = '0') then
422 spi_miso <= dat_reg(127); --zapisujeme nejdriv MSB
427 --sestupna hrana SS, pripravime data pro prenos
428 if (ce0_old = "10" ) then
429 income_data_valid<='0';
430 dat_reg(127 downto 96) <= position(31 downto 0); --pozice
431 dat_reg(95 downto 93) <= hal_in(1 to 3); --halovy sondy
432 dat_reg(92 downto 81) <= index_position(11 downto 0); --position of irc_i
433 dat_reg(80 downto 72) <=adc_m_count(8 downto 0); --count of measurments
434 --data order schould be: ch2 downto ch0 downto ch1
435 dat_reg(71 downto 0) <= adc_channels(71 downto 0); --current mesurments
436 spi_miso <= position(31); --prepare the first bit on SE activation
437 elsif (ce0_old = "01") then --rising edge of SS, we should read the data
438 pwm_en_p(1 to 3)<=dat_reg(126 downto 124);
439 pwm_en_n(1 to 3)<=dat_reg(123 downto 121);
440 --usable for up to 16-bit PWM duty cycle resolution (pwm_width):
441 pwm_match(1)(pwm_width-1 downto 0)<=dat_reg(pwm_width+31 downto 32);
442 pwm_match(2)(pwm_width-1 downto 0)<=dat_reg(pwm_width+15 downto 16);
443 pwm_match(3)(pwm_width-1 downto 0)<=dat_reg(pwm_width-1 downto 0);
444 income_data_valid<='1';
448 clock_monitor: process (pll_clkout, gpio_clk, clkmon_dly1, clkmon_wdg, clkmon_fail_next)
450 if pll_clkout'event and pll_clkout = '1' then
451 clkmon_dly1 <= gpio_clk;
452 clkmon_dly2 <= clkmon_dly1;
453 if clkmon_dly1 = '0' and clkmon_dly2 = '1' then
455 clkmon_fail_next <= '0';
456 elsif clkmon_wdg > 0 then
457 clkmon_wdg <= clkmon_wdg - 1;
458 clkmon_fail_next <= '0';
461 clkmon_fail_next <= '1';
463 clkmon_fail <= clkmon_fail_next;
467 async_rst: process (gpio_clk, reset_async, reset_sync)
469 if reset_async = '1' then
471 elsif gpio_clk'event and gpio_clk = '1' then
472 failsafe <= next_failsafe or reset_sync;
476 sync_rst: process (gpio_clk, reset_async)
478 if gpio_clk'event and gpio_clk = '1' then
479 reset_sync <= reset_async;