माइक्रोकंट्रोलर स्लीप रेस कंडीशन


11

निम्नलिखित कोड को चलाने वाले एक माइक्रोकंट्रोलर को देखते हुए:

volatile bool has_flag = false;

void interrupt(void) //called when an interrupt is received
{
    clear_interrupt_flag(); //clear interrupt flag
    has_flag = true; //signal that we have an interrupt to process
}

int main()
{
    while(1)
    {
        if(has_flag) //if we had an interrupt
        {
            has_flag = false; //clear the interrupt flag
            process(); //process the interrupt
        }
        else
            sleep(); //place the micro to sleep
    }
}

मान लीजिए कि if(has_flag)स्थिति झूठी का मूल्यांकन करती है और हम नींद के निर्देश को निष्पादित करने वाले हैं। राइट इससे पहले कि हम नींद अनुदेश निष्पादित, हम एक अवरोध प्राप्त करते हैं। हम रुकावट छोड़ने के बाद, हम नींद के निर्देश पर अमल करते हैं।

यह निष्पादन अनुक्रम वांछनीय नहीं है क्योंकि:

  • जागने और बुलाने के बजाय माइक्रोकंट्रोलर सो गया process()
  • यदि बाद में कोई रुकावट न आए, तो माइक्रोकंट्रोलर कभी भी नहीं जाग सकता है।
  • process()अगले व्यवधान तक कॉल को स्थगित कर दिया गया है।

इस दौड़ की स्थिति को होने से रोकने के लिए कोड कैसे लिखा जा सकता है?

संपादित करें

कुछ माइक्रोकंट्रोलर, जैसे ATMega, में स्लीप इनेबल्ड बिट है जो इस स्थिति को उत्पन्न होने से रोकता है (इसको इंगित करने के लिए Kvegaoro धन्यवाद)। JRoberts एक उदाहरण कार्यान्वयन प्रदान करता है जो इस व्यवहार को उदाहरण देता है।

PIC18s में अन्य माइक्रो, इस बिट नहीं है, और समस्या अभी भी होती है। हालाँकि, इन माइक्रो को इस तरह से डिज़ाइन किया गया है कि व्यवधान अभी भी मूल जागृति को जागृत कर सकता है कि क्या वैश्विक व्यवधान सक्षम बिट सेट किया गया है (यह इंगित करने के लिए सुपरकैट धन्यवाद)। ऐसे आर्किटेक्चर के लिए, समाधान सोने जाने से ठीक पहले वैश्विक रुकावटों को अक्षम करना है। यदि नींद निर्देश को निष्पादित करने से ठीक पहले एक बाधा आग लग जाती है, तो बाधा हैंडलर को निष्पादित नहीं किया जाएगा, कोर जाग जाएगा, और एक बार वैश्विक रुकावटों को फिर से सक्षम करने के बाद, बाधित हैंडलर निष्पादित किया जाएगा। छद्म कोड में, कार्यान्वयन इस तरह दिखेगा:

int main()
{
    while(1)
    {
        //clear global interrupt enable bit.
        //if the flag tested below is not set, then we enter
        //sleep with the global interrupt bit cleared, which is
        //the intended behavior.
        disable_global_interrupts();

        if(has_flag) //if we had an interrupt
        {
            has_flag = false; //clear the interrupt flag
            enable_global_interrupts();  //set global interrupt enable bit.

            process(); //process the interrupt
        }
        else
            sleep(); //place the micro to sleep
    }
}

क्या यह व्यावहारिक या सैद्धांतिक सवाल है?
आंद्रेजाको

सिद्धांत रूप में आप एक टाइमर का उपयोग करते हैं जो आपको हर बार एक बार उठता है (स्वीकार्य मूल्य दर्ज करें) एमएस और फिर कुछ भी नहीं करने पर सोने के लिए वापस चला जाता है।
ग्रैडी प्लेयर

1
मैं interrupt_flagएक के रूप में करना होगा int, और हर बार इसे बढ़ाने के लिए रुकावट होती है। फिर बदलने if(has_flag)के लिए while (interrupts_count)और फिर नींद। फिर भी, आप लूप से बाहर निकलने के बाद रुकावट हो सकते हैं। यदि यह एक समस्या है, तो क्या प्रसंस्करण खुद को बाधित कर रहा है?
२१

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

1
@TRISAbits: PIC 18x पर, मैंने अपने उत्तर में वर्णित दृष्टिकोण ठीक काम करता है (यह उस भाग का उपयोग करते समय मेरा सामान्य डिजाइन है)।
सुपरकैट

जवाबों:


9

