Speicherverwaltung

I. Der (onboard) Flash-Speicher

Dieses Tutorial befasst sich mit Funktionen die dazu dienen, sich mit der Ansteuerung des Flash-Speichers auf einem JControl-Modul vertraut zu machen. Es wird gezeigt, wie die Dimensionen des Flash-Speichers bestimmt werden, wie Daten in den Speicher geschrieben und wieder ausgelesen werden können.




Die Speicherdimensionen

Die Speicherdimensionen setzen sich aus drei Komponenten zusammen: Bytes pro Sektor, Anzahl der Sektoren und Anzahl der Speicherbänke. Je nach Produktausstattung können diese Dimensionen variieren. Für einen problemlosen Zugriff auf den Speicher ist es also unerlässlich, die Dimensionen des Speichers zu bestimmen, auf den ein laufendes Programm zugreifen soll.

Ein Beispiel:. Bei einem JControl/SmartDisplay http://www.domologic.com/services/ch3/index_de.html enthält jede Speicherbank 64kB, womit ein solches Modul in der Standardausführung genau eine Speicherbank besitzt. Diese Bank ist aufgeteilt in 512 Sektoren und jeder Sektor besteht aus 128 Bytes.

1    /**
2     * Java file created by JControl/IDE
3     *
4     * @author RSt
5     * @date 03.11.04 17:23
6     *
7     */
8    import java.io.IOException;
9    import jcontrol.comm.RS232;
10    
11    public class FlashDimensions {
12    
13      static String flashDimensions = "";
14      static RS232 myRS232;
15    
16        public FlashDimensions() {
17          try{
18            myRS232 = new RS232();//default = 19200 Baud
19          }catch(IOException e){
20          }
21          flashDimensions = jcontrol.system.Management.getProperty("flash.format");
22        }
23    
24        public static void main(String[] args) {
25            new FlashDimensions();
26            myRS232.println(flashDimensions);
27            for(;;);//Stops execution of this program.
28        }
29    }
Listing 1: FlashDimensions.java

Das obige Programm gibt (auf einem Standard-JControl/SmartDisplay) über die serielle Schnittstelle den String "512x128x1" ({Sektoren}x{Bytes/Sektor}x{Bänke}) aus, welcher die Speicherdimensionen des Beispiels (s.o.) widerspiegelt. Aus diesem String (die entsprechende Programmzeile ist hervorgehoben) kann ein Programm also während des Betriebs die Dimensionen des eingebauten Flash-Speichers bestimmen, sodass dem Benutzer die Daten zur Verfügung stehen, die er für den sicheren Zugriff auf den Speicher braucht.

Hinweis aus der Praxis:. Es gestaltet sich bei Speicheroperationen sehr einfach, in die 0-1-Falle zu geraten: Die Indizes der Bänke, Sektoren und Bytes beginnen bei 0 und reichen bis zu der entsprechenden Anzahl-1. Bei zwei Speicherbänken stehen also die Bänke 0 und 1 zur Verfügung. Dies ist zwar i.d.R. bekannt, bleibt aber dennoch eine häufige Ursache für Speicherzugriffsfehler.



Daten in den Speicher schreiben

Um Daten in den Speicher zu schreiben, werden zunächst dessen Dimensionen benötigt. Nun ist es notwendig etwas über die Methoden herauszufinden, die die JControl-API http://www.jcontrol.org/current/docs/api/index.html für den Zugriff auf den Flash-Speicher bereitstellt. Die folgenden Klassen beinhalten entsprechende Methoden:

Als Beispiel wird hier die Klasse jcontrol.io.Flash betrachtet. Um mit ihr überhaupt auf den Speicher zugreifen zu können, muss eine Instanz dieser Klasse (mit new) erzeugt werden. Dem Konstruktor (Flash()) kann dabei die Speicherbank (als int) übergeben werden, auf die bei Speicheroperationen zugegriffen werden soll (Flash(speicherbank)). Mit der Flash-Instanz und den Speicherdimensionen ist nun alles vorhanden, was der Anwender braucht, um Daten zu speichern.

Für das Schreiben von Daten wird hier die Methode write der Klasse jcontrol.io.Flash verwendet, welche 4 Paramter verlangt:

Tipp: Die Klasse jcontrol.io.Flash verfügt außerdem über die Methode getUsableSectors(), die dem Benutzer anzeigt, wie viele Sektoren ihm für eigene Daten zur Verfügung stehen. Das ist besonders dann nützlich, wenn die zu beschreibende Speicherbank dieselbe ist, die das auszuführende Programm beherbergt. Es ist nicht in die Sektoren zu schreiben, die das Programm beinhalten.

Das folgende Beispielprogramm schreibt den String "Welcome to JControl!!!" an den Anfang des 0ten Sektors von Bank 0.

1    /**
2     * Java file created by JControl/IDE
3     *
4     * @author RSt
5     * @date 04.11.04 14:34
6     *
7     */
8    import java.io.IOException;
9    import jcontrol.io.Flash;
10    
11    public class FlashWrite {
12    
13        private static Flash myFlash;
14    
15        public FlashWrite() {
16            try{
17                //Initiate Flash object with context to bank 0
18                myFlash = new Flash(0);
19            }catch(IOException e){
20            }
21        }
22       
23        public static void main(String[] args) {
24            new FlashWrite();
25            String writeThis = "Welcome to JControl!!!";
26            byte[] data = writeThis.getBytes();
27            try{
28                //write data to memory:
29                myFlash.write(data, 0, data.length, 0);
30            }catch(IOException e){
31            }
32            for(;;);//Stops execution of this program.
33        }
34    }
Listing 2: FlashWrite.java

Ob die Daten korrekt geschrieben wurden, lässt sich bei diesem Programm nur mit dem Simulator der JControl/IDE überprüfen. Der Inhalt des entsprechenden Sektors kann in dessen Flash Viewer (Bild 1) sichtbar gemacht werden. Im folgenden Abschnitt (Daten aus dem Speicher lesen) wird das Beispielprogramm so erweitert werden, dass die geschriebenen Daten wieder eingelesen und auf der seriellen Schnittstelle ausgegeben werden.

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

Die oben erwähnten Klassen jcontrol.storage.FlashStream und jcontrol.storage.FlashTlv basieren auf der hier benutzten Klasse jcontrol.io.Flash und implementieren einige hilfreiche Funktionen. So ermöglicht die Klasse FlashStream z.B. das kontinuierliche Schreiben, bzw. Lesen einzelner Zeichen (char), wohingegen die Klasse FlashTlv spezielle Dateien erzeugt.



Daten aus dem Speicher lesen

Wenn Daten aus dem Speicher gelesen werden sollen, ist es ebenfalls notwendig, die Speicherdimensionen zu kennen. Ebenso wie beim Schreiben von Daten muss eine Instanz der Klasse jcontrol.io.Flash ezeugt werden, um auf den Speicher und die entsprechende Bank zugreifen zu können. Für das Lesen aus dem Speicher wird hier die Methode read der Klasse jcontrol.io.Flash verwendet.

Wie die Methode write, so erwartet auch read 4 Paramter:

Folgendes Programm schreibt wiederum den String "Welcome to JControl!!!" an den Anfang des 0ten Sektors von Bank 0. Allerdings werden diese Daten hier wieder ausgelesen und zum Zwecke der Überprüfung auf der seriellen Schnittstelle ausgegeben.

1    /**
2     * Java file created by JControl/IDE
3     *
4     * @author RSt
5     * @date 04.11.04 15:49
6     *
7     */
8    import java.io.IOException;
9    import jcontrol.comm.RS232;
10    import jcontrol.io.Flash;
11    
12    public class FlashRead {
13    
14        static Flash myFlash;
15        static RS232 myRS232;
16    
17        public FlashRead() {
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 FlashRead();
29            String writeThis = "Welcome to JControl!!!";
30            byte[] data = writeThis.getBytes();
31            byte[] read = new byte[data.length];
32            try{
33                //write data to memory:
34                myFlash.write(data, 0, data.length, 0);
35                //read Flash content:
36                myFlash.read(read, 0, read.length, 0);
37                //write read data to serial port
38                myRS232.println(new String(read));
39            }catch(IOException e){
40            }
41            for(;;);//Stops execution of this program.
42        }
43    }
Listing 3: FlashRead.java

Die Ausgabe des Programms kann nun mit der RS232-Konsole der JControl/IDE oder einem anderen Terminal-Programm überprüft werden.



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:

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.



© 2000-2006 DOMOLOGIC Home Automation GmbH. All Rights Reserved.