Hilfe beim Sketch verkleinern

Is ja cool! Das spart ja noch mehr und macht weiteren Raum für Spielerei.
Man(n) lernt halt nie aus. Aber das werde ich mir nach meinem Umzug
in Ruhe und genau ansehen.
Besten Dank

Schön, wenn es gefällt!

Noch mehr Raum, geht auch noch.
Aber auf Kosten der Taktgenauigkeit.

const byte ledtakt[] PROGMEM = {60,25,40,75,33,90,57,24,100,68,73,80,37,75,254,97,105};
byte ledtime[sizeof(ledtakt)];

inline void toggle(const uint8_t pin)
{
  uint8_t bit  = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  *portInputRegister(port) = bit;
}

byte zeitMerker = 0; // millis() ErsatzStoff


void setup()
{
  DDRD = 0b01111111;
  DDRA = 0b00000011;
  DDRB = 0b11111111;
}

void loop() 
{
     for( byte LED = 0; LED < 17; LED++ ) 
     {
         if(zeitMerker - ledtime[LED] >= pgm_read_byte(&ledtakt[LED]))
         {
            ledtime[LED] = zeitMerker;
            toggle(LED);
            //digitalWrite( LED, !digitalRead(LED) );       
         }
     } 
     _delay_ms(99); // 1 ms für die Verarbeitung 
     zeitMerker++;   
}

ungetestet

Ich schätze mal, hier ist dann so ziemlich Ende der Fahnenstange:

const byte ledtakt[] PROGMEM = {60,25,40,75,33,90,57,24,100,68,73,80,37,75,254,97,105};
byte ledtime[sizeof(ledtakt)];

inline void toggle(const uint8_t pin)
{
  uint8_t bit  = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  *portInputRegister(port) = bit;
}

byte zeitMerker = 0; // millis() ErsatzStoff

int main()
{
  DDRD = 0b01111111;
  DDRA = 0b00000011;
  DDRB = 0b11111111;
  for(;;)
  {
       for( byte LED = 0; LED < 17; LED++ ) 
       {
           if(zeitMerker - ledtime[LED] >= pgm_read_byte(&ledtakt[LED]))
           {
              ledtime[LED] = zeitMerker;
              toggle(LED);
              //digitalWrite( LED, !digitalRead(LED) );       
           }
       } 
       _delay_ms(99); // 1 ms für die Verarbeitung 
       zeitMerker++;   
  }
}

ungetestet

Kompiliert für einen Mega

Der Sketch verwendet 580 Bytes (0%) des Programmspeicherplatzes
Globale Variablen verwenden 18 Bytes (0%) des dynamischen Speichers

Ausgabe der letzten Fassung:

Der Sketch verwendet 260 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.

Hmmm, in beiden ungetestet-Versionen fehlte oben jeweils #include <util/delay.h> Nachdem ich das eingebunden hatte übersetzte er es anstandslos. Doch irgendein Problem ist in beiden Fassungen: Er startet und blinkt anfangs nett wie eh und je ... nach einigen Umdrehungen hängt sich der 2313 auf und macht nix mehr. Alles via UNO R3 auf einen 2313 mit 17 LEDs übertragen.

Das reizt mich aber ungemein, die Philosophie dahinter zu verstehen. Muß jedoch (leider) erst den Umzug abwarten...

Wenn ich "zeitmerker" auf unsigned long setze ... hängt er sich zwar nicht mehr auf, aber nach einer gewissen Anzahl Umdrehungen fängt alles an wild zu flackern. Da muss ich mal bei Gelegenheit auf die Suche gehen... interessiert mich nämlch ungemein!

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

KA, warum er das bei mir nicht anmäckert

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

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.

#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

// Ich liebe diese Battles "ich kann besser" da lernt man als nicht "C"ler ungemein viel
Danke.
Gruß
DerDani

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.

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

#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!

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

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:

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:

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.


Floetzinger:
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.

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

Wenn nötig, dann sind die Zeiten neu anzuordnen

#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

Ich möchte mal sagen: Eine gute Teamleistung!

und

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:

;***********************************************************
;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ß" :wink:
Beste Grüße
Rudi

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...

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)

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.
:slight_smile:

Ach, so einer bist du.....
Ja, ja, hätte ich mir ja fast denken können.

Aus meiner Vergangenheit: Forth

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

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... :frowning:

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