breakin

Problem between AVR and FPGA

Recommended Posts

Hi,

I'm writing a serial SRAM-interface between AVR and the SRAM available to the FPGA. Aim is to learn VHDL/FPGA programming so I'm not taking easiest route here. But I have a problem!

I now have a small program on the AVR-side that transmits ones and zeroes to the fpga at a very low rate (say one per second now during debug).
I'm using the MOSI-pin for this.

When switching from 0 to 1 I detect _one_ rising edge on the fpga (by tracking value from last clock and current clock and looking for a 0->1 transition).
When switching from 1 to 0 I detect _multiple_ rising edges on the fpga. There should be none.

My question is if the AVR outputs correct nice digital signals that are interpreted as ones and zeros on the fpga, or do I need to process them somehow?
Is there something special about the MOSI pin?

All my VHDL programs looks fine during simulation so now I'm looking at other external factors. My VHDL program is still under suspicion of course!

Thanksful for any help I can get!

Share this post


Link to post
Share on other sites

You will need to eventually filter those, and also do some clock domain crosssing. All depends on exactly what you want to do. Simulation and real-world differs a lot when the IO pins are used.

Care to share more information ?

  • Like 1

Share this post


Link to post
Share on other sites

Hi Alvieboy,

So my main goal right now is:
* Learn VHDL
* Being able to program in something where SD-cards etc is easy (AVR, ZPUino etc) to make high-level things easier
* Doing FPGA stuff where I can access SRAM at the same time as the SD-card thing is running (time multiplexed accesses so SRAM I guess)
* Learning electronics rather than build systems... that is not doing too much makefiles etc but rather do it myself

I started using zpuino but it hogged the SRAM (I think I've talked about this before here with you) so I switched to the AVR. I realize that I can probably run zpuino from block ram or remake it, but then it didn't felt like it was helping me. Felt too makefile-y.
I was able to read/write sd-cards from the AVR by simply routing the SPI-bus to the SD-card using an ISE sketch.
Then I started making a SRAM interface between AVR and FPGA and there is where I am right now.

My naive thinking was that as long as I ran the AVR slow enough the FPGA would percieve HIGH as 1 and LOW as 0. I would get multiple 1 but by looking for the sequence 0,0,0,1 I would know I had a rising edge. From your answer I realize that I probably need to account for weird stuff I've read some things about but doesn't understand yet. I am doing this now...

I was hoping that by synchronizing ("sampling" as I like to think about it) the signal and having AVR-speed slow compared to fpga-speed (two second pulses on AVR and fpga running at 180mhz) it would sort itself out. The inputs are digital.. Boy was I naive ;)

When AVR turns from say 1 to 0 it might fluctuate for a few FPGA cycles (the FPGA runs much faster) so that I must perhaps check for say X ones in a row before I conclude that I have a 1? When there is no transition on the data-pin I hope that I can assume that I get all ones or all zeros depending on the current stable state...?

I realize that I am a total newbie and feel free to ignore me or point my to some tutorial. But I must confess that I am learning a lot by simply doing it the hard way ;)

Thanks for your time!

Cheers,

Anders.

Share this post


Link to post
Share on other sites

Why don't you use a SPI slave on the FPGA side ? You can reuse the one we have for wishbone access.
It should work well up to 80MHz. Don't use small speeds - these are more problematic actually.

 

Share this post


Link to post
Share on other sites

Hm...

I assume that the SPI-slave is a ready-made VHDL thing that I can instantiate in a sketch or something that processes SPI signals from input pins. But I have to generate the signal from something and that would be the AVR or something else. So the component you are talking about needs to solve the same problem I'm having right now, o I could take a look at it? The reason I'm using so slow speed is that I need to do it in order to be able to debug the FPGA using LEDs. I can't observe stuff at 80mhz! ;)

Currently I'm just using digitalWrite on the AVR side so I realize things will be really slow. Maybe you have something to accelerate SPI on the AVR-side.

I think I need to learn how to interface with digital signals from the outside since that is what I want a fpga for in the first place ;) 

Once I can program the AVR and send signals to-from vhdl I can start making more complicated VHDL, perhaps a soft-core of my own. AVR has serial port etc which makes it nice to debug my fpga thingy. Eventually I will hopefully not use the AVR at all... but I will still have to interface with external gadgetry where I have this problem. So I need to learn.

