Go Down

Topic: Hilfe beim Sketch verkleinern (Read 4677 times) previous topic - next topic

combie

Wenn das #include <util/delay.h> fehlt...

KA, warum er das bei mir nicht anmäckert
Alle sagen: Das geht nicht!
Einer wusste das nicht und probierte es aus.
Und: Es ging nicht.

RudiDL5

Ich weiß auch nicht wo der Haken bei mir sein kann.
Benutzte IDE: 1.8.5 Hourly Build 2017/08/28 06:33

combie

#47
Nov 07, 2017, 04:58 am Last Edit: Nov 07, 2017, 05:24 am by combie
Werde nochmal drüber schauen...
Aber nicht innerhalb der nächsten 36H.

Habe die letzten Versionen mit einer IDE 1.6.12 erstellt.
Daher wohl das unterschiedliche Verhalten beim Include.


Die Durchdreher beim abspielen haben sicherlich was mit der Standard Integer Arithmetik, zu tun.
Wäre zumindest mein erster Ansatz.


Soweit wie möglich die Byte Verarbeitung erzwungen.
Code: [Select]
#include <Arduino.h>

const uint8_t size = 17;
const uint8_t ledtakt[size] PROGMEM = {60,25,40,75,33,90,57,24,100,68,73,80,37,75,254,97,105};
uint8_t ledtime[size];

/*
inline void toggle(const uint8_t pin)
{
  uint8_t bit  = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  *portInputRegister(port) = bit;
}
*/
uint8_t zeitMerker = 0; // millis() ErsatzStoff

int main()
{
  DDRD = 0b01111111;
  DDRA = 0b00000011;
  DDRB = 0b11111111;
//  Serial.begin(9600);
  while(1)
  {
       for( uint8_t LED = 0; LED < size ; LED++ )
       {
           uint8_t diff = zeitMerker - ledtime[LED];
           uint8_t takt = pgm_read_byte(&ledtakt[LED]);
           if(diff >= takt)
           {
              ledtime[LED] = zeitMerker;
              uint8_t bit  = digitalPinToBitMask(LED);
              uint8_t port = digitalPinToPort(LED);
              *portInputRegister(port) = bit;
           }
       }
       _delay_ms(99); // 1 ms für die Verarbeitung
       zeitMerker++; 
  //     Serial.println(zeitMerker,HEX);
  }
}

*auch quasi ungetestet*

Alle sagen: Das geht nicht!
Einer wusste das nicht und probierte es aus.
Und: Es ging nicht.

volvodani

#48
Nov 07, 2017, 08:17 am Last Edit: Nov 07, 2017, 08:18 am by volvodani
// Ich liebe diese Battles "ich kann besser" da lernt man als nicht "C"ler ungemein viel
Danke.
Gruß
DerDani
"Komm wir essen Opa!" - Satzzeichen retten Leben!

RudiDL5

Nur schade dass ich im Moment viel zu wenig Zeit für diese Dinge habe. Es ist in der Tat eine sehr erfrischende Unterhaltung mit auch für mich hohem Lerneffekt. Die Arduino-Welt inkl. C kenne ich erst seit 3 Jahren - und fast täglich kommt eine Menge Stoff hinzu. combie's Ausführungen rufen ganz laut danach, näher untersucht zu werden. Vor allen Dingen, wenn man (wie ich) gerne mit den kleinen AVRs hantiert und oft jedes Byte 2x umdrehen muss.

RudiDL5

Trotz Zeitmangel juckte es in den Fingern:
combie's letzte Fassung ... Minus #include <Arduino.h> ... Minus Kommentar-Block "toggle()" ... Plus #include <util/delay.h>

Code: [Select]

#include <util/delay.h>

const uint8_t size = 17;
const uint8_t ledtakt[size] PROGMEM = {60,25,40,75,33,90,57,24,100,68,73,80,37,75,254,97,105};
uint8_t       ledtime[size];
uint8_t       zeitMerker = 0; // millis() ErsatzStoff

