• Content Count

  • Joined

  • Last visited

  • Days Won


Posts posted by hamster

  1. Hi!

    What you want to do is to create a DDR Output primitive , set the outputs to "0" and "1", and then connect the clock to the DDR Register's clock.

    It's called "clock forwarding" and it is a pretty standard technique to make a clock visible to the outside world.

    Oh, and I think you might have the wrong FPGA selected in your project settings. That is want is causing the "Bitfile is incompatible" error.


    Library UNISIM;
    use UNISIM.vcomponents.all;
    ODDR1 : ODDR  generic map(DDR_CLK_EDGE => "SAME_EDGE",  INIT => '0', SRTYPE => "SYNC") 
                 port map (Q => output_pin, C => clk100, CE => '1', D1 => '0', '1', R => '0', S => '0');


  2. 13 hours ago, xc6lx45 said:


    one thing comes to mind: for a power line grid frequency of 50 Hz, you can use a 20 ms moving-average window over the data, notches out the power line hum (which is probably visible somewhere at such high resolution)


    The AD7193 can be configured to filter at 50 Hz or 60 Hz to solve this issue.

    However, for this use it isn't such a big deal. The inputs are very low impedance as they are over a 1 ohm shunt, so it would take a very powerful field to make a noticeable signal.

  3. I've been working on a project and it is looking pretty nice. It is an ESP32 microcontroller, talking SPI to a PMOD AD5 that has two inputs across a 1 ohm 5W current sense resistor.

    At the highest ADC gains the steps are  2.5nA, but full range is about 20mA.

    I am currently currently running with a gain of 8, and can measure currents from a few nA through to about 300mA.

    Below is a graph of the startup current of another ESP32, with a spike a little after 30s when I get an image over WiFi - for now the data is just logged to a serial port at 50S/s and then I graphed in a Google Sheet.

    I intend to use it to test the deep-sleep performance in various modes, and to see the impact of firmware changes.


  4. Once you have an idea of the frequency, you then might want to look at using a COSTAS loop to follow the frequency. You can use the frequency and phase information from the tracking loops to recover any modulated data. 


  5. I've been working on my first large FPGA project in a long while, implementing DisplayPort in Verilog, using the Nexys Video as my development platform.

    I've got it working, and better than that I've got the standard 720p resolution working, and tomorrow I should have 1080p working too. Currently it uses 800 LUTs and 700 FFs, and 1 BRAM.

    If interested you can follow along or help with development at https://github.com/hamsternz/DisplayPort_Verilog



  6. My suggestion would be to use one of the push-buttons as a "Store switch value in X", and another as "Store switch value in Y".

    You could maybe use the other buttons as "Show me X" and "Show me Y", and the center button as "Show me X*Y" - with no buttons pushed it could just show you the value of the switches.

  7. On 9/30/2018 at 3:03 PM, zygot said:

    Yeah, that's what's stuck in my craw. I was able to put off mentioning my feelings about this post until today. It's been too long since I made a credible attempt at any sort of jitter analysis but I still have the after-taste of it being quite hard. I'm sure that there are labs that can properly characterize this kind of thing but they have very expensive equipment and timing sources plus a lot more accrued experience than I'll ever have. My only real point is that I feel very uncomfortable about coarse treatment of a complicated subject in the absence of a very knowledgeable moderator.

    Still, it's one of those ideas that are hard  to get out of one's head... like certain jingles or pop tunes of yore.

    So... wouldn't be interesting to have, say 4, PPS sources and compare outputs... you know, if one can figure out how to do that meaningfully. I still wouldn't want to be making any claims. Perhaps it's just so late that most of my brain has gone to sleep...

    Interestingly enough I do have four different GPS modules sitting on my bench at the moment. I may just try that if I get enough spare time...

  8. On 9/30/2018 at 8:01 AM, zygot said:

    @hamster,The text says that "my FPGA board's onboard 100MHz oscillator is 100,000,800 Hz". I'm not sure how you are measuring that but I am sure that it isn't that all the time, at any instant or over any particular interval. You board's 100 MHz oscillator frequency has age, temperature, and voltage dependent characteristics on top of the  initial error.

    I can at least offer you one answer... In a seperate test, 3,684,732,345,578 cycles of the FPGA's 100MHz clock passed over 36,848 (second intervals (a little over 10 hours). That is an average of 100,000,877 cycles per second.

    The distribution of counts ranged from 100,000,489 to 100,001,193, which is +/- 352 counts, which when graphed look very much like a normal distribution. 90% of counts fell between 100,000,715 and 100,001,010

    If we can assume and that the start and end pulse were +/- 400 counts (4us) the maximum worst-case error will be 800 counts, which has little impact on the average frequency of 100,000,877 Hz during the time I was collecting data.

    I am sure that the reference signal generated by this design is very poor, it will have many terrible attributes. But I am sure that when it comes to measuring the passage of time it will be far better than the on-board crystal oscillator, which is off by around 8.77 parts per million at standard lounge conditions.


  9. I had some spare time the other night, and connected the pulse per second output of a GPS module to a BASYS3, and then worked of the world's worst GPS disciplined 1MHz source - maybe better described as 1,000,000 pulses per second, because of jitter in the output.


    It would be an interesting project for somebody to rework/extend this, add CORDIC sine function and an DAC, to make a GPS referenced sine wave generator.

  10. set_value: process(btn)
         if rising_edge(btn1) then
           value1 <= switches;
         end if;
       end process;
    display: process(btn2,value1, switches) 
          if btn2 = '1' then
            leds <= std_logic_vector(unsigned(value1)+unsigned(switches));
            leds <= switches;
          end if;
        end process;

    I haven't coded it and tested it, but with something like the above code should be possible to make an "add two binary numbers" calculator.

    It is filled with errors in form and style (e.g. using a button input as a clock), but it should be possible to get something close to what you describe working, without jumping head-first into the technicalities of synchronous design.

  11. On 8/29/2018 at 12:11 AM, Joseph Fourier said:

    @hamster  I was able to run your AXI Slave interface. It works great!

    It is now very easy to exchange information between PS and PL, and it even supports execute-in-place (e.g. I can put ARM instructions to register file and run PS CPU directly from it).


    I have some questions about your AXI Slave design:

    1) AXI_a*size has no effect on INCR type of burst transactions, but according to AXI protocol: the increment value depends on the size of the transfer. You set it only for WRAP type, is it correct? Thus, burst size is always 0 for INCR type?

    2) Do you know how PS initiates INCR burst type? A kind of memset/memcpy need to be used for that or an incrementing pointer will also work?

    3) Where WRAP type is necessary? How to use PS to work in WRAP mode?


    You may also update your wiki page with following:

    0) Create provided VHDL files

    1) Create a block-diagram and add PS IP core to it

    2) Apply configuration provided by your board's pre-settings; this will set all necessary initialization settings for PS (e.g. clock frequencies, DDR bindings, etc.)

    3) Press auto-configure (or how it's called) ==> this will connect PS IP to DDR and to fixed IO

    4) Add "External ports" to the diagram (create new AXI_CLK and AXI external ports) and connect them to PS ports

    5) Generate VHDL wrapping code for this block diagram

    6) Put generated system under axi_test_top by renaming it to axi_test_wrapper (default name is design_#_wrapper in my Vivado version)

    7) This will auto-connect block-diagram external ports with axi_test_top

    8 ) Add constrains file and rename/uncomment external ports where necessary

    9) Generate bitstream

    10) File->Export->Hardware and create .hwf file which contains PS configuration

    11) Open Xilinx SDK and create a new project: select  .hwf  file as Hardware BSP for this project

    12) Now, Xilinx SDK will auto-generate few .c and .h files which contain necessary PS initialization ==> clocks, IRQs, DDR, etc.

    13) Add hello_world.c application to the project


    @hamster Thank you very much. I've learned a bunch of new things thanks to your help!



    Hi! You are welcome - notes added: http://hamsterworks.co.nz/mediawiki/index.php/Simple_AXI_Slave#Notes_from_the_Internet


    1) Might be a bug - if it is, email me the fix :)

    2) No idea - but you need to have the correct number of transfers to stop the bus form locking up. I suspect DMA might be needed.

    3) "Where WRAP type is necessary? How to use PS to work in WRAP mode?" Interesting question. I assume that it is used to fill cache lines. The data at the address being requested is delivered first, then the rest of the cache line is filled. As this address range is uncached I suspect it is unused.

  12. 2 hours ago, Joseph Fourier said:

    >> That is based on the address window assigned to the AXI port in the PS configuration.

    In that case for a completely open description there must be an additional source file where this information is presented, no?

    Yes, of course. But at the time I was playing with that project was only interested in developing a working understanding of AXI. 

    I assume there is a magical binary file that contains all the configuration bits for the PS subsystem block, that forms part of the configuration/boot image for the Zynq....

  13. 6 hours ago, Joseph Fourier said:

    Your simple AXI slave looks very interesting, thanks! What I still don't understand:

    1) how do you get this number: (uint32_t *)(0x43C0<<16)

    is it a kind of memory-mapped AXI register in PS address space? but I cannot find it in documentation

    2) is your hello.c program a standalone code (will run not under Linux), right? It would be helpful to see a Makefile or just commands how to build an image from C code.

    Thanks for your great help!

    1) That is based on the address window assigned to the AXI port in the PS configuration. Look at the screen grab below the block diagram for the PS in that web page.

    2) The hello Program was made in the Eclipse IDE that Vivado provides for bare-metal development. Under linux you will either need a devices driver, or using shared memory or something, or I would tend to open /dev/mem and seek and write in there for a quick hack.


  14. 2 hours ago, Joseph Fourier said:

    For PS to write to BRAM, PL must contain an AXI logic configured, right? Otherwise I cannot see other data channels on the Zynq diagram

    Yes. An AXI Slave interface would be needed to read/write to one of the BRAM ports, and the PL design can read/write to the second port on the BRAM.

    Another other option might be to make an AXI master, that can write into and/or read from the PS's memory., but architecting this way seems wrong.

    The last option would be to route some of the MIO pins into the fabric, but this gives you a very narrow, restrictive low bandwidth connection compared to a AXI slave.

  15. Hi,

    I haven't been around here much lately, but I saw your post and thought I had something of use to you.

    Here is an AXI Slave, connected to the a PL, written in only VHDL: It only decodes a few addresses, and doesn't decode the entire assigned address range.


    Feel free to drop me an email, but it has been a while since I've had spare time to do any of this stuff....

  16. Depending on what you are after, a full FFT might not be appropriate. It also depends on your desired throughput rates (e.g. 48KS/s for audio, or 100MS/s for radio work).

    'Srreaming' FFT functions are possible, where the oldest sample is removed from the calculation and the new sample added - but the data can't be 'windowed', which can be a problem.

    Maybe if you told.us more.about the.end result you are after?

  17. I think it is best to view it as a car assembly line.

    The quickest way to assemble a car is for each team to do their step one after each other - a car will take the combined time of all operations, but you are only building one car at a time. Fine if you a build a single Mclaren F1 race car.

    The quickest way to assemble lots of cars is a production line. Each team does their step, and then the car moves on to the next team for the next process. Making the first car takes (number of steps) * (length of longest step). But once you have your first car you get another car every (length of longest step).

    But what if mounting a motor takes five minutes, and the next longest operation takes only three minutes? You can only make one car every five minutes, and the rest of the teams are idle for at least 40% of the time.

    The solution might be to split mounting the engine into two steps, each taking up to three minutes. Then you can make a car every three minutes. In FPGA-speak, this is pipelining to get the highest clock speed. Big gains are easy at first, but then it gets harder and harder to get any faster, as more parts of the design become critical to the timing of the overall pipeline.

    The other solution might be to combine pairs of the three minute steps so no step takes longer than 5 minutes. That way you only need half the resources, yet can still produce a car every five minutes... this is the "once you meet your FPGA's timing constraints, then re-balancing the pipeline can save you resources" strategy. 


  18. Oh, sorry - I forgot to answer.

    2) This is a post-implementation view. So any optimizations that could be made have been made. I am guessing (and this is only guessing) that during the optimization thnigs have been pushed around. Are you displaying a full range of colours? or just a couple? The 24bit RGB seems to have been reduced to just a couple of bits.

    You can assign a "KEEP" attribute to the signals in the video generator block, and it should not optimize them away.

  19. 1) it is easier to explain why this is. 

    An internal PLL had to lock on to the pixel clock. If it fails to lock (because the clock is out of range when it attempted to lock) or it becomes unlocked (e.g. the clock stops or changes frequency) it needs to be reset so it can start liocking back onto the now stable input clock again.

    I willwill answer (2) when I am not on my phone :-)