इस मामले के लिए आमतौर पर किसी प्रकार का हार्डवेयर समर्थन होता है। उदाहरण के लिए, AVRs का seiनिर्देश निम्न निर्देश पूरा होने तक बाधित करने वाले डिफर्सर्स को सक्षम करने का निर्देश देता है। इसके साथ एक कर सकते हैं:

forever,
   interrupts off;
   if has_flag,
      interrupts on;
      process interrupt;
   else,
      interrupts-on-and-sleep;    # won't be interrupted
   end
end

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


बहुत बढ़िया जवाब! आपके द्वारा प्रदान किया गया एल्गोरिथ्म वास्तव में एक AVR पर वास्तव में अच्छी तरह से काम करता है। सलाह के लिये धन्यवाद।
TRISAbits

3

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

इस तरह के डिजाइन पर, विश्वसनीय नींद के व्यवहार को प्राप्त करने के लिए एक सरल तरीका यह है कि मुख्य लूप की जांच एक ध्वज को स्पष्ट करें और फिर जांचें कि क्या यह जानता है कि किसी भी कारण से प्रोसेसर को जागृत होना चाहिए। उस दौरान होने वाली कोई भी रुकावट जो उन कारणों में से किसी को भी प्रभावित कर सकती है, उन्हें झंडा लगाना चाहिए। यदि मुख्य लूप को जागते रहने का कोई कारण नहीं मिला, और यदि ध्वज सेट नहीं हुआ है, तो मुख्य लूप को बाधित करना चाहिए और ध्वज को फिर से जांचना चाहिए [शायद एक जोड़े के बाद NOP निर्देश अगर यह संभव है कि एक रुकावट जो लंबित हो जाए एक अक्षम-व्यवधान अनुदेश के दौरान कार्रवाई की जा सकती है के बाद से संबंधित निर्देश के साथ जुड़े ऑपरेंड लाने के लिए पहले से ही प्रदर्शन किया गया है]। यदि ध्वज अभी भी सेट नहीं है, तो सो जाओ।

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

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

void select_view_user(int default_user)
{
  int current_user;
  int ch;
  current_user = default_user;
  do
  {
    lcd_printf(0, "User %d");
    lcd_printf(1, ...whatever... );
    get_key();
    if (key_hit(KEY_UP)) {current_user = (current_user + 1) % MAX_USERS};
    if (key_hit(KEY_DOWN)) {current_user = (current_user + MAX_USERS-1) % MAX_USERS};
    if (key_hit(KEY_ENTER)) view_user(current_user);
  } while(!key_hit(KEY_EXIT | KEY_TIMEOUT));
}

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


महान जवाब के लिए धन्यवाद सुपरकैट। इंटरप्ट को निष्क्रिय करना और फिर सो जाना एक शानदार समाधान है बशर्ते कि कोर किसी भी रुकावट स्रोत से जागृत हो, भले ही वैश्विक रुकावट बिट सेट / स्पष्ट हो। मैंने PIC18 इंटरप्ट हार्डवेयर योजनाबद्ध पर एक नज़र डाली, और यह समाधान काम करेगा।
TRISAbits

1

इंटरप्ट पर जगाने के लिए माइक्रो प्रोग्राम करें।

विशिष्ट विवरण आपके द्वारा उपयोग किए जा रहे माइक्रो के आधार पर अलग-अलग होंगे।

फिर मुख्य () दिनचर्या को संशोधित करें:

int main()
{
    while(1)
    {
        sleep();
        process(); //process the interrupt
    }
}

1
वेक-ऑन-इंटरप्ट आर्किटेक्चर प्रश्न में माना जाता है। मुझे नहीं लगता कि आपका उत्तर प्रश्न / समस्या को हल करता है।
२१:३३

@angelatlarge पॉइंट स्वीकार किया गया। मैंने एक कोड उदाहरण जोड़ा है जो मुझे लगता है कि मदद करता है।
jwygralak67

@ jwygralak67: सुझाव के लिए धन्यवाद, लेकिन आप जो कोड प्रदान करते हैं, वह समस्या को प्रक्रिया में स्थानांतरित कर देता है () दिनचर्या, जो अब परीक्षण करना है कि क्या प्रक्रिया को निष्पादित करने से पहले व्यवधान उत्पन्न हुआ है () शरीर।
TRISAbits

2
यदि व्यवधान उत्पन्न नहीं हुआ था, तो हम क्यों जागे हैं?
२०:१३

1
@Jobert: हम एक पिछले व्यवधान से जागृत हो सकते हैं, प्रक्रिया () दिनचर्या को पूरा कर सकते हैं, और जब हम (है_फ्लैग) परीक्षण और नींद से ठीक पहले पूरा करते हैं, तो हमें एक और रुकावट मिलती है, जो उस समस्या का कारण बनता है जिसका मैंने वर्णन किया है। सवाल।
TRISAbits
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.