Flash Speicherung

Funktionsweise
Jedes Bit wird in eine Speicherzelle (FET) gespeichert. Im Gegensatz zum FPGA ist diese Speicherzelle nicht flüchtig.

Ansteuerung
Wie bei RAMs: über eine Matrixordnung. Es wird Zeilenweise oder in ganzen Sektoren gespeichert. Jede Zeile entspricht einem Word einer bestimmten Bit-Länge.
Man spricht FLASH Speicher selten direkt an, sondern nutzt Schnittstellen.

Im Embedded Bereich
Brauchen einen externen Speicherplatz zum Speichern von Daten oder zum Booten des Betriebssystems und der Applikationen. Flash-Speicher werden ROMs vorgezogen, da man diese auswechseln kann. Dadurch ist ein Update der Firmware möglich, was beim ROM nicht der Fall ist. Eine SD-Karte (ebd. ein Flash Speicher) ist eine Alternative zu Flash-ICs.

Spezialitäten
– sind langsam
– können auch als HD-Ersatz genommen werde
– EEPROMs sind die bekanntesten Flash Speicher
– Jeder USB-Stick hat einen Flash-Speicher und einen Microkontroller

SD Karten

Als externer Speicherplatz kann eine SD (Secure Digital Memory) Karte genommen werden. Es gibt die Mini- und Micro-Ausführung.

Spezialitäten
– Ihr Speicherprinzip ist die Flash-Speicherung.
– Speicherbereich kann partitioniert werden:
In einem Teil liegt ein System-Image, im anderen Teil das File Sytem
– besitzt einen internen Controller
– 9 Kommunikationspins
– SD-Karten mit integriertem WLAN oder GPS
– SD-Karte mit USB-Stecker Typ A (normaler Stecker) zum Anschliessen

In Enbedded Systemen
Das Betriebssystem und die Applikatins Software wird meist in Flash Speichern abgelegt und von dort gebootet. Man kann aber auch eine genug grosse SD-Karte zum Booten des Systems nehmen.

Kommunikation
Die Kommunikation basiert auf dem SPI-Prinzip.
SD_Pins– Initialisierungssequenz:
Schützt vor unberechtigtem Zugriff auf die Daten
– Pin 1: Kartenerkennung (Dateinleitung 3)
– Pin 2: Kommandos (Befehl/Antwort)
– Pin 3/6: GND
– Pin 4: VCC
– Pin 5: CLK
– Pin 7/8/9: Data (Datenleitung 0, 1, 2)

wx Hex Editor

Dieser Hex-Editor zeichnet sich über mächtige Speicheroptionen aus:

  • Die Hexwerte können mit Speicheroffset gespeichert werden
  • Hexwerte können mit ASCII-Interpretation gespeichert werden
  • Hexwerte können als C-Array mit einer wählbaren Datengrösse (int8_t, int16_t, int32_t, ..) gespeichert werden

Dies erleichtert die Weiterverarbeitung der eingelesenen Daten.


Debuggen von Speicher

Der Inhalt des Speichers (z.B.) eines Arrays muss in ein File kopiert werden. Das File wird eingelesen.

wxHexEditor

Im Menu können unter VIEW unterschiedliche Fenster (Pannel genannt) aktiviert werden.

Linke Fenster
Zeigt die selektierten Daten in unterschiedlichen Formaten an (Pannel Dateninterpreter) und in der Mitte das Infopannel.

Hauptfenster oben

Mehrere Files  können parallel angezeigt werden.

Hauptfenster unten

Ist die Ascii Interpretation des Inhalts. Das Pannel wird TextControl genannt.

VHDL speicher, buffer, register

Inputdaten müssen teilweise abgelegt werden. Wie wird dies in VHDL umgesetzt?

  • man kann per IP RAM anschliessen und dort per Adresse die Daten hineinschreiben.
  • Das VHDL-eigene Speicherprinzip sind jedoch die Flip- Flops. Alle Daten die gespeichert werden sollen, werden in (Vektoren) von Flip-Flops abgelegtff_speicher
    Signale führen Wert in und aus dem Flip-Flop

    -- input
    signal s_next_value: std_logic_vector(7 downto 0);
    -- gespeichert
    signal s_current_value: std_logic_vector(7downto0);
-- input in ff-signal ablegen
s_next_value <= input;

-- input speichern
input_register: process (all)
begin
.    if (reset = '1') then
.        s_current_value <= (others => '0');
.    elsif (clk'event) and (clk = '1') then
.        -- ausgang ff  erhält  eingang ff
.        s_current_value <= s_next_value; 
.  end if; 
end process;

 

speicher_mit_enable

Normalerweise wird das Inputsignal nicht asynchron an den Eingang des Flip-Flops gelegt. Oft entscheidet ein enable_signal, wann die Daten vor den Eingang gelegt werden sollen. (Dies geschieht mit einem Multiplexer.)

-- input speichern
input_register: process (all)
begin
.    if (reset = '1') then
.        s_current_value <= (others => '0');
.    elsif (clk'event) and (clk = '1') then
.        -- ausgang ff  erhält  eingang ff
.        s_current_value <= s_next_value; 

.        if (s_enable = '1') then
           s_next_value <= input;
        else
           s_nex_value <= s_current_value;
        end if;
.  end if; 
end process;

Dynamische Speicherzuweisung C: „Allocation“

Nicht dynamisch
Definiert man eine Variable, Konstante oder ein Array mit fixer Länge char array[5] , so ist die Länge des Speicherplatzes klar und die Speicherzuweisung ist nicht dynamisch.
Nicht dynamische Speicherzuweisungen werden im STACK abgelegt.

Grund für dynamisch
Die Grösse des Arrays ändert sich während der Verarbeitung. Man kann das Array nicht auf eine fixe Grösse initialisieren.
Eine dynmische Speicherzuweisung nennt man Allozierung. Die Daten werden im HEAP abgelegt.

Vorgehen
1. Speicherplatz reservieren
Dies geschieht über die Funktion malloc().  Es ist zwingend, dass man die Anzahl Bytes nennt.  int *buffer1 = malloc(n * sizeof(data));.  N bezeichnet die Anzahl daten, data bezeichnet die Grösse eines Datenpackets.
Die Funktion sizeof( )  gibt immer die Anzahl Bytes der Variable zurück.
2. Auf dynamische Daten zugreiffen
Die Funktion malloc() gibt als Returnwert die Adresse zurück. Auf dynamische Daten kann nur über den Pointer zugegriffen werden. Ein direkter Zugriff über den Variablennamen auf die Daten ist nicht möglich. data1 = buffer1[0];
3. Speicherplatz freigebe
free(buffer1); Wird Speicherplatz nicht mehr freigegeben, so entsteht ein Memory Leak. Ohne free() verkleinert sich die Speicherkapazität des RAMs.

Speicherorte: Die „Segmente“ im RAM

Grundstruktur Datenablage
Ein ausführbares Programm (*.exe) teilt seine Daten in vier Segmente ein: *.code, *.data, *, heap und Stack.

code_data_heap code_data_heap_chinese

Codesegment
Liegt bei der tiefsten Adresse. Hier liegt der Maschinencode. Häufig liegen hier auch die Konstanten. Das Codesegment kann mit einem Schreibschutz versehen werden, also nur gelesen werden.

Datensegment
Hier liegen die initialisierten globalen Variablen sowie wenn eine lokale Variable als static definiert wurde. Sind Variablen nicht initialisiert, so liegen sie im BSS Segment.

Heap
Enthält nur dynamische Variablen, die mit malloc() zur Laufzeit generiert und wieder gelöscht werden.

Stack
Legt alle sich ändernden Daten zur Laufzeit ab und holt sie permanent wieder. Ständiges Wechseln der Daten. Deshalb braucht es einen Stack Pointer, der jeweils die aktuelle Speicherstelle weiss.
Der Stack liegt an der höchsten Adresse.
Im Stack liegen alle lokalen Variablen.

 

 

VHDL Code von Speicher starten

Datei.pof
Der Speicher braucht ein bistream als Synthese.  Deshalb muss neben der *.sof-Datei auch eine *.pof-Datei erzeugt werden.

Grundeinstellung ändern
Bei der Synthese, soll gleich auch die *.pof-Datei generiert werden.
Assignments/Device     Taste: Device and Pin Options    /Configuration
Auswählen von:           Active Serial
Hacken bei:                     v   Use configuration device:       Auto (oder auswählen)
.                                            v   Generate compressed bitstream


Konvertieren *.sof zu *.pof

File/Convert Programming Files…/    Folgende EinstellungeProgramming file type:        Programmer Object File (.pof)
Configuration device:           (siehe Namen auf Board)
File name:                                  <pfad>/name.pof
Input files to convert:            – Anklicken SOF Data
.                                                      – Add File..
.                                                      – outputfile/datei.sof  aus Ordner Synthese
Generate

Programmer Einstellungen
Mode:                                          Active Serial Programming
File:                                              *.sof löschen
.                                                      *.pof adden
Device:                                          <name des Speichers> ! nicht des FPGA

Auf Board
!!!!! Schalter auf Programm !!! nur so entsteht Verbindung zu Speicher.

Speicher Timing Zeitverlauf

Das Timing (einhalten der Setup- und Hold-Zeit) ist eine Fehlerquelle für ungültige Daten.

Bsp. eines Schreibe-Zyklus
Ein neuer Zylkus beginnt bei der fallenden Flanke
   Da Daten leicht verzögert ankommen, beginnt der neue Zyklus
nach der fallenden Flanke. Die Verzögerung darf nicht so gross sein,
dass die setup Zeit verletzt wird.
(t_setup = Zeit, in der Daten vor CLK anliegen müssen)
Ausführen des Befehls bei steigender Flanke
Hier ist es ein Schreibbefehl. Auch der Lesebefehl wird bei steigender Flanke
ausgeführt.
Der Befehl wird leicht verzögert ausgeführt.
Um den Befehl recht auszuführen, darf die Hold Zeit nicht verletzt werden.
(t_hold = Zeit, in der die Daten nach dem CLK noch anliegen müssen)

Bereits kurz nach der ausführenden Flanke sind die Daten wieder Weg und der neue Zyklus beginnt.

Timing_Speicher

FPGA
Speicher haben intern einen Takt. Dadurch entfällt das Timingproblem.

Speicherzeilen und Speichertiefe

Speicherbreite
Die Speicherbreit ist oft identisch mit der Busbreite.
Ist sie dies nicht, muss mit Byte-enable das Ansprechen geregelt werden.
Word
= Breite einer Bit-Zeile (32-Bit, 16-Bit, ..)
= Speicherbreite
.               1 Word hat m Bits.
Bit      = Einzelne Speicherzelle.

Speichertiefe
Die Tiefe hängt von der Anzahl Adressleitungen ab.
Führen zum Speicher n Adressleitunge,  so ist der Speicher
2^n  (Word-)Zeilen tief.
Bsp.         2 Adressleitungen = 4 Speicherzeilen (Words) auslesbar

Speichergrösse
Word-Grösse x Anzahl Zeilen = m x 2^n
Bsp. Word = 32 Bit,  16 Adressleitungen
Speichergrösse:  4 x 2^16 =
4 x 2^3 x 2^3 x 2^10 = 4 x 8 x 8 x 1’000 =
32 x 8’000 = 256 kBytes

Organisation_Speicherzelle

 

 

 

 

Byte enable

Grund
Entspricht die Speicherbreite nicht der Breite des Buses, so müssen die Bytes des Busses über enable aufgeteilt werden können.
Mit enable sagt man, ob man den ersten oder zweiten Teil der Busbreite will.

Bsp
32-Bit-System für einen Baustein nur 16 Bit (z.B. für ein IO-Port oder ein Speicherbaustein).
ByteEnable

Byte_enable_0:
Bezieht sich auf die höheren Bits des Datan-Signals im Bus:   Data[16] – Data[31]
Byte_enable_1:
Bezieht sich auf die tieferen Bits der aktuellen Busdaten:     Data[0] – Data[15].

Setzt man Byte_enable_0, so werden nur die 15 oberen Bits des akutellen Bussiganals geschrieben oder gelesen.

Aktuelle Busdaten und Speichervorgang
Hier liegen in einem Speicher bereits Daten an den Adressen a0, a1 und a2.
Auf dem Bus liegt ein aktuelles Datenpaket (data) von 32 Bit.
Teile (oder auch das ganze) Datenpaket sollen auf die belegten Speicheradressen geschrieben werden.

Byte_Enable_timing

Da auch der Befehl Lesen aktiviert ist, wird „zeitgleich“ von der bestehenden Adresse auch der Wert an den Datenausgang (q) gelegt.