Hello everyone!
I'm quite new to FPGA developing and VHDL. I'm trying to make a simple
serial interface to communicate with a MCU (a 3 wires SPI like
interface, more precisely).
I use a DE0-nano board from Altera, which has a few LEDs and buttons on
it.
Since I have a weird behavior of my entity, I made a really simple one
that only shifts data on the rising edge of the clock. To illustrate
that, I make 4 LEDs light one after the other but rather than doing
what's excepted, some of them don't light and it jumps directly to the
next one (instead of lighting L7 then L6 then L5 then L4, it does L7
then L5 after only one clock pulse, for instance). These "jumps" seem to
occur when SDO goes from high to low.
A counter in the process indicates that it executes twice when the jumps
occur (the LED 3 should turn off after 8 clock pulses but it does after
4 only).
The weird thing is that when I use a button on the board as a clock and
press the button myself, data is correctly shifted and the LEDs behave
as expected.
(Just switching in the entity parameters between the external clock
signal and the button output).
I've checked again and again the pin assigments, that doesn't seem to be
the problem.
It must be something I've done wrong, but I really don't see what, so
i'm begging for help ^^
Thanks for your time and your advice on that problem that really annoys
me!
Here is the entity :
1
entitySPI3_slaveis
2
port(
3
4
SCLK:instd_logic;-- Serial clock (generated by MCU)
5
SDO:outstd_logic;-- Serial data out
6
CS:instd_logic;-- Pulled low by MCU to initiate com
7
8
LED:outstd_logic_vector(7downto0)-- 8 LEDs on the board
Sacha wrote:>> The weird thing is that when I use a button on the board as a clock and> press the button myself, data is correctly shifted and the LEDs behave> as expected.> (Just switching in the entity parameters between the external clock> signal and the button output).>
Where does that external clock come from?
If you just use a switch to simulate a clock you may see bouncing.
The buttons on the board are probably hardware debounced.
A problem with your code is that cpt_dat is the output of a register
because you assign a value in within the if(rising_edge...)
But on the other hand you assign a value outside this "clocked" if so
the cpt_dat is just something combinatorial built with CS.
What I called "the external clock" is the clock used for the serial com
which comes from the MCU.
Indeed, there is an IC that debounces the signal between the buttons and
the FPGA.
Sacha wrote:> What I called "the external clock" is the clock used for the serial com> which comes from the MCU.>> Indeed, there is an IC that debounces the signal between the buttons and> the FPGA.
Make sure that there is NO ringing on the clock line. FPGA are very fast
and ringing also can cause double clocking.
Unless you need a very fast (greater 50-100 MHz) SPI speed, it is much
more flexible and stable to oversample the input with a fast internal
clock.
Take a look at this posting from our guru, Lothar Miller
Beitrag "Re: Erfahrung mit SPI Slave und Spartan 6 FPGA?"
(It's german, but the vhdl sample is small enough, also you can try
google translate)
Schlumpf wrote:> additional the code you wrote could cause a combinatorial clock.> You should check this in your synthesis report.
Basically it is an ansynchronous reset, but with an incomplete
sensitivity list. Synplify Pro will also complain that not all registers
are assigned in the reset path.
I was about to try to make a sort of buffer between the incomming signal
clock and the entity clock input.
I'll take a look at what you suggested and come back when I've got
something new, thanks for fast help guys! :-)
Schlumpf wrote:> Lattice User wrote:>> Basically it is an ansynchronous reset>> You are right.> A strange way to code it, but you are right.
Of course strange ways to encode it may result in failing of the
synthesizer to recognise it. And the you may end up with a combinatorial
clock.
I used the oversampling example in the link you gave me and the circuit
seems to behave as expected now. Thx guys, I was really blocked on this
one!
So if I understood well, the clock signal was not clean enough and
oscillations faster than the internal board clock (which is 50 MHz) made
the process trigger twice? Thus, Sampling using this 50 MHz clock
filtered out the oscillations?
Also, this lead me to a few questions regarding good or bad design
practice:
- Is it a good practice to do that sampling for every entity (I mean,
wherever it is possible)?
- Also, is it better to use synchroneous resets or asynchroneous? In the
more general way?
Rectification: it works only on the rising edge of the clock, not on the
falling edge.
If the data is shifted out when the sclkSR is "10", then the double
trigger still occurs.
Sacha wrote:> and> oscillations faster than the internal board clock (which is 50 MHz) made> the process trigger twice?
No, it is independet of the internal clock.
If you wire the SCK directly to the clock of a register, SCK is the
clock of the register. And the registers of a FPGA are very fast. So a
small ringing of far less than 1ns can caus double trigger of that
register. And your counter counts double.
Sacha wrote:> Is it a good practice to do that sampling for every entity (I mean,> wherever it is possible)?
No, you only have to sample all signals which are not driven from the
same clock as the target register is driven.
If you have different components (it is called components and not
entities) within one clock domain (all registers are driven by the same
clock), you don´t have to sample the signals
Sacha wrote:> - Also, is it better to use synchroneous resets or asynchroneous? In the> more general way?
It is better to use the synchroneous reset. When releasing a
asynchroneus reset the different latencys to the registers can caus that
some registers are still in reset state and some not when the next
active edge of clock occours. So e.g. in a counter a couple of registers
start counting whilst some registers are still in reset state.
But this method needs more logic ressources in the FPGA becaus the reset
ist handled like any other signal.
Modern FPGAs have special reset paths with almost no latency or skew to
the register's dedicated reset inputs. If you use these GSR (Global Set
Reset) and synchronize the external reset signal with one synchronizer
stage (at least two registers) it should be fine.
Sacha wrote:> Rectification: it works only on the rising edge of the clock, not on the> falling edge.> If the data is shifted out when the sclkSR is "10", then the double> trigger still occurs.
I think you have a very bad hardware setup, and not only ringing but
also crosstalk.
Lothars code is still vunerable to glitches (ie.e from crosstalk) when
they occur at the wrong moment.
In a bad environment you can add (glitch) filters to the inputs as a
last resort. But try to fix the setup.
I am assuming you are using two boards connected with some single wires.
How is the ground connected?
Schlumpf wrote:> No, it is independet of the internal clock.> If you wire the SCK directly to the clock of a register, SCK is the> clock of the register. And the registers of a FPGA are very fast. So a> small ringing of far less than 1ns can caus double trigger of that> register. And your counter counts double.>
I mean, using the board's clock to sample the clock has the effect of
filtering out the noise as sampling acts partially as a low-pass filter.
But yes I understand what you're saying :)
I fixed the problem by reducing the sampling frequency to 1 MHz instead
of 50.
I think you're right, I'm connecting the 2 boards in a very dirty way
since I'm only trying some things out. Simple wires, a breadboard and
the 2 boards are powered by USB cables. Same for the ground, only a wire
connects them.
Lattice User wrote:> Lothars code is still vunerable to glitches (ie.e from crosstalk) when> they occur at the wrong moment.
You're right, but thats the way 99,9% of SPI devices behave: they rely
on clean signals on the copper wire. Of there is some kind of xtalk or
EMC problems then those have to be fixed on board level...
Sacha wrote:> I fixed the problem by reducing the sampling frequency to 1 MHz instead> of 50.
You did not "fix" the problem! I would say: you just reduced the
probability of a fault by a factor of 50...
So I reduced it by a probability which is way greater since I didn't
encounter it from that point.
You don't think that the cause was a fast oscillation on the SCLK line?