int main()
{
  DDRD = 0b01111111;
  DDRA = 0b00000011;
  DDRB = 0b11111111;

  while(1)
  {
    for( uint8_t LED = 0; LED < size ; LED++ )
    {
      uint8_t diff = zeitMerker - ledtime[LED];
      uint8_t takt = pgm_read_byte(&ledtakt[LED]);
      if(diff >= takt)
      {
        ledtime[LED] = zeitMerker;
        uint8_t bit  = digitalPinToBitMask(LED);
        uint8_t port = digitalPinToPort(LED);
        *portInputRegister(port) = bit;
      }
    }
    _delay_ms(99); // 1 ms für die Verarbeitung
    zeitMerker++;
  }
}

Kompliert mit IDE 1.8.5 ... Übertragen via UNO R3 auf Tiny 2313 ...
Der Sketch verwendet 252 Bytes (12%) des Programmspeicherplatzes. Das Maximum sind 2048 Bytes.
Globale Variablen verwenden 18 Bytes (14%) des dynamischen Speichers, 110 Bytes für lokale Variablen verbleiben. Das Maximum sind 128 Bytes.


Und es blinkt seit gut einer Stunde nett, lustig und stabil vor sich hin. Optimal!
Quote
Ich schätze mal, hier ist dann so ziemlich Ende der Fahnenstange
Dem stimme ich zu!

Beste Grüße, ich bin dann mal fort und packe weiter meine Kisten...
Rudi


combie

#51
Nov 08, 2017, 09:22 am Last Edit: Nov 08, 2017, 09:23 am by combie
Schön!

Fein, dass es jetzt funktioniert.

Auch ist es ein Zeichen dafür, dass man den Datentypen, bei Berechnungen/Vergleichen, erhebliche Aufmerksamkeit widmen muss. Ins besondere den impliziten Konvertierungen.

Jetzt:
Quote
Der Sketch verwendet 252 Bytes (12%) des Programmspeicherplatzes. Das Maximum sind 2048 Bytes.
Globale Variablen verwenden 18 Bytes (14%) des dynamischen Speichers, 110 Bytes für lokale Variablen verbleiben. Das Maximum sind 128 Bytes
Zu Anfang:
Quote
Der Sketch verwendet 2738 Bytes (133%) des Programmspeicherplatzes. Das Maximum sind 2048 Bytes.
Globale Variablen verwenden 262 Bytes (204%) des dynamischen Speichers, -134 Bytes für lokale Variablen verbleiben. Das Maximum sind 128 Bytes.
Eingedampft, auf deutlich unter 10%, sowohl Ram, als auch Flash.

Ich möchte mal sagen: Eine gute Teamleistung!

---
Beim Ram kann nichts mehr zu holen sein.
17 Byte für das Array und 1 Byte für den Zeitzähler.

Beim Flash sitzt noch was drin, wenn man denn Assembler, statt C++ verwenden würde:
1. kleinere Optimierungen bei dem Algorithmus
2. Verzicht auf die Stack Initialisierung
3. Verzicht auf die Interrupt Tabelle
4. Weg von den Arduino Pin Nummern.

Zu 3:
Wir nutzen keine ISR, also könnte in dem Bereich auch Code platziert werden.
19 Vektoren sind so einzusparen, 38 Byte (wenn ich mich nicht verrechnet habe)

Zu 4:
Da ist noch erhebliches Potential!
Die 17 Pins, * 2 Tabellen, ca 34Byte


Zusammengenommen, bestenfalls, geschätzte weitere 90Byte mögliche Flash Einsparung.


------------
Hilfe!
Wenn ich geahnt hätte, dass ihr alle so viel Hirnschmalz für mein Problem verbraucht, hätte ich niemals nach Lösungsvorsachläge gefragt. Ihr seid ja famos.
Danke euch allen!
Ganz im Gegenteil!
Ich habe dir zu danken!

Als das größte Lob unter Hackern gilt: Spannende Frage!

Und die hast du geliefert!
Eine interessante, spannende, Frage.



Alle sagen: Das geht nicht!
Einer wusste das nicht und probierte es aus.
Und: Es ging nicht.

combie

Zu 4:
Verzicht auf die Arduinonummerei
Die Pins und Zeiten sind jetzt neu zugeordnet.

Wenn nötig, dann sind die Zeiten neu anzuordnen

Code: [Select]
#include <util/delay.h>

const uint8_t size = 17; // anzahl LED Pins

const uint8_t ledtakt[size] PROGMEM = { 60,  25,  40,  75,  33,  90,  57,  24,  100, 68, 73, 80, 37, 75, 254,  97, 105};
// Register Pin Zuordnung             {PB0   PB1  PB2  - - -  - - - - - - PB7 | PD0  PD1 - - - - - - - - PD6 | PA0 PA1}

