• Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by hamster

  1. Hi, I haven't looked at the board's specs, but you can find examples at https://github.com/hamsternz/ArtyEtherentTX (100BaseT on the Arty board) https://github.com/hamsternz/FPGA_GigabitTx (1000BaseT on the Nexys Video board). They should be helpful to you.
  2. Sort of pen-and-papered it. 0xCCCCCCCD is 0.8*2^32, so it is d = i * (4/5*2^32) / 2^32 which reduces to d = i/10 expecting that I would have to do a fixup to pick up rounding errors, but then found it wasn't needed. It turns out that GCC does this optimization by default, but uses a 32-bit multiply that splits the result across two registers (EDX:EAX), but the above method doesn't touch EDX so leaves a register free, and can be a tad quicker.
  3. Tonight I discovered that this is a fast way to divide by 10 unsigned div10(unsigned x) { #ifdef REF /* Implement 32-bit division using divide */ return x/10; #else return (x * 0xCCCCCCCDLLU)>>35; #endif } Just wanted to post it here in case it becomes of use to somebody. A variant It could most likely be used with a DSP48 block to divide shorter (20 or 23 bit) binary numbers with much less resources and latency than a 10-bit binary divider.
  4. hamster

    Change ROM COE

    For the definitive word on how to infer memory blocks, including code examples, have a look at https://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_1/ug901-vivado-synthesis.pdf from page 95. It covers everything from the simplest single port RAMs/ROMs to dual port RAMs with different data widths, with byte enables. For the large part, the same patterns also work in ISE. page 148 & 149 might be of special interest. It has "Initializing Block RAM From an External Data File VHDL Coding Example" and "Initializing Block RAM From an External Data File Verilog Coding Example"
  5. hamster

    Change ROM COE

    Hi! I too share your pain :-) I now infer all my ROMs - using code like this: library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity beacon is Port ( clk : in STD_LOGIC; leds : out STD_LOGIC_VECTOR (7 downto 0)); end beacon; architecture Behavioral of beacon is type a_data is array(0 to 31) of std_logic_vector(7 downto 0); signal data : a_data := ( x"01",x"02",x"04",x"08",x"10",x"20",x"40",x"80", x"01",x"02",x"04",x"08",x"10",x"20",x"40",x"80", x"01",x"01",x"02",x"02",x"04",x"04",x"08",x"08", x"10",x"10",x"20",x"20",x"40",x"40",x"80",x"80"); signal counter : unsigned(26 downto 0) := (others => '0'); begin process(clk) begin if rising_edge(clk) then leds <= data(to_integer(counter(counter'high downto counter'high-4))); counter <= counter+1; end if; end process; end Behavioral; This is something I had open right now - the counter is longer than it would need to be for a ROM address, passed in as a parameter for the module. It isn't very much work to make a script that converts your source data (in whatever format) into the entire Verilog/VHDL module, and it means that your code will work with other FPGA vendors tooling. If you track down some Arcade Game implementations for an FPGA they usually have a script to do exactly this - it is against the rules to include the ROM dumps in the code base. For example - https://github.com/bhamadicharef/bombjack-papilioplus-fpga/tree/master/romgen_source
  6. HI, This is a case when using shift registers can make your life so much easier in the constants - you can almost draw what you want to see library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity dac is Port ( clk : in STD_LOGIC; dac_clk : out STD_LOGIC; dac_cs : out STD_LOGIC; dac_ld : out STD_LOGIC; dac_data : out STD_LOGIC); end dac; architecture Behavioral of dac is signal clk_sr : std_logic_vector(3 downto 0) := "0011"; signal cs_sr : std_logic_vector(19 downto 0) := x"C0003"; signal data_sr : std_logic_vector(19 downto 0) := x"00000"; signal ld_sr : std_logic_vector(19 downto 0) := x"FFFFE"; signal counter : unsigned(2 downto 0) := "000"; type t_table is array(0 to 7) of std_logic_vector(15 downto 0); signal table : t_table := ( x"8000",x"E000",x"FFFF",x"E000", x"8000",x"2000",x"0000",x"2000"); begin process(clk) begin if rising_edge(clk) then -- Set the outputs dac_clk <= clk_sr(clk_sr'high); dac_cs <= cs_sr(cs_sr'high); dac_data <= data_sr(data_sr'high); dac_ld <= ld_sr(ld_sr'high); -- shift the data shift registers if clk_sr = "1001" then cs_sr <= cs_sr(cs_sr'high-1 downto 0) & cs_sr(cs_sr'high); data_sr <= data_sr(data_sr'high-1 downto 0) & data_sr(data_sr'high); ld_sr <= ld_sr(ld_sr'high-1 downto 0) & ld_sr(ld_sr'high); -- put a new data value in the data shift register, when needed needed if cs_sr(15) = '1' and cs_sr(14) = '0' then data_sr(15 downto 0) <= table(to_integer(counter)); counter <= counter + 1; end if; end if; -- Shift the clock shift registers clk_sr <= clk_sr(clk_sr'high-1 downto 0) & clk_sr(clk_sr'high); end if; end process; end Behavioral; I've attached the simulation image
  7. Hi! I've hooked up a CMOD-A7 to an audio codec board designed for the Raspberry Pi, getting ready to play with some audio. You can find the VHDL source at http://hamsterworks.co.nz/mediawiki/index.php/STGL5000#sgtl5000_interface.vhd It is still rough and ready, but it works
  8. hamster

    SERDES: A first project

    The SERDES isn't super tricky to use once working (esp for outputs), but getting it to work the first time is quite hard. Make sure that you follow the clocking design in the user guide exactly. You don't have the flexibility to use just any clocking resource to drive them - you must use the correct MMCM connections and the correct buffers The bit ordering can be a confusing, when thinking about the order of the bits on the wire. In the user guide there is a picture that is helpful, showing the order the bits leave the SERDES block and then arrive at the receiver. The spec sheet limits performance to about 1Gb/s or 1.25Gb/s (for a 500 or 600 MHz toggle rate). They can work a little bit faster than this, but of course that is out of spec.
  9. Hi! Is the USB stick formatted with FAT32? I have had no problem with loading a bit file from a USB stick on my Basys3... except when it was formatted with NTFS ;-)
  10. Hi deltaepsilon3, You can talk directly to the Ethernet interfaces - here is something for the Arty Board, showing the level of complexity needed http://hamsterworks.co.nz/mediawiki/index.php/ArtyEthernet For Gigabit Ethernet it is much the same http://hamsterworks.co.nz/mediawiki/index.php/GigabitTX With a bit of experimentation you can replace the data payload with your samples, and implement some form of flow control (so you only send packets when you have data to send. Mike
  11. hamster

    inquiry on Artix7 board

    At a glance, from the last screen shot it seems you are sampling 10 channels, so that look to be about 100k samples per channel per second... I haven't used the XADC that much at all. You would really need to have a a quick read of the user guide to find the bits of interest, then read them closely to find out exactly what you want to do. Mike
  12. This little module might be of use to somebody - it sends 16-bit values to an external serial device, as four ascii hexidecimal digits (eg "12AB"), with new lines and carriage returns. http://hamsterworks.info/index.php/Hw_tx_binary_as_ascii The sample design send the settings of the 16 slide switches every time the center button is pressed.
  13. hamster

    inquiry on Artix7 board

    The XADC is a Dual 12-bit ADC. 1MS/s ADC. You are you getting the data off of the ARTY for analysis? Or are you using a Microblaze CPU? Are you getting 1,000,000 reading per second? The ADCs are shared between multiple channels, so if you have 5 channels enabled you will at best only get 200k samples per channel. It can also be set up as bipolar or unipolar mode - are you sure you have it configured right? can you show any of your configuration? For unipolar signals the XADC's range is only from 0.0V to 1.0V - are you sure you are not driving it out of this range?
  14. A few reasons are... a - The introduction of logic hazards can cause glitches : https://en.wikipedia.org/wiki/Hazard_(logic) b - Routing of clocks is very complex - It is hard to ensure that the same clock edge appears all over the FPGA at almost exactly the same time. Sometimes this is achieved with 'slight of hand' (e.g. using a on-chip PLL to advance phase of the clock, so that by the time it reaches the edge of the chip is in back phase with the original signal). Low-skew paths also exist, but are restricted to small areas of the FPGA, and the clock has to be connected to the correct pin to be placed and routed correctly. c - FPGAs and their tools are designed to behave predictably under the "synchronous digital design" paradigm (something like https://hps.hs-regensburg.de/scm39115/homepage/education/courses/red/2_SynchronousDigitalCircuitDesignRules.pdf). If you work outside the paradigm you will be fighting against the tools and their assumptions. d - There is almost nothing that you are unable to code in an FPGA friendly way, but there are infinitely many ways to write FPGA-hostile code. If you want your FPGA to place nice with you, you have to play nice with it. So you can either add an RC filter to debounce you switch, or you can sample it using a reliable clock.
  15. I know this sounds wrong, but.... A good way to convert 8-bit binary into Decimal Digits is most likely a 256 entry lookup table, giving an two 4-bit results. Yes, it will seem a lot of code, but it will implement very efficient, is fast, and will use very little power. You can also replace a lot of logic, if your conversion would otherwise involve constants (e.g. if you also need to calculate "out_val = k * in_val + c", like you would to convert degrees C into degrees F)
  16. It does look a little odd. It looks as though it will move bits into data_reg every cycle that "spi_clk" is high, TRANSCIEVE: process(clk) begin if rising_edge(clk) if slave_select = '0' then -- slave is selected if spi_clk_tick = '1' and spi_clk_tick_last = '0' then -- seen the rising edge on spi_clk, so grab the data data_reg <= data_reg(6 downto 0) & mosi_sync; end if; end if; -- remember the current spi_clk_tick signal so we can detect if it -- changes from '0' to '1' in the next cycle spi_clk_tick_last <= spi_clk_tick; end if; end process;
  17. A while ago there was a thread about writing a 'combination lock' design for an FPGA board. I finally got around to updating my Wiki with the design: http://hamsterworks.co.nz/mediawiki/index.php/Combination_Lock A short video of it in action is here:
  18. When I get this it is usually the uppercase/lowercase of the top level signals doens't match those used in the .XDC file. This is the only place case matters in a VHDL project!
  19. To make a single-cycle pulse on 'x_rising_edge' when signal 'x' changes from '0' to '1': signal x_last : std_logic := '0'; signal x_rising_edge : std_logic := '0'; ... inside a clocked process.... if x_last = '0' and x = '1' then x_rising_edge <= '1'; else x_rising_edge <= '0'; end if; x_last <= x;
  20. Yep - completely agree. If you were to use this (I'm thinking of using it for generating a changing VGA pixel clock) you should probably use the inverted 'LOCKED' signal as a reset for the critical bits of your design, or have your design organised so any 'badness' will get flushed out quickly (which shouldn't be a problem for a VGA controller - assuming I don't reset the clock midway through a memory transaction).
  21. Oh - ignore the Debug Hub message - it just means that your project does not have a debug code (aka. Embedded Virtual Logic Analyser) in the project. You will need to tinker with the FSM. My first suggestion would be when the user input changes from what is on the screen, jump to the starting state for the FSM so it re-displays everything. something along the lines of this early on in the FSM, to capture what is on the screen: current_bcd <= bcd; and have the rest of the fsm display what is in "current_bcd" Then, in the end state of the FSM: if bcd /= current_bcd then .... do stuff here to restart the FSM, most likely changing lcd_cmd_ptr end if; That way you should have a reasonably responsive display.
  22. I've never used the this display, but on other display the second line start on address C0, (http://www.avrfreaks.net/forum/problem-second-line-2x16-lcd) So try this: Change 14 => "10"&X"20", -- blank To: 14 => "00"&X"C0", -- Move to second line This might also be of use: https://mil.ufl.edu/3744/docs/lcdmanual/commands.html
  23. So if you add a top-level port of "bcd : in std_logic_vector(7 downto 0)" (enough for two digits as a test) then within the module you could do the following: a. replace "constant" with "signal" on LCD_CMDS b. Add a couple of assignments to overwrite the desired values in the array. Add a couple of concurrent assignments: LCD_CMDS(15) <= x"3" & bcd_value(7 downto 4); LCD_CMDS(14) <= x"3" & bcd_value(3 downto 0); That will overwrite the "Di" in "Digilent" with two digits. Once you get this working, you can follow your nose to add the extra digits (e.g. make 'bcd' wider, overwrite extra digits, change the commands being sent to the display so you can access the second line, remove the shift...)
  24. HI! Ignoring the JA and JB ports that are required to talk to the display hardware, what would your module's ideal interface look like? Would it be a register based interface, where you write data to be displayed, (e.g. digit 0 in register 0): addr[4:0], din[7:0], writeEnable or would it be just a minimal interface for each digit you want to show: digit0[3:0], decimal0, blank0, digit1[3:0], decimal1, blank1, ... digitX[3:0], decimalX, blankX Or would it expose the ASCII nature of the display, allowing you to show almost anything? character0[7:0], character1[7:0], ... characterX[7:0] Or would it be a stream interface: din[7:0], data_enable, first_byte_of_packet Have you thought how you would manage the cursor (if it is needed at all)? Once you have that sketched out, the you are in the position of how to implement the innards of the module...
  25. hamster

    MMCM dynamic clocking

    Hi D@n! Have you checked if output of a SERDESE2 can be looped back into the fabric? Or would you need to push it back through a pin. The max jitter that an MMCM block is guaranteed to lock on is 1ns. Not sure if that is +/- 0.5ns RMS or not. If the SERDES output could be looped back to the MMCM then the the MMCM could potentially wipe the jitter (but you might need to reset the MMCM when you change frequency