स्केच इतनी जगह और स्मृति क्यों लेते हैं?


12

जब मैं इस स्केच को YUN के लिए संकलित करता हूं:

int led = 7;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  digitalWrite(led, HIGH);
}

मुझे मिला:

स्केच 5,098 बाइट्स (17%) प्रोग्राम स्टोरेज स्पेस का उपयोग करता है।

अधिकतम 28,672 बाइट्स है। ग्लोबल वैरिएबल डायनामिक मेमोरी के 153 बाइट्स (5%) का उपयोग करते हैं, जिससे स्थानीय चरों के लिए 2,407 बाइट्स निकल जाते हैं। अधिकतम 2,560 बाइट्स है।

यहां तक ​​कि जब मैं बेमेलिनम स्केच संकलित करता हूं:

void setup() {                
  // setup    
}

void loop() {
  // loop
}

मुझे मिला:

स्केच कार्यक्रम भंडारण स्थान के 4,548 बाइट्स (15%) का उपयोग करता है।

अधिकतम 28,672 बाइट्स है। ग्लोबल वैरिएबल डायनामिक मेमोरी के 151 बाइट्स (5%) का उपयोग करते हैं, जिससे स्थानीय चरों के लिए 2,409 बाइट्स निकल जाते हैं। अधिकतम 2,560 बाइट्स है।

एक नंगे न्यूनतम स्केच को 15% प्रोग्राम स्टोरेज स्पेस आवंटित क्यों किया जाता है? और एक बहुत ही साधारण स्केच कार्यक्रम के भंडारण स्थान का 17% हिस्सा क्यों लेता है? Arduino वेबसाइट के अनुसार :

अपने कार्यक्रम में बहुत सारे तार होने से इसका उपयोग करना आसान है। उदाहरण के लिए, एक घोषणा की तरह: char message[] = "I support the Cape Wind project.";SRAM में 33 बाइट्स डालता है (प्रत्येक वर्ण एक बाइट लेता है, साथ ही '\ 0' टर्मिनेटर)।

हालाँकि, इनमें से किसी भी स्केच में कोई भी ऐलान नहीं किया गया है।

ऐसा लगता है जैसे वे अन्य पुस्तकालयों / वर्गों का आयात या उपयोग कर सकते हैं जिन्हें मैं निर्दिष्ट नहीं करता। शायद यह एक सिस्टम डिफॉल्ट लाइब्रेरी को आयात करता है? या यह कुछ और है?

जवाबों:


6

YUN एक कॉम्बो है। भाग Arduino और भाग OpenWRT (लिनक्स)। आपका प्रश्न Arduino के संदर्भ में है। जहां यह वास्तव में एक लियोनार्डो के समान एक ATmega32u4 है और एक UNO (ATmega328p) नहीं है। 32u4 (लियो) USB पर वर्चुअल सीरियल पोर्ट के माध्यम से संचार करता है (संक्षिप्त उत्तर: यह समर्थित होने की आवश्यकता है) , जहां UNO के पास एक वास्तविक सीरियल पोर्ट (उर्फ UART) है। नीचे AVR प्रोसेसर के लिए अलग-अलग बोर्ड प्रकार के आंकड़े बनाए गए हैं।

UNO पर ध्यान दें कि एक बाहरी चिप है जो USB को सीरियल पोर्ट के DTR पिन में परिवर्तित करता है जो बूटलोडर को रिबूट करने के लिए कनेक्ट होने पर ATmega328 के रीसेट पिन को टॉगल करता है। इसके विपरीत लियो / यूं के यूएसबी से सीरियल 32u4 के फर्मवेयर में लागू किया गया है। इसलिए लियो या यूएन की 32u4 चिप को रिमोट से रिबूट करने के लिए लोड किए गए फर्मवेयर को हमेशा यूएसबी क्लाइंट साइड ड्राइवर का समर्थन करना चाहिए। जिसकी खपत लगभग 4K है।

