TIA TIA zum Compile dynamische Arrays

vollmi

Level-3
Beiträge
5.425
Reaktionspunkte
1.403
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich hab hier ein paar S7-1517 3pn/dp FW 2.9 (selbes Problem bei 2.8)

Eine von 20 CPUs geht alle paar Tage bis Wochen auf Stop wegen Zugriffsfehler.
Temporärer CPU-Fehler: Bereichslängenfehler in FB 12
betrifft OB 1-Ausführung
Lesezugriff Flüchtiger DB-Bereich
fehlerhafte Adresse, Operand ersetzt

interne Adressierungsdetails: Caddr=16#00000103, Bereich: Flüchtiger DB-Bereich, Adr: 268436105
Der Code ist relativ kurz und übersichtlich.
Code:
FUNCTION_BLOCK "FB_OBJ_Webserver"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_IN_OUT
      Signal_WEB_Array : Array[*] of "Signal_OBJ_LST_WEB";
      Austausch : "Signal_Austausch_1";
   END_VAR

   VAR
      Signal_index : DInt;
   END_VAR

   VAR_TEMP
      untereGrenze : DInt;
      obereGrenze : DInt;
      Laenge : Int;
      index : Int;
   END_VAR


BEGIN
    #untereGrenze := LOWER_BOUND(ARR := #Signal_WEB_Array, DIM := 1);
    #obereGrenze := UPPER_BOUND(ARR := #Signal_WEB_Array, DIM := 1);
    #Laenge := DINT_TO_INT(#obereGrenze - #untereGrenze);
    
    
    
    REGION generalabfrage
        
        IF #Austausch.Generalabfrage THEN
            FOR #index := #untereGrenze TO #obereGrenze DO
                IF #Signal_WEB_Array[#index].BA <> 0 THEN
                    #Signal_WEB_Array[#index].New := TRUE;
                END_IF;
            END_FOR;
            #Austausch.Generalabfrage := FALSE;
        END_IF;
        
    END_REGION
    
    REGION Signalupdate
        
        IF NOT (#Signal_index >= #untereGrenze AND #Signal_index <= #obereGrenze) THEN
            #Signal_index := #untereGrenze;
        END_IF;
        
        IF NOT #Austausch.Signal.New THEN
            WHILE #Signal_index >= #untereGrenze AND #Signal_index <= #obereGrenze DO
                IF #Signal_WEB_Array[#Signal_index].New THEN
                    #Austausch.Signal := #Signal_WEB_Array[#Signal_index];
                    #Signal_WEB_Array[#Signal_index].New := FALSE;
                    EXIT;
                END_IF;
                #Signal_index += 1;
            END_WHILE;
        END_IF;
        
    END_REGION
    
    REGION lokal setzen
        
        IF #Austausch.Signal_Set.Set THEN
            FOR #index := #untereGrenze TO #obereGrenze DO
                IF #Signal_WEB_Array[#index].Config.SID = #Austausch.Signal_Set.SID AND
                    #Signal_WEB_Array[#index].Config.LID = #Austausch.Signal_Set.LID THEN
                    #Austausch.Signal_Set.Set := false;
                    #Austausch.Signal_Set.SID := 0;
                    #Austausch.Signal_Set.LID := 0;
                    IF #Austausch.Signal_Set.BA > 0 AND #Austausch.Signal_Set.BA <= 4 THEN
                        #Signal_WEB_Array[#index].BA := #Austausch.Signal_Set.BA;
                    END_IF;
                    #Signal_WEB_Array[#index].Soll_LST := #Austausch.Signal_Set.Soll_LST;
                    #Signal_WEB_Array[#index].OverrideAktiv := #Austausch.Signal_Set.OverrideAktiv;
                    EXIT;
                END_IF;
            END_FOR;
        END_IF;
        
    END_REGION
    
    
END_FUNCTION_BLOCK

Wie könnte ich hier einen dynamisch auftretenden Zugriffsfehler provozieren?
Im Rot markierten Vereich zähle ich den Index zwar vor ende nochmal hoch. Aber ich geh dann ja wieder in die while Prüfung und dürfte da dann direkt rausfallen.
Mir gehen da die Ideen etwas aus. Das ist übrigens ein Bibliotheksbaustein, der ist noch auf 20 weiteren exakt gleich konfigurierten CPUs drauf. Aber es passiert nur bei dieser einen.
Bevor ich jetzt Zeile für Zeile mit einem Dummymerker markiere um den exakten Ausprungspunkt und Zugriffsadresse rauszufinden, dache ich. Frag mal vielleicht hat einer ne iIee.
 
Nur mal interesse halber, hast du den einen zeitgesteuerten OB auf deiner CPU am laufen ( OB30 )?
Ich denke hier an folgendes Problem:
https://www.sps-forum.de/threads/ti...itgesteuerten-ob-30.103104/page-6#post-787615

Evtl. entsteht bei dir das Problem ( bei zufälliger OB30 Unterbrechung ) an folgender Stelle (sporadischer Wert 0 ):
Code:
#untereGrenze := LOWER_BOUND(ARR := #Signal_WEB_Array, DIM := 1);
#obereGrenze := UPPER_BOUND(ARR := #Signal_WEB_Array, DIM := 1);
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Nur mal interessehalber, hast du den einen zeitgesteuerten OB auf deiner CPU am laufen ( OB30 )?
Ich denke hier an folgendes Problem:
https://www.sps-forum.de/threads/ti...itgesteuerten-ob-30.103104/page-6#post-787615

Evtl. entsteht bei dir das Problem ( bei zufälliger OB30 Unterbrechung ) an folgender Stelle (sporadischer Wert 0 ):
Hm jup den hab ich drin. Brauch ich aber eigentlich nicht mehr. Ich nehme ihn mal testweise raus.
 
Oder wie von Siemens vorgeschlagen mal folgendes testen:

Code:
statt:
#untereGrenze := LOWER_BOUND(ARR := #Signal_WEB_Array, DIM := 1);
ändern auf:
#tempDINT := LOWER_BOUND(ARR := #Signal_WEB_Array, DIM := 1);
#untereGrenze : = tempDINT;

...
 
Wobei das Problem bei @NBerger ja eher war, dass er dann im OB30 eine 0 in der Variable hatte und nicht direkt in den
folgenden Zeilen des Code. Schwer zu sagen aber mehr fällt mir dazu leider auch nicht ein

Nicht das mit TEMP Variablen doch noch etwas im argen ist. Bei Unterbrechung...
Gerade weil es bei dir so hochsporadisch ist.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Evtl. könntest du Versuche machen, indem du deinen Code auf eine Test CPU lädst ( vielleicht deinen Aufruf einige mal hintereinander ) und den OB30 auf die Mindestaufrufzeit von 0,5ms stellst.

Nur zum testen.
 
Zuletzt bearbeitet:
DAs müsste ich dann übernächste Woche mal ausprobieren. Wenn ich wieder im Land bin. Ich hab jetzt testweise den OB 30 und 31 enfernt und den inhalt in ob1 umgezogen. War eh unnötig das auf feste Zeiten zu setzen.
Wenn der Fehler dann nicht mehr auftaucht, weiss ich auch mehr.
 
Hallo René, welchen Codeteil wolltest Du rot markieren?

Ich sehe in dem Code nur eine anfällige Stelle: Wenn eine unterbrechende Task die Instanz-Variable Signal_index verändert. Das könntest Du so umschreiben, daß nach der Überprüfung mit einer Kopie in einer TEMP-Variable gearbeitet wird.

Evtl. entsteht bei dir das Problem ( bei zufälliger OB30 Unterbrechung ) an folgender Stelle (sporadischer Wert 0 ):
Code:
#untereGrenze := LOWER_BOUND(ARR := #Signal_WEB_Array, DIM := 1);
#obereGrenze := UPPER_BOUND(ARR := #Signal_WEB_Array, DIM := 1);
Das glaube ich eher nicht. Ich glaube ganz fest, daß bei diesem Code nichts schiefgehen kann. Wenn da falsche Werte in #untereGrenze oder #obereGrenze gelangen könnten, dann könnte man keiner S7-1500 mehr trauen.

Harald
 
Was wäre denn wenn nach dem ersten Durchlauf die Variable #Signal_index hochgezählt wurde
und z.B. auf 10 steht und bei einem zweiten Durchlauf folgende Bedingung nicht gegeben wird
und die Signal_Index somit nicht neu beschrieben wird.

Code:
IF NOT (#Signal_index >= #untereGrenze AND #Signal_index <= #obereGrenze) THEN
    #Signal_index := #untereGrenze;
END_IF;
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
WHILE #Signal_index >= #untereGrenze AND #Signal_index <= #obereGrenze DO
Hallo René, welchen Codeteil wolltest Du rot markieren?

Den mit der While Schleife

Ich sehe in dem Code nur eine anfällige Stelle: Wenn eine unterbrechende Task die Instanz-Variable Signal_index verändert. Das könntest Du so umschreiben, daß nach der Überprüfung mit einer Kopie in einer TEMP-Variable gearbeitet wird.

Hätt ich auch gesagt. Allerdings Signal_index ist ja eine Statische Variable. Sollte von extern also nicht verändert werden können, es sei denn ich schreib irgendwo auf die Instanz. Das tue ich aber nie.

Das glaube ich eher nicht. Ich glaube ganz fest, daß bei diesem Code nichts schiefgehen kann. Wenn da falsche Werte in #untereGrenze oder #obereGrenze gelangen könnten, dann könnte man keiner S7-1500 mehr trauen.

Ich hoffe immernoch, dass ich irgendwo einen Fehler mache.

Was wäre denn wenn nach dem ersten Durchlauf die Variable #Signal_index hochgezählt wurde
und z.B. auf 10 steht und bei einem zweiten Durchlauf folgende Bedingung nicht gegeben wird
und die Signal_Index somit nicht neu beschrieben wird.

Code:
IF NOT (#Signal_index >= #untereGrenze AND #Signal_index <= #obereGrenze) THEN
    #Signal_index := #untereGrenze;
END_IF;

Müsste dann nicht
Code:
WHILE #Signal_index >= #untereGrenze AND #Signal_index <= #obereGrenze DO

direkt bei end_while weitermachen?
Den Code den du zitiert hast, habe ich ja nur drin, dass ich am ende wieder einen startwert bei 0 habe.
Ich könnte das ja auch in der Schleife direkt machen. Also wieder auf 0 bei überlauf. Und dann mit Exit ausspringen. Dachte halt ist so etwas übersichtlicher.
 
Die Variable "index", welche in den FOR-Schleifen verwendet wird, ist ein INT. Die ARRAY-Grenzen sind jedoch DINT. Es ist aus Sicht des aufmerksamen Lesers nicht auszuschließen, dass hier der Wertebereich überschritten wird. Selbiges gilt für "Laenge", wobei hier korrekterweise noch "+1" addiert werden müsste. "Laenge" wird aber ohnehin nicht weiter verarbeitet.
 
Weiß jemand ab wann bei TIA der L-Stack wieder einsehbar ist? Da könnte man zumindest sehen welchen Wert #index hat und die Ober- und Untergrenzen.
Du könntest auch diese Variablen wenn möglich in den Stat Bereich verschieben, dann könntest du dir im Instanz-DB die Werte einmal ansehen.

Mit den Adressangaben im Diagnosepuffer lässt sich auch nichts anfangen, zumindest sind die Adressen unabhängig vom Wert des fehlerhaften Index.
 
Zurück
Oben