mikrocontroller.net

Forum: Compiler & IDEs neuen Datentyp (10-bit) zur Speicheroptimierung erstellen


Autor: Tobias K. (tobias-k)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Hallo Community,

ich arbeite gerade an einem Prgramm mit dem ich Melodien über einen uC 
(ATmega8a)abspielen möchte. Das Programm funktioniert einwandfrei und 
die Melodien Werden in zwei 8-bit Array mit einmal dem Ton (Zahlenwerte 
0 - 38) und im anderen der Tondauer (Zahlenwerte 0 - 15).

Auf diese Art und weise verschwende ich jedoch 6 bit von insgesagt 16 
bit, da ich ja nur 6 + 4 bit brauche. Ich könnte also 37,5% Speicher 
einsparen und bei bisher 650 verwendeten Byte ist das nicht zu 
vernachlässigen.

Gibt es eine einfache oder gute Möglichkeit den kompletten Speicher 
auszunutzen?

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tobias K. schrieb:
> Gibt es eine einfache oder gute Möglichkeit den kompletten Speicher
> auszunutzen?

Bei der Tondauer ist es ja einfach. Da du dafür genau 4 Bit brauchst, 
kannst du einfach zwei Stück in ein Byte schreiben, dann hast du schon 4 
von deinen 6 Bit gespart.
Ob es sich jetzt lohnt, die restlichen 2 Bit auch noch einzusparen, 
musst du dir überlegen. Vielleicht kannst du dir ja alternativ noch ein 
nettes Zusatzfeature einfallen lassen, für das du die Bits nutzen kannst 
(z.B. vibrato).

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn der Speicher kanpp ist, nimm einfach den ATmega328.

