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
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
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
(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
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
Here is the entity :
entity SPI3_slave isport (
SCLK : instd_logic; -- Serial clock (generated by MCU)
SDO : outstd_logic; -- Serial data out
CS : instd_logic; -- Pulled low by MCU to initiate com
LED : outstd_logic_vector(7downto0) -- 8 LEDs on the board
architecture behave of SPI3_slave issignal cpt_dat : integerrange0to8 := 7; -- Counterbeginprocess(SCLK)
beginif (CS = '0') thenif (rising_edge(SCLK)) then
LED(3) <= '1'; -- To -- To simulate data outcase cpt_dat iswhen6 =>
SDO <= '0';
SDO <= '1';
SDO <= '0';
SDO <= '1';
SDO <= '0';
SDO <= '1';
SDO <= '1';
-- LEDs turned on one after the other
LED(4) <= '0';
LED(5) <= '0';
LED(6) <= '0';
LED(7) <= '0';
LED((cpt_dat mod 4) + 4) <= '1';
-- Counter goes from 7 to 0-- LED 3 off when counter reaches 0if (cpt_dat /= 0) then
cpt_dat <= cpt_dat - 1;
LED(3) <= '0';
endif; -- Rising edgeelse-- CS = '1'
cpt_dat <= 7;
endif; -- CSendprocess;
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.
if (rising_edge(SCLK)) thenif (CS = '0') then
if (cpt_dat /= 0) then
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.
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
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
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
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
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
- 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?
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
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
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
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...