Arduino में कार्य सूचक कार्य परमाणु हैं?


11

निम्नलिखित स्निपेट्स टिमरने पुस्तकालय स्रोत कोड से हैं :

// TimerOne.h:
void (*isrCallback)();

// TimerOne.cpp:
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  Timer1.isrCallback();
}

// TimerOne.cpp:
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
  if(microseconds > 0) setPeriod(microseconds);
  isrCallback = isr; // register the user's callback with the real ISR
  TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
  resume();                                                                                            
}

प्रश्न: यदि टाइमर पहले से चल रहा है, और मुख्य प्रोग्राम कॉल करता है attachInterrupt(), तो क्या फ़ंक्शन पॉइंटर असाइनमेंट के दौरान टाइमर की बाधा हो सकती है isrCallback = isr;? फिर, भाग्यशाली समय के साथ, Timer1.isrCallback();फ़ंक्शन पॉइंटर आंशिक रूप से नए पते के पुराने और आंशिक रूप से शामिल होगा, जिससे आईएसआर एक फर्जी स्थान पर कूद जाएगा?

मुझे लगता है कि यह मामला हो सकता है, क्योंकि फ़ंक्शन पॉइंटर्स निश्चित रूप से 1 बाइट से अधिक व्यापक हैं, और एक्सेस> 1 बाइट डेटा परमाणु नहीं है। संभव workarounds हो सकता है:

  • हमेशा detachInterrupt()यह सुनिश्चित करने के लिए कॉल करें कि कॉलिंग से पहले टाइमर नहीं चल रहा है attachInterrupt(), अर्थात टाइमर 1 डॉक्स को स्पष्ट करें।
  • या, टाइमर को संशोधित करें, टाइमर ओवरफ्लो को अक्षम करने से कुछ समय पहले अस्थायी रूप से व्यवधान उत्पन्न होता है isrCallback = isr;

क्या यह समझ में आता है, या कुछ Timer1स्रोत या फ़ंक्शन पॉइंटर असाइनमेंट में कुछ है जो मैंने याद किया है?

जवाबों:


7

अटैचमेंट () और detachInterrupt () के लिए कोड पर एक नज़र डालें /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/WInterrupts.c(अच्छी तरह से, जहां वे एक मैक पर हैं, वैसे भी। अन्य OSes पर Arduino फ़ाइल संरचना शायद पथ के निचले स्तरों में समान दिखती है)।

ऐसा प्रतीत होता है कि संलग्नक () मानता है कि प्रश्न में रुकावट अभी तक सक्षम नहीं है क्योंकि यह बिना किसी सावधानी के फ़ंक्शन सूचक को लिखता है। ध्यान दें कि detachInterrupts () अपने वेक्टर को NULL-पॉइंटर लिखने से पहले लक्ष्य व्यवधान को निष्क्रिय करता है। इसलिए मैं कम से कम detachInterrupt()/ attachInterrupt()जोड़ी का उपयोग करूं

मैं इस तरह के किसी भी कोड को एक महत्वपूर्ण अनुभाग में चलाना चाहता हूं, खुद। यह आपका पहला तरीका प्रतीत होता है (डिटैच करें, फिर संलग्न करें) काम करेगा, हालांकि मुझे यकीन नहीं है कि यह दुर्भाग्य से समय पर बाधित नहीं हो सकता है। आपके MCU की डेटाशीट उस पर कहने के लिए अधिक हो सकती है। लेकिन न तो मुझे यकीन है कि इस बिंदु पर हूँ, कि एक वैश्विक cli()/ sei()यह या तो न होगा। ATMega2560 डेटाशीट, खंड 6.8, कहता है "जब अवरोध को सक्षम करने के लिए SEI निर्देश का उपयोग करते हैं, तो SEI के बाद का निर्देश किसी भी लंबित व्यवधान से पहले निष्पादित किया जाएगा, जैसा कि इस उदाहरण में दिखाया गया है", का अर्थ है कि यह बाधित होने पर एक बफर को बाधित कर सकता है। बंद हैं।


यह वास्तव में स्रोतों के लिए गोता लगाने के लिए उपयोगी है :) टिमरने के अटैच / डिटैच इंटरप्ट मैकेनिज्म को मानक (WInterrupt) के समान ही किया जाता है और इसलिए इसमें समान "सुविधाएँ" हैं।
जूनस पुलकका

0

ऐसा लगता है कि आपके पास एक बिंदु है। तार्किक बात यह है कि इस तरह से व्यवधान को निष्क्रिय करना होगा कि आप उन्हें फिर से सक्षम न करें यदि वे पहली जगह में अक्षम थे। उदाहरण के लिए:

  uint8_t oldSREG = SREG;  // remember if interrupts are on
  cli();                   // make the next line interruptible
  isrCallback = isr;       // register the user's callback with the real ISR
  SREG = oldSREG;          // turn interrupts back on, if they were on before

"व्यवधान को सक्षम करने के लिए एसईआई निर्देश का उपयोग करते समय, एसईआई के बाद के निर्देश को किसी भी लंबित अंतराल से पहले निष्पादित किया जाएगा, जैसा कि इस उदाहरण में दिखाया गया है"

इसका उद्देश्य आपको इस तरह कोड लिखना है:

  sei ();         // enable interrupts
  sleep_cpu ();   // sleep

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


क्या यह अधिक कुशल नहीं होगा TIMSK1=0; TIFR1=_BV(TOV1); isrCallback=isr; TIMSK1=_BV(TOIE1);? यह एक सीपीयू रजिस्टर को बख्शता है और इंटरप्ट लेटेंसी में योगदान नहीं करता है।
एडगर बॉनट

ICIE1, OCIE1B, OCIE1A जैसे अन्य बिट्स के बारे में क्या? मैं विलंबता के बारे में समझता हूं, लेकिन बीच में एक दो घड़ी चक्र के साथ सामना करने में सक्षम होना चाहिए जो उपलब्ध नहीं है। दौड़ की स्थिति हो सकती है। व्यवधान को पहले से ही ट्रिगर किया जा सकता है (यानी सीपीयू में ध्वज सेट है) और TIMSK1 को बंद करने से शायद इसे संभाला न जा सके। ऐसा न हो इसके लिए आपको TOV1 (TIFR1 में 1 लिखकर) रीसेट करना होगा। वहाँ अनिश्चितता मुझे यह सोचने की ओर ले जाती है कि विश्व स्तर पर रुकावटों को रोकना अधिक सुरक्षित है।
निक गैमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.