uint8_t ledtime[size]; // merker für den Zeitablauf

uint8_t zeitMerker = 0; // millis() ErsatzStoff

// Schwellwerte
const byte schwelleB = 8;  // 8 Bit in Port B (bit 0 bis 7)
const byte schwelleD = 7;  // 7 bit in Port D (bit 8 bis 14)
// der Rest muss in Port A stecken            (bit 15 und 16)


int main()
{
  DDRB = 0b11111111;
  DDRD = 0b01111111;
  DDRA = 0b00000011;
 
  while(1)
  {
       for( uint8_t LED = 0; LED < size ; LED++ )
       {
           uint8_t diff = zeitMerker - ledtime[LED];
           uint8_t takt = pgm_read_byte(&ledtakt[LED]);
           if(diff >= takt)
           {
         
              ledtime[LED] = zeitMerker;
              byte bit = LED; // das Bit, welches es zu verarbeiten gilt
             
              if(bit<schwelleB)
              {
                PINB = (1<<bit);
                continue;
              }
             
              bit -= schwelleB;
              if(bit<schwelleD)
              {
                PIND = (1<<bit);
                continue;
              }
             
              bit -= schwelleD;
              PINA = (1<<bit);
           }
       }
       _delay_ms(99); // 1 ms für die Verarbeitung
       zeitMerker++; 
  }
}

*auch wieder ungetestet, bin mitten auf dem Acker, keinerlei Arduino zur Hand*
Alle sagen: Das geht nicht!
Einer wusste das nicht und probierte es aus.
Und: Es ging nicht.

RudiDL5

#53
Nov 08, 2017, 09:55 pm Last Edit: Nov 08, 2017, 11:06 pm by RudiDL5
Quote
Ich möchte mal sagen: Eine gute Teamleistung!
und
Quote
Eine interessante, spannende, Frage.
Das sehe ich genau so.

Vor allen Dingen, weil die letzte combie-Version ebenfalls funktionierte und noch mal wieder einiges an FLASH einsparte:
Der Sketch verwendet 244 Bytes (11%) des Programmspeicherplatzes. Das Maximum sind 2048 Bytes.
Globale Variablen verwenden 18 Bytes (14%) des dynamischen Speichers, 110 Bytes für lokale Variablen verbleiben. Das Maximum sind 128 Bytes.


Nun denn, die obigen Hinweise auf Assembler sind genau diejenigen gewesen, die mir auch vorschwebten. Also bin ich hingegangen, habe den *.HEX-Output von meinen Disassembler entflechten lassen und das ganze Programm etwas (sofern es meine Zeit erlaubte) untersucht. Einige Zuordnungen der einzelnen C++-Zeilen konnte ich (noch) nicht genau identifizieren. Mir fehlt einfach die Zeit für nähere Beschäftigung damit. Dennoch zeigt es, dass noch eine gute Hand voll Bytes drin sitzen. Wahrscheinlich würde es noch sparsamer im FLASH werden, wenn man so etwas direkt in Assembler anfängt.

Egal, den Code habe ich hier eingebunden. Sieht wahrscheinlich wie Kauderwelsch aus und ist noch nicht optimal kommentiert:
Code: [Select]

;***********************************************************
;17 LEDs an AT Tiny 2313 bei 8 MHz
;-----------------------------------------------------------
;Idee: "Floetzinger" (Member Forum Arduino.CC)
;Optimierung: "conbie" & "RudiDL5" (Menber Forum Arduino.CC)
;***********************************************************

;defines
;--------------------------------------------
.equ   SREG = 0x3F
.equ   RAMSTART = 0x0060
.equ   DDRB = 0x17
.equ   DDRD = 0x11
.equ   DDRA = 0x1A
.equ   schwelleB = 8
.equ   schwelleD  = 7

;datasegment
;--------------------------------------------
  .dseg
  .org RAMSTART
zeitMerk: .byte 1
ledTime: .byte 17

;codesegment
;--------------------------------------------
.cseg
.org 0
pwron:      RJMP        resvect               

