Guten Abend! Ich möchte möglichst viele 5 Bit breite Datensätze speichern. Bisher habe ich im RAM ein Byte Array (uint8_t Daten[1024]) angelegt und in jedem Byte einen 5 bit breiten Datensatz gespeichert. Damit verschenke ich 3 * 1024 potentielle Speicherstellen. Wenn ich einen Zeiger hätte, der 5 Bit weit zeigt, wäre das Problem zu lösen. Leider weiß ich nicht, wie ich einen solchen Zeiger erstellen kann. Könnt Ihr helfen? Eine Nebenbedingung ist aber, es darf nicht allzuviel Rechenzeit dauern, weil die 5 bit breiten Datensätze möglichst schnell von einem Port gelesen werden müssen. Es soll ein Logic Analyzer werden. Ich benutze C auf einem Atmega 328P. Danke!
>Wenn ich einen Zeiger hätte, >der 5 Bit weit zeigt, wäre das Problem zu lösen. Sowas gibt es nicht.
ArduStemmi schrieb: > nicht allzuviel Rechenzeit dauern, weil die 5 bit breiten Datensätze > möglichst schnell von einem Port gelesen werden müssen. Vergiss es. Dein RAM ist byteorientiert, alles was davon abweicht, kostet Rechenzeit. Oder andersrum: für 5 von 8 Kombinationen fallen dann gleich 2 der aufwändigen Speicheroperationen zusätzlich zusammen mit den nötigen Schiebe- und Maskieroperationen an...
@ArduStemmi (Gast) >jedem Byte einen 5 bit breiten Datensatz gespeichert. Damit verschenke >ich 3 * 1024 potentielle Speicherstellen. Wenn ich einen Zeiger hätte, >der 5 Bit weit zeigt, wäre das Problem zu lösen. Leider weiß ich nicht, >wie ich einen solchen Zeiger erstellen kann. Könnt Ihr helfen? Du musst dir eine Funktion schreiben, welche deine 5 Bit Datensatz in das 8 Bit Array einfügt. Dazu brauchst du Bitmanipulation, in dem Artikel sind auch Beispiele drin.
1 | void write_5bit(uint8_t data, uint16_t index) { |
2 | // selber ausfüllen
|
3 | }
|
4 | |
5 | uint8_t read_5bit(uint16_t index) { |
6 | uint8_t data; |
7 | // selber ausfüllen
|
8 | return data; |
9 | }
|
> Eine >Nebenbedingung ist aber, es darf nicht allzuviel Rechenzeit dauern, weil >die 5 bit breiten Datensätze möglichst schnell von einem Port gelesen >werden müssen. Es soll ein Logic Analyzer werden. Alles relativ. Welche maximale Samplerate strebst du an? 100kHz? Vielleicht reichen ja auch 4 Bit, dann kannst du einfach 2 Samples in 1 Byte packen.
ArduStemmi schrieb: > Ich möchte möglichst viele 5 Bit breite Datensätze speichern. Bisher > habe ich im RAM ein Byte Array (uint8_t Daten[1024]) angelegt und in > jedem Byte einen 5 bit breiten Datensatz gespeichert. Pack deine Datenbits in 40Bit große Datenblöcke. Dann wird alles gut.
das klingt doch nicht wirklich kompliziert. Dafür würde ich einfach mal in einem C Forum fragen oder Pascal! Ja Pascal :-) klingt jetzt komisch ist aber so, die Leute dort sind meist extrem Hilfreich, und können Dir den richtigen Denkanstoß geben Ich hätte da schon eine Idee, weiß aber auch nicht wie das geschickt umgesetzt wird. Hier wirst Du nur hören, geht nicht, gibts nicht oder kauf Dir ein Buch :-)
Das mit den 4 Bit klingt schonmal gut :-) Ich dachte eher an fortlaufend sammeln und sobald 8 Vollständig sind schreiben oder so Gibt sicher noch etliche andere schnelle Lösungen
bzw 10 bit splitten in 5 und dann warten bis das nächste 8er Paket kommt..jeder der hier jetzt wieder rummaulen will, soll erstmal überlegen, dann versteht er wie ich es meine
Tom Thomsen schrieb: > Pack deine Datenbits in 40Bit große Datenblöcke. Dann wird alles gut. Wobei man bei AVRs mangels effizienter Shifts etwas kreativ vorgehen muss. Also erst 8 4-Bit Blöcke speichert und fehlenden Bits in einem Byte sammelt.
Versuch einmal http://www.c-howto.de/tutorial-strukturierte-datentypen-bitfelder.html mit 8 Member a 5 Bit als packed und schau was der Compiler daraus macht. Besser wird das von Hand auch nicht. Dann kannst du entscheiden: Speicher vs. Geschwindigkeit.
>Dann kannst du entscheiden: Speicher vs. Geschwindigkeit.
Wenn man dann noch einen ATMeg1284 mit 16kB RAM nimmt
fällt die Wshl nicht mehr ganz so schwer. Oder gleich
einen Cortex-M4;) Der wäre mit per Timer getriggertem
DMA sowieso besser geeignet für einen LA.
MSP430 schrieb im Beitrag #4470101: > Besser wird das von Hand auch nicht. Doch. Bei einem AVR wird es schneller, wenn man die 5 Bits in 4+1 aufspaltet und getrennt speichert. Das macht aber kein Compiler von sich aus. Darf er nicht.
:
Bearbeitet durch User
Tom Thomsen schrieb: > Pack deine Datenbits in 40Bit große Datenblöcke. Dann wird alles gut. Das klingt gut, aber wie mache ich 40 bit große Datenblöcke?
ArduStemmi schrieb: > Ja! Aber wie greife ich auf Bit 0, 5, 10, ... 35 zu? Du rechnest dir erst mal mit viel Aufwand die passende Adresse aus und maskierst dann am besten über eine Tabelle das passende Bit heraus. Langer Rede kurzer Sinn: es ist unsinnig. Nimm einen grösseren Controller und/oder lies 8 Bits ein. Nicht umsonst haben übliche LA genau solche Podbreiten...
Ich würde es in 8 bit Variablen lassen. Du kannst über Bitmanipulation 2 5-bit zahlen in 2 8-bit Variablen Speichern Würde dann so ausschauen var1 var2 -------- -------- 12345123 45..... die Zahlen beschreiben die Wertigkeit der 5 bit zahl. Aufwendig wird es wenn du genau den x-ten Wert adressieren möchtest. Hier würde ich Bytenummer = (Anzahl_5-bit_var * 5)/8 // Berechnet dir in welchen Byte deine 5 bit anfangen start nummer = (anzahle_5-bit_var * 5)%8 // Berechnet die stelle des ersten Bytes der 5-bit zahl bsp bytenummer: 1 2 3 byte: 01234567 01234567 01234567 ..... -------- -------- ------- 5-bit: 12345123 45123451 23451234 5..... gesucht x Startadresse der 3. 5bit Wertes (x) 3.var Bytenummer 3*5/8 = 2 start nummer 2*5%8 = 7 Nun musst du nur einen Start wert bestimmen und den Speicher Reservieren Grüße basti195
:
Bearbeitet durch User
Du verschenkst 3072 Bit wenn du 8 Bit Variablen verwendest. Ist ja beeindruckend. Bist du dir vollkommen sicher, dass sich dafür der Thread überhaupt gelohnt hat, geschweige denn das Programmieren und der Performanceverlust durch die Bitoperationen?
Das ist richtig! Einer der wichtigsten Gründe, warum ich mich mit Mikrocontrollern beschäftige, ist das damit verbundene Lernen! In Wirklichkeit brauche ich gar keinen Logicanalyzer! Aber ich wollte mich mal mit der Sache umfassend beschäftigen. Also das komplette Programm: Hardwareentwurf und Basteln, Mikrocontroller programmieren und PC-Programm mit allerlei Schnickschnack schreiben! In diesem Zusammenhang kam mir die Frage, ob man den RAM nicht Bit für Bit beschreiben und lesen kann! Das geht scheinbar nicht ohne aufwendiges Bitgeschiebe (also viel Zeit, naja im Mikrosekundenbreich viel) Wieder was gelernt! Ich werde von fünf auf vier Kanäle wechseln und kann dann 2048 Samples speichern! Ich habe übrigens bei 16 MHz auf 800 kHz samplingrate (entspricht 1,25 Mikrosekunden Samplingtime) gebracht! Passt ganz genau, weil es muss ja ein ganzzahliges Vielfaches von 0,0625 Mikrosekunden sein! Ach ja! Geeicht ist es nicht! Es ist so genau wie der Quartz taktet! Für meine Anwendung ausreichend! Und Spaß macht das!
Hier ein Beispiel, wie Du es implementieren könntest:
1 | #include <assert.h> |
2 | #include <stdint.h> |
3 | #include <stdio.h> |
4 | #include <stdlib.h> |
5 | |
6 | void write_value(uint8_t* data, uint16_t pos, uint8_t value) |
7 | {
|
8 | uint16_t start_byte = pos * 5 / 8; |
9 | uint8_t start_bit = pos * 5 % 8; |
10 | |
11 | uint8_t low_mask = 0x1F << start_bit; |
12 | uint8_t low_value = (value << start_bit) & low_mask; |
13 | data[start_byte] = (data[start_byte] & ~low_mask) | low_value; |
14 | |
15 | if (start_bit > 3) |
16 | {
|
17 | uint8_t high_mask = (0x1F << start_bit) >> 8; |
18 | uint8_t high_value = ((value << start_bit) >> 8) & high_mask; |
19 | data[start_byte + 1] = (data[start_byte + 1] & ~high_mask) | high_value; |
20 | }
|
21 | }
|
22 | |
23 | uint8_t read_value(const uint8_t* data, uint16_t pos) |
24 | {
|
25 | uint16_t start_byte = pos * 5 / 8; |
26 | uint8_t start_bit = pos * 5 % 8; |
27 | |
28 | uint8_t value = (data[start_byte] >> start_bit) & 0x1F; |
29 | if (start_bit > 3) |
30 | {
|
31 | value |= ((data[start_byte + 1] << 8) >> start_bit) & 0x1F; |
32 | }
|
33 | |
34 | return value; |
35 | }
|
36 | |
37 | uint8_t raw_data[1024]; |
38 | uint8_t compressed_data[640]; |
39 | |
40 | int main(void) |
41 | {
|
42 | for (uint16_t i = 0; i < 1024; ++i) |
43 | {
|
44 | uint8_t value = rand() % 32; |
45 | raw_data[i] = value; |
46 | write_value(compressed_data, i, value); |
47 | }
|
48 | |
49 | for (uint16_t i = 0; i < 1024; ++i) |
50 | {
|
51 | assert(read_value(compressed_data, i) == raw_data[i]); |
52 | }
|
53 | }
|
Auf einem AVR dürfte das allerdings ziemlich Rechenzeit kosten, hauptsächlich wegen den Bitshifts um variable Länge.
:
Bearbeitet durch User
Danke für Deine Bemühungen! Du hast natürlich Recht! Für 800 kHz ungeeignet! Aber für Samplingrates kleiner 100 kHz könnte es gehen! Ich werde das mal testen!
Fuer etwas aehnliches: 4 10 bit AD-gewandelte Werte in 5 Bytes zu packen habe ich mir fuer die Midrange PICs (12F675/683, 16F684) mal eine Assemblerroutine programmiert. Die kann ich dann bequem vom Compiler aus aufrufen und brauch das widerliche Geschiebe nicht in C zu formulieren. Die Routine zum "Einpacken" und zum "Auspacken" ist lustigerweise dieselbe. (Die Speicherbereiche auf denen gearbeitet wird, natuerlich nicht.) > Einer der wichtigsten Gründe, warum ich mich mit Mikrocontrollern > beschäftige, ist das damit verbundene Lernen! Dann mach mal. Mehr als ein wenig Zeit und "Brain" braucht es nicht.
Ich habe auch mal ne Beispielimplementierung gemacht, bin aber wohl schon zu spät...
ein anderes Beispiel
1 | struct set_of_eight // 5 bytes |
2 | {
|
3 | uint8_t first :5; |
4 | uint8_t second :5; |
5 | uint8_t third :5; |
6 | uint8_t fourth :5; |
7 | uint8_t fifth :5; |
8 | uint8_t sixth :5; |
9 | uint8_t seventh :5; |
10 | uint8_t eigth :5; |
11 | }__attribute__((packed)); |
Nocheine Beispielimplementierung, diesmal mit 4 bit Blöcken am Anfang und das 5te am ende
Wie schon gesagt wurde, vergiss es, es wird einfach deutlich langsamer sein. Wenn du die 30% extra RAM nicht hast, nimm einen größeren Controller.
Eben. Man sollte nicht den Schinken nach der Wurst werfen.
Falk B. schrieb: > Eben. Man sollte nicht den Schinken nach der Wurst werfen. Das sagen die Hochsprachler immer. Und genau deswegen merkt man von dem Leistungszuwachs der Hardware in den letzten Jahrzehnten auch so gut wie garnix. Alles wurde in immer tieferen Schichten von in Hochsprachen geschriebenen Abstraktionen versenkt... Das klappte in den 80ern, 90ern und auch in den 00er Jahren noch ziemlich gut. Aber seitdem etwa ab 2008 das Moore'sche Gesetz doch ein wenig in's Hinken gekommen ist, merkt man doch sehr deutlich, dass dieser Weg letztlich in den Abgrund führen wird, ja führen muss. Das Lustige ist, dass ausgerechnet eine Sprache, die das Prädikat "Hochsprache" eigentlich garnicht verdient, den Weg in den Abgrund geebnet hat. Und diese Sprache heißt "C". Und sie wird wohl auch bis zum bitteren Ende signifikant beteiligt sein...
Es gibt verschiedene Arten es zu realisieren, und es spricht auch nichts dagegen mehrere parallel zu implementieren. z.B. - Einfach die bits verschwenden, dafür maximale Samplerate - den mode nur 4 Bits zu speichern, die dann in ein Byte zu packen, fehlt ein bit, aber doppelte länge, evt etwas langsammer - 8 Bytes auf einmal einlesen, einlesen b1 und b2, 4+4 bit zusammen packen wegschreiben, das 5 bit in ein anderes byte reinschieben, nach 8 spamples auch das wegschreiben. - Einlesen, gucken ob der Wert identisch mit dem vorherigen, dann einen Counter zählen, bis 3 Bit, Die drei Bit werden dann in den freien Bits abgelegt. - wie vorher nur das die Wiederholung im Extrabyte gespeichert wird oder die 3 Bit noch mitbenutzt, damit kann man je nach Signal lange Aufzeichungsdauer erreichen. Später beim Benutzen sucht man sich den Mode aus, den man braucht hohe Samplingrate oder lange Aufzeichung. Beim überprüfen von seriellen Bussen reicht oft 2 oder 3 Bit. Wichtig ist nur das beim Einlesen jedes Sample den gleichen Abstand zum nächsten hat, da sonst das Timing nachher nicht stimmt. Bei Auswerten hat man Zeit und muss nicht so tricksen. Wenn man eine sehr effektive Einleseroutine haben will, kann man da schon einiges an Zeit reinstecken.
@ArduStemmi Das könnte man doch mit einer Hard-/Softwarekombination lösen. Beim LA willst Du ja nur wissen ob am Messpunkt zum Zeitpunkt x L oder H Pegel anliegt. Du brauchst also einen Puffer in welchen der Pegel entsprechend Deiner gewünschten Samplingrate eingeschrieben wird. Für sowas verwendet man normalerweise ein Schieberegister. Die Daten werden hierbei bei jedem Sampleimpuls in das Schieberegister seriell eingeschrieben und stehen nach 8 Samples an den Ausgängen des Registers. Jetzt kann man das Register auslesen und damit ein 8 Bit breites Datenwort, welches man nun als Byte speichern könnte. Dann werden wieder 8 Samples eingelesen und das Register ausgelesen. Das Auslesen des Registers muß natürlich zwischen 2 Samples passieren. Du brauchst natürlich für jeden Kanal ein Register. Das Einschreiben in die Register wird mit dem gleichen Impuls für alle Register ausgelöst, also für alle Kanäle synchron. So würde ich das realisieren. Nachteil es braucht natürlich zusätzliche Hardware. Vorteil die Anzahl der Kanäle kann sehr groß gewählt werden, allerdings geht das auf Kosten der Samplerate, da ja alle Register nach jedem 8. Sample zwischen 2 Samples gelesen werden müssen. Ist nur mal so als Denkanstoß gedacht und erhebt keinen Anspruch auf Perfektion. Zeno
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.