Forum: FPGA, VHDL & Co. Asynchroner Datenbus an FPGA


von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

ich hab hier einen kleinen FPGA (LatticeMACHXO) an einem 
Adress/Datenbus. Im FPGA sind eine paar Register die über den Datenbus 
gelesen und beschrieben werden können. Ein gemeinsamer Takt steht nicht 
zur Verfügung. Der Takt des FPGAs ist aber so hoch das ich mindestens 
eine (evtl. mehr) Flanken während der Low-Zeit des WR-Signals habe. Das 
Ganze sieht (vereinfacht) zur Zeit etwa so aus:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;   
4
5
entity slave is
6
7
port( 
8
    -- data bus from host
9
    DATA:   inout std_logic_vector(15 downto 0);  
10
    ADR:    in std_logic_vector(5 downto 1);
11
    RD:     in std_logic;
12
    WR:     in std_logic;
13
    CS:     in std_logic;
14
   
15
    -- system interface
16
    RST:        in std_logic;   -- Global system reset
17
    CLK:        in std_logic;   -- 25MHz clock
18
    
19
    );
20
end;
21
22
architecture behavior of slave is
23
    
24
    -- internal mapping register of direct inputs
25
    signal gpio_out     : std_logic_vector(15 downto 0);
26
    
27
    -- internal spi related register
28
    signal spi_reg_out  : std_logic_vector(0 to 15);
29
    
30
begin
31
    
32
    ----------------------------------------------------------------------------
33
    -- clock synchronous stuff for SPI and data bus connection
34
    process (CLK, RST, WR)
35
    begin
36
        if RST = '0' then        
37
38
            spi_reg_out <= (others => '0');
39
            gpio_out <= (others => '0');
40
        
41
        elsif falling_edge(CLK) then
42
            
43
            if CS = '0' and WR = '0' then
44
                
45
                if ADR = "10000" then          -- write to 16 (spi output)
46
                    spi_reg_out <= DATA;
47
                elsif ADR = "10010" then       -- write to 18 (gpio output)
48
                    gpio_out <= DATA;
49
                end if;            
50
            
51
            elsif cs_int = '1' then
52
            
53
                --SPI state machine
54
                -- some code here
55
                
56
            end if;
57
                    
58
        end if;
59
    end process;
60
    
61
end behavior;

Leider hab ich damit ab und an (bei rund 1% der Zugriffe) falsche Daten 
im FPGA. Wie macht man sowas den richtig? Ich würde die Daten ja mit der 
steigenden Flanke von WR übernehmen wenn CS = '0'. Aber dann hab ich 
zwei asynchrone Takte im System was die Sache auch nicht wirklich 
vereinfacht. Ich bin leider nicht so der VHDL Experte.

Matthias

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Wie macht man sowas den richtig?
Der Ansatz passt schon:
1. Schritt: asynchrones Übernehmen der Daten (und der Adresse) in ein 
lokales Pufferregister mit der steigenden Flanke von WR
2. Schritt: Einsynchronisieren von WR und eine synchrone 
Flankenerkennung der steigenden Flanke, dabei die Daten synchron aus dem 
lokalen Pufferregister übernehmen

> Aber dann hab ich zwei asynchrone Takte im System
> was die Sache auch nicht wirklich vereinfacht.
Das ist hier nicht schlimm, denn mit der WR-Signal kann sauber die 
Datenübergabe geregelt werden.

So wie du es machst:
1
            if CS = '0' and WR = '0' then
2
                
3
                if ADR = "10000" then          -- write to 16 (spi output)
4
                    spi_reg_out <= DATA;
5
                elsif ADR = "10010" then       -- write to 18 (gpio output)
6
                    gpio_out <= DATA;
7
                end if;
müssen die Adressen bereits bei der fallenden Flanke des WR-Signals 
stabil sein, sonst könnten irgendwelche Daten an die falsche Adresse 
geschrieben werden.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.