progmem:    .dw        0x3C19                ;  60; 25;
            .dw        0x284B                ;  40; 75;
            .dw        0x215A                ;  33; 90;
            .dw        0x3918                ;  57; 24;
            .dw        0x6444                ; 100; 68;
            .dw        0x4950                ;  73; 80;
            .dw        0x254B                ;  37; 75;
            .dw        0xFE61                ; 254; 97;
            .dw        0x6900                ; 105;  0;

resvect:  CLR        r1                    ; SREG
            OUT        SREG,      r1         ; "

            LDI        r26,       LOW(RAMSTART)
            LDI        r27,       HIGH(RAMSTART)

;main
;--------------------------------------------
SER        r24                   ; DDRB = 0b11111111
            OUT        DDRB,      r24        ; "
            LDI        r24,       0x7F       ; DDRD = 0b01111111
            OUT        DDRD,      r24        ; "
            LDI        r24,       0x03       ; DDRA = 0b00000011
            OUT        DDRA,      r24        ; "

;while
;--------------------------------------------
            LDI        r20,       0x01       
            LDI        r21,       0x00       
while1:    LDI        r26,       0x61       
            LDI        r27,       0x00       
            LDI        r24,       0x00       
            LDI        r25,       0x00       

;for
;--------------------------------------------
L_006E:    LDS        r19,       zeitMerk   ; diff = zeitMerk - ledTime[LED]
            MOV        r18,       r24        ; "
            MOVW        r31:r30,   r25:r24    ; " (berechnet zeiger auf progmem-
            SUBI        r30,       0xFE       ; "  adressen für "Z" OHNE isr-vectoren)
            SBCI        r31,       0xFF       ; "

            LPM        r30,       Z          ; takt = pgm_read_byte( &ledTakt[LED] )
            LD          r22,       X          ; "
            MOV        r23,       r19        ; "
            SUB        r23,       r22        ; "

            CP          r23,       r30        ; if( diff >= takt )
            BRCS        next                  ;   ...

            ST          X,         r19        ; if( bit < schwelleB )
            CPI        r24,       schwelleB  ;   ...
            CPC        r25,       r1         ;
            BRCC        L_00A0                ;
            MOVW        r23:r22,   r21:r20    ;
            MOV        r0,        r24        ;
            RJMP        L_0098                ;

L_0094:    LSL        r22                   ;
            ROL        r23                   ;

L_0098:    DEC        r0                    ;
            BRPL        L_0094                ;
            OUT        0x16,      r22        ; schreibt BIT nach PORT B
            RJMP        next                  ; continue

L_00A0:    LDI        r19,       0xF8       ; if( bit < schwelleD )
            ADD        r19,       r24        ;   ...
            CPI        r19,       schwelleD  ;
            BRCC        L_00B8                ;
            MOVW        r23:r22,   r21:r20    ;
            RJMP        L_00B0                ;

L_00AC:    LSL        r22                   ;
            ROL        r23                   ;
L_00B0:    DEC        r19                   ;
            BRPL        L_00AC                ;

            OUT        0x10,      r22        ; schreibt BIT nach PORT D
            RJMP        next                  ; continue

L_00B8:    SUBI        r18,       0x0F       ;
            MOVW        r23:r22,   r21:r20    ;
            RJMP        L_00C2                ;

L_00BE:    LSL        r22                   ;
            ROL        r23                   ;
L_00C2:    DEC        r18                   ;
            BRPL        L_00BE                ;
            OUT        0x19,      r22        ; schreibt BIT nach Port A

next:      ADIW        r25:r24,   0x01       ; "next" FOR ?
            ADIW        r27:r26,   0x01       ; "
            CPI        r24,       0x11       ; "
            CPC        r25,       r1         ; "
            BRNE        L_006E                ; "

;_delay_ms(99)
;--------------------------------------------
del99:      LDI        r23,       0xBF       
            LDI        r24,       0x6A       
            LDI        r25,       0x02       
del99_1:    SUBI        r23,       0x01       
            SBCI        r24,       0x00       
            SBCI        r25,       0x00       
            BRNE        del99_1               

;zeitMerker++
;--------------------------------------------
            LDS        r24,       zeitMerk
            SUBI        r24,       0xFF     
            STS        zeitMerk,  r24       

;end of while(1)
;--------------------------------------------
            RJMP        while1