Thanks for taking your time. I realize that I might come off stubborn wanting to do things my way, but I just want to understand the puzzle. 

Cheers,
Anders.

Share this post


Link to post
Share on other sites

Which SPI-thing did you mean specifically?

I found

https://github.com/GadgetFactory/Papilio-Schematic-Library/blob/master/Libraries/Wishbone_Peripherals/spi.vhd#L78
and
https://github.com/GadgetFactory/Papilio-Schematic-Library/blob/master/Libraries/Wishbone_Peripherals/COMM_zpuino_wb_SPI.vhd

Both take clkrise, clkfall and samprise from outside. Does that hint at pre-filtered inputs? Did you mean me to look elsewhere?

Share this post


Link to post
Share on other sites

https://github.com/alvieboy/ZPUino-HDL/blob/master/zpu/hdl/zpuino/boards/papilio-duo/S6LX9/spiwb.vhd

You can connect it (almost) directly to the SRAM controller https://github.com/alvieboy/ZPUino-HDL/blob/master/zpu/hdl/zpuino/memory/sram/sram_ctrl8.vhd, using the pipelined-nonpipelined wrapper https://github.com/alvieboy/ZPUino-HDL/blob/master/zpu/hdl/zpuino/lib/wishbone/wb_master_np_to_slave_p.vhd

You don't need to worry about filtering and cross-domain clocking, the spiwb will do that for you.

You can find example code in Papilio Duo documentation (wishbone access from AVR). Note that accesses are 32-bit wide and need to be aligned (and no masking is provided).

Alvie

Share this post


Link to post
Share on other sites

Hi,

Back from easter weekend. Will try it like you described.

Later I will probably try to figure out how spiwb does the filtering since I need to read signals from other external gadgetry that doesn't speak SPI/wishbone but needs access to the SRAM.

Cheers,
Anders.

Share this post


Link to post
Share on other sites

Before posting here I had something that I thought was similar to what they showed in the latter article.

In spiwb falling_edge and rising_edge is used on a non-clock signal. https://www.doulos.com/knowhow/fpga/synchronisation/ argues against that, at least against using it all over the place. However in trying their approach I still end without a stable signal. Might be problems elswhere!

Either way I'm trying to understand the difference, but all parts of being a newbie and learning. Thanks for the links! There is obviously something subtle (to me) in them that I haven't grasped yet. I'm currently trying the duplicate the method from spiwb to see if the system as a whole works then.

Cheers,
Anders.

Share this post


Link to post
Share on other sites

I'm sorry, where is "spiwb" using edges on a non-clock signal ? How did you reach that conclusion ?

Here's the top level instantiation on Papilio Duo. You can see clock is assigned to WING_A(13):

  spiwb_inst: spiwb
    port map (
      nCS   => WING_A(10), --AVR_nCS,
      SCK   => WING_A(13), --AVR_SCK,
      MOSI  => WING_A(11), --AVR_MOSI,
      MISO  =>    avrspimiso, --WING_A(12), --AVR_MISO,
      MISOTRIS  => avrspimisotris,--WING_A(12), --AVR_MISO,
      clk   => sysclk,
      rst   => sysrst,

 

Here's the PAR report for the Papilio Duo.  As you can see the clock is there.

 

**************************
Generating Clock Report
**************************

+---------------------+--------------+------+------+------------+-------------+
|        Clock Net    |   Resource   |Locked|Fanout|Net Skew(ns)|Max Delay(ns)|
+---------------------+--------------+------+------+------------+-------------+
|              sysclk |  BUFGMUX_X2Y2| No   |  860 |  0.751     |  2.142      |
+---------------------+--------------+------+------+------------+-------------+
|     WING_A_13_BUFGP |  BUFGMUX_X2Y1| No   |   38 |  0.730     |  2.132      |
+---------------------+--------------+------+------+------------+-------------+
|      sysclk_sram_we | BUFGMUX_X3Y13| No   |    1 |  0.000     |  2.065      |
+---------------------+--------------+------+------+------------+-------------+

Alvie

 

Share this post


Link to post
Share on other sites

Hi,

First let me say that while that was the conclusion I reached, I'm not saying I am right! And while I'm trying to connect dots I'm just painting by numbers and trying to make it fit together right now. I'm sure a deeper understanding will form in time ;)

