माइक्रोकंट्रोलर्स और एफएसएम उदाहरण में इंटरप्ट हैंडलिंग


9

प्रारंभिक प्रश्न

माइक्रोकंट्रोलर में व्यवधानों से निपटने के बारे में मेरा एक सामान्य प्रश्न है। मैं MSP430 का उपयोग कर रहा हूं, लेकिन मुझे लगता है कि प्रश्न को अन्य यूसीएस तक बढ़ाया जा सकता है। मैं जानना चाहूंगा कि कोड के साथ-साथ बार-बार बाधित / अक्षम करने के लिए एक अच्छा अभ्यास है या नहीं। मेरा मतलब है, अगर मेरे पास कोड का एक हिस्सा है जो हस्तक्षेप करने के लिए संवेदनशील नहीं है (या इससे भी बदतर, किसी भी कारण से, बीच में नहीं सुनना चाहिए), क्या यह बेहतर है:

  • पहले इंटरप्ट को अक्षम करें और फिर महत्वपूर्ण अनुभाग के बाद उन्हें फिर से सक्षम करें।
  • संबंधित ISR के अंदर एक ध्वज लगाएं और (व्यवधान को निष्क्रिय करने के बजाय), ध्वज को महत्वपूर्ण खंड से पहले झूठे पर सेट करें और इसे सही पर रीसेट करें, बस के बाद। ISR के कोड को निष्पादित होने से रोकने के लिए।
  • दोनों में से कोई भी, इसलिए सुझावों का स्वागत है!

अपडेट: इंटरप्ट और स्टेट चार्ट

मैं एक विशिष्ट स्थिति प्रदान करूंगा। आइए हम मान लें कि हम एक राज्य चार्ट को लागू करना चाहते हैं, जो 4 ब्लॉकों से बना है:

  1. संक्रमण / प्रभाव।
  2. शर्तों से बाहर निकलें।
  3. प्रवेश गतिविधि।
  4. गतिविधि करें।

यह वही है जो एक प्रोफेसर ने हमें विश्वविद्यालय में पढ़ाया था। संभवतः, इस योजना का पालन करने का सबसे अच्छा तरीका यह नहीं है:

while(true) {

  /* Transitions/Effects */
  //----------------------------------------------------------------------
  next_state = current_state;

  switch (current_state)
  {
    case STATE_A:
      if(EVENT1) {next_state = STATE_C}
      if(d == THRESHOLD) {next_state = STATE_D; a++}
      break;
    case STATE_B:
      // transitions and effects
      break;
    (...)
  }

  /* Exit activity -> only performed if I leave the state for a new one */
  //----------------------------------------------------------------------
  if (next_state != current_state)
  {
    switch(current_state)
    {
      case STATE_A:
        // Exit activity of STATE_A
        break;
      case STATE_B:
        // Exit activity of STATE_B
        break;
        (...)
    }
  }

  /* Entry activity -> only performed the 1st time I enter a state */
  //----------------------------------------------------------------------
  if (next_state != current_state)
  {
    switch(next_state)
    {
      case STATE_A:
        // Entry activity of STATE_A
        break;
      case STATE_B:
        // Entry activity of STATE_B
        break;
      (...)
    }
  }

  current_state = next_state;

  /* Do activity */
  //----------------------------------------------------------------------
  switch (current_state)
  {
    case STATE_A:
      // Do activity of STATE_A
      break;
    case STATE_B:
      // Do activity of STATE_B
      break;
    (...)
  }
}

आइए हम यह भी मान लें कि STATE_Aमैं, बटन के एक सेट (डिबौस सिस्टम, आदि) के साथ आने वाली एक बाधा के प्रति संवेदनशील होना चाहता हूं। जब कोई इनमें से एक बटन दबाता है, तो एक अवरोध उत्पन्न होता है और इनपुट पोर्ट से संबंधित ध्वज को एक चर में कॉपी किया जाता है buttonPressed। यदि बहस किसी तरह से 200 एमएस पर सेट है (वॉचडॉग टाइमर, टाइमर, काउंटर, ...) हमें यकीन है कि buttonPressed200 एमएस से पहले एक नए मूल्य के साथ अपडेट नहीं किया जा सकता है। यह वही है जो मैं आपसे पूछ रहा हूं (और खुद :) निश्चित रूप से)

क्या मुझे STATE_Aछोड़ने से पहले डीओ गतिविधि को बाधित करने और अक्षम करने की आवश्यकता है?

/* Do activity */
//-------------------------------------
switch (current_state)
{
  case STATE_A:
    // Do activity of STATE_A
    Enable_ButtonsInterrupt(); // and clear flags before it
    // Do fancy stuff and ...
    // ... wait until a button is pressed (e.g. LPM3 of the MSP430)
    // Here I have my buttonPressed flag ready!
    Disable_ButtonsInterrupt();
    break;
  case STATE_B:
    // Do activity of STATE_B
    break;
  (...)
}

एक तरीका है कि मुझे यकीन है कि अगले चरण में अगली बार मैं execxute ब्लॉक 1 (संक्रमण / प्रभाव) मुझे यकीन है कि स्थिति बदलाव के साथ जाँच कर रहा हूँ बाद में एक बाधा के पिछले मूल्य होता है ओवरराइट से नहीं आ रहे हैं रहा हूँ में buttonPressedहै कि मैं जरूरत है (हालांकि यह असंभव है कि ऐसा होता है क्योंकि 250 एमएस को समाप्त होना चाहिए)।


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

जवाबों:


17

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

हालांकि, मशीन आपकी सेवा करने के लिए है, अन्य तरीके से नहीं। अंगूठे के सामान्य नियम केवल खराब प्रोग्रामर को वास्तव में बुरा कोड लिखने से रोकना है। यह समझना बेहतर है कि मशीन कैसे काम करती है और फिर आर्किटेक्ट को वांछित कार्य करने के लिए उन क्षमताओं का दोहन करने का एक अच्छा तरीका है।

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

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

या, ध्वज के बजाय एक-शब्द काउंटर का उपयोग करें। अग्रभूमि कोड एक अलग चर रखता है जिसमें अंतिम काउंटर होता है, जिसने सिस्टम को अपडेट किया है। यह लाइव काउंटर का एक घटाया हुआ घटाव करता है जो सहेजने के लिए एक समय में कितने टिकों को संभालने के लिए सहेजे गए मान को घटाता है। यह अग्रभूमि कोड को एक समय में 2 N -1 घटनाओं तक याद करने की अनुमति देता है , जहां N एक मूल शब्द में बिट की संख्या है जहां ALU परमाणु को संभाल सकता है।

प्रत्येक विधि के फायदे और नुकसान का अपना सेट है। एक भी सही उत्तर नहीं है। दोबारा, समझें कि मशीन कैसे काम करती है, तो आपको अंगूठे के नियमों की आवश्यकता नहीं होगी।


7

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

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

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

यदि आपके महत्वपूर्ण खंड को केवल एक ही बाधा की आवश्यकता होती है जिसे निष्पादित नहीं किया जाना चाहिए, लेकिन अन्य को निष्पादित किया जाना चाहिए, तो दूसरा दृष्टिकोण व्यवहार्य लगता है।

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

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


5

यदि आपने निर्धारित किया है कि कोड का एक खंड निर्बाध रूप से चलना चाहिए, तो असामान्य परिस्थितियों को छोड़कर, आपको कार्य पूरा करने के लिए न्यूनतम अवधि के लिए व्यवधान को अक्षम करना चाहिए, और उसके बाद उन्हें फिर से सक्षम करना चाहिए।

संबंधित ISR के अंदर एक ध्वज लगाएं और (व्यवधान को निष्क्रिय करने के बजाय), ध्वज को महत्वपूर्ण खंड से पहले झूठे पर सेट करें और इसे सही पर रीसेट करें, बस के बाद। ISR के कोड को निष्पादित होने से रोकने के लिए।

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

यदि आप कोड के साथ काम कर रहे हैं, जहां व्यवधान लंबा है, तो एक ध्वज जैसा कि आप सुझाव देते हैं कि समस्या का समाधान हो सकता है, लेकिन यह तब भी बेहतर होगा जब आप बाधित में अत्यधिक कोड को खत्म करने के लिए कोड को फिर से फैक्टर न कर सकें ।

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

  • यदि महत्वपूर्ण खंड के दौरान कोई व्यवधान नहीं हुआ, तो किसी को भी निष्पादित नहीं किया जाता है।
  • यदि एक खंड महत्वपूर्ण खंड के दौरान होता है, तो एक के बाद एक निष्पादित होता है।
  • यदि महत्वपूर्ण खंड के दौरान कई व्यवधान उत्पन्न होते हैं, तो केवल एक को निष्पादित किया जाता है।

