• Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by hamster

  1. hamster

    MMCM dynamic clocking

    Hey, something else I just saw when reading the clocking guide was: MMCM Counter Cascading The CLKOUT6 divider (counter) can be cascaded with the CLKOUT4 divider. This provides a capability to have an output divider that is larger than 128. CLKOUT6 feeds the input of the CLKOUT4 divider. There is a static phase offset between the output of the cascaded divider and all other output dividers. And: CLKOUT4_CASCADE : Cascades the output divider (counter) CLKOUT6 into the input of the CLKOUT4 divider for an output clock divider that is greater than 128, effectively providing a total divide value of 16,384. So that can divide a 600 MHz VCO down to 36.6 kHz.
  2. Have a look at https://www.xilinx.com/support/documentation/user_guides/ug472_7Series_Clocking.pdf - you will want to use a MMCM, as the minimum input frequency for a PLL in 19Mhz. If you use the MCM to get 100MHz you will need to multiply by 50, to get at the absolute minimum VCO frequency of 600MHz, then divide that by 6 to get a 100MHz.clock. (see from page 38 of https://www.xilinx.com/support/documentation/data_sheets/ds181_Artix_7_Data_Sheet.pdf for the operating ranges of the MMCM and PLL). You can also 'cheat' and use an IP block, which will do all the calculations for you.
  3. Prompted by another thread here ( https://forum.digilentinc.com/topic/4180-mmcm-dynamic-clocking/ ), I've been experimenting the the Dynamic Reconfiguration Port on the Artix-7 MMCM You can find the code and constraints for the Basys3 here: http://hamsterworks.co.nz/mediawiki/index.php/MMCM_reset It might be of interest to somebody (e.g. to change a VGA clock frequency dynamically).
  4. hamster

    MMCM dynamic clocking

    I feel a bit bad about posting a minor novel here, but here is an example of going from "5 cycles on, 5 off" (i.e. divide by 10) to "10 on, 10 off" (device by 20). The VCO is initially to 800 MHz with CLK0 being VCO divide by 8.... so after config you get 100MHz. Push the button and you get 800/20 = 40MHz, release the button and you get 80MHz. It is all really hairy in practice! EDIT: Through experimentation I just found that you don't need to reset the MMCM if you are not changing the VCO frequency. So the 'rst' signal in the code below isn't needed (and LOCKED will stay asserted). -------------------------------------------------------------------------------------------------------- -- Playing with the MMCM DRP ports. -- see https://www.xilinx.com/support/documentation/application_notes/xapp888_7Series_DynamicRecon.pdf -- for the Dynamic Reconviguration Port addresses -------------------------------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; library UNISIM; use UNISIM.VComponents.all; entity mmcm_reset is Port ( clk_100 : in STD_LOGIC; btn_raw : in STD_LOGIC; led : out STD_LOGIC_VECTOR (15 downto 0)); end mmcm_reset; architecture Behavioral of mmcm_reset is signal btn_meta : std_logic := '0'; signal btn : std_logic := '0'; signal speed_select : std_logic := '0'; signal counter : unsigned(26 downto 0) := (others => '0'); signal debounce : unsigned(15 downto 0) := (others => '0'); signal clk_switched : std_logic := '0'; signal clk_fb : std_logic := '0'; type t_state is (state_idle_fast, state_go_slow_1, state_go_slow_2, state_go_slow_3, state_idle_slow, state_go_fast_1, state_go_fast_2, state_go_fast_3); signal state : t_state := state_idle_fast; ----------------------------------------------------------------------------- --- This is the CLKOUT0 ClkReg1 address - the only register to be played with ----------------------------------------------------------------------------- signal daddr : std_logic_vector(6 downto 0) := "0001000"; signal do : std_logic_vector(15 downto 0) := (others => '0'); signal drdy : std_logic := '0'; signal den : std_logic := '0'; signal di : std_logic_vector(15 downto 0) := (others => '0'); signal dwe : std_logic := '0'; signal rst : std_logic := '0'; begin MMCME2_ADV_inst : MMCME2_ADV generic map ( BANDWIDTH => "OPTIMIZED", -- Jitter programming (OPTIMIZED, HIGH, LOW) CLKFBOUT_MULT_F => 8.0, -- Multiply value for all CLKOUT (2.000-64.000). CLKFBOUT_PHASE => 0.0, -- Phase offset in degrees of CLKFB (-360.000-360.000). -- CLKIN_PERIOD: Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). CLKIN1_PERIOD => 10.0, CLKIN2_PERIOD => 0.0, -- CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for CLKOUT (1-128) CLKOUT1_DIVIDE => 1, CLKOUT2_DIVIDE => 1, CLKOUT3_DIVIDE => 1, CLKOUT4_DIVIDE => 1, CLKOUT5_DIVIDE => 1, CLKOUT6_DIVIDE => 1, CLKOUT0_DIVIDE_F => 8.0, -- Divide amount for CLKOUT0 (1.000-128.000). -- CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for CLKOUT outputs (0.01-0.99). CLKOUT0_DUTY_CYCLE => 0.5, CLKOUT1_DUTY_CYCLE => 0.5, CLKOUT2_DUTY_CYCLE => 0.5, CLKOUT3_DUTY_CYCLE => 0.5, CLKOUT4_DUTY_CYCLE => 0.5, CLKOUT5_DUTY_CYCLE => 0.5, CLKOUT6_DUTY_CYCLE => 0.5, -- CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for CLKOUT outputs (-360.000-360.000). CLKOUT0_PHASE => 0.0, CLKOUT1_PHASE => 0.0, CLKOUT2_PHASE => 0.0, CLKOUT3_PHASE => 0.0, CLKOUT4_PHASE => 0.0, CLKOUT5_PHASE => 0.0, CLKOUT6_PHASE => 0.0, CLKOUT4_CASCADE => FALSE, -- Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE) COMPENSATION => "ZHOLD", -- ZHOLD, BUF_IN, EXTERNAL, INTERNAL DIVCLK_DIVIDE => 1, -- Master division value (1-106) -- REF_JITTER: Reference input jitter in UI (0.000-0.999). REF_JITTER1 => 0.0, REF_JITTER2 => 0.0, STARTUP_WAIT => FALSE, -- Delays DONE until MMCM is locked (FALSE, TRUE) -- Spread Spectrum: Spread Spectrum Attributes SS_EN => "FALSE", -- Enables spread spectrum (FALSE, TRUE) SS_MODE => "CENTER_HIGH", -- CENTER_HIGH, CENTER_LOW, DOWN_HIGH, DOWN_LOW SS_MOD_PERIOD => 10000, -- Spread spectrum modulation period (ns) (VALUES) -- USE_FINE_PS: Fine phase shift enable (TRUE/FALSE) CLKFBOUT_USE_FINE_PS => FALSE, CLKOUT0_USE_FINE_PS => FALSE, CLKOUT1_USE_FINE_PS => FALSE, CLKOUT2_USE_FINE_PS => FALSE, CLKOUT3_USE_FINE_PS => FALSE, CLKOUT4_USE_FINE_PS => FALSE, CLKOUT5_USE_FINE_PS => FALSE, CLKOUT6_USE_FINE_PS => FALSE ) port map ( -- Clock Outputs: 1-bit (each) output: User configurable clock outputs CLKOUT0 => clk_switched, CLKOUT0B => open, CLKOUT1 => open, CLKOUT1B => open, CLKOUT2 => open, CLKOUT2B => open, CLKOUT3 => open, CLKOUT3B => open, CLKOUT4 => open, CLKOUT5 => open, CLKOUT6 => open, -- Dynamic Phase Shift Ports: 1-bit (each) output: Ports used for dynamic phase shifting of the outputs PSDONE => open, -- Feedback Clocks: 1-bit (each) output: Clock feedback ports CLKFBOUT => clk_fb, CLKFBOUTB => open, -- Status Ports: 1-bit (each) output: MMCM status ports CLKFBSTOPPED => open, CLKINSTOPPED => open, LOCKED => open, -- Clock Inputs: 1-bit (each) input: Clock inputs CLKIN1 => clk_100, CLKIN2 => '0', -- Control Ports: 1-bit (each) input: MMCM control ports CLKINSEL => '1', PWRDWN => '0', -- 1-bit input: Power-down RST => rst, -- 1-bit input: Reset -- DRP Ports: 16-bit (each) output: Dynamic reconfiguration ports DCLK => clk_100, -- 1-bit input: DRP clock DO => DO, -- 16-bit output: DRP data DRDY => DRDY, -- 1-bit output: DRP ready -- DRP Ports: 7-bit (each) input: Dynamic reconfiguration ports DADDR => DADDR, -- 7-bit input: DRP address DEN => DEN, -- 1-bit input: DRP enable DI => DI, -- 16-bit input: DRP data DWE => DWE, -- 1-bit input: DRP write enable -- Dynamic Phase Shift Ports: 1-bit (each) input: Ports used for dynamic phase shifting of the outputs PSCLK => '0', PSEN => '0', PSINCDEC => '0', -- Feedback Clocks: 1-bit (each) input: Clock feedback ports CLKFBIN => clk_fb ); speed_change_fsm: process(clk_100) begin if rising_edge(clk_100) then di <= (others => '0'); dwe <= '0'; den <= '0'; case state is when state_idle_fast => if speed_select = '1'then state <= state_go_slow_1; -- High 10 Low 10 di <= "0001" & "001010" & "001010"; dwe <= '1'; den <= '1'; end if; when state_go_slow_1 => if drdy = '1' then state <= state_go_slow_2; end if; when state_go_slow_2 => rst <= '1'; state <= state_go_slow_3; when state_go_slow_3 => rst <= '0'; state <= state_idle_slow; when state_idle_slow => di <= (others => '0'); if speed_select = '0' and drdy = '0' then state <= state_go_fast_1; -- High 5 Low 5 di <= "0001" & "000101" & "000101"; dwe <= '1'; den <= '1'; end if; when state_go_fast_1 => if drdy = '1' then state <= state_go_fast_2; end if; when state_go_fast_2 => rst <= '1'; state <= state_go_fast_3; when state_go_fast_3 => rst <= '0'; state <= state_idle_fast; end case; end if; end process; dbounce_proc: process(clk_100) begin if rising_edge(clk_100) then if speed_select = btn then debounce <= (others => '0'); elsif debounce(debounce'high) = '1' then speed_select <= not speed_select; else debounce <= debounce + 1; end if; -- Syncronise the button btn <= btn_meta; btn_meta <= btn_raw; end if; end process; show_speed_proc: process(clk_switched) begin if rising_edge(clk_switched) then counter <= counter + 1; led(7 downto 0) <= std_logic_vector(counter(counter'high downto counter'high-7)); end if; end process; led(15) <= speed_select; end Behavioral;
  5. hamster

    MMCM dynamic clocking

    1. Yes, the MMCM has ports that allow reprogramming - but it is quite involved. See around page 75 of https://www.xilinx.com/support/documentation/user_guides/ug472_7Series_Clocking.pdf Making sure that your timing constraints are correct is also quite tricky. 2. No, you will not get that range out if it - it still has to be in spec for the MMCM (from a few MHz to a few hundred - check the datasheet). Also switching will cause glitches if not done right - to avoid this you need to use a BUFGMUX, (NOTE: for a BUFGMUX to switch, you need to clock edges appearing on both of it's inputs!) I've not done it myself, but I suggest you use use the MMCM to generate a few fixed frequencies (e.g. 33MHz, 10MHz) then have divide by 10 counter hung of them, to give you 3.3MHz, 1.0MHz, 333kHz, 100kHz and so on. Then have two N:1 MUXes use a few to select which frequency clock you want to use. e.g: case a is when "000" => clk_a <= clk_33000kHz; when "001" => clk_a <= clk_10000kHz; Then feed clk_a and clk_b into a BUFGMUX (you may need a BUFG to here to get the signals back on the clocking networks), and switch between them - first change the input used for the inactive clock to the desired frequency (e.g. if clk_a is being used, change the selection for clk_b) then change the select input to the BUFGMUX to switch over onto that clock. Here's an experiment of mine, that might give you ideas: http://hamsterworks.co.nz/mediawiki/index.php/Single_Step
  6. I collected 6GB more data today, and took some photos. I'll make a blog / build-log entry over the next few days. It was using the testpoints on the KiwiSDR cape for a beaglebone - http://kiwisdr.com/
  7. I used the Nexys2's EPP-like parallel interface on my latest (not all that much) FPGA related project - a software GPS receiver. The FPGA was used to capture the raw one-bit samples form a GPS receiver front end at 5,456 MB/s for 200 seconds, without dropping a single bit. I miss the ease of use and the high bandwidth of the old EPP interface... The FPGA code and the C source to read data from it is at https://github.com/hamsternz/Full_Stack_GPS_Receiver/tree/master/misc
  8. If you do want to use your input pin as a clock you can, by routing the signal through a BUFG primative - after you include the something like: -- include the library of primitives library UNISIM; use UNISIM.VComponents.all; ........ i_BUFG: BUFG PORT MAP ( i => raw_pin, o => slow clock); The downside is that the skew between the input clock and the clock signal inside the FPGA isn't the best - but for 8.x MHz or it will have no impact. You might also want to consider using a FIFO, esp if the amount of data is high. Assigning one array to the other requires two flip-flops per bit, however a FIFO can use either Block RAM or distributed RAM and only needs to hold one copy of the data, so will use a lot less resources. The FIFO can also do data width conversion and provide flow control signals too.
  9. @Notarobot's code is much the same as mine in function. But style is a different. I wonder why it isn't just a single process like this: process(clk) begin if(rising_edge(clk)) then if nreset = '0' then if DFF1 /= DFF2 then q_reg <= (others => '0'); -- reset counter elsif q_reg(N-1) = '0' then q_reg <= q_reg + 1; else DB_out <= DFF2; end if; DFF1 <= button_in; DFF2 <= DFF1; else q_reg <= (others => '0'); DFF1 <= '0'; DFF2 <= '0'; end if; end if; end process;
  10. Oh, and with regards to test benches. Somethings are hard to prove with test benches, and easy to prove in real life. Especially things that involve timescales needed for human interaction. Take the seven-segment display module. A 'full' test bench for that would be hard (test each digit for each value - 64 test patterns, each requiring at least enough time to update all output signals, 300 million cycles simulation cycles, and each blink test would need at least 64 million cycles for the counter to roll over - so half a billion simulation cycles. Then it would need to inspect the simulation output, to check that the correct LEDs were on at the correct time. Far easier to connect the digits to the switches on the dev board, the buttons to the blink inputs, download the design and manually verify it - a physical/manual test-bench :-) So I write VHDL testbenches when I know I will need to debug or otherwise inspect behavior of the internals. For a button debouncer my personal view is that a test bench is a bit over the top, and it is hard to have the correct assumptions of how bad a really bad switch is - and all my projects are for my own enjoyment, so I don't have to design to commercial standards of proof.
  11. @Tickstart Here's my equivalent of the 7-seg code you posted, just for comparison - it is just a hack, so the blink rate and update rates were just convenient, rather than to any hidden spec! library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity seven_seg is Port ( clk : in STD_LOGIC; segments : out STD_LOGIC_VECTOR (6 downto 0); seg_select : out STD_LOGIC_VECTOR (3 downto 0); digit0 : in STD_LOGIC_VECTOR (3 downto 0); blink0 : in STD_LOGIC; digit1 : in STD_LOGIC_VECTOR (3 downto 0); blink1 : in STD_LOGIC; digit2 : in STD_LOGIC_VECTOR (3 downto 0); blink2 : in STD_LOGIC; digit3 : in STD_LOGIC_VECTOR (3 downto 0); blink3 : in STD_LOGIC); end seven_seg; architecture Behavioral of seven_seg is signal digit_count : unsigned(25 downto 0); signal to_decode : std_logic_vector(3 downto 0); begin -- GFEDCBA with to_decode select segments <= "1000000" when "0000", -- Zero "1111001" when "0001", -- One "0100100" when "0010", -- Two "0110000" when "0011", -- Three "0011001" when "0100", -- Four "0010010" when "0101", -- Five "0000010" when "0110", -- Six "1111000" when "0111", -- Seven "0000000" when "1000", -- Eight "0011000" when "1001", -- Nine "0001000" when "1010", -- A "0000011" when "1011", -- B "1000110" when "1100", -- C "0100001" when "1101", -- D "0000110" when "1110", -- E "0001110" when others; -- F process(clk) begin if rising_edge(clk) then seg_select <= "1111"; -- active low! case digit_count(digit_count'high-6 downto digit_count'high-7) is when "00" => seg_select(0) <= blink0 AND digit_count(digit_count'high); to_decode <= digit0; when "01" => seg_select(1) <= blink1 AND digit_count(digit_count'high); to_decode <= digit1; when "10" => seg_select(2) <= blink2 AND digit_count(digit_count'high); to_decode <= digit2; when others => seg_select(3) <= blink3 AND digit_count(digit_count'high); to_decode <= digit3; end case; digit_count <= digit_count + 1; end if; end process; end Behavioral;
  12. Hi! So here is how I would do it.... First thoughts about the design - nothing particularly tricky in timing or complexity, so might as well have a single clock domain running at the board's system clock (100Mhz or 50Mhz or whatever). The only thing that is timing sensitive is the button debounce, so a little bit of tweaking might be needed there. At a glance the following low level components are needed: - debounce : a button debouncer. Important point - this just generates a single-cycle pulse when a button has been held down long enough inputs - clk - button_raw outputs - button_debounced - up_down_counter : An Up/Down counter with Clock enable. The guts are as follows: if rising_edge(clk) then if clock_enable = 1 then if count_up = '1' and count_down = '1' then NULL; elsif count_up = '1' then count <= count + 1; elsif count_down = '1' then count <= count - 1; end if; end if; end if; inputs - clock - clock_enable - count_up - count_down outputs - digit (4 bits) - next_prev_counter : Much like the up_down counter, but outputs "0001", "0010", "0100" or "1000" based on 'next' & 'prev' inputs Bonus points for it changes to an output of "0000" if no next or prev input is received for 5 seconds inputs - clock - next - prev outputs - active (4 bits, 'one hot' encoded) - seven_seg_display : Takes four 4-bit values and displays them on the seven segment display. Maybe add four 'blink' inputs to indicate which digit is active (or use the decimal point?) (This will be the most demanding of the modules) inputs - clock - digit0 (4 bits) - blink0 - digit1 (4 bits) - blink1 - digit2 (4 bits) - blink2 - digit3 (4 bits) - blink3 outputs - segments (7 bits) - segment_select (4 bits) - lock_unlock_test : Takes four 4-bit values and asserts the 'unlock' output. A nice idea would be to debounce this - e.g. the correct code has to be present for a second before the unlock signal is asserted. So then it would be - Writing each of these five components - Testing each of these in isolation (either with simulation or on H/W). For newbies H/W is best, just to see how hard debug is, discovering why simulation is so awesome. With that done, then just assemble the entire system with a top level 'structural' module, with the following component instances: - 4 x debounce : One for each button (up, down, left, right) - 1 x next_prev_counter : Logically used to select the digit with focus - connect the next to the debounced right button, the prev to the debounced left button - 4 x up_down_counter : One for each digit connect the count_up to the debounced up button connect the count_down to the debounced down button connect the clock_enable to the output of the next_prev_counter, so only one digit will change at a time. - 1 x seven_seg_display : Wire the digits to each of the up_down_counter instances. connect the blink input to the output of the next_prev_counter, so you can see which digit has focus. - 1x lock_unlock_test : Connect all the digits to the outputs of the up_down_counters, and connect the unlock output to the secret device of great importance (or just a spare LED!) And if your low-level testing has been good, it should all just work! (yes, in a perfect world.. )
  13. With HDLs I think it is quite important to "do it your way, and do it wrong" as much as possible and see what happens and understand why it is wrong. For example, the OP's debounce code is most likely a free-running n-bit counter, with code along the lines of: process(clk) begin if rising_edge(clk) then counter <= counter+1; end if; end process; process(counter) begin if rising_edge(count(counter'high)) then debounced_button <= input_button; end if; end process Which is so close to being the correct way to sample a signal, but is flawed for use in an FPGA for quite subtle reasons that are 'magic' to a newbie. Exploring why it is wrong is the fun part of FPGAs for me. BTW this is what a 'more correct' version looks like, but still is broken for yet more subtle reasons. :-( process(clk) begin if rising_edge(clk) then if counter = 0 then debounced_button <= input_button; end if; counter <= counter+1; end if; end process; So here is a bulletproof version: process(clk) begin if rising_edge(clk) then if counter = 0 then debounced_button <= synced_button; end if; counter <= counter+1; synced_button <= input_button; end if; end process; The take-away wisdom being "always synchronise your async inputs" and "try really hard to never have more than one clock"
  14. Oh, here's a few comments on the O.P's code. Most of the problems is that the adder's clock isn't an actual clock signal - it is the two buttons ORed together. To make this sort of design work you want an adder that has a "Clock Enable" ("CE") signal. That way the clock can tick every cycle, and the 'trigger' signal can drive the "Clock Enable" input. The more subtle issue is that their is something close to a race condition - the pressing of the buttons changes the input to the adder, but the pressing of the button also triggers the adder. Which will happen first? Who knows? An experiment in bad form could be to have trigger be "trigger <= NOT(btnU or btnD);" - that way the adder would be clocked by the falling edge of the button signal (i.e. on the downpress the input is set to either 'minus' or 'plus', and on the lift the adder is clocked. However, you still have a race condition - will add_sub be reset to 'zero' before or after the adder actually responds to the clock input? if btnD = '1' then add_sub <= minus; elsif btnU = '1' then add_sub <= plus; else add_sub <= zero; -- (sub zero lol) end if; If you change that bit of code to this, as well as the change to trigger to clock on button lift: if btnD = '1' then add_sub <= minus; elsif btnU = '1' then add_sub <= plus; end if; It will most likely give warnings about inferred latches, but it might work as expected. It is still not good synchronous design though, but still might be interesting. PS. Good choice of board to learn on too :-)
  15. Worse than metastability is just simple timing issues - a signal takes a short period of time to get along the wires in the FPGA - just using indicative numbers, maybe a nanosecond or so. If the signal for a button is being used in the top left and bottom right of the chip the downstream logic see a skewed value on the wire. If a design is running at 100MHz (10ns cycle) there is a 1 in 10 chance of failure (a metastability error is much less likely 1 in 1 million chance) The solution is the same though - for any asynchronous signal latch it in a flip-flop before you use it.
  16. I Hadn't picked up a board in a while (we are trying to get our house ready for sale, so I've been picking up paint brushes!) So here is a quick design I knocked out to achieve your aim, with all the tricks I think need to be added. I've found my Basys3 and it works for me - it might work for you too. The big difference is "use IEEE.NUMERIC_STD.ALL;" and, it allowing the use of "unsigned" data type, to which you can add and subtract. Feel free to ask questions - most of the design decisions are quite arbitrary and you might have better ideas! library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity up_down is Port ( clk : in STD_LOGIC; btn1_raw : in STD_LOGIC; btn2_raw : in STD_LOGIC; leds : out STD_LOGIC_VECTOR (3 downto 0)); end up_down; architecture Behavioral of up_down is -- For synchronizing into the clock domain signal btn1_meta : std_logic := '0'; signal btn2_meta : std_logic := '0'; signal btn1 : std_logic := '0'; signal btn2 : std_logic := '0'; -- Fro debouncing the synchronised signals -- Length defines the 'hold time' for the debouncing - 2^19 cycles signal debounce1 : unsigned(19 downto 0) := (others => '0'); signal debounce2 : unsigned(19 downto 0) := (others => '0'); signal debounced1 : std_logic := '0'; signal debounced2 : std_logic := '0'; -- For detecting the rising edges of the debounced signals signal debounced1_last : std_logic := '0'; signal debounced2_last : std_logic := '0'; signal count : unsigned(3 downto 0) := (others => '0'); begin leds <= std_logic_vector(count); -------------------------------------------- -- Process to synchronise the button signals -------------------------------------------- sync_proc: process(clk) begin if rising_edge(clk) then btn1 <= btn1_meta; btn2 <= btn2_meta; btn1_meta <= btn1_raw; btn2_meta <= btn2_raw; end if; end process; ---------------------------------------------- -- Process to debounce the buttons, to generate -- 'debouncedX' that is stable for 2^19 cycles ----------------------------------------------- debounce_proc: process(clk) begin if rising_edge(clk) then if btn1 = '0' then if debounce1(debounce1'high) = '1' then -- Count down if the button is lifted debounce1 <= debounce1 - 1; else -- snap down to zero once the MSB clears debounce1 <= (others => '0'); end if; else if debounce1(debounce1'high) = '0' then -- Count up if the button is pressed debounce1 <= debounce1 + 1; else -- snap down to zero once the MSB is set debounce1 <= (others => '1'); end if; end if; debounced1 <= std_logic(debounce1(debounce1'high)); if btn2 = '0' then if debounce2(debounce2'high) = '1' then -- Count down if the button is lifted debounce2 <= debounce2 - 1; else -- snap down to zero once the MSB clears debounce2 <= (others => '0'); end if; else if debounce2(debounce2'high) = '0' then -- Count up if the button is pressed debounce2 <= debounce2 + 1; else -- snap down to zero once the MSB is set debounce2 <= (others => '1'); end if; end if; debounced2 <= std_logic(debounce1(debounce1'high)); end if; end process; ---------------------------------------------- -- A process to detect the rising edges in the -- debounced signals and then update the counter ----------------------------------------------- count_proc: process(clk) begin if rising_edge(clk) then if debounced1 = '1' and debounced1_last = '0' and debounced2 = '1' and debounced2_last = '0' then -- both buttons pressed at the same time. NULL; elsif debounced1 = '1' and debounced1_last = '0' then -- Count up count <= count + 1; elsif debounced2 = '1' and debounced2_last = '0' then -- Count down count <= count - 1; end if; -- Remember button states for next cycle debounced1_last <= debounced1; debounced2_last <= debounced2; end if; end process; end Behavioral;
  17. Oh, I've just used Vivado on a freshly re-installed Win10 laptop and had to use this fix again. Just remember to either reboot once the drivers have correctly installed, or kill off the "hw_server" process.
  18. Hi You want to map the values of [-128 to +127] to [0 to 255]. So either just add 128, or XOR with binary 10000000
  19. Your code looks fine, so as far as I can guess you have two possible problems. 1) Your I/O pins are not connected as expected (e.g. you constraints are set wrong) 2) Your clock is not ticking Humm... Maybe I have found it. Have a look at page 21 of https://www.xilinx.com/support/documentation/university/XUP Boards/XUPZYBO/documentation/ZYBO_RM_B_V6.pdf "Keep in mind that CLK125 will be disabled when the Ethernet PHY (IC1) is held in hardware reset by driving the PHYRSTB signal low." You may also need to add the PHYRSTB signal to your design and drive it high, to bring the Ethernet PHY out of reset and start your 125MHz clock ticking. Ouch - that is a trap for beginers
  20. Hi! Can you also post the active lines of the XDC file you are using? Don't bother posting the comments :-) It should be something like... set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { clk }]; create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { clk }]; set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }]; set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }]; set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; based on https://github.com/Digilent/ZYBO/blob/master/Resources/XDC/ZYBO_Master.xdc
  21. Hi Greg765, +1 for synchronizing the RX signal. I'm a bit confused by having multiple processes in the same clock domain, The interactions take a while to understand... I'ld have to simulate it, but I think your problem is that your tick counters are getting out of alignment with the data. I would try this for an idea.... Have a counter that just counts through the entire 9 and half bit times, but only starts counting when RxD_sync is zero. (It will need to be 18 bits long if you use UNSIGNED types): constant half_bit : natural := 5902; -- This is clock speed / baud_rate / 2; if counter == 0 then if RxD_sync = '0' then counter <= counter+1; end if; else if counter = half_bit*19 then -- 19/2 bit counts = middle of stop bit count <= 0; else counter <= counter+1; end if; end if And then sample the bits when the counter is in the center of the bits, which might look something like this: case counter is when half_bit*3 => data_out(0) <= RxD_sync; when half_bit*5 => data_out(1) <= RxD_sync; when half_bit*7 => data_out(2) <= RxD_sync; when half_bit*9 => data_out(3) <= RxD_sync; when half_bit*11 => data_out(4) <= RxD_sync; when half_bit*13 => data_out(5) <= RxD_sync; when half_bit*15 => data_out(6) <= RxD_sync; when half_bit*17 => data_out(7) <= RxD_sync; end case; (of course you will need to wrap it up in a nice clocked process and all that, but 80% of the code is there). It might not be the most efficient of implementation in terms of logic resources, and it is super-sensitive to noise on the RX signal causing a false start bit, but it is pretty simple to debug as an initial test and should work second time. Designing for ease of debug / least complexity / least chance of needing debug is a good habit...
  22. The SD card is connected to the Zynq's MIO pins so you do not need to constrain anything. The MIO pins are defined in the Zynq Processing System's configuration - in the IP block you define of the pins are used for for what function (e.g. Serial, Ethernet, SPI...) The MIO pins have fixed pin assignments on the Chip's package, so no XDC entries are needed - you just need to define the MIO settings to match the board's layout. Here is the screen you want to look for (although this is NOT correctly configured for the Zybo!):
  23. hamster

    4 tap FIR filter

    @Dan - You will give away all the secrets! - Yes the to_signed(255,8) was one of a few talking points. I find modeling it in a spreadsheet is the best way to play with filter values to ensure you use the best precision and avoid overflows. and to play with different scaling values - have the "ideal" filter in floating point, and then try different scaling and roundings. To handle rounding I sometimes to subtract 2^(n-1) from negative total values before truncating to n bits in length...
  24. hamster

    4 tap FIR filter

    1) See http://hamsterworks.co.nz/mediawiki/index.php/Minimal_XADC_design for a very minimal XADC using primatives (if that is your thing!) 2) Here is a really simple framework for your filter. Although it looks straightforward you will have to look at everything very closely. Issues and subtleties lurk in almost every line - type conversions, overflow errors, timing errors. very poor use of resources, implicit assumptions about intermediate type, rounding, precision errors - it has the general form of the answer you are looking for, but will not work without you working hard to see what is going on. I recommend you set up a project in Vivado, and then have a close look at the RTL schematic to see what it actually describes, then try and design and pass pathological data through it in the simulator to show up the errors (such as overflows and underflows). However, the line you are looking for in the 20-bit to 12-bit conversion is the one after the "begin" statement. library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity filter is Port ( clk : in STD_LOGIC; in_sample : in STD_LOGIC_VECTOR(11 downto 0); in_data_enable : in STD_LOGIC; out_sample : out STD_LOGIC_VECTOR(11 downto 0); out_data_enable : out STD_LOGIC); end filter; architecture Behavioral of filter is type t_data is array(0 to 4) of signed(11 downto 0); type t_kernel is array(0 to 4) of signed(7 downto 0); signal data : t_data := (others => (others => '0')); signal kernel : t_kernel := (to_signed( 10,8), to_signed( -10,8), to_signed( 255,8), to_signed( -10,8), to_signed( 10,8)); signal updated_data : std_logic := '0'; signal total : signed(19 downto 0) := (others => '0'); begin -------------------------------------------------- -- Type conversion and scaling -------------------------------------------------- out_sample <= std_logic_vector(total(19 downto 8)); process(clk) begin if rising_edge(clk) then --------------------------------------- -- Process any data received last cycle --------------------------------------- if updated_data = '1' then total <= (data(0) * kernel(0)) + (data(1) * kernel(1)) + (data(2) * kernel(2)) + (data(3) * kernel(3)) + (data(4) * kernel(4)); out_data_enable <= '1'; end if; -------------------------------------------- -- Receive any new data presented this cycle -------------------------------------------- if in_data_enable = '1' then data(1 to 4) <= data(0 to 3); data(0) <= signed(in_sample); updated_data <= '1'; end if; end if; end process; end Behavioral;