Jak naprawdę zmniejszyć szkic

9

Chcę zrobić szkic tak mały, jak to możliwe, do celów testowych. Problem polega na tym, że kiedy kompiluję szkic BareMinimum (z pustą konfiguracją i pętlą), otrzymuję 466 bajtów dla Uno i ogromną 4,242 dla Leonardo. Czy jest jakiś sposób na napisanie własnego kodu, który nie ma żadnych dodatkowych funkcji (mianowicie Timer0 dla millis()i delay()). Chciałbym również móc wyłączyć funkcje klawiatury / myszy dla Leonardo.

Doktor
źródło
4
Czy nie należy tego oznaczać Leonardo, a nie Uno (i skupić się na jednej planszy)? To są osobne pytania.
asheeshr
Po prostu wskazuję, że pusty skompilowany szkic jest duży dla wielu płyt, zwłaszcza tych natywnych opartych na USB
TheDoctor
Chciałbym również móc wyłączyć funkcje klawiatury / myszy dla Leonardo. to drugie pytanie.
asheeshr

Odpowiedzi:

3

Powinieneś być w stanie stworzyć własną definicję planszy za pomocą niestandardowego pliku deski.txt zgodnie z https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification . Jak widzę, definicja Leonarda zawiera kilka funkcji USB. Mam nadzieję, że włączenie kompilacji 4K opiera się na tych flagach, a nie na typie procesora.

Tam, gdzie deski.txt użyłyby uploadu, sekcje bootloadera z Leonardo i kompilacji z uno.

Wszystko to przy założeniu, że kompilacja biblioteki podstawowej nie używa flag specyficznych dla procesora do włączenia funkcji USB.

Jeśli dostaniesz taką pracę. napisz z powrotem, jestem pewien, że inni byliby zainteresowani takimi.


Niedawno natknąłem się na to ograniczenie 4K w wersji demonstracyjnej biblioteki, która faktycznie zmaksymalizowała UNO i musiałam ją zainstalować

#if !defined(__AVR_ATmega32U4__)
...

wokół dużej części dodatkowych elementów szkicu, które pasują do Leonarda.

Założyłem (błędnie), że to 4K było, ponieważ nadal zawierałem Serial.print, który po USB CDC na Leo. Ale widzę, że po zrzutie pamięci pustego szkicu wciąż tam są.

C:\Users\mflaga\AppData\Local\Temp\build8958339595868119500.tmp>avr-objdump -d sketch_feb13a.cpp.elf > sketch_feb13a.cpp.elf.lst

Co ma sens. Ponieważ Leonardo nadal wymaga klienta USB-CDC (4K), aby wykryć połączenie 1200 Baud z AVR-DUDE, aby udaremnić zdalny restart.


Stąd tworzenie niestandardowego pliku board.txt bez USB w kompilacji również musi mieć

leonardo.upload.use_1200bps_touch=true

oddalony.

Po załadowaniu do celu wymagałoby to synchronizacji przesyłania z ręcznym resetowaniem celu. Ponieważ utracono możliwość zdalnego restartu.

mpflaga
źródło
zaktualizowano, dlaczego 4K jest nadal kompilowany, nawet jeśli pominięto Serial.print.
mpflaga
3

Niedawno chciałem to dokładnie zrobić. Ponieważ nie ma na to przyjemnego sposobu, skończyło się na napisaniu łatki do wtyczki Stard sardime-text arduino, aby dokładnie to zrobić. Zostało to następnie zaakceptowane, więc powinno być w każdej aktualnej instalacji Stino.

Dodaje to nową opcję do Stino:

wprowadź opis zdjęcia tutaj

Korzystanie z tego trybu daje wyniki kompilacji takie jak następujące:

W przypadku Uno:

Rozmiar szkicu binarnego: 172 bajty (maksymalnie 32256 bajtów, 0,53 procent).
Szacowane użycie pamięci: 0 bajtów (maksymalnie 1024 bajty, 0,00 procent).

Dla Leonarda

Rozmiar szkicu binarnego: 240 bajtów (z maksymalnie 28672 bajtów, 0,84 procent).
Szacowane użycie pamięci: 0 bajtów (maksimum 2560 bajtów, 0,00 procent).

Właściwie programowania Leonardo z powyższym skompilowanej wyjścia jest prawdopodobnie zły pomysł, ponieważ może przerwać funkcję auto-reset, ale mógłby , gdyby chciał. Porada dla mpflagi za zwrócenie uwagi na to w swojej odpowiedzi.

Pamiętaj, że raporty pamięci są w rzeczywistości niepoprawne, ale to osobny problem .

Kod użyty do powyższego to:

int main()
{
    while (1)
    {

    }
}

Niektóre uwagi:

  • Nie pisze się „szkic” już nie, że kiedykolwiek faktycznie nie napisać szkic. Piszesz programy . Kropka. Nie obchodzi mnie, co chcą powiedzieć wackos Arduino, nie zmieniają terminów.
  • Całe zarządzanie przerwaniami odbywa się ręcznie. Oznacza to brak milis()lub podobne.
  • Ci mogą nadal korzystać z bibliotek Arduino szeregowych i tak dalej, jeśli chcesz. Musisz #include <Arduino.h>.
  • Ty definiujesz main. Nigdy nie wracasz z main. Jeśli chcesz skonfigurować rzeczy, dzieje się to przed while (1).