यदि आपका सिस्टम जटिल है और इंटरप्ट को अधिक ट्रैक करना है, तो आपको व्यवधानों को ट्रैक करने और तदनुसार संचालित करने के लिए अधिक जटिल सिस्टम डिजाइन करना होगा।

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

इससे सभी लेकिन बहुत, बहुत कम स्थितियों को समाप्त करना चाहिए जहां आपको एक निर्बाध कोड अनुभाग की आवश्यकता हो सकती है।


मैंने उस स्थिति को बेहतर ढंग से समझाने के लिए पोस्ट अपडेट की है जो मैं :) पर काम कर रहा हूँ :)
Umberto D.

1
आपके उदाहरण कोड में, मैं आवश्यक नहीं होने पर विशिष्ट बटन व्यवधान को अक्षम करने पर विचार करूंगा और आवश्यकता पड़ने पर सक्षम करूंगा। ऐसा बार-बार करना डिजाइन द्वारा इसका मुद्दा नहीं है। वैश्विक रुकावटों को छोड़ दें, ताकि जरूरत पड़ने पर आप बाद में अन्य व्यवधानों को जोड़ सकें। वैकल्पिक रूप से, जब आप राज्य A पर जाते हैं तो ध्वज को रीसेट करें और अन्यथा इसे अनदेखा करें। यदि बटन दबाया जाता है और ध्वज सेट होता है, तो कौन परवाह करता है? इसे तब तक नज़रअंदाज़ करें जब तक आप राज्य में वापस नहीं आ जाते
एडम डेविस

हाँ! यह एक समाधान हो सकता है क्योंकि वास्तविक डिज़ाइन में मैं अक्सर LPM3 (MSP430) में जाता हूं, वैश्विक अवरोधों के साथ सक्षम है और मैं LPM3 से बाहर निकलता हूं, जैसे ही एक रुकावट का पता चलता है, निष्पादन को फिर से शुरू करना। तो एक समाधान वह है जिसे आपने प्रस्तुत किया है जो मुझे लगता है कि कोड के दूसरे भाग में रिपोर्ट किया गया है: जैसे ही मुझे उस राज्य की गतिविधि करना शुरू करना चाहिए, जो इसे चाहिए और संक्रमण खंड में जाने से पहले अक्षम हो जाए। एक और संभावित समाधान हो सकता है कि "गतिविधि ब्लॉक करें" को छोड़ने से पहले बाधित को निष्क्रिय करें और कुछ समय बाद (जब?) को फिर से सक्षम करें?
अम्बर्टो डी।

1

ISR के अंदर एक झंडा लगाना जैसा कि आप वर्णन करते हैं कि शायद यह काम नहीं करेगा क्योंकि आप मूल रूप से उस घटना को अनदेखा कर रहे हैं जिसने व्यवधान उत्पन्न किया है। विश्व स्तर पर व्यवधानों को निष्क्रिय करना आमतौर पर एक बेहतर विकल्प है। जैसा कि दूसरों ने कहा है, आपको बहुत बार ऐसा नहीं करना चाहिए। ध्यान रखें कि किसी भी निर्देश के माध्यम से किए गए किसी भी पढ़ने या लिखने के बाद से निर्देश को निष्पादित करने या इसे करने की आवश्यकता नहीं है।

बहुत कुछ इस बात पर निर्भर करता है कि आप किस तरह के संसाधनों को साझा करने का प्रयास कर रहे हैं। यदि आप ISR से मुख्य कार्यक्रम (या इसके विपरीत) के लिए डेटा खिला रहे हैं, तो आप FIFO बफर जैसा कुछ लागू कर सकते हैं। एकमात्र परमाणु ऑपरेशन पढ़ने और लिखने वाले पॉइंटर्स को अपडेट करने वाला होगा, जो आपके द्वारा अक्षम किए गए समय के साथ कम से कम समय खर्च करता है।


0

एक सूक्ष्म अंतर है जिसे आपको ध्यान में रखना चाहिए। आप किसी व्यवधान या "अवहेलना" और व्यवधान को संभालने में "देरी" करने का चुनाव कर सकते हैं।

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

कभी-कभी हम व्यवधान की अवहेलना करना चाहते हैं। सबसे अच्छा तरीका हार्डवेयर स्तर पर रुकावट को रोक सकता है। अक्सर एक बाधा नियंत्रक या समान होता है जहां हम कह सकते हैं कि कौन से इनपुटों में रुकावट उत्पन्न होनी चाहिए।

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