RSLogix 5000 array data consistency

pete91

Member
Join Date
Feb 2014
Location
Prague
Posts
5
Hi,

I've got an issue with externally read DINT array data consistency on A-B 1769-L33ER controller.

I'm periodically reading (writing) data from (to) the controller using TuxEIP library and sometimes there is a inconsistency in the data read from PLC.

PLC:
periodic task, 5ms period

Program tags:
Code:
Name		Alias For	Data Type	External Access	Const
---------------------------------------------------------------------
undef				DINT		None		1
doUpdate			DINT		Read/Write	0
i				DINT		None		0
init				DINT		Read/Write	0
myArray				DINT[31,3]	Read Only	0
myCount		myArray[30,1]	DINT		Read Only	0
myIndex		myArray[30,0]	DINT		Read Only	0
myIteration	myArray[30,2]	DINT		Read Only	0

Program main (and only) routine:
Code:
if init <> 0
then
	init := 0;

	size(myArray, 0, myCount);
	myCount := myCount - 1;	// last item is used for metadata

	for i := 0 to myCount - 1
	do
		myArray[i, 0] := 0;
		myArray[i, 1] := 0;
		myArray[i, 2] := 0;
	end_for;

	myIteration := 0;
	myIndex := 0;
	doUpdate := 0;
end_if;

if doUpdate <> 0
then
	doUpdate := 0;
	myIteration := myIteration + 1;

	// Update item data
	myArray[myIndex, 0] := myIteration;
	myArray[myIndex, 1] := myIteration MOD 13;
	myArray[myIndex, 2] := myIteration MOD 19;

	myIndex := (myIndex + 1) MOD myCount;

	// Initialize next item
	myArray[myIndex, 0] := undef;
	myArray[myIndex, 1] := undef;
	myArray[myIndex, 2] := undef;
end_if;

PC:

Code:
ConnectToPLC();

int index = 0;
const int undef = -1;
const int itemSz = 3;
const int itemCount = 30;
const int arraySz = itemSz * (itemCount + 1);
const int ixOfIndex = itemSz * itemCount;
int array[arraySz];

WriteDINTTag("init", 1);

for (;;)
{
	WriteDINTTag("doUpdate", 1);
	ReadDINTArrayTag("myArray", array, arraySz);

	int newIndex = array[ixOfIndex];

	while (index != newIndex)
	{
		int id = array[itemSz * index];
		int param1 = array[itemSz * index + 1];
		int param2 = array[itemSz * index + 2];

		if (id == undef)
		{
			// ERROR!!!
		}

		index = (index + 1) % itemCount;
	}

	sleep(5);
}

After a while of running (varies from several seconds to several minutes) I reach the situation that the myIndex aka array[90] is already updated while the related item is not, e.g.:

PLC (that is OK):
Code:
myIndex		3

myArray[0,0]	639
myArray[0,1]	2
myArray[0,2]	12
myArray[1,0]	640
myArray[1,1]	3
myArray[1,2]	13
myArray[2,0]	641
myArray[2,1]	4
myArray[2,2]	14
myArray[3,0]	-1
myArray[3,1]	-1
myArray[3,2]	-1
myArray[4,0]	614
myArray[4,1]	3
myArray[4,2]	6
myArray[5,0]	615
myArray[5,1]	4
myArray[5,2]	7
...
myArray[30,0]	3
myArray[30,1]	30
myArray[30,2]	641

vs. PC:
Code:
index		2
newIndex	3

array[0]	639
array[1]	2
array[2]	12
array[3]	640
array[4]	3
array[5]	13
array[6]	-1
array[7]	-1
array[8]	-1
array[9]	613
array[10]	2
array[11]	5
array[12]	614
array[13]	3
array[14]	6
array[15]	615
array[16]	4
array[17]	7
...
array[90]	3
array[91]	30
array[92]	641

It looks like an array write caching in PLC. Values myArray[30, 0] (myIndex) and array[30, 2] (myIteration) have already been synchronized while the myArray[2, ...] and myArray[3, ...] have not.

Is there a way how to force a tag memory to gets synchronized or something like that in RSLogix 5000?

I am pretty sure that the problem is not caused neither by TuxEIP library nor the network communication - I'm able to transfer tons of data without a problem.
 
There's nothing to prevent any communication driver, TUXEIP or otherwise, from reading your array tags while the routine is still executing its loop with the pointer somewhere in the middle.

The Copy Synchronous (CPS) instruction is the only way I know of to move a block of data in the Logix operating system with data consistency. CPS locks the source and the destination tags until the CPS instruction is complete.

This is different from (and slower than) the Copy (COP) instruction, which moves data in 32-bit blocks.

You might need another array tag as a buffer between your For/Next loop and the PC application.
 
Eddie, thanks for your reply but I don't think that my problem is about the read/write synchronization. At least not on the algorithm level. The algorithm is designed with respect to possible read and write collisions (however the task execution shouldn't been interrupted by network communication because of its high priority).

The problem is that the index incrementation that is done AFTER the data actualization appears in the read memory block BEFORE the updated data. Even if I try to use different (base) tag for storing the array index and synchronize the (array item alias) myIndex value with that tag at the end of the routine the behavior is the same.

I'm able to handle the problem by synchronizing the (local) index tag with the myIndex alias at the beginning of the next routine iteration and that seems quite stable (I wasn't able to reproduce the data inconsistency any more). However I think that this is just a workaround not a solution.

As I wrote in my first post it looks like a memory caching layer on the controller. Are there any details available about the memory access principles on A-B controllers? I wasn't able to find any documentation.
 
I see a handshake issue

Remember that communications is asynchronous to the PLC scan - ie can happen at any time

  • PC - Sets doUpdate
  • PLC Sets to Sets doUpdate to Zero and starts updating the array
  • PC reads the array
  • PLC finishes updating the array

Better is for PC to wait for a flag from the PLC to say update is complete then read the array

eg
Code:
PC WriteDINTTag("doUpdate", 1);
repeat 
[INDENT]ReadDINTTag ("doUpdate", doUpdate);
until doUpdate = 0;
[/INDENT]

then ReadDINTArrayTag("myArray", array, arraySz);
etc ...

and in the PLC do not set doUpdate = 0 until after the array has been updated



Additional notes: when I was programming SCADA PLC communication drivers we could have multiple requests active at the same time
that means that your write request could be active at the same time as the read request and be executed in the same communications timeslice inside the PLC
 
Michael, I already have a notification flag that tells me, that the data has been completely updated. That is the myIndex tag which is updated after the data update. I just read both the data and flag in one reading and use the data when the flag is set. The doUpdate tag i used just to avoid multiple incrementations between two readings (when task is running in continuous mode).

The problem is that sometimes when I read the array (which includes both the data and the myIndex tag) the index value is incremented already but the data are not.
 
Michael, I already have a notification flag that tells me, that the data has been completely updated. That is the myIndex tag which is updated after the data update. I just read both the data and flag in one reading and use the data when the flag is set. The doUpdate tag i used just to avoid multiple incrementations between two readings (when task is running in continuous mode).

The problem is that sometimes when I read the array (which includes both the data and the myIndex tag) the index value is incremented already but the data are not.

does that mean that you are buffering the whole array before the myIndex tag is updated? - Yes as it is offset 90

does that also mean that you should not do WriteDINTTag("doUpdate", 1); until the myindex tag changes?


Look again at the PC code. you cause a write to occur every 5 seconds no matter what myindex is doing
 
Last edited:
I am not sure what exactly do you mean by buffering the whole array.

I've got an array of 30 events. One event is represented by 3 DINTs. Moreover there is one extra "event" for holding metadata (like next event index) => two-dimensional array DINT[31,3].

I do read the whole array of events plus metadata every for-loop iteration in PC part. (The read array is represented as a single-dimensional in PC which might be confusing.) If the newIndex value that corresponds to the myIndex alias tag in PLC changes it means that new event has been written in PLC and I do process the event.

In my real program I do not have any doUpdate tag. New events are logged (which means written into the shared array) based on the significant values read from sensors. I was just able to reproduce the same behavior using the minimal program from my first post. The doUpdateTag is just an flag for generating new event.

The problem simply is that sometimes if I do:

in PC: read array from PLC

array[x] == 0
array[y] == 0

then in PLC:

array[x] := 1; // was 0 before
array[y] := 1; // was 0 before

and then in PC: read array from PLC again

I do receive sometimes:

array[x] == 0;
array[y] == 1;

which means that the value of array[y] gets updated (in the controller memory from which - I guess - the array has been read) before the value of array[x] although the instruction for update value array[x] is executed before the instruction for update array[y]. Moreover this happens even if there is a lot of other instructions between the update of array[x] and array[y] in PLC.
 
It seams to me that it is not an issue that array[y] is getting updated before array[x]. More likely the when the response to the read from the PC is being created it is happening around array[x]:=1 and array[y]:=1.

PC -> request read.
PLC- > start building response. (at this point array[x]==0, array[y]==0)
PLC-> communications copies array[x] into the buffer (array[x]==0)
PLC-> communications routines suspended to to ladder
PLC-> updates array[x]:=1, array[y]:=1
PLC-> communications pick up where they left off (array[y]==1)
PC-> receives array[x]==0, array[y]==1

I have not worked with TuxEIP directly but I have written my own communications in python and I ran into this.

Have you looked at the connection with wireshark?

My solution was to buffer the array (as suggested above).
I created 2 bools, CreateBuffer and BufferCreated and BufferArray[1000]

PC -> set CreateBuffer.
PLC -> CreateBuffer [ons] CPS work to BufferArray
PLC -> set buffer created
PC -> Wait for Buffer Created
PC -> fetch BufferArray
PC -> reset CreateBuffer, BufferCreated.

This worked for me, YMMV.
 
Thank you all guys (NevisGroup especially for the detailed explanation), now I understand what you were trying to tell me.
 

Similar Topics

Hey all, I am trying to figure out how to import some alarm messages without having to type them all in by hand. They are in the format of an...
Replies
4
Views
1,126
Hello i have been trying to figure out a good way to take hex and convert it to an array of SINT[]. Here is what my failed attempt looks like.
Replies
5
Views
1,267
I have a subroutine that gets called to copy a UDT In an array to a tag. This subroutine will be called around once per minute and has been...
Replies
4
Views
2,118
Hello! I have an application where I can only have 3 pumps running out of 6. I load the pumpRunning bits into an array. What I need to do is...
Replies
6
Views
3,132
Hello Currently have a project in which I have to find the highest value in a dint array. Once the highest value is found I will have to move...
Replies
20
Views
11,477
Back
Top Bottom