Connor Wolf
źródło
@jfpoilpret Nazywasz to IDE? Bardziej jak notatnik z makrami ...
Ron
@ Ron-E Nie nazywam tego IDE, Arduino IDE to jego nazwa, więc po prostu użyłem jego nazwy, chociaż nie jest to warte tego imienia.
jfpoilpret
2
@FakeName Zły język jest niedozwolony w witrynach Stack Exchange (patrz: stackoverflow.com/help/behavior ). W tym przypadku zredagowałem go, ale w przyszłości spróbuj powstrzymać się przed użyciem przekleństw. Dzięki.
Peter Bloomfield
2

Chociaż zależy to od szkicu, możesz nieco zmniejszyć rozmiar, ponownie wykorzystując kod metodami.

Weź ten kod:

int led = 13;
int val;

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

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  val = digitalRead(10);
}

1 322 bajty na Arduino Uno. Teraz zmniejszmy to trochę:

int led = 13;
int val;

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

void loop() {
  for(uint8_t i = 0; i < 8; i++) {
    blink(HIGH);
    blink(LOW);
  }    
  val = digitalRead(10);
}

void blink(uint8_t state) {
  digitalWrite(led, state);   // turn the LED to the right state
  delay(1000);                // wait for a second
}

1194 bajty. To około 10% mniej!

W każdym razie, chociaż nie zmniejsza to w znacznym stopniu szkicu, czasem może być najłatwiejszą drogą, gdy masz dwa bajty ponad limit lub po prostu chcesz stworzyć bardziej kompaktowy szkic na początku, nie tracąc żadnej funkcjonalności. Nie jest tak w każdej sytuacji, ale czasem uważam ją za przydatną.

Anonimowy pingwin
źródło
Ogólnie rzecz biorąc, jeśli wyciągniesz kod do funkcji, kompilator wykona ciężką pracę, a resztę zrobi dla ciebie.
Cybergibbons
@Cybergibbons Czy możesz to zdefiniować [dla użytkowników, którzy się z tym nie znają]?
Anonimowy pingwin
3
Jeśli podzielisz kod na funkcję, która nie jest wydajna, generalnie kompilator wstawi ją za Ciebie. Jednak kompilator nigdy nie podzieli kodu na funkcje. Dlatego prawie zawsze lepiej jest pisać więcej funkcji.
Cybergibbons
1
Dodatkowo włączenie kodu w funkcje znacznie ułatwia czytanie i zrozumienie
Przy użyciu bezpośredniego dostępu do portu rozmiar jest zmniejszany do 646 bajtów. Używając tylko avr-libc (bez rdzenia Arduino), dochodzi do 220 bajtów.
Edgar Bonet
0

@ pingwin pingwinowy, na pewno możemy Chociaż kod kompiluje się w 1180 bajtów flash + 13 bajtów RAM dla Uno na moim komputerze, możemy to poprawić :) więc wyzwanie golfa zaakceptowane i kilka przydatnych wskazówek, ponieważ jesteśmy w branży uczenie się.

Krok 1: zmniejsz wymagania zmienne. Używanie int dla portu ledowego wydaje się nieco przesadne, z pewnością nie mamy 65535 adresowalnych portów IO na arduino :) Więc zmieniamy go na bajt tylko dla zabawy. Później zmienimy to na #define, ale aby pokazać wpływ używania zbyt dużych typów zmiennych.

byte led = 13;
int val;

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

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Kompiluje do 1172 bajtów + 13 bajtów RAM. Oszczędza to 8 bajtów pamięci flash z powodu mniejszej liczby wymaganych operacji dla bajtu zamiast liczby całkowitej. Spodziewałbym się 12 bajtów pamięci RAM, ale dobrze. Nie tak bardzo, ale każdy zapisany bajt jest dobry.

Krok 2: zmień zmienną na definiuje, kiedy ma to sens. Na przykład bajt led nie jest potrzebny, szpilka sama się nie wylutuje.

#define LED 13
int val;

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

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Kompiluje do 1142 bajtów flash + 11 bajtów pamięci RAM. Zapisano już 38 bajtów. Wynika to z mniejszej liczby operacji rejestru wymaganych do pobrania wartości int. Zapisaliśmy również 2 bajty z pamięci RAM. (wciąż zastanawiam się, dlaczego bajt nie skompilował się w 1 mniej bajtu pamięci RAM .....)

Krok 3: zoptymalizuj kod. Widzę 2 opóźnienia. Zastanawiam się, czy zmienię to na 1 opóźnienie, by zaoszczędzić miejsce, ale muszę obliczyć wartość kołka LED i przełączyć go (odwrócić). Możemy to zrobić za pomocą digitalRead (), ale czy pozwoli to zaoszczędzić miejsce?

#define LED 13
int val;
void setup() {                
  pinMode(LED, OUTPUT);     
}
void loop() {
  blink();
  val = digitalRead(10);
}
void blink() {
  digitalWrite(LED, !digitalRead(LED));   // toggle the led based on read value
  delay(1000);               // wait for a second and spare yourself the other delay
}

Kompiluje do 1134 bajtów + 11 bajtów ram. Tak! kolejne 8 bajtów. To daje w sumie 46 bajtów i 2 mniej wierszy kodu.

Kolejna ogólna wskazówka dotycząca zmniejszania rozmiaru kodu. Nie używaj klasy String. Jest OGROMNY, dowiedz się, jak radzić sobie z tablicami znaków, strcpy (), strcmp (). Jeśli masz tylko kilka podstawowych operacji na łańcuchach, użycie klasy String powoduje głównie marnowanie miejsca zarówno na pamięć flash, jak i pamięć RAM.

Patrick Deelman
źródło