Aber was solls? Das Programm wurde noch mal kürzer:
;-------------------------------------
;Alles Okay, keine Fehler vorhanden
;Bytes .CSEG:  178 von max. 2048
;Bytes .DSEG:   18 von max.  128
;Bytes .ESEG:    0 von max.  128
;-------------------------------------


2738 Bytes zu 178 Bytes FLASH
262 Bytes zu 18 Bytes SRAM

So viel zum Thema "Hilfe mein Sketch ist zu groß" ;)
Beste Grüße
Rudi

combie

#54
Nov 08, 2017, 10:36 pm Last Edit: Nov 08, 2017, 10:52 pm by combie
Ja...

So wirds gehen.
Um jedes Byte kämpfen...

Wie hasste das denn kompiliert?
(egal, finde ich selber raus...)

Aber jetzt beim Assembler, sind wir eigentlich an dem Punkt, wo ich aus dem Rennen bin.
Habe mich irgendwann entschieden, den C++ Weg zu gehen!


Aber was solls...
Vielleicht ist es ja jetzt an der Zeit mal wieder 131 Befehle (in der Tiefe) zu lernen.
.........



------------


Da ist mir noch einer eingefallen...

Quote
Beim Ram kann nichts mehr zu holen sein.
Denn es gibt ja noch:
GPIOR0
GPIOR1
GPIOR2


Also
Statt:
uint8_t zeitMerker = 0; // millis() ErsatzStoff

Dieses einsetzen:
#define zeitMerker  GPIOR0

Wieder 1 Byte gespart.

Und noch 2 in Reserve behalten.....
(Gilt natürlich auch für Assembler)
Alle sagen: Das geht nicht!
Einer wusste das nicht und probierte es aus.
Und: Es ging nicht.

RudiDL5

Quote
Wie hasste das denn kompiliert?
Zugegeben - auf eine recht schräge Art. Im letzten Frühjahr hatte ich einen Durchhänger und wollte von kleineren Sketches eigentlich "nur mal so" analysieren, was eigentlich im *.HEX-Output "tatsächlich" alles drin ist und wie das ganze letztendlich funktioniert. Aus dieser Idee ist zunächst ein Disassembler entstanden. Immer mehr Blut geleckt ... habe ich den immer weiter verbessert. Der Assembler selbst ist daraus eigentlich "zwangsläufig" entstanden. Alles in DELPHI. Er nimmt auch #includes, .macros und prüft, ob ein einzelnes Kommando für den jeweilgen Controller erlaubt ist. Übertragen werden die Bytes via USBasp. Ebenso können Fuses gelesen/geschrieben werden.

Okay, AVR-Studio kannte ich zwar, aber erstens ist der mir letztes Jahr mit einem PC gestorben und irgendwie ist mir das Ding zu sehr überladen. Ich mag meinen kleinen Dis/Assembler sehr und kann damit alles machen was ich will. Auch wenn er bei weitem nicht an das Studio heranreicht. Aber für meine paar Tiny-Versuche läuft das Teil sehr gut.

So auch das o.g. Programm seit Stunden jetzt brav blinkt.
:)

combie

#56
Nov 08, 2017, 11:10 pm Last Edit: Nov 08, 2017, 11:12 pm by combie
Ach, so einer bist du.....
Ja, ja, hätte ich mir ja fast denken können.

Aus meiner Vergangenheit: Forth
Alle sagen: Das geht nicht!
Einer wusste das nicht und probierte es aus.
Und: Es ging nicht.

RudiDL5

Ja ja, so einer bin ich ... :D

Dass du Forth machst habe ich schon mal irgendwo aufgeschnappt. Oha, lang lang ist es her, als ich selbst in Forth experimentierte. Ist 'ne interessante Sache, das Buch dazu hatte ich erst vor wenigen Wochen noch in der Hand. Ich erinnere mich gerne an die Stack-Sachen daraus, wenn ich mal so etwas brauche.

Ich sage mal "gute Nacht". Morgen ist wieder "Handwerk" angesagt... :(

Floetzinger

sorry, Arbeit hat mich aufgehalten.
Unglaublich, was da so zusammen geschrumpft wird.
Ich denk dann mal übetr ein neues zu lösendes problem nach  :smiley-mr-green:  :smiley-evil:
War übrignes sehr spannend, wie ihr euch dann mal so nach Vorn gepeitscht habt.
Respekt!

Go Up