12bit Integer in Array aus Bytes umsortieren. Optimierung

Hallo Arduino Forum!

Zusammenhang:
Ich arbeite grade an einer Lichtsteuerung mit einem Texas Instruments TLC5940. Um den Chip zum laufen zu bringen habe ich mich der Anleitung “Demystifying the TLC5940” bedient und auch alles zum Laufen bekommen und soweit verstanden.
Bei verschiedenen Tests habe ich nun gesehen, dass mein Code nicht innerhalb der 512us durch läuft, nach denen durch einen Interrupt ein Array aus Bytes an den Chip übertragen wird.

Frage:
Die untenstehende Funktion muss im schlimmsten Fall 16 mal ausgeführt werden und beansprucht jeweils 80us für sich, also 1280us.
Gibt es eine Möglichkeit diese auf unter 512us zu drücken, oder zumindest unterhalb von 1024us? Eigentlich sortiert sie ja nur 12bit eines integers “Helligkeit” in ein Array von bytes “transferByte” ein.

Hier mein Code für die Funktion:

#define AnzahlLED 16

int Helligkeit[AnzahlLED];		//aktuelle Helligkeit der LEDs 0-4095
byte transferByte[AnzahlLED*3/2];//die 16 12-bit Werte sollen zum Übertragen in 24 werte mit 8bit gewandelt werden
byte bitNr,byteNr;				//Hilfsvariable für die Schleifen in den transferByte_aktualisieren Routinen


void transferByte_aktualisieren (int LED){ 
//Funktion zum Übertragen von 12-bit-PWM in bytes, damit diese über SPI übertragen werden können
	time=micros();


//dadurch, dass 12-bit in 8-bit gewandelt werden beginnen die byte abwechselnd bei bit 0 oder 4, abhängig ob LED grade oder ungrade	
	if(bitRead(LED,0)) bitNr=4; 
	else {bitNr=0;}
		

//byteNr festlegen. In welchem Byte müssen die 12-bit angefangen werden zu schreiben (switch-case aus Geschwindigkeitsgründen, keine multiplikation oder Division)
	switch(LED){ 
		case 0: byteNr= 0; break;
		case 1: byteNr= 1; break;
		case 2: byteNr= 3; break;
		case 3: byteNr= 4; break;
		case 4: byteNr= 6; break;
		case 5: byteNr= 7; break;
		case 6: byteNr= 9; break;
		case 7: byteNr= 10; break;
		case 8: byteNr= 12; break;
		case 9: byteNr= 13; break;
		case 10:byteNr= 15; break;
		case 11:byteNr= 16; break;
		case 12:byteNr= 18; break;
		case 13:byteNr= 19; break;
		case 14:byteNr= 21; break;
		case 15:byteNr= 22; break;
	}
	
	for(j=0;j<12;j++)
	{	//alle 12 bit in die bytes schreiben, MSB links höchster Wert zuerst
		bitWrite(transferByte[byteNr],bitNr,bitRead(Helligkeit[LED],j));
		
		bitNr++;
		if (bitNr>7)
		{ //am Ende des Bytes zum Anfang des nächsten Bytes springen
			bitNr=0;
			byteNr++;
		}
	}
	Serial.print(micros()-time);
	Serial.print(" ");
}

Danke schonmal für mögliche Tips ! Gerne auch Arduino fremder Code. Falls nötig würde ich den Code noch weiter kommentieren

Bronko5:
Danke schonmal für mögliche Tips ! Gerne auch Arduino fremder Code. Falls nötig würde ich den Code noch weiter kommentieren

OMG!

Das hier läuft als Code für alle 16 Helligkeitswerte zusammen ungefähr gleichlange wie Dein Code für 1 Helligkeitswert:

void transferByte_aktualisieren() //Funktion zum Übertragen von 12-bit-PWM in bytes, damit diese über SPI übertragen werden können
{
  unsigned long timer=micros();
  byte countH=0;
  byte countB=0;
  do
  {
    transferByte[countB]=highByte(Helligkeit[countH]);
    transferByte[countB+1]=lowByte(Helligkeit[countH])<<8 + highByte(Helligkeit[countH+1]);
    transferByte[countB+2]=lowByte(Helligkeit[countH+1]);
    countH+=2;
    countB+=3;
  } while (countH<AnzahlLED);
  timer=micros()-timer;
  Serial.print("Zeit: ");Serial.print(timer);
  Serial.println();
}

Wenn ich mich nicht schwer täusche…

Edit/Nachtrag: Muss ich da jetzt noch Kommentare anbringen, oder erkennst Du, wie ich in der do/while-Schleife immer die Werte von 2 Integern in 3 Bytes umkopiere?

— Moment mal, so stimmt es noch nicht ganz - stay tuned!

super, da steig ich durch !
Warte natürlich noch auf deine Korrektur und dann werde ich das morgen gleich ausprobieren! Ich denke ich erspar mir alleine schon einiges, indem ich bei deinem Code die 12-bit nicht einzeln einsortieren muss, sondern gleich das ganze überschreibe

Bronko5:
super, da steig ich durch !

Na prima!

Bronko5:
Warte natürlich noch auf deine Korrektur

Hier dann die korrigierte Version:

void transferByte_aktualisieren() //Funktion zum Übertragen von 12-bit-PWM in bytes, damit diese über SPI übertragen werden können
{
  unsigned long timer=micros();
  byte countH=0;
  byte countB=0;
  do
  {
    transferByte[countB]=lowByte(Helligkeit[countH]);
    transferByte[countB+1]=highByte(Helligkeit[countH]) | lowByte(Helligkeit[countH+1]<<4);
    transferByte[countB+2]=lowByte(Helligkeit[countH+1])>>4 | highByte(Helligkeit[countH+1]<<4);
    countH+=2;
    countB+=3;
  } while (countH<AnzahlLED);
  timer=micros()-timer;
  Serial.print("Zeit: ");Serial.print(timer);
  Serial.println();
}

Ich konnte wohl nochmal Faktor 2 rausholen, so dass in der Hälfte der Zeit, die Deine Funktion für einen einzigen Wert benötigt, gleich alle 16 Werte passend umkopiert worden sind. Gesamtbeschleunigung um gut Faktor 32.

D.h. die Funktion konnte nicht nur unter 1024µs und unter 512µs gedrückt werden, sondern sogar unter 40µs!

Das “Serial.print” muß man da natürlich aus der Funktion herausnehmen, wenn sie häufiger laufen soll, sonst bremst der volle Serial-Puffer das Programm aus.

D.h. die Funktion konnte nicht nur unter 1024µs und unter 512µs gedrückt werden, sondern sogar unter 40µs!

Na dann hab ich ja jetzt massig Rechenzeit gewonnen für zusätzliche Features!

Hab den Code getestet und scheint wunderbar zu funktionieren! Danke nochmal. Wenn ich die Tage Zeit habe vergleiche ich noch, wieviel im Gesamtprogramm im Schnitt eingespart wurde.

Schönes Wochenende noch!