EmbDev.net

Forum: FPGA, VHDL & Verilog VHDL process issue : double execution


von Sacha (Guest)


Rate this post
useful
not useful
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
entity SPI3_slave is
2
port (
3
  
4
  SCLK    : in std_logic; -- Serial clock (generated by MCU)
5
  SDO    : out std_logic; -- Serial data out
6
  CS    : in std_logic; -- Pulled low by MCU to initiate com
7
  
8
  LED : out std_logic_vector(7 downto 0) -- 8 LEDs on the board
9
10
);
11
end SPI3_slave;
12
13
14
architecture behave of SPI3_slave is
15
16
signal cpt_dat  : integer range 0 to 8 := 7; -- Counter
17
18
begin
19
20
process(SCLK)
21
    begin
22
23
  if (CS = '0') then
24
  
25
    if (rising_edge(SCLK)) then
26
27
        LED(3) <= '1'; -- To 
28
29
                                -- To simulate data out
30
        case cpt_dat is
31
        when 6 =>
32
          SDO <= '0';
33
        when 5 =>
34
          SDO <= '1';
35
        when 4 =>
36
          SDO <= '0';
37
        when 3 =>
38
          SDO <= '1';
39
        when 2 =>
40
          SDO <= '0';
41
        when 1 =>
42
          SDO <= '1';
43
        when others =>
44
          SDO <= '1';
45
        end case;
46
        
47
        -- LEDs turned on one after the other
48
        LED(4) <= '0';
49
        LED(5) <= '0';
50
        LED(6) <= '0';
51
        LED(7) <= '0';
52
        LED((cpt_dat mod 4) + 4) <= '1';
53
        
54
                                -- Counter goes from 7 to 0
55
                                -- LED 3 off when counter reaches 0
56
        if (cpt_dat /= 0) then
57
          cpt_dat <= cpt_dat - 1;
58
        else
59
          LED(3) <= '0';
60
        end if;
61
      
62
63
    end if; -- Rising edge
64
    
65
  else -- CS = '1'
66
      cpt_dat <= 7;
67
68
  end if; -- CS
69
  
70
71
    end process;
72
73
end behave;

von Lattice User (Guest)


Rate this post
useful
not useful
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.

von Schlumpf (Guest)


Rate this post
useful
not useful
You should wirte the line
1
  if (CS = '0') then

after the line
1
  if (rising_edge(SCLK)) then

like this
1
  if (rising_edge(SCLK)) then
2
     if (CS = '0') then
3
        ....
4
        if (cpt_dat /= 0) then
5
           ...
6
        else
7
           ...
8
        end if;
9
     else
10
        ...
11
     end if;
12
  end if;

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.

von Sacha (Guest)


Rate this post
useful
not useful
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.

von Schlumpf (Guest)


Rate this post
useful
not useful
additional the code you wrote could cause a combinatorial clock.
You should check this in your synthesis report.

von Lattice User (Guest)


Rate this post
useful
not useful
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.

von Sacha (Guest)


Rate this post
useful
not useful
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! :-)

von Schlumpf (Guest)


Rate this post
useful
not useful
Lattice User wrote:
> Basically it is an ansynchronous reset

You are right.
A strange way to code it, but you are right.

von Lattice User (Guest)


Rate this post
useful
not useful
This is a bit more complete version from Lothar (last posting in above 
thread)

Beitrag "Re: Erfahrung mit SPI Slave und Spartan 6 FPGA?"

von Lattice User (Guest)


Rate this post
useful
not useful
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.

von Schlumpf (Guest)


Rate this post
useful
not useful
So probably it´s a good idea to code it in a "usual" way and if the 
problem still occurs he should check the clock-signal for ringing

von Sacha (Guest)


Rate this post
useful
not useful
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?

von Sacha (Guest)


Rate this post
useful
not useful
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.

von Schlumpf (Guest)


Rate this post
useful
not useful
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.

von Lattice User (Guest)


Rate this post
useful
not useful
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?

von Sacha (Guest)


Rate this post
useful
not useful
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.

von Lothar M. (Company: Titel) (lkmiller) (Moderator)


Rate this post
useful
not useful
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...

von Sacha (Guest)


Rate this post
useful
not useful
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?

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.