Speicheroperationen für Fortgeschrittene

In den vorigen Abschnitten wurde gezeigt, wie die Dimensionen des Flash-Speichers bestimmt und Daten in den Speicher geschrieben und wieder ausgelesen werden können. In diesem Abschnitt soll nun vermittelt werden, wie man mit diesen Kenntnissen derart auf den Speicher zugreift, dass zu schreibende Daten an einer bestimmten Stelle im Speicher stehen und beim Hineinschreiben keine Daten aus dem Speicher verloren gehen. Dieser Abschnitt bezieht sich speziell auf die Klassejcontrol.io.Flash.

Die generelle Problematik: In den bisherigen Beispielprogrammen dieses Kapitels wurden die Daten (der String "Welcome to JControl!!!") an den Anfang des 0ten Sektors in Bank 0 geschrieben. Wenn der Beispiel-String nun nicht im 0ten Byte beginnen soll, sondern z.B. im 5ten, so kann dies der write-Methode der Klasse jcontrol.io.Flash nicht direkt mitgeteilt werden. Alle Bytes die geschrieben werden sollen, werden an den Anfang des Zielsektors geschrieben (der Parameter startindex bezieht sich nur auf das übergebene Byte-Array "data"). Die zu schreibenden Bytes müssen also schon im Byte-Array an der Stelle stehen, an der sie später im Zielsektor erscheinen sollen. Soll also der Beispiel-String im 5ten Byte beginnen, so muss dessen erstes Byte auch im Byte-Array an 5ter Stelle stehen und data ab (Start-)Index 0 in den Speicher übertragen werden. Dabei stellt sich die Frage: "Was ist mit den ersten 5 Bytes des Byte-Arrays zu tun?" Diese Bytes werden ja ebenfalls in den Speicher übertragen und überschreiben die dort bereits vorhandenen Bytes, was nicht gerade wünschenswert ist.

Die zusätzliche Problematik der Hardware: Hierbei handelt es sich um die Art des Speicherzugriffs auf Hardware-Ebene. Bei Schreibzugriffen auf den Flash-Speicher wird jedes Mal der komplette Zielsektor geschrieben. Das bedeutet anschaulich, dass damit auch die Bytes des Speichers gelöscht werden, die sich hinter dem letzten geschriebenen Byte im Sektor befinden. Diese Bytes werden automatisch mit dem Wert 255 (0xFFh, bzw 11111111b) gefüllt.

Die Lösung: Für einen verlustfreien Schreibzugriff auf den Flash-Speicher müssen folgende Aktionen ausgeführt werden:

  •  Zielsektor auslesen und in einem Puffer ablegen
  •  Zu schreibende Daten in die Daten des Puffers einfügen
  •  Den veränderten Puffer wieder in den Zielsektor schreiben

Um die Auswirkungen dieser Vorgehensweise zu verdeutlichen, schreibt das folgende Beispielprogramm (Listing 4) zuerst den String "012345678901234567890123456789" in den Flash-Speicher. Das soll zeigen, dass die vorhandenen Bytes im Zielsektor nicht verändert werden. Außerdem werden am Schluss des Programms 10 Bytes mehr aus dem Speicher gelesen, als hineingeschrieben wurden. Das Programm ist außerdem für die Standardausführung der JControl-Module ausgelegt und benutzt daher eine Puffergröße von 128 Bytes (=Sektorgröße des Standard-Speichers).

1    /**
2     * Java file created by JControl/IDE
3     *
4     * @author RSt
5     * @date 04.11.04 17:30
6     *
7     */
8    import java.io.IOException;
9    import jcontrol.comm.RS232;
10    import jcontrol.io.Flash;
11    
12    public class FlashBufferedWriteRead {
13    
14      static Flash myFlash;
15      static RS232 myRS232;
16    
17        public FlashBufferedWriteRead() {
18          try{
19            //Initiate Flash object with context to bank 0:
20          myFlash = new Flash(0);
21          //Initiate RS232 object for printing messages:
22          myRS232 = new RS232();//default = 19200 baud
23        }catch(IOException e){
24        }
25        }
26    
27        public static void main(String[] args) {
28            new FlashBufferedWriteRead();
29            String firstWrite = "012345678901234567890123456789";//30 characters
30            byte[] firstData = firstWrite.getBytes();
31            String writeThis = "Welcome to JControl!!!";//String to write
32            //Assumed usage of standard JControl/SmartDisplay or -/Sticker!!!
33            byte[] buffer = new byte[128];//Buffer for existing sector content
34            byte[] data = writeThis.getBytes();//Bytes representing the String
35            byte[] read = new byte[40];//For controlling written data
36            int targetPos = 5;//Position of the first byte of 'data' in memory
37            try{
38              //write firstWrite into sector 0:
39              myFlash.write(firstData, 0, firstData.length, 0);
40              //read complete sector 0:
41              myFlash.read(buffer, 0, buffer.length, 0);
42              //integrate data into buffer:
43              for(int i=0 ; i < data.length ; i++){
44                buffer[i+targetPos] = data[i];
45              }
46              //write bytes into memory (complete sector):
47              myFlash.write(buffer, 0, buffer.length, 0);
48              //read Flash content:
49              myFlash.read(read, 0, read.length, 0);
50              //write read data to serial port:
51              myRS232.println(new String(read));
52            }catch(IOException e){
53        }
54        for(;;);//Stops execution of this program.
55        }
56    }
Listing 4: FlashBufferedWriteRead.java

Der Speicherinhalt kann nun entweder mit dem Flash Viewer des Simulators der JControl/IDE kontrollieren (Bild 2) oder anhand der Ausgabe auf der seriellen Schnittstelle.

Bild 2: Inhalt des Flash-Speichers (Bank 0, Sektor 0)

Bild 3 zeigt die Daten, die auf der seriellen Schnittstelle ausgegeben werden. Der hintere Teil der Ausgabe besteht aus 10 gleichen Sonderzeichen (ÿ). Diese kommen daher, dass 10 Zeichen mehr aus dem Speicher gelesen wurden, als hinein geschrieben wurden. Jene Zeichen treten also dann auf, wenn unbeschriebene Speicherbereiche ausgelesen werden.

Bild 3: Ausgabe auf der seriellen Schnittstelle

Achtung: In dem Beispielprogramm (Listing 4) wurde auf eine Überprüfung der Speichergrenzen verzichtet. In der Praxis ist unbedingt darauf zu achten, ob Daten über Sektor- oder gar Speicherbank-Grenzen hinaus reichen. Falls Daten über solche Bereichsgrenzen hinaus geschrieben werden, resultiert dies in einer OutOfMemoryException.