Einzelnes Bit im RAM schreiben oder lesen

Gast #4470055
Lesenswert?

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!
Moderator (Firma: Titel) Persönliche Seite #4470069
Lesenswert?

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...
#4470072
Lesenswert?

@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.
Gast #4470078
Lesenswert?

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.
Gast #4470079
Lesenswert?

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 
:-)
Gast #4470110
Lesenswert?

>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.
Moderator (Firma: Titel) Persönliche Seite #4470199
Lesenswert?

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...
Persönliche Seite #4470206
Lesenswert?

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
Gast #4470221
Lesenswert?

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?
Gast #4470250
Lesenswert?

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!
#4470261
Lesenswert?

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.
Gast #4470312
Lesenswert?

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.
Gast #4470415
Lesenswert?

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));
Gast #4471547
Lesenswert?

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...
Gast #4471623
Lesenswert?

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.
Gast #4471867
Lesenswert?

@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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren