VHDL: बिट्स की गिनती करते समय मॉड्यूल बेतरतीब ढंग से विफल हो जाता है


9

पृष्ठभूमि

यह एक व्यक्तिगत परियोजना है; यह FPGA को N64 से जोड़ने के संबंध में, बाइट मान जो FPGA को प्राप्त करता है उसे UART के माध्यम से मेरे कंप्यूटर पर भेजा जाता है। यह वास्तव में बहुत अच्छा काम करता है! दुर्भाग्य से यादृच्छिक समय पर, डिवाइस विफल हो जाएगा, फिर ठीक हो जाएगा। डिबगिंग के माध्यम से, मैं इस समस्या का पता लगाने में कामयाब रहा, हालांकि मैं इसे ठीक करने के तरीके पर अडिग हूं क्योंकि मैं वीएचडीएल के साथ काफी अक्षम हूं।

मैं अभी कुछ दिनों के लिए वीएचडीएल के साथ कर रहा हूं और मैं इसे हल करने में असमर्थ हो सकता हूं।

समस्या

मेरे पास F64A में N64 सिग्नल को मापने वाला एक आस्टसीलस्कप है, और दूसरा चैनल FPGA के आउटपुट से जुड़ता है। मेरे पास काउंटर मूल्य रिकॉर्ड करने वाले डिजिटल पिन भी हैं।

अनिवार्य रूप से, N64 एक STOP बिट सहित 9 डेटा बिट्स भेजता है। काउंटर प्राप्त डेटा बिट्स को गिनता है और जब मैं 9 बिट्स तक पहुंचता हूं, तो FPGA UART के माध्यम से संचारित करना शुरू कर देता है।

यहाँ सही व्यवहार है: यहां छवि विवरण दर्ज करें

FPGA नीला तरंग है और नारंगी तरंग N64 का इनपुट है। प्राप्त करने की अवधि के लिए, मेरा FPGA "इकोस" डिबगिंग उद्देश्यों के लिए इनपुट का संकेत है। FPGA के 9 तक पहुंचने के बाद, यह UART के माध्यम से डेटा संचारित करना शुरू करता है। ध्यान दें कि डिजिटल पिन 9 तक गिना जाता है और N64 समाप्त होने के तुरंत बाद FPGA आउटपुट कम हो जाता है।

यहाँ एक विफलता का एक उदाहरण है:

यहां छवि विवरण दर्ज करें

ध्यान दें कि काउंटर 2 और 7 को काटता है! FPGA अंत तक पहुंचता है, N64 से अगली शुरुआत के लिए इंतजार कर रहा है, लेकिन कुछ भी नहीं। तो FPGA बार और बाहर ठीक हो जाता है।

यह N64 प्राप्त मॉड्यूल के लिए VHDL है। इसमें काउंटर शामिल है: s_bitCount।

library IEEE;
use IEEE.STD_LOGIC_1164.all;   
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity N64RX is
     port(
         N64RXD : in STD_LOGIC;                    --Data input
         clk25 : in STD_LOGIC;
         clr : in STD_LOGIC; 
         tdre : in STD_LOGIC;                      --detects when UART is ready
         transmit : out STD_LOGIC;                 --Signal to UART to transmit  
         sel : out STD_LOGIC; 
         echoSig : out STD_LOGIC;
         bitcount : out STD_LOGIC_VECTOR(3 downto 0);
         data : out STD_LOGIC_VECTOR(3 downto 0)   --The significant nibble
         );
end N64RX;

--}} End of automatically maintained section

architecture N64RX of N64RX is 

type state_type is (start, delay2us, sigSample, waitForStop, waitForStart, timeout, count9bits, sendToUART);

signal state: state_type;
signal s_sel, s_echoSig, s_timeoutDetect : STD_LOGIC;
signal s_baudCount : STD_LOGIC_VECTOR(6 downto 0);  --Counting variable for baud rate in delay
signal s_bitCount : STD_LOGIC_VECTOR(3 downto 0);  --Counting variable for number of bits recieved 
signal s_data : STD_LOGIC_VECTOR(8 downto 0);   --Signal for data

constant delay : STD_LOGIC_VECTOR(6 downto 0) := "0110010";  --Provided 25MHz, 50 cycles is 2us 
constant delayLong : STD_LOGIC_VECTOR(6 downto 0) := "1100100";

begin 

n64RX: process(clk25, N64RXD, clr, tdre)
begin
    if clr = '1' then
        s_timeoutDetect <= '0';
        s_echoSig <= '1';
        s_sel <= '0';
        state <= start;
        s_data <= "000000000";
        transmit <= '0'; 
        s_bitCount <= "0000";
        s_baudCount <= "0000000";  
    elsif (clk25'event and clk25 = '1') then    --on rising edge of clock input
        case state is
            when start =>   
                --s_timeoutDetect <= '0';
                s_sel <= '0';
                transmit <= '0';        --Don't request UART to transfer   
                s_data <= "000000000";
                s_bitCount <= X"0";   
                if N64RXD = '1' then
                    state <= start;
                elsif N64RXD = '0' then     --if Start bit detected
                    state <= delay2us;
                end if;    

            when delay2us =>                 --wait two microseconds to sample
                --s_timeoutDetect <= '0';
                s_sel <= '1';
                s_echoSig <= '0';
                if s_baudCount >= delay then    
                    state <= sigSample;
                else
                    s_baudCount <= s_baudCount + 1;
                    state <= delay2us;
                end if;  

            when sigSample => 
                --s_timeoutDetect <= '1';
                s_echoSig <= N64RXD;
                s_bitCount <= s_bitCount + 1;
                s_baudcount <= "0000000";
                s_data <= s_data(7 downto 0) & N64RXD;      
                state <= waitForStop;   

            when waitForStop => 
                s_echoSig <= N64RXD;
                if N64RXD = '0' then
                    state <= waitForStop;
                elsif N64RXD = '1' then
                    state <= waitForStart;
                end if;   

            when waitForStart => 
                s_echoSig <= '1';
                s_baudCount <= s_baudCount + 1; 
                if N64RXD = '0' then 
                    s_baudCount <= "0000000";
                    state <= delay2us;
                elsif N64RXD = '1' then 
                    if s_baudCount >= delayLong then
                        state <= timeout;
                    elsif s_bitCount >= X"9" then
                        state <= count9bits;
                    else
                        state <= waitForStart;
                    end if;
                end if;     

            when count9bits =>  
                s_sel <= '0';
                if tdre = '0' then
                    state <= count9bits;
                elsif tdre = '1' then
                    state <= sendToUART;
                end if;   

            when sendToUART =>
                transmit <= '1';
                if tdre = '0' then
                    state <= start;
                else
                    state <= sendToUART;
                end if;

            when timeout =>
                --s_timeoutDetect <= '1';
                state <= start;

        end case;   
    end if;
end process n64RX;  
--timeoutDetect <= s_timeoutDetect;
bitcount <= s_bitCount;
echoSig <= s_echoSig;
sel <= s_sel;
data <= s_data(4 downto 1);

end N64RX;

तो, कोई विचार? डिबगिंग टिप्स? Finite State Machines को कोड करने के टिप्स?

इस बीच, मैं इसके साथ खेलता रहूँगा (मेरे पास यह अंततः होगा)! स्टैक एक्सचेंज में मेरी मदद करें, आप मेरी एकमात्र आशा हैं!

संपादित करें

मेरी डिबगिंग में एक और खोज, स्टेट्स वेटफॉरस्टार्ट से वापस वेटफोरटॉप तक छलांग लगाएंगे। मैंने प्रत्येक राज्य को '5' के बराबर वेटफॉरस्टार्ट और '4' के बराबर वाट्सफोरटॉप के साथ एक मूल्य दिया। नीचे दी गई छवि देखें: यहां छवि विवरण दर्ज करें


1
आपके पहले केस ब्लॉक में, लाइन "s_bitCount <= X" 0 ";" क्या वह एक्स एक टाइपो है?
ट्रैविसबार्टले

@ trav1s नहीं, कि "X" षोडश आधारी को दर्शाता है। तो X "0" वास्तव में बाइनरी में "0000" है।
निक विलियम्स

1
मुझे लिंटर के माध्यम से कोड को चलाने में कुछ त्रुटियां हुईं। सिग्नल N64RXD और tdre को अनुक्रमिक प्रक्रिया, लाइन 36 की संवेदनशीलता सूची में उपयोग नहीं किया जाना चाहिए।
ट्रैविसबार्टले

1
@ trav1s सूचक के लिए धन्यवाद, मैंने उन मापदंडों को हटा दिया; आप सही हैं, वे आवश्यक नहीं हैं। मेरे पास अभी भी दुर्भाग्य है। गुंजाइश के साथ, मैंने यह पता लगाने के लिए सिग्नल जोड़े कि मैं किस राज्य में हूं। किसी कारण से, FPGA "WaitForStart" से वापस "waForStop" से कूदता है, जिसमें कोई राज्य नहीं है! यही कारण है कि यह गिनती नहीं है क्योंकि FPGA उस स्थिति तक नहीं पहुंचता है जहां यह बिट गिना जाता है। "वापस कूदो" मुद्दा प्रतीत होता है।
निक विलियम्स

1
लेकिन "WaitForStart" -> "WaitForStop" संक्रमण अमान्य है। एक ही चक्र में उस कूद को बनाने का कोई तरीका नहीं है। यह सुनिश्चित करने के लिए बहुत बारीकी से जांच करें कि बीच में बहुत संक्षिप्त स्थिति नहीं है। अन्यथा, एक हार्डवेयर / समय दोष होना चाहिए।
ट्रैविसबार्टले

जवाबों:


9

मुझे आरएक्स डेटा लाइन पर एक सिंक्रोनाइज़र नहीं दिखता है।

सभी एसिंक्रोनस इनपुट्स को सैंपलिंग क्लॉक के साथ सिंक्रनाइज़ किया जाना चाहिए। इसके कुछ कारण हैं: मेटास्टेबिलिटी और रूटिंग। ये अलग-अलग समस्याएं हैं लेकिन अंतर-संबंधित हैं।

FPGA कपड़े के माध्यम से संकेतों के प्रचार के लिए समय लगता है। FPGA के भीतर घड़ी नेटवर्क को इन "यात्रा" देरी की भरपाई करने के लिए डिज़ाइन किया गया है ताकि FPGA के भीतर सभी फ्लिप फ्लॉप घड़ी को ठीक उसी क्षण देखें। सामान्य रूटिंग नेटवर्क में यह नहीं होता है, और इसके बजाय नियम पर निर्भर करता है कि सभी सिग्नल घड़ी बदलने से पहले थोड़े समय के लिए स्थिर होना चाहिए और घड़ी के बदलाव के बाद थोड़े समय के लिए स्थिर रहें। समय के इन छोटे बिट्स को एक दिए गए फ्लिप फ्लॉप के लिए सेटअप और होल्ड टाइम के रूप में जाना जाता है। टूलचैन के स्थान और मार्ग घटक में विशिष्ट डिवाइस के लिए रूटिंग देरी की बहुत अच्छी समझ है और यह एक बुनियादी धारणा है कि एक सिग्नल सेटअप का उल्लंघन नहीं करता है और FPGA में फ्लिप फ्लॉप के समय को पकड़ता है।

जब आपके पास ऐसे सिग्नल होते हैं जो सैंपलिंग घड़ी के साथ सिंक्रनाइज़ नहीं होते हैं तो आप उस स्थिति में समाप्त हो सकते हैं जहां एक फ्लिप फ्लॉप सिग्नल का "पुराना" मान देखता है क्योंकि नए मूल्य को प्रचारित करने का समय नहीं मिला है। अब आप अवांछनीय स्थिति में हैं जहाँ एक ही संकेत को देखने वाले तर्क दो भिन्न मूल्यों को देखते हैं। यह गलत संचालन का कारण बन सकता है, दुर्घटनाग्रस्त राज्य मशीनों और सभी प्रकार के कड़े निदान करने के लिए।

दूसरा कारण यह है कि आपको अपने सभी इनपुट संकेतों को सिंक्रनाइज़ करना चाहिए, जिसे मेटास्टेबिलिटी कहा जाता है। इस विषय पर खंड लिखे गए हैं लेकिन संक्षेप में, डिजिटल तर्क सर्किटरी अपने सबसे बुनियादी स्तर पर एक एनालॉग सर्किट है। जब आपकी क्लॉक लाइन बढ़ जाती है तो इनपुट लाइन की स्थिति कैप्चर हो जाती है और यदि उस समय इनपुट उच्च या निम्न स्तर का नहीं होता है, तो नमूना फ्लिप फ्लॉप द्वारा एक अज्ञात "इन-बीच" मान कैप्चर किया जा सकता है।

जैसा कि आप जानते हैं, FPGAs डिजिटल जानवर हैं और एक संकेत पर अच्छी तरह से प्रतिक्रिया नहीं करते हैं जो न तो उच्च है और न ही कम है। इससे भी बदतर, अगर उस अनिश्चित मूल्य का नमूना फ्लिप फ्लॉप के रूप में होता है और FPGA में यह सभी प्रकार की विचित्रता पैदा कर सकता है क्योंकि तर्क के बड़े हिस्से अब एक अनिश्चित मूल्य देखते हैं और इसे समझने की कोशिश करते हैं।

समाधान संकेत को सिंक्रनाइज़ करने के लिए है। अपने सबसे बुनियादी स्तर पर इसका मतलब है कि आप इनपुट पर कब्जा करने के लिए फ्लिप फ्लॉप की एक श्रृंखला का उपयोग करते हैं। कोई भी मेटास्टेबल स्तर जो पहले फ्लिप फ्लॉप द्वारा कब्जा कर लिया गया था और इसे बनाने में कामयाब रहा, इससे पहले कि यह आपके जटिल तर्क को हिट करे, इसे हल करने का एक और मौका मिलता है। दो फ्लिप फ्लॉप आमतौर पर इनपुट को सिंक्रनाइज़ करने के लिए पर्याप्त से अधिक हैं।

एक मूल सिंक्रोनाइज़र ऐसा दिखता है:

entity sync_2ff is
port (
    async_in : in std_logic;
    clk : in std_logic;
    rst : in std_logic;
    sync_out : out std_logic
);
end;

architecture a of sync_2ff is
begin

signal ff1, ff2: std_logic;

-- It's nice to let the synthesizer know what you're doing. Altera's way of doing it as follows:
ATTRIBUTE altera_attribute : string;
ATTRIBUTE altera_attribute OF ff1 : signal is "-name SYNCHRONIZER_IDENTIFICATION ""FORCED IF ASYNCHRONOUS""";
ATTRIBUTE altera_attribute OF a : architecture is "-name SDC_STATEMENT ""set_false_path -to *|sync_2ff:*|ff1 """;

-- also set the 'preserve' attribute to ff1 and ff2 so the synthesis tool doesn't optimize them away
ATTRIBUTE preserve: boolean;
ATTRIBUTE preserve OF ff1: signal IS true;
ATTRIBUTE preserve OF ff2: signal IS true;

synchronizer: process(clk, rst)
begin
if rst = '1' then
    ff1 <= '0';
    ff2 <= '0';
else if rising_edge(clk) then
    ff1 <= async_in;
    ff2 <= ff1;
    sync_out <= ff2;
end if;
end process synchronizer;
end sync_2ff;

सिंक्रनाइज़ेशन के async_in इनपुट के लिए N64 कंट्रोलर के आरएक्स डेटा लाइन के लिए भौतिक पिन कनेक्ट करें, और अपने UART के आरएक्सडी इनपुट से सिंक_आउट सिग्नल को कनेक्ट करें।

असंबद्ध सिग्नल अजीब मुद्दे पैदा कर सकते हैं। सुनिश्चित करें कि FPGA तत्व से जुड़ा कोई भी इनपुट जो सिग्नल पढ़ने की प्रक्रिया की घड़ी के लिए सिंक्रनाइज़ नहीं है, सिंक्रनाइज़ है। इसमें पुशबटन, UART 'rx' और 'cts' सिग्नल शामिल हैं ... कुछ भी जो उस घड़ी के लिए सिंक्रनाइज़ नहीं है जिसे FPGA सिग्नल का नमूना लेने के लिए उपयोग कर रहा है।

(एक तरफ: मैंने कई साल पहले www.mixdown.ca/n64dev पर पेज लिखा था। मुझे बस एहसास हुआ कि मैंने लिंक को तोड़ दिया है जब मैंने आखिरी बार साइट को अपडेट किया था और सुबह में ठीक करूंगा जब मैं कंप्यूटर पर वापस आऊंगा। मुझे पता नहीं था कि बहुत से लोगों ने उस पेज का इस्तेमाल किया है!)


महान और व्यापक उत्तर के लिए धन्यवाद! मैं इसे एक कोशिश देने जा रहा हूं और अपनी मशीन को और मजबूत बनाऊंगा।
निक विलियम्स

2
यह वास्तव में मेटास्टेबिलिटी (हालांकि यह एक चिंता का विषय है) के साथ बहुत कम है, और एसिंक्रोनस इनपुट से विभिन्न एफएफ के लिए अलग-अलग पथ देरी के साथ सब कुछ करना है जो राज्य चर के बिट्स को पकड़ते हैं।
डेव ट्वीड

तुम सही हो, @DaveTweed; मैं दोनों को एक साथ लुभाता हूं और यह गलत सोच वाली सोच है।
akohlsmith

मैंने अपने जवाब को संपादित करने के लिए @ DaveTweed की टिप्पणियों को ध्यान में रखा है।
akohlsmith

1
@akohlsmith कमाल! मैंने सिंक्रनाइज़र को जोड़ा और इसका समाधान था। इसके अलावा, यह एक अविश्वसनीय संयोग है कि आपने मिश्रण पृष्ठ लिखा है; मुझे N64 प्रोटोकॉल पर संसाधनों का एक समूह मिला जिसने उस लेख को संदर्भित किया और मुझे निराशा हुई कि लिंक टूट गया था। इसे ठीक करने के लिए धन्यवाद।
निक विलियम्स

6

आपकी समस्या यह है कि आप अपने राज्य मशीन में निर्णय लेने के लिए बिना संकेत के संकेतों का उपयोग कर रहे हैं। राज्य मशीन में उपयोग करने से पहले आपको उन सभी बाहरी संकेतों को डबल-एफएफ सिंक्रोनाइज़र के माध्यम से खिलाना चाहिए।

यह राज्य मशीनों के साथ एक सूक्ष्म समस्या है जो किसी भी राज्य संक्रमण में उत्पन्न हो सकती है जिसमें राज्य चर में दो या अधिक बिट्स में बदलाव शामिल है। यदि आप एक अनसिंक्रनाइज़ किए गए इनपुट का उपयोग करते हैं, तो बिट्स में से एक बदल सकता है, जबकि दूसरा बदलने में विफल रहता है। यह आपको एक अलग राज्य में ले जाता है, और यह एक कानूनी स्थिति हो सकती है या नहीं भी हो सकती है।

वह अंतिम कथन यही है कि आपको हमेशा when others => ...अपने राज्य मशीन केस स्टेटमेंट में एक डिफ़ॉल्ट मामला (VHDL में ) क्यों होना चाहिए, जो आपको किसी भी अवैध राज्य से कानूनी रूप से ले जाता है।


हाँ, यह निष्कर्ष मैं अलग-थलग करने वाला था, लेकिन मैं पर्याप्त जानकारी प्राप्त करने से पहले इसे कूदना नहीं चाहता था ...
ट्रैविबार्टले

1
लानत है, तुमने इसके लिए मुझे हराया। मैं इसे एक टैबलेट पर अपने सभी टाइपिंग पर दोष देता हूं। :-)
akohlsmith

@akohlsmith, पूर्व में सबसे तेज़ बंदूक होना केवल एक ही चीज़ नहीं है जो जवाब देने में मायने रखती है। आपका उत्तर उपयोगी है, और स्पष्ट रूप से धोखा नहीं था क्योंकि आपने इसे इतनी जल्दी पोस्ट किया था।
ट्रैविसबार्टले

मैं सोचता when others =>था कि मदद कर रहा था, लेकिन यह पता चला है कि यह आपको वह नहीं मिलता है जो आप दावा करते हैं (किसी भी सिंथेसाइज़र के तहत मैंने इस्तेमाल किया है) जब तक कि आप यह सुनिश्चित करने के लिए विशेषताओं को नहीं जोड़ते हैं कि संश्लेषण आपको "सुरक्षित" राज्य मशीन चाहिए। सामान्य व्यवहार एक-गर्म प्रतिनिधित्व का अनुकूलन करना है और पुनर्प्राप्ति तर्क प्रदान नहीं करना है। उदाहरण के लिए xilinx.com/support/answers/40093.html और synopsys.com/Company/Publications/SynopsysInsight/Pages/… देखें ।
मार्टिन थॉम्पसन

वाह! यह एक शानदार टिप है और यह एक आकर्षण की तरह काम करता है।
निक विलियम्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.