यदि USB की जरूरत नहीं थी और किसी UNO पर किसी अन्य लाइब्रेरी रिसोर्स को BareMinimum.ino के रूप में नहीं बुलाया गया था, तो मुख्य Arduino Library के लिए केवल 466 बाइट्स की आवश्यकता है।

एक UNO पर BareMinimum.ino के संकलित आँकड़े (ATmega328p)

Sketch uses 466 bytes (1%) of program storage space. Maximum is 32,256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2,039 bytes for local variables. Maximum is 2,048 bytes.

एक लियोनार्डो पर BareMinimum.ino के संकलन आँकड़े (ATmega32u4)

Sketch uses 4,554 bytes (15%) of program storage space. Maximum is 28,672 bytes.
Global variables use 151 bytes (5%) of dynamic memory, leaving 2,409 bytes for local variables. Maximum is 2,560 bytes.

एक युन पर ATMINimum.ino के संकलन आँकड़े (ATmega32u4)

Sketch uses 4,548 bytes (15%) of program storage space. Maximum is 28,672 bytes.
Global variables use 151 bytes (5%) of dynamic memory, leaving 2,409 bytes for local variables. Maximum is 2,560 bytes.

7

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

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


तो मूल रूप से यह सभी प्रकार के मानक पुस्तकालयों में आपके बिना पूछे संकलन करता है? साफ।
hichris123

हां, मैं आमतौर पर इसे "ब्लोट" कहता हूं, लेकिन यह वास्तव में एक प्रयोज्य चीज है। Arduino एक कम प्रवेश स्तर का वातावरण है जो बस बहुत अधिक विचार के बिना काम करता है। यदि आपको अधिक आवश्यकता है, तो Arduino आपको वैकल्पिक पुस्तकालयों का उपयोग करने की अनुमति देता है या आप नंगे धातु के खिलाफ संकलन कर सकते हैं। आखिरी शायद Arduino.SE के लिए दायरे से बाहर है
jippie

मेरा @mpflaga उत्तर देखें। उतना ब्लोट नहीं है। या कम से कम कार्यक्षमता के लिए मुख्य पुस्तकालय में कम से कम। जब तक स्केच नहीं कहा जाता है, तब तक वास्तव में बहुत अधिक मानक पुस्तकालयों को शामिल नहीं किया जाता है। बल्कि 15% 32u4 के USB समर्थन के कारण है।
एमफ्लगागा

4

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

नीचे एक न्यूनतम ब्लिंक प्रोग्राम के तीन संस्करण दिए गए हैं, जो हर सेकंड पिन 13 पर एलईडी को टॉगल करता है। सभी तीन संस्करणों को एक uno (कोई USB शामिल नहीं) के लिए avr-gcc 4.8.2, avr-libc 1.8.0 और arduino-core 1.0.5 (मैं Arduino IDE का उपयोग नहीं करता) का उपयोग करके संकलित किया गया है।

सबसे पहले, मानक Arduino रास्ता:

const uint8_t ledPin = 13;

void setup() {
    pinMode(ledPin, OUTPUT);
}

void loop() {
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    delay(1000);
}

यह 1018 बाइट्स के लिए संकलित है। दोनों avr-nmऔर disassembly का उपयोग करके , मैंने उस आकार को अलग-अलग कार्यों में तोड़ दिया। सबसे बड़े से लेकर सबसे छोटे:

 148 A ISR(TIMER0_OVF_vect)
 118 A init
 114 A pinMode
 108 A digitalWrite
 104 C vector table
  82 A turnOffPWM
  76 A delay
  70 A micros
  40 U loop
  26 A main
  20 A digital_pin_to_timer_PGM
  20 A digital_pin_to_port_PGM
  20 A digital_pin_to_bit_mask_PGM
  16 C __do_clear_bss
  12 C __init
  10 A port_to_output_PGM
  10 A port_to_mode_PGM
   8 U setup
   8 C .init9 (call main, jmp exit)
   4 C __bad_interrupt
   4 C _exit
-----------------------------------
1018   TOTAL

ऊपर की सूची में, पहला कॉलम बाइट्स में आकार है, और दूसरा कॉलम बताता है कि क्या कोड Arduino कोर लाइब्रेरी (ए, 822 बाइट्स कुल) से आता है, सी रनटाइम (सी, 148 बाइट्स) या उपयोगकर्ता (यू , 48 बाइट्स)।

जैसा कि इस सूची में देखा जा सकता है, सबसे बड़ा कार्य टाइमर 0 ओवरफ़्लो रुकावट को नियंत्रित करने वाला रूटीन है। यह दिनचर्या ट्रैकिंग समय के लिए जिम्मेदार है, और इसकी आवश्यकता है millis(), micros()और delay()। दूसरा सबसे बड़ा कार्य है init(), जो PWM के लिए हार्डवेयर टाइमर सेट करता है , TIMER0_OVF को बाधित करता है और USART (जो बूटलोडर द्वारा उपयोग किया जाता है) को डिस्कनेक्ट करता है। यह और पिछले फ़ंक्शन दोनों को परिभाषित किया गया है <Arduino directory>/hardware/arduino/cores/arduino/wiring.c

अगला C + avr-libc संस्करण है:

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    DDRB |= _BV(PB5);     /* set pin PB5 as output */
    for (;;) {
        PINB = _BV(PB5);  /* toggle PB5 */
        _delay_ms(1000);
    }
}

अलग-अलग आकारों का टूटना:

104 C vector table
 26 U main
 12 C __init
  8 C .init9 (call main, jmp exit)
  4 C __bad_interrupt
  4 C _exit
----------------------------------
158   TOTAL

यह सी रनटाइम के लिए 132 बाइट्स और उपयोगकर्ता कोड के 26 बाइट्स हैं, जिसमें इनलाइन फ़ंक्शन भी शामिल है _delay_ms()

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

#include <avr/io.h>
#define io(reg) _SFR_IO_ADDR(reg)

    sbi io(DDRB), 5  ; set PB5 as output
loop:
    sbi io(PINB), 5  ; toggle PB5
    ldi r26, 49      ; delay for 49 * 2^16 * 5 cycles
delay:
    sbiw r24, 1
    sbci r26, 0
    brne delay
    rjmp loop

इसे avr-gcc -nostdlibकेवल 14 बाइट्स में इकट्ठा किया जाता है, जिनमें से अधिकांश का उपयोग टॉगल को विलंबित करने के लिए किया जाता है ताकि पलक दिखाई दे। यदि आप उस विलंब लूप को हटाते हैं, तो आप एक 6-बाइट प्रोग्राम के साथ समाप्त होते हैं जो बहुत तेज़ी से झपकाता है (2 मेगाहर्ट्ज पर):

    sbi io(DDRB), 5  ; set PB5 as output
loop:
    sbi io(PINB), 5  ; toggle PB5
    rjmp loop

3

मैंने एक पोस्ट लिखी कि एक एलईडी को ब्लिंक करने में 1000 बाइट्स क्यों लगते हैं?

संक्षिप्त उत्तर है: " दो एलईडी को ब्लिंक करने में 2000 बाइट्स नहीं लगते हैं !"

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

यहां तक ​​कि अगर आप उनका उपयोग नहीं करते हैं, तो मानक पुस्तकालयों में "टिक्स" को गिनने के लिए कोड शामिल है ताकि आप वर्तमान "समय" (कॉल करके millis()) पता लगा सकें । ऐसा करने के लिए इसे कुछ रुकावट सेवा दिनचर्या के ओवरहेड को जोड़ना होगा।

यदि आप इस स्केच पर नीचे (Arduino Uno पर) सरल करते हैं, तो आपको प्रोग्राम मेमोरी का उपयोग 178 बाइट्स (IDE 1.0.6 पर) नीचे मिलता है:

int main ()
  {
  DDRB = bit (5);
  while (true)
    PINB = bit (5);
  }

ठीक है, 178 बाइट्स इतना नहीं है, और उसमें से पहले 104 बाइट्स हार्डवेयर इंटरप्ट वैक्टर (4 बाइट्स प्रत्येक, 26 वैक्टर के लिए) हैं।