Autor: Tobias K. (tobias-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Bei der Tondauer ist es ja einfach. Da du dafür genau 4 Bit brauchst,
> kannst du einfach zwei Stück in ein Byte schreiben, dann hast du schon 4
> von deinen 6 Bit gespart.

Danke für den Tipp, die Idee hatte ich auch schon und werde ich 
vermutlic hauch umsetzten. Die restlichen 2 Bit wären da nicht so 
einfach unter zu bringen. Gibt es C ne möglichkeit einen 6 bit Datentyp 
zu definieren, der mir einfach nacheinander en Speicher auffüllt, weil 
mit bitschieberein wird das nicht allzu toll

Autor: Bauform B. (bauformb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn man Ton und Dauer zusammenfasst, kommt man auf 624 unterschiedliche 
Noten. Im wirklichen Leben verwendet eine Melodie aber nur einen kleinen 
Teil davon. Du könntest max. 255 unterschiedliche Noten erlauben und die 
Melodie in einem normalen Byte Array speichern.

Zum Abspielen gehst du einen Umweg über eine Lookup Table, die dir 
Tonhöhe und Tondauer für eine bestimmte Note liefert. Diese Tabelle muss 
nur so viele Einträge haben, wie die Melodie unterschiedliche Noten hat. 
"Alle meine Entchen" für Xylophon kommt mit weniger als 16 aus ;) Da 
könnte man auch noch 2 Noten pro Melodie-Byte speichern.

Der GCC kennt __attribute__((packed)) für ein typedef struct. Damit kann 
man im Prinzip beliebig kurze Datentypen erzeugen. Allerdings wird der 
Code für die Zugriffe auf gepackte Daten u.U. ziemlich groß und langsam.

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Tobias K. schrieb:
> Gibt es C ne möglichkeit einen 6 bit Datentyp zu definieren, der mir
> einfach nacheinander en Speicher auffüllt, weil mit bitschieberein wird
> das nicht allzu toll

Nein, so etwas gibt es nicht, und um Bitschieberei kämst Du so oder so 
nicht herum. Der Compiler würde sie, wenn er Datentypen unterstützen 
würde, die kleiner sind als ein Byte, zwar vor Dir verbergen, aber 
geshiftet werden muss so oder so.

Auch Bitfelder helfen Dir nicht bei Deinem Problem.

Entweder Speicher sparen und wüste Shift-Orgien, oder Speicher 
"verschwenden" mit deutlich weniger Programmieraufwand.

Du könntest natürlich auch überlegen, ob Deine Datenstruktur so, wie sie 
ist, sinnvoll ist. Musst Du für jeden angeschlagenen Ton jedesmal 
einzeln dessen Lautstärke festlegen, oder würde es nicht vielmehr 
genügen, nur bei Lautstärkenänderungen die Lautstärke festzulegen?

Dann könntest Du mit einem Byte pro Operation - Ton anschlagen bzw. 
Lautstärke ändern - auskommen.

Was hier übrigens fehlt, ist die Zeitinformation; wie lange soll ein Ton 
erklingen? Auch das könntest Du in diesem Format unterbringen, wenn Du 
die oberen zwei Bits eines jeden Bytes für die Unterscheidung 
Ton/Lautstärke/Länge vorsiehst, hast Du jeweils sechs Bits (0..63) für 
den jeweiligen Wert zur Verfügung.

Und Du brauchst immer noch nur ein Byte pro Kommando.

Eine Melodie könnte dann so aussehen:

D4 L5 T1 T5 T7 L3 D2 T2 L5 D4 T3 T8 T16 L1 T1 L8 D1 T8 T9

(T für Ton, L für Lautstärke und D für Dauer)

Autor: Amateur (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist kein Problem die Daten zu "packen", aber...
Hast Du so viel Rechenleistung über?

Da fallen bei jedem Datum etliche Zwischenbefehle an.
1. Eigene Adressberechnungen.
2. Schiebebefehle.
3. Maskierungssachen.

Bei Tönen geht es oft relativ zügig zu.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tobias K. schrieb:
> die Melodien Werden in zwei 8-bit Array mit einmal dem Ton (Zahlenwerte
> 0 - 38) und im anderen der Tondauer (Zahlenwerte 0 - 15).

39 x 39 x 39 = 59319. Du kannst also 3 Ton-Werte in 16 Bits packen. Ist 
halt etwas langsamer, da ranzukommen.

: Bearbeitet durch User
Autor: mh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Auch Bitfelder helfen Dir nicht bei Deinem Problem.
Man kann Bitfelder benutzen, um das Problem zu lösen.

Ziel ist es, diesen "10 Bit Datentypen" in ein Array ohne padding zu 
speichern. Es gibt genau 4 Möglichkeiten, wie die 10 Bit in 2 
aufeinander folgenden Bytes angeordnet sein können. Es werden also 4 
Bitfelder benötigt.
struct tb1 {
  unsigned int fB : 4;
  unsigned int sB : 6;
  unsigned int f1 : 6;
};
struct tb2 {
  unsigned int f1 : 2;
  unsigned int fB : 4;
  unsigned int sB : 6;
  unsigned int f2 : 4;
};
struct tb3 {
  unsigned int f1 : 4;
  unsigned int fB : 4;
  unsigned int sB : 6;
  unsigned int f2 : 2;
};
struct tb4 {
  unsigned int f1 : 6;
  unsigned int fB : 4;
  unsigned int sB : 6;
};
void set(int index, uint8_t* data, int8_t fourBit, int8_t sixBit)
{ 
  int const offset = index * 10 / 8;
  switch(index % 4) {
    case 0: {
      struct tb1* p = (struct tb1*)&data[offset];
      p->fB = fourBit;
      p->sB = sixBit;
      break;
    }
    case 1: {
      struct tb2* p = (struct tb2*)&data[offset];
      p->fB = fourBit;
      p->sB = sixBit;
      break;
    }
    case 2: {
      struct tb3* p = (struct tb3*)&data[offset];
      p->fB = fourBit;
      p->sB = sixBit;
      break;
    }
    case 3: {
      struct tb4* p = (struct tb4*)&data[offset];
      p->fB = fourBit;
      p->sB = sixBit;
      break;
    }
  }
}
void get(int index, uint8_t const* data, int8_t* fourBit, int8_t* sixBit)
{
  int const offset = index * 10 / 8;
  switch(index % 4) {
    case 0: {
      struct tb1* p = (struct tb1*)&data[offset];
      *fourBit = p->fB;
      *sixBit = p->sB;
      break;
    }
    case 1: {
      struct tb2* p = (struct tb2*)&data[offset];
      *fourBit = p->fB;
      *sixBit =p->sB;
      break;
    }
    case 2: {
      struct tb3* p = (struct tb3*)&data[offset];
      *fourBit = p->fB;
      *sixBit =p->sB;
      break;
    }
    case 3: {
      struct tb4* p = (struct tb4*)&data[offset];
      *fourBit = p->fB;
      *sixBit =p->sB;
      break;
    }
  }
}

Autor: Tobias K. (tobias-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die ganzen tollen Antworten. Werde jetzt vermutlich einfach 
die Dauern (4bit) immer zu zweit in ein Byte packen, da sich das nicht 
allzu kompliziert realisieren lässt.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Was hier übrigens fehlt, ist die Zeitinformation; wie lange soll ein Ton
> erklingen?

Ich hätte vermutet, dass der Paramter "Tondauer" das angibt. ;-)
Ich glaub, du hast da was verwechselt.

Autor: W.S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tobias K. schrieb:
> Auf diese Art und weise verschwende ich jedoch 6 bit von insgesagt 16
> bit

Dann speichere deine Melodie eben nicht als Array, sondern als 
Bitstream. Einfach nahtlos die jeweils 10 Bit aneinanderkleben und 
fertig. Das Auseinandernehmen geht genauso einfach - jedenfalls bei 
einem 32 Bitter. Kann dein µC wenigstens 16 Bit Operationen ohne 
Umstände?

Also etwa in dem Stil:
unsigned int Akku;
unsigned int tmp;
int bitcount;
unsigned int* P;

if (bitcount < 10)
{ tmp = *P++;
  Akku = Akku | (tmp<<bitcount);
  bitcount+= 10;
}
result = akku & 0x3FF;
bitcount -= 10;

W.S.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:
> Kann dein µC wenigstens 16 Bit Operationen ohne Umstände?

Das wird der

Tobias K. schrieb:
> ATmega8a

eher nicht können. Der kann nicht mal 8 Bit um mehr als 1 Bit am Stück 
schieben. Dein Code wird darauf also besonders ineffizient sein. Spielt 
aber vielleicht an der Stelle gar keine so große Rolle.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Der kann nicht mal 8 Bit um mehr als 1 Bit am Stück schieben.

Er kann auch 4 Bit und 8 Bit am Stück und GCC weiss das. ;-)

Solange die Shiftcount konstant ist, und der Datentyp nicht zu breit, 
gibt GCC sich respektable Mühe, effizienten Code auszuwerfen.

: Bearbeitet durch User
Autor: W.S. (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
A. K. schrieb:
> Solange die Shiftcount konstant ist, und der Datentyp nicht zu breit

.. was beides hier nicht zutrifft.

Fazit: Der Chip ist zu mickrig für diesen Einsatz.

W.S.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
>> Solange die Shiftcount konstant ist, und der Datentyp nicht zu breit
>
> .. was beides hier nicht zutrifft.
> Fazit: Der Chip ist zu mickrig für diesen Einsatz.

Es kommen nur 2 Feldlängen vor. Folglich kann man einen Bitstream 
implementieren, ohne dynamische Shifts verwenden zu müssen.

GCCs Optimierung der Shifts für AVR betrifft 16-Bit Daten. Das ist 
hierfür breit genug.

Ein besserer µC ist dafür freilich von Vorteil. Wenn der Dividieren 
kann, dann geht auch die erwähnte und sparsamste Radix-39 Codierung 
recht flott.

: Bearbeitet durch User
Autor: Rolf Magnus (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:
> A. K. schrieb:
>> Solange die Shiftcount konstant ist, und der Datentyp nicht zu breit
>
> .. was beides hier nicht zutrifft.
>
> Fazit: Der Chip ist zu mickrig für diesen Einsatz.

Oder das Programm ist nicht ausreichend für den Chip optimiert. Ob man 
jetzt gleich auf eine komplett andere Architektur umsteigen muss, nur 
weil die Trivial-Implementation von ein paar Bit-Schieberein sonst nicht 
effizient wäre?

Autor: Karl K. (karl2go)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Fazit: Der Chip ist zu mickrig für diesen Einsatz.

Klarer Full für einen 10-Bitter. Der kann das.

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tobias K. schrieb:
> Ich könnte also 37,5% Speicher einsparen und bei
> bisher 650 verwendeten Byte ist das nicht zu vernachlässigen.

Alternativ könntest du auch die Melodie ins Flash legen (mit __flash 
oder PROGMEM). Damit ist deine Melodie zwar nicht kleiner, aber du 
sparst RAM. Im Gegensatz zum Flash geizen die Chips mit RAM. :-)

Autor: Sempfdazugeber (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
Ich musste auch mal 4 x 10 bit AD-Werte etwas umpacken.
(In 5 Bytes a 8 Bit.)

Über C habe ich mir gar nicht erst den Kopf zerbrochen,
sondern gleich den Assembler angeworfen.

Herausgekommen ist eine lustige Schiebeorgie, die bemerkenswerterweise
beim Aufruf sowohl die Daten packen als auch entpacken kann.
Wohlgemerkt mit der selben Routine.
Wie nicht anders zu erwarten reichen genau 42 Zeilen Assembler dafür.


Das soll in C erstmal einer nachmachen...

Autor: S. R. (svenska)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Sempfdazugeber schrieb:
> Wohlgemerkt mit der selben Routine.

Du hättest die Routine ja netterweise dazulegen können.
So bist du nur ein Schwafler. Tacuisses, philosophus mansisses.

Autor: Sempfdazugeber (Gast)
Datum:

Bewertung
-4 lesenswert
nicht lesenswert
> Du hättest die Routine ja netterweise dazulegen können.

Die war fuer einen Kleinen PIC und haette dem TO also so nuex genuetzt.

Der TO soll sich gefaelligst selber mit Assembler beschaeftigen.
Fuer Copy & Pasta spende ich hier nicht!

Autor: S. R. (svenska)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
>> Tacuisses, philosophus mansisses.
> Fuer Copy & Pasta spende ich hier nicht!

Danke für den Beweis. :-D

Autor: Sempfdazugeber (Gast)
Datum:

Bewertung
-4 lesenswert
nicht lesenswert
> Danke für den Beweis.

Nuex zu danken. :-=

Autor: Sempfdazugeber (Gast)
Datum:

Bewertung
-7 lesenswert
nicht lesenswert
P.S.:

> ein Schwafler

Schwafler sind die, die ihre Postings mit:

> Hallo Community,

beginnen und selber nuex zu 100 % zustande bringen.
Wenn nur C im Kopf ist, kann auch nur C rauskommen.

Eine Datenwortbreite von 10 bit legt auf einem 8 bit Controller
ohnehin eine schnelle Assemblerroutine nahe.

Und wenn da bei ihm da nuex ist, muss er es halt lernen.
Nur der harte Weg ist der richtige.


Lächeln und Winken!

Autor: Da D. (dieter)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Moby, bist du es?

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sempfdazugeber schrieb:
> Wie nicht anders zu erwarten reichen genau 42 Zeilen Assembler dafür.
>
> Das soll in C erstmal einer nachmachen...

Was? Dass man so viele Zeilen dafür braucht?

Autor: 2⁵ (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Sempfdazugeber schrieb:
> Ich musste auch mal 4 x 10 bit AD-Werte etwas umpacken.
> (In 5 Bytes a 8 Bit.)

Wie waren denn Ein- und Ausgabendaten kodiert? Z.B. die 4x 10bit als 4x 
16 Bit Ints und die 5 Byte? 4x8 Bit und dann ein Byte mit den restlichen 
4x2 Bit? Oder als Bit-Stream?

> Herausgekommen ist eine lustige Schiebeorgie, die bemerkenswerterweise
> beim Aufruf sowohl die Daten packen als auch entpacken kann.
> Wohlgemerkt mit der selben Routine.

Ohne Fallunterscheidung? Dann können die Eingabedaten wohl nicht als 
4x16Bit kodiert gewesen sein...

> Wie nicht anders zu erwarten reichen genau 42 Zeilen Assembler dafür.

In C werden es wohl deutlich unter 42 Zeilen sein. Wäre jetzt nur 
interessant, wie viel Zeilen Assemblercode der Compiler daraus macht.

Autor: Sempfdazugeber (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
> Was? Dass man so viele Zeilen dafür braucht?

Ja, das Loop Unrolling ist schuld daran!
Aber, es soll ja schnell gehn.
Aber es sind gut investierte 42 Worte im Flash.

> Rolf M.

Bist du der von der beirischen Trinkerrunde?

Autor: Sempfdazugeber (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
> die 4x 10bit als 4x 16 Bit Ints
[x]

> und die 5 Byte? 4x8 Bit und dann ein Byte mit den restlichen
> 4x2 Bit? Oder als Bit-Stream?
Wie speichert man wohl 5 Byte...

(Tipp: hintereinander...)

Es ging bei mir auch um Wandlerdaten von einem AD.
Und kein schnoedes Tongepiepse.


> In C werden es wohl deutlich unter 42 Zeilen sein. Wäre jetzt nur
> interessant, wie viel Zeilen Assemblercode der Compiler daraus macht.

Nicht schwafeln sondern machen!

Autor: Sempfdazugeber (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
>> sowohl die Daten packen als auch entpacken kann.
>> Wohlgemerkt mit der selben Routine.

> Ohne Fallunterscheidung? Dann können die Eingabedaten wohl nicht als
> 4x16Bit kodiert gewesen sein...

Unsigned ints waren es.
Das Resultat waren 5 unsigned chars.
Beim Auspacken natuerlich andersrum.

Auf eine C-Routine die das ebenfalls ohne Fallunterscheidung
schafft, waere ich ja mal gespannt :-).

Und ja: Es gibt keine Fallunterscheidung zwischen den
Operationen Packen und Entpacken in der Assemblerroutine.

Was in den 4 uints steht, landet in den 5 uchars und vice versa.
In einem Arbeitsgang.


> Moby, bist du es?
[ ]

Autor: W.S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> GCCs Optimierung der Shifts für AVR betrifft 16-Bit Daten. Das ist
> hierfür breit genug.
>
> Ein besserer µC ist dafür freilich von Vorteil. Wenn der Dividieren
> kann, dann geht auch die erwähnte und sparsamste Radix-39 Codierung
> recht flott.

OK, dann geht die Schieberei ja doch ausreichend gut. Aber vom 
Dividieren würde ich doch eher absehen.

W.S.

Autor: W.S. (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Sempfdazugeber schrieb:
> Ich musste auch mal 4 x 10 bit AD-Werte etwas umpacken.
> (In 5 Bytes a 8 Bit.)

jaja.

So, nachdem hier viel Senf geflossen ist, kommt zum Abschluß noch ne 
Portion Mayo:
; Protokoll 3: vierkanalig, 9 Bit
; Kanäle 0, 2, 3, 4, hier A,B,C,D genannt
; Byte-Block-Aufbau:
;    Seb_A    Seb_B    Seb_C    Seb_D    Seb_E    Seb_F
; 76543210 76543210 76543210 76543210 76543210 76543210   Bitnummern
; 0001000A 1AAAAAAA 1ABBBBBB 1BBBCCCC 1CCCCCDD 1DDDDDDD   Kanäle

prot_3:  MOVLW  10h
         MOVWF  Seb_A
         MOVF   Avalue0+1,W   ; A
         MOVWF  Seb_B
         BTFSC  Seb_B,7
         BSF    Seb_A,0
         BSF    Seb_B,7
         MOVF   Avalue2+1,W   ; B
         MOVWF  Seb_C
         MOVF   Avalue2,W
         MOVWF  Seb_D
         RLF    Avalue0,F     ; 9. Bit-->Carry
         RRF    Seb_C,F       ; als MSB in Seb_C
         RRF    Seb_D,F
         BSF    Carry
         RRF    Seb_C,F       ; Seb_C ist jetzt fertig
         RRF    Seb_D,F
         BSF    Carry
         RRF    Seb_D,F       ; B ist jetzt untergebracht
         MOVLW  B'11110000'
         ANDWF  Seb_D,F
         SWAPF  Avalue3+1,W
         ANDLW  B'00001111'
         IORWF  Seb_D,F       ; hi(C) ist jetzt untergebracht

         SWAPF  Avalue3+1,W
         ANDLW  B'11110000'
         MOVWF  Seb_E
         BTFSC  Avalue3,7
         BSF    Seb_E,3
         BSF    Carry
         RRF    Seb_E,F      ; C ist jetzt komplett untergebracht

         MOVF   Avalue4+1,W
         MOVWF  Seb_F
         RLF    Avalue4,W
         RLF    Seb_F,F
         SKIP   NC
         BSF    Seb_E,1
         BTFSC  Seb_F,7
         BSF    Seb_E,0
         BSF    Seb_F,7

Das war von mir, ist rund 10 Jahre alt und stammt aus meiner eigenen 
Firmware für den FA-NWT (Funkamateur-Wobbler). Und es sind dort 9 Bit 
pro Meßwert und 7 zu benutzende Bits in den zu sendenden Bytes.

Quasi Radio Eriwan.

Klar: In Hochsprache notiert sich sowas viel einfacher, aber was da als 
MC herauskommt, ist gerade in solchen Fällen gruseliger. So ist das 
eben, wenn man was auf nem 8 Bitter durchziehen muß.

W.S.

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sempfdazugeber schrieb:
> Nicht schwafeln sondern machen!

Sagt der Schwafler.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Sempfdazugeber schrieb:
>> Was? Dass man so viele Zeilen dafür braucht?
>
> Ja, das Loop Unrolling ist schuld daran!

Ja, das ist eben der Nachteil, wenn man das in Assembler macht: Da muss 
man sich um sowas von Hand kümmern.

>> Rolf M.
>
> Bist du der von der beirischen Trinkerrunde?

?

Autor: Yalu X. (yalu) (Moderator)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Warum ist Geschwindigkeit hier überhaupt ein Thema?

Selbst die kürzesten Töne werden mindestens 10 ms lang sein, sonst würde
man sie gar nicht mehr als solche wahrnehmen. Nachdem der ATmega die
Periodendauer eines Tons in ein entsprechendes Timer-Register
geschrieben hat, hat er somit alle Zeit der Welt, um die Daten für den
nächsten Ton vorzubereiten.

Sempfdazugeber schrieb:
> Ich musste auch mal 4 x 10 bit AD-Werte etwas umpacken.
> (In 5 Bytes a 8 Bit.)
>
> Über C habe ich mir gar nicht erst den Kopf zerbrochen,
> sondern gleich den Assembler angeworfen.
>
> Herausgekommen ist eine lustige Schiebeorgie, die bemerkenswerterweise
> beim Aufruf sowohl die Daten packen als auch entpacken kann.
> Wohlgemerkt mit der selben Routine.
> Wie nicht anders zu erwarten reichen genau 42 Zeilen Assembler dafür.

Hast du den Code mit NOPs aufgefüllt, um auf die 42 zu kommen? ;-)

Da der TE keine 10-Bit-Zahlen braucht, sondern jeweils eine 4Bit- und
eine 6-Bit-Zahl, ist noch jede Menge zusätzlicher Bit-Operationen nötig,
um am Ende jeden der insgesamt 8 Zahlenwerte in einem eigenen Register
stehen zu haben.

Der Assemblercode im Anhang nimmt 5 Bytes mit den gepackten Daten für 4
Töne entgegen und liefert in 20 Taktzyklen die 4 Notenwerte und die 4
Dauern in 8 Bytes zurück. Das dabei verwendete Packschema ist im
Kommentar ganz am Anfang beschrieben. Ich habe den Code nicht getestet,
hoffentlich enthält er trotzdem keine Fehler.

: Bearbeitet durch Moderator
Autor: PittyJ (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hatte gerade nach Flash-Bausteinen gesucht.
256 KBytes SPI Flash kosten 82 Cent. Für diesen Preis würde ich mir die 
Bitpackerei ersparen.

Autor: Joerg W. (joergwolfram)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke, das geht auch problemlos mit 8 Bit je Note. Anstelle einer 
Tondauer würde ich den Notenwert nehmen:

1/1, 3/4, 1/2, 3/8, 1/4, 3/16, 1/8, 1/16

sind 8 Werte, für die man 3 Bits benötigt.

Es bleiben 5 Bits für die Note (Tonhöhe) übrig. Das ergibt 32 Tonhöhen, 
was gegenüber den 38 geforderten zuwenig ist. Die meisten Melodien 
spielen sich zwischen 1-2 Oktaven ab, also könnte man 30 Tonhöhen 
verwenden und die Vorletzte als Pause und die Letzte für 8 Steuercodes 
nutzen:

- +1 Oktave
- -1 Oktave
- Beginn Wiederholung 1-fach
- Beginn Wiederholung 2-fach
- Beginn Wiederholung 3-fach
- Beginn Wiederholung 4-fach
- Ende Wiederholung
- Ende vom Lied

Ebenso könnte man noch eine weitere Note "abzwacken" und damit 8 
Laustärkestufen realisieren. Der AVR kann die Steuercodes schnell genug 
auswerten, so dass die Verzögerung eher im einstelligen 
Mikrosekunden-Bereich liegt und damit unhörbar ist.

Jörg

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Einfach nahtlos die jeweils 10 Bit aneinanderkleben und
> fertig. Das Auseinandernehmen geht genauso einfach

Man braucht ja nur 4 Fälle zu unterscheiden, dann ist man wieder an 
einer Bytegrenze.

Autor: W.S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Man braucht ja nur 4 Fälle zu unterscheiden

Ich vermute mal, daß das Ausführen dieser Unterscheidungen genauso viel 
oder mehr an Rechenzeit und Code kostet wie die variable Verschiebung.

W.S.

Autor: A. K. (prx)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:
> Ich vermute mal, daß das Ausführen dieser Unterscheidungen genauso viel
> oder mehr an Rechenzeit und Code kostet wie die variable Verschiebung.

Bei AVRs kostet ein ausgeführter Sprung nur einen Takt mehr als ein 
nicht ausgeführter, dynamische 16-Bit Shifts hingegen benötigen 5 Takte 
pro Bit.

Bei 16/32-Bittern mit Barrelshifter ist eine Fallunterscheidung jedoch 
ungünstig und mit tiefer Pipeline und Sprungvorhersage wirds erst recht 
kompliziert.

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.