If you look in your clock report I think it says that WING_A_13_BUFGP is clocked.

This would be due to statements involving falling_edge(SCK) and rising_edge(SCK) in spiwb.vhd. SCK is connected to WING_A(13) accordingly to your top level instantation.

The article I linked (https://www.doulos.com/knowhow/fpga/synchronisation/) argued that if you turned too many signals (or possibly IO-pins) into clocks you would eat up some sort of resource on the fpga. They offered an alternative that did not use rising_edge/falling_edge on the SPI-clock. However they only claimed support for signals moving slowly compared to CLK so maybe a properly clocked approach is needed to reach 80-100mhz (for the running with ~200mhz system clock).

I'm trying to get a version using clocked resources to work since I'm not able to make their method work even for really slow moving signals.

Cheers,
Anders.

Share this post


Link to post
Share on other sites

What I initially meant was that spiwb were creating a new clock by using falling/rising_edge on a signal other than the SYSTEM clock. But in doing so it becomes a clock. But you are right that spiwb are not using falling/rising_edge on a non-clock signal! I'm currently trying your approach, it seems quite sensible for what I want to do! From the datasheet the FPGA in DUO has 16 global clock lines so it is ok to use them :) I realize now more what you are doing in spiwb so thanks for taking the time!

Share this post


Link to post
Share on other sites

Well, you seem to have misunderstood that article a bit.

What he refers to is how to capture a transition on an input signal (usually a control signal), like the "strobe" example. These signals are not clocks, and should not be used like clocks. Indeed that is the correct way to do it (and what we do btw in many devices - and what we do (the resync part) on every papilio pin [see pad.vhd for details].

On the contrary, the SPI SCK signal is a clock, and as such it is routed directly inside the FPGA fabric and drives the required logic. It could be oversampled, but that would cost much more resources because you'd have to resync also the MOSI signal. Could have the advantage of not requirign other clock-crossing, but would limit its speed to ~25Mhz (you should do at least a 4x oversample on the signal).

Alvie

Share this post


Link to post
Share on other sites

Hm.

I hear what you are saying :) But currently I'm driving the SPI-clock myself using digitalWrite from the AVR at a rate of 1 change per second. Hence I'm oversampling (if that simply means reading often enough not to miss pulses). So I would expect the method from the article to work, unless there is something special about the SPI-clock.
I detect a rising edge when the clock goes from 0->1, but sometimes when going from 1->0 I get multiple rising/falling edges which is not what I'm sending unless the SPI has a life of its own.

Is there a reason why I couldn't treat it as a strobe if I'm going slowly enough? I'm not actually doing SPI properly, just using the pins...

The reason I keep asking question is that I feel that should learn the strobe-case as well and I can't figure out why I can't get it to work with the SPI-clock-pin...

I will read up in pad.vhd to see if I'm simply doing the strobe-approach incorrectly or if something else is going on. Will also try a different pin to see if the SPI-clock is different somehow...

Cheers,
Anders.

Share this post


Link to post
Share on other sites

Care to share your VHDL code ? Yes, the signals are quite stable, so you should not see any "bouncing".
You are not using Open-Drain on AVR side, right ? You're driving them directly to '1' or '0'.

Alvie

Share this post


Link to post
Share on other sites

If I had send you the source code you would have laughed when you discovered that I set up pinmode correctly for all pins _except_ the SPI-clock pin that I wanted to work. It was simply left at the default value which was not what I wanted. Setting it to OUTPUT just made everything work.

So I'm a long time programmer so when I end up in weird territory I simplify as much as possible. Hence only using one pin etc. Earlier I think that the sd-card code set it up correctly but I had commented it all out when trying to get this to work.

So the good news is that due to this I've learned a lot. Thanks!

Cheers,
Anders.

Share this post


Link to post
Share on other sites

Let me re-iterate how happy I am for all the help. While the error in my simple scenario turned out to be simple in the end I learned a lot about how to do this properly.
Thanks for being so helpful!

My memory interface almost works and things mostly behaves as I expected them to when I started out so I'm on track!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now