तो यकीनन, एलईडी को ब्लिंक करने के लिए केवल 74 बाइट्स की आवश्यकता होती है। और इसमें से 74 बाइट्स वास्तव में ग्लोबल मेमोरी को इनिशियलाइज़ करने के लिए कंपाइलर द्वारा उत्पन्न कोड हैं। यदि आप दो एल ई डी ब्लिंक करने के लिए पर्याप्त कोड जोड़ते हैं:

int main ()
  {
  DDRB = bit (5);  // pin 13
  DDRB |= bit (4);  // pin 12

  while (true)
    {
    PINB = bit (5); // pin 13
    PINB = bit (4); // pin 12
    }
  }

फिर कोड का आकार बढ़कर 186 बाइट्स हो जाता है। तो इसलिए आप यह तर्क दे सकते हैं कि 186 - 178 = 8एक एलईडी को ब्लिंक करने में केवल बाइट्स का ही समय लगता है ।

तो, एक एलईडी झपकी करने के लिए 8 बाइट्स। मेरे लिए बहुत कुशल लगता है।


यदि आप घर पर इसे आज़माने के लिए ललचाते हैं, तो मुझे यह संकेत देना चाहिए कि पोस्ट किए गए कोड को दो एल ई डी ब्लिंक करने के दौरान, यह वास्तव में बहुत तेजी से करता है। वास्तव में, वे 2 मेगाहर्ट्ज पर पलक झपकते हैं - स्क्रीनशॉट देखें। चैनल 1 (पीला) पिन 12 है, चैनल 2 (सियान) पिन 13 है।

12 और 13 पिन की तेजी से ब्लिंकिंग

जैसा कि आप देख सकते हैं, आउटपुट पिंस में 2 मेगाहर्ट्ज की आवृत्ति के साथ एक चौकोर लहर है। पिन 13 कोड में पिन के टॉगल करने के आदेश के कारण पिन 12 से पहले राज्य में 62.5 ns (एक घड़ी चक्र) बदलता है।

इसलिए जब तक आपके पास मेरी तुलना में बेहतर आंखें नहीं हैं, आप वास्तव में किसी भी निमिष प्रभाव को नहीं देखेंगे।


एक मनोरंजक अतिरिक्त के रूप में, आप वास्तव में एक पिन को टॉगल करने के रूप में प्रोग्राम स्पेस की समान मात्रा में दो पिन टॉगल कर सकते हैं ।

int main ()
  {
  DDRB = bit (4) | bit (5);  // set pins 12 and 13 to output

  while (true)
    PINB =  bit (4) | bit (5); // toggle pins 12 and 13
  } // end of main

यह 178 बाइट्स में संकलित है।

यह आपको उच्च आवृत्ति प्रदान करता है:

पिंस 12 और 13 के बहुत तेजी से ब्लिंकिंग

अब हम 2.66 मेगाहर्ट्ज तक हैं।


यह समझदारी का एक टन बनाता है। तो क्या मानक पुस्तकालयों का निर्माण समय पर स्वचालित रूप से शामिल किया जाता है? और आप उन्हें कैसे शामिल नहीं कर पाए ?
hichris123

2
लिंकर आक्रामक कोड का उपयोग नहीं करता है। कॉल नहीं करने से init()(जैसा कि सामान्य main()करता है) तब फ़ाइल wiring.c (जिसमें है init) को इसमें लिंक नहीं किया गया था। परिणामस्वरूप, बाधा हैंडलर (के लिए millis(), micros()आदि) के लिए प्रसंस्करण छोड़ दिया गया था। यह संभवतः इसे छोड़ना विशेष रूप से व्यावहारिक नहीं है, जब तक कि आपको कभी भी चीजों को समय की आवश्यकता न हो, लेकिन तथ्य यह है कि स्केच आकार में बढ़ता है जो आप इसमें डालते हैं। उदाहरण के लिए, यदि आप सीरियल का उपयोग करते हैं, तो प्रोग्राम मेमोरी और रैम दोनों एक हिट लेते हैं।
निक गैमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.