From a37856cc8156cc5f1bd07eb760ec08627056c752 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Wed, 8 Feb 2017 20:00:18 +0100 Subject: [PATCH] microzed_apo: Include RGB LEDs PWM driver. Signed-off-by: Pavel Pisa --- system/ip/spi_leds_and_enc_1.0/component.xml | 28 ++++-- .../ip/spi_leds_and_enc_1.0/hdl/cnt_div.vhdl | 62 +++++++++++++ .../spi_leds_and_enc_1.0/hdl/pulse_gen.vhdl | 68 ++++++++++++++ .../hdl/spi_leds_and_enc_v1_0.vhd | 92 +++++++++++++++++-- 4 files changed, 237 insertions(+), 13 deletions(-) create mode 100644 system/ip/spi_leds_and_enc_1.0/hdl/cnt_div.vhdl create mode 100644 system/ip/spi_leds_and_enc_1.0/hdl/pulse_gen.vhdl diff --git a/system/ip/spi_leds_and_enc_1.0/component.xml b/system/ip/spi_leds_and_enc_1.0/component.xml index cbb33ae..971a728 100644 --- a/system/ip/spi_leds_and_enc_1.0/component.xml +++ b/system/ip/spi_leds_and_enc_1.0/component.xml @@ -266,7 +266,7 @@ viewChecksum - a5dd367c + 9d17111f @@ -282,7 +282,7 @@ viewChecksum - a5dd367c + 9d17111f @@ -750,14 +750,22 @@ hdl/qcounter_nbit.vhdl vhdlSource + + hdl/pulse_gen.vhdl + vhdlSource + hdl/dff3cke.vhdl vhdlSource + + hdl/cnt_div.vhdl + vhdlSource + hdl/spi_leds_and_enc_v1_0.vhd vhdlSource - CHECKSUM_2b8cd74c + CHECKSUM_1580b40d @@ -778,10 +786,18 @@ hdl/qcounter_nbit.vhdl vhdlSource + + hdl/pulse_gen.vhdl + vhdlSource + hdl/dff3cke.vhdl vhdlSource + + hdl/cnt_div.vhdl + vhdlSource + hdl/spi_leds_and_enc_v1_0.vhd vhdlSource @@ -902,8 +918,8 @@ AXI_Peripheral spi_leds_and_enc_v1.0 - 3 - 2017-02-08T13:24:43Z + 4 + 2017-02-08T18:56:50Z /home/pi/fpga/zynq/canbech-sw/system/ip/spi_leds_and_enc_1.0 @@ -912,7 +928,7 @@ 2016.1 - + diff --git a/system/ip/spi_leds_and_enc_1.0/hdl/cnt_div.vhdl b/system/ip/spi_leds_and_enc_1.0/hdl/cnt_div.vhdl new file mode 100644 index 0000000..e65e562 --- /dev/null +++ b/system/ip/spi_leds_and_enc_1.0/hdl/cnt_div.vhdl @@ -0,0 +1,62 @@ +-- +-- * Counter - divider * +-- +-- part of LXPWR motion control board (c) PiKRON Ltd +-- idea by Pavel Pisa PiKRON Ltd +-- +-- license: BSD +-- +-- This file is used in "RPI PMS motor control" as frequency divider - divides by 6 + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity cnt_div is + generic ( + cnt_width_g : natural := 4 + ); + port + ( + clk_i : in std_logic; --clk to divide + en_i : in std_logic; --enable bit? + reset_i : in std_logic; --asynch. reset + ratio_i : in std_logic_vector(cnt_width_g-1 downto 0);--initial value + q_out_o : out std_logic --generates puls when counter underflows + ); +end cnt_div; + +architecture behavioral of cnt_div is + signal cnt_val_s : natural range 0 to (2**cnt_width_g - 1); --counter value before DFF + signal cnt_val_r : natural range 0 to (2**cnt_width_g - 1); --counter value after DFF +begin + +comb: process (reset_i, en_i, ratio_i, cnt_val_r) + begin + if reset_i = '1' then --reset detection + cnt_val_s <= to_integer(unsigned(ratio_i)); --set initial value + q_out_o <= '0'; --reset output + else + if en_i = '0' then --stop-state + cnt_val_s <= cnt_val_r; --hold the value + q_out_o <= '0'; --reset output + else + if cnt_val_r <= 1 then --counter underflows + cnt_val_s <= to_integer(unsigned(ratio_i)); --set initial value + q_out_o <= '1'; --set output + else + cnt_val_s <= cnt_val_r - 1; --decrement counter + q_out_o <= '0'; --reset output + end if; + end if; + end if; + end process; + +seq: process + begin + wait until clk_i'event and clk_i = '1'; + cnt_val_r <= cnt_val_s; + end process; + +end behavioral; + diff --git a/system/ip/spi_leds_and_enc_1.0/hdl/pulse_gen.vhdl b/system/ip/spi_leds_and_enc_1.0/hdl/pulse_gen.vhdl new file mode 100644 index 0000000..e682b45 --- /dev/null +++ b/system/ip/spi_leds_and_enc_1.0/hdl/pulse_gen.vhdl @@ -0,0 +1,68 @@ +-- +-- * pulse generator * +-- +-- based on code from LXPWR motion control board (c) PiKRON Ltd +-- idea by Pavel Pisa PiKRON Ltd +-- +-- license: BSD +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity pulse_gen is + generic ( + duration_width_g : natural := 4 + ); + port + ( + clk_i : in std_logic; --clk to divide + en_i : in std_logic; --enable bit? + reset_i : in std_logic; --asynch. reset + trigger_i : in std_logic; --start to generate pulse + duration_i : in std_logic_vector(duration_width_g-1 downto 0);--duration/interval of the pulse + q_out_o : out std_logic --generates pulse for given duration + ); +end pulse_gen; + +architecture behavioral of pulse_gen is + signal cnt_val_s : natural range 0 to (2**duration_width_g - 1); --counter value before DFF + signal cnt_val_r : natural range 0 to (2**duration_width_g - 1); --counter value after DFF +begin + +comb: process (reset_i, en_i, duration_i, trigger_i, cnt_val_r) + begin + if reset_i = '1' then --reset detection + cnt_val_s <= 0; --set defined value + q_out_o <= '0'; --reset output + else + if en_i = '0' then --stop-state + cnt_val_s <= cnt_val_r; --hold the value + else + if trigger_i = '1' then --trigger pulse generator + if to_integer(unsigned(duration_i)) = 0 then + q_out_o <= '0'; + else + q_out_o <= '1'; + end if; + cnt_val_s <= to_integer(unsigned(duration_i)); --set initial value + elsif cnt_val_r = 0 then --pulse finished + cnt_val_s <= cnt_val_r; + q_out_o <= '0'; --set output + else + cnt_val_s <= cnt_val_r - 1; --decrement counter + q_out_o <= '1'; --reset output + end if; + end if; + end if; + end process; + +seq: process + begin + wait until clk_i'event and clk_i = '1'; + cnt_val_r <= cnt_val_s; + end process; + +end behavioral; + diff --git a/system/ip/spi_leds_and_enc_1.0/hdl/spi_leds_and_enc_v1_0.vhd b/system/ip/spi_leds_and_enc_1.0/hdl/spi_leds_and_enc_v1_0.vhd index 883ffa4..aca0a68 100644 --- a/system/ip/spi_leds_and_enc_1.0/hdl/spi_leds_and_enc_v1_0.vhd +++ b/system/ip/spi_leds_and_enc_1.0/hdl/spi_leds_and_enc_v1_0.vhd @@ -143,9 +143,40 @@ architecture arch_imp of spi_leds_and_enc_v1_0 is ); end component; + component cnt_div is + generic ( + cnt_width_g : natural := 4 + ); + port + ( + clk_i : in std_logic; --clk to divide + en_i : in std_logic; --enable bit? + reset_i : in std_logic; --asynch. reset + ratio_i : in std_logic_vector(cnt_width_g-1 downto 0);--initial value + q_out_o : out std_logic --generates puls when counter underflows + ); + end component; + + component pulse_gen is + generic ( + duration_width_g : natural := 4 + ); + port ( + clk_i : in std_logic; --clk to divide + en_i : in std_logic; --enable bit? + reset_i : in std_logic; --asynch. reset + trigger_i : in std_logic; --start to generate pulse + duration_i : in std_logic_vector(duration_width_g-1 downto 0);--duration/interval of the pulse + q_out_o : out std_logic --generates pulse for given duration + ); + end component; + constant spi_data_width : integer := 48; constant spi_clk_div : integer := 10; constant enc_number : integer := 3; + constant pwm_width : integer := 8; + constant pwm_ratio : std_logic_vector(pwm_width-1 downto 0) := + std_logic_vector(to_unsigned(2 ** pwm_width - 1, pwm_width)); signal fsm_clk : std_logic; signal fsm_rst : std_logic; @@ -177,7 +208,12 @@ architecture arch_imp of spi_leds_and_enc_v1_0 is signal enc_cha_filt : std_logic_vector(enc_number downto 1); signal enc_chb_filt : std_logic_vector(enc_number downto 1); signal enc_sw_filt : std_logic_vector(enc_number downto 1); - signal enc_changes : std_logic_vector(enc_number * 3 - 1 downto 0); + signal enc_sw_changed : std_logic_vector(enc_number downto 1); + signal enc_pos_changed : std_logic_vector(enc_number downto 1); + + signal pwm_cycle_start : std_logic; + signal pwm_rgb1_sig : std_logic_vector(2 downto 0); + signal pwm_rgb2_sig : std_logic_vector(2 downto 0); begin @@ -246,6 +282,18 @@ spi_leds_and_enc_v1_0_spi_fsm_inst: spi_leds_and_enc_v1_0_spi_fsm transfer_ready => spi_transfer_ready ); +cnt_div_inst: cnt_div + generic map ( + cnt_width_g => pwm_width + ) + port map ( + clk_i => fsm_clk, + en_i => spi_transfer_ready, + reset_i => fsm_rst, + ratio_i => pwm_ratio, + q_out_o => pwm_cycle_start + ); + irc_block: for i in enc_number downto 1 generate filt_cha: dff3cke port map ( @@ -254,7 +302,7 @@ irc_block: for i in enc_number downto 1 generate d_i => enc_cha(i), q_o => enc_cha_filt(i), ch_o => open, - ch_1ck_o => enc_changes((i - 1) * 3 + 0) + ch_1ck_o => open ); filt_chb: dff3cke port map ( @@ -263,7 +311,7 @@ irc_block: for i in enc_number downto 1 generate d_i => enc_chb(i), q_o => enc_chb_filt(i), ch_o => open, - ch_1ck_o => enc_changes((i - 1) * 3 + 1) + ch_1ck_o => open ); filt_sw: dff3cke port map ( @@ -272,7 +320,7 @@ irc_block: for i in enc_number downto 1 generate d_i => enc_sw(i), q_o => enc_sw_filt(i), ch_o => open, - ch_1ck_o => enc_changes((i - 1) * 3 + 2) + ch_1ck_o => enc_sw_changed(i) ); qcounter: qcounter_nbit generic map ( @@ -288,11 +336,41 @@ irc_block: for i in enc_number downto 1 generate a_fall => open, b_rise => open, b_fall => open, - ab_event => open, + ab_event => enc_pos_changed(i), ab_error => open ); end generate; +pwm_rgb1_block: for i in 2 downto 0 generate + pwm_rgb1: pulse_gen + generic map ( + duration_width_g => pwm_width + ) + port map ( + clk_i => fsm_clk, + en_i => spi_transfer_ready, + reset_i => fsm_rst, + trigger_i => pwm_cycle_start, + duration_i => output_led_rgb1(i * 8 + 7 downto i * 8), + q_out_o => pwm_rgb1_sig(i) + ); + end generate; + +pwm_rgb2_block: for i in 2 downto 0 generate + pwm_rgb2: pulse_gen + generic map ( + duration_width_g => pwm_width + ) + port map ( + clk_i => fsm_clk, + en_i => spi_transfer_ready, + reset_i => fsm_rst, + trigger_i => pwm_cycle_start, + duration_i => output_led_rgb2(i * 8 + 7 downto i * 8), + q_out_o => pwm_rgb2_sig(i) + ); + end generate; + fsm_clk <= s00_axi_aclk; fsm_rst <= not s00_axi_aresetn; @@ -344,8 +422,8 @@ data_logic_process :process -- output_led_rgb2 : out std_logic_vector(23 downto 0); -- output_led_direct : out std_logic_vector(7 downto 0); - spi_out_rgb1 <= output_led_direct(2 downto 0); - spi_out_rgb2 <= output_led_direct(5 downto 3); + spi_out_rgb1 <= output_led_direct(2 downto 0) or pwm_rgb1_sig; + spi_out_rgb2 <= output_led_direct(5 downto 3) or pwm_rgb2_sig; spi_out_led3 <= output_led_direct(6); spi_out_led4 <= output_led_direct(7); -- 2.39.2