Rs422 to RS232 communication problem in Automation Studio

Hello everyone,

I had to get the sensor I used for an application I made for rs 422, but since the X90CP154_60_00 controller I use supports rs232, I use a converter every now and then. When I look at the sensor’s own interface, I can record at a recording speed of 400 Hz and above without repeating the data, but in the recordings I receive on the Automation Studio side, I get a recording result of 30 Hz and around, the data repeats very often.

I would be very grateful if you can check my communication code I shared below and suggest me a solution. Sincerely regards.


#include <bur/plctypes.h>
#include <stdint.h>
#ifdef _DEFAULT_INCLUDES
	#include <AsDefault.h>
#endif

int findSequenceIndices(const uint8_t* array, int size) {
	int i;
	for (i = 0; i < size - 1; i++) {
		if (array[i] == 170 && array[i + 1] == 85) {  // Check if the sequence matches
			return i;  // Store the index
		}
	}
	return -1;
}

int16_t to_signed_16bit(uint8_t msb, uint8_t lsb) {
	int16_t value = (lsb << 8) | msb;
	return value >= 0x8000 ? value - 0x10000 : value;
}

uint16_t to_unsigned_16bit(uint8_t msb, uint8_t lsb) {
	return (lsb << 8) | msb;
}


void _INIT ProgramInit(void){
	Receiver.Commands.open_receive = 1;
}

void _CYCLIC ProgramCyclic(void){
	switch (Receiver.step) {
		case FRM_WAIT:
			if (Receiver.Commands.open_receive == 1) {
				Receiver.step = FRM_OPEN;
			}
			break;

		case FRM_OPEN:
			// Call the FRM_xopen function block
			Receiver.FRM_xopen_0.enable = 1;
			Receiver.FRM_xopen_0.device = (UDINT)DeviceName;
			Receiver.FRM_xopen_0.mode = (UDINT)DeviceConfig;
			Receiver.FRM_xopen_0.config = &(Receiver.xopenConfig);
			
			FRM_xopen(&Receiver.FRM_xopen_0);
			
			
			if (Receiver.FRM_xopen_0.status == 0) {
				Receiver.step = FRM_READ;
			} else if (Receiver.FRM_xopen_0.status == BUSY) {
				Receiver.step = FRM_OPEN;
			} else {
				Receiver.step = FRM_ERROR;
			}
			break;

		case FRM_READ:
			Receiver.FRM_read_0.enable = 1;
			Receiver.FRM_read_0.ident = Receiver.FRM_xopen_0.ident;
			FRM_read(&Receiver.FRM_read_0);

			if (Receiver.FRM_read_0.status == 0) {
				if (Receiver.FRM_read_0.buflng <= sizeof(Receiver.receive_data)) {
					memcpy(Receiver.receive_data, Receiver.FRM_read_0.buffer, Receiver.FRM_read_0.buflng);

					int indices = findSequenceIndices(Receiver.receive_data, Receiver.FRM_read_0.buflng);
					if (indices >= 0) {
						KernelRawData.Heading = to_unsigned_16bit(Receiver.receive_data[8], Receiver.receive_data[9]);
						KernelRawData.Pitch = to_signed_16bit(Receiver.receive_data[10], Receiver.receive_data[11]);
						KernelRawData.Roll = to_signed_16bit(Receiver.receive_data[12], Receiver.receive_data[13]);

						Heading = (double)KernelRawData.Heading / 100.0;
						Pitch = (double)KernelRawData.Pitch / 100.0;
						Roll = (double)KernelRawData.Roll / 100.0;
					} else {
						// Eşleşme bulunamadı, hata işleme
						Receiver.step = FRM_ERROR;
					}
				} else {
					// Buffer boyutu yetersiz, hata işleme
					Receiver.step = FRM_ERROR;
				}
				Receiver.step = FRM_RBUF;
			} else if (Receiver.FRM_read_0.status == frmERR_NOINPUT) {
				Receiver.step = FRM_READ;
			} else {
				Receiver.step = FRM_ERROR;
			}
			break;

		case FRM_COPY_RD_DATA:
			memset(Receiver.receive_data, 0, sizeof(Receiver.receive_data));
			memcpy(Receiver.receive_data, Receiver.FRM_read_0.buffer, Receiver.FRM_read_0.buflng);
			
			indices = findSequenceIndices(Receiver.receive_data, sizeof(Receiver.receive_data));
//			if(indices>=0){
			KernelRawData.Heading = to_unsigned_16bit(Receiver.receive_data[8], Receiver.receive_data[9]);
			KernelRawData.Pitch   = to_signed_16bit(Receiver.receive_data[10]  , Receiver.receive_data[11]);
			KernelRawData.Roll    = to_signed_16bit(Receiver.receive_data[12] , Receiver.receive_data[13]);

			Heading  = (double)KernelRawData.Heading  / 100.0;
			Pitch    = (double)KernelRawData.Pitch   / 100.0;
			Roll     = (double)KernelRawData.Roll    / 100.0;
//			}
			
			
			Receiver.step = FRM_RBUF;
			break;

		case FRM_RBUF:
			Receiver.FRM_rbuf_0.enable 	= 1;
			Receiver.FRM_rbuf_0.ident 	= Receiver.FRM_xopen_0.ident;	
			Receiver.FRM_rbuf_0.buffer 	= Receiver.FRM_read_0.buffer;
			Receiver.FRM_rbuf_0.buflng 	= Receiver.FRM_read_0.buflng;
				
			FRM_rbuf(&Receiver.FRM_rbuf_0);
			
			if (Receiver.FRM_rbuf_0.status == 0) {
				if (Receiver.Commands.close == 1) {
					Receiver.Commands.open_receive = 0;
					Receiver.step = FRM_CLOSE;
				} else {
					Receiver.step = FRM_READ;
				}
			} else if (Receiver.FRM_rbuf_0.status == BUSY) {
				Receiver.step = FRM_RBUF;
			} else if (Receiver.FRM_rbuf_0.status == frmERR_INVALIDBUFFER) {
				Receiver.step = FRM_READ;
			} else {
				Receiver.step = FRM_ERROR;
			}
			break;

		case FRM_CLOSE:
			
			Receiver.FRM_close_0.enable = 1;
			Receiver.FRM_close_0.ident  = Receiver.FRM_xopen_0.ident;
			
			FRM_close(&Receiver.FRM_close_0);
			
			if (Receiver.FRM_close_0.status == 0) {
				Receiver.Commands.close = 0;
				Receiver.step = FRM_WAIT;
			} else if (Receiver.FRM_close_0.status == BUSY) {
				Receiver.step = FRM_CLOSE;
			} else {
				Receiver.step = FRM_ERROR;
			}
			break;

		case FRM_ERROR:
			
			break;

		default:
			break;
	}
}





PROGRAM _INIT
	Receiver.Commands.open_receive := TRUE;
END_PROGRAM

PROGRAM _CYCLIC
	CASE Receiver.step OF
		FRM_WAIT:	(*--- wait for command*)
			
			IF Receiver.Commands.open_receive = TRUE THEN								(*command for Receiver activation*)
				Receiver.step := FRM_OPEN;
			END_IF			
		
			(*close will be requested in step FRM_RBUF*)
		
		FRM_OPEN:	(*--- open serial interface*)
			
			(*Parameters for FRM_xopen()*)
			Receiver.FRM_xopen_0.enable := TRUE;
			Receiver.FRM_xopen_0.device := ADR('IF1');											(*Devicename --> see your serial interface properties*)
			Receiver.FRM_xopen_0.mode 	:= ADR('/PHY=RS232 /BD=115200 /DB=8 /PA=N /SB=1'); 		(*Modestring --> specifies the seria operation mode*)
			Receiver.FRM_xopen_0.config := ADR(Receiver.xopenConfig) ;							(*Additional Parameters, optional*)
			
			(*Additional Parameters for FRM_xopen()*)
			//			Receiver.xopenConfig.idle 		:= 10;											(*Idle time between two characters*)
			//			Receiver.xopenConfig.delimc 	:= 0;											(*activate two delimeters*)
			//			Receiver.xopenConfig.delim[0] 	:= 0; 											(*e.g. CR - carridge return -> dec 13*)
			//			Receiver.xopenConfig.delim[1] 	:= 0; 											(*e.g. LF - line feed -> dec 10*)
			//			Receiver.xopenConfig.tx_cnt 	:= 3;											(*number of transmit buffers*)
			//			Receiver.xopenConfig.rx_cnt 	:= 3; 											(*number of receive buffers*)
			//			Receiver.xopenConfig.tx_len 	:= 256; 										(*length of transmit buffers*)
			//			Receiver.xopenConfig.rx_len 	:= 256; 										(*lenght of receive buffers*)
			//			Receiver.xopenConfig.argc 		:= 0;											(*activate additional options*)
			//			Receiver.xopenConfig.argv 		:= 0;											(*parameters for additional options (check help)*)
		
			Receiver.FRM_xopen_0();														(*call the FRM_xopen() function*)
			
			IF Receiver.FRM_xopen_0.status = 0 THEN
				Receiver.step := FRM_READ;												(*Interface opend successfully --> next step*)
			ELSIF Receiver.FRM_xopen_0.status = BUSY THEN
				Receiver.step := FRM_OPEN;												(*operation not finished yet --> call again*)
			ELSE
				Receiver.step := FRM_ERROR;												(*function returned errorcode --> check help*)
			END_IF			
			
		FRM_READ:	(*--- read data from serial interface*)
			Receiver.FRM_read_0.enable := TRUE;
			Receiver.FRM_read_0.ident := Receiver.FRM_xopen_0.ident;
			
			Receiver.FRM_read_0();														(*call the FRM_read() function*)
			
			IF Receiver.FRM_read_0.status = 0 THEN
				Receiver.step := FRM_COPY_RD_DATA;										(*system returned a valid data --> next step*)
			ELSIF Receiver.FRM_read_0.status = frmERR_NOINPUT THEN
				Receiver.step := FRM_READ;												(*no data available --> call again*)
			ELSIF Receiver.FRM_read_0.status = frmERR_INPUTERROR THEN
				Receiver.step := FRM_RBUF;												(*received Frame with defective characters, skip data*)
			ELSE
				Receiver.step := FRM_ERROR;												(*function returned errorcode --> check help*)
			END_IF			
			
		
		FRM_COPY_RD_DATA: (*--- copy data out of the receive buffer*)
			
			memset(ADR(Receiver.receive_data),0,300);			(*clear read_data buffer*)
			memcpy(ADR(Receiver.receive_data),Receiver.FRM_read_0.buffer,Receiver.FRM_read_0.buflng);     (*copy and evaluate read data*)
			
			
			
			Receiver.step := FRM_RBUF;																	(*release read buffer*)

		FRM_RBUF:	(*--- release readbuffer*)
		
			(*Parameters for FRM_rbuf()*)
			Receiver.FRM_rbuf_0.enable 	:= TRUE;
			Receiver.FRM_rbuf_0.ident 	:= Receiver.FRM_xopen_0.ident;					(*ident from FRM_xopen()*)
			Receiver.FRM_rbuf_0.buffer 	:= Receiver.FRM_read_0.buffer;					(*read buffer*)
			Receiver.FRM_rbuf_0.buflng 	:= Receiver.FRM_read_0.buflng;					(*length of sendbuffer*)
   			
			Receiver.FRM_rbuf_0();														(*call the FRM_rbuf() function*)
			
			IF Receiver.FRM_rbuf_0.status = 0 THEN
				IF Receiver.Commands.close = TRUE THEN
					Receiver.Commands.open_receive := FALSE;							(*disable command open_send*)
					Receiver.step := FRM_CLOSE;											(*request to close serial port*)
				ELSE				
					Receiver.step := FRM_READ;											(*read again*)
				END_IF
			ELSIF Receiver.FRM_rbuf_0.status = BUSY THEN
				Receiver.step := FRM_RBUF;												(*operation not finished yet --> call again*)
			ELSIF Receiver.FRM_rbuf_0.status = frmERR_INVALIDBUFFER THEN					
				Receiver.step := FRM_READ;												(*buffer is invalid --> read again*)
			ELSE
				Receiver.step := FRM_ERROR;												(*function returned errorcode --> check help*)
			END_IF			
		
		FRM_CLOSE:	(*--- close the interface*)
			Receiver.FRM_close_0.enable := TRUE;
			Receiver.FRM_close_0.ident := Receiver.FRM_xopen_0.ident;					(*ident from FRM_xopen()*)			
			
			Receiver.FRM_close_0();														(*call the FRM_close() function*)
			
			IF Receiver.FRM_close_0.status = 0 THEN
				Receiver.Commands.close := FALSE;										(*disable close command*)
				Receiver.step := FRM_WAIT;												(*closed interface successfully --> wait step*)
			ELSIF Receiver.FRM_close_0.status = BUSY THEN
				Receiver.step := FRM_CLOSE;												(*operation not finished yet --> call again*)
			ELSE
				Receiver.step := FRM_ERROR;												(*function returned errorcode --> check help*)
			END_IF
			
		FRM_ERROR:	(*--- error handling*)
		; (*not implementet yet, check help for error codes*)
	END_CASE	
END_PROGRAM

PROGRAM _EXIT
	(* Insert code here *)
	 
END_PROGRAM


Frm Read status is not always but occasionally 60. I guess this means that there are times when we cannot get data. Am I correct and if so, does it have anything to do with the code or configuration? Or is it completely related to the sensor or converter?

The task cycle (where this task is called) also influences the possible througput.
In what cycle time is this task called?
Try otherwise a faster cycle time.

How is the convertor connected to the sensor. Is this with 4 signals RS422 or two signals RS485 ?

The xopenConfig.idle setting is normally 4 and not 10.
A lower setting, means the frame is accepted faster.

Task itself only works with 1.6 ms in cyclic 2 but I can reduce this time to 0.8 ms. On the other side of the converter the connection to the sensor is done as RS422, now I will test the xopenconfig.idle change you suggested.

Unfortunately, I didn’t experience any improvement when I made the change you suggested. If there are other settings you suggest here, I would be happy to try them.

Hello,

I have solved the issue by integrating the following code block, and I wanted to share the solution with you. As Corne Geerts mentioned, the most important changes were made to the xopenConfig.idle variable along with the len and cnt parameters of the rx and tx variables. Thanks to these modifications, I am now able to receive data at 625 Hz.

Receiver.xopenConfig.idle = 2;   // Maximum idle time of 10 ms
Receiver.xopenConfig.delimc = 0;  // Use two frame terminator characters
Receiver.xopenConfig.delim[0] = 0; // CR (Carriage Return)
Receiver.xopenConfig.delim[1] = 0; // LF (Line Feed)
Receiver.xopenConfig.tx_cnt = 2;   // Default number of buffers
Receiver.xopenConfig.rx_cnt = 2;   // Increase the number of buffers for reading
Receiver.xopenConfig.tx_len = 16;  // Optimize with a smaller buffer
Receiver.xopenConfig.rx_len = 16;  // Use a larger buffer for reading
Receiver.xopenConfig.argc = 0;     // Use additional arguments
Receiver.xopenConfig.argv = 0;

1 Like