[Date Prev][Date Next][Date Index]

Problems with motorRecord





Folks,

I have studied the OMS driver support code which is used by Tim Mooney's
motorRecord and I can see the problems with it, i.e. why it ties up the CPU
with polling.

Here is how is presently works:

- If there are any motors moving then motor_task() will call query_axis() at the
  polling interval.

- query_axis() calls set_status() which reads the position of the motor

- set_status() reads the position with the following code (for motors without
  encoders)
		send_mess(card,AXIS_INFO,oms_trans_axis[signal]);
		recv_mess(card,q_buf,2);

  This sends a message to the card requesting the position and then reads the
  response string back from the card.

- This is the critical code in send_mess()
	for(p=com;*p!='\0';p++)
	{
		trys=0;
		while( !(pmotor->status&STAT_TRANS_BUF_EMPTY) )
		{
			if(trys>MAX_COUNT)
			{
				Debug(1,'Time_out occured in send\n',0);
				trys=0;
			}
			if(pmotor->status&STAT_ERROR)
			{
				Debug(1,'error occured in send\n',0);
			}
			trys++;
		}
		pmotor->data=*p;
	}

    This code sits in a tight loop testing whether the board is ready to 
    receive another character, writes the characters to the board, and repeats
    until the string is done. This is how the old driver support for the
    steppermotorRecord also works, and Bob Delesio told me he tested it and the
    OMS board can accept the characters essentially as fast as they can be
    sent, so this code may be OK. It is worth verifying this.

- This is the critical code in recv_mess
		for(piece=0,trys=0;piece<3&amp;&amp;trys<MAX_COUNT;trys++)
		{
			if(pmotor->status&amp;STAT_INPUT_BUF_FULL)
			{
				c=pmotor->data;
				Debug(7,'%02x',c);

				switch(piece)
				{
				case 0: /* header */
					if(c=='\n'||c=='\r') head_size++;
					else
					{
						piece++;
						com[i++]=c;
					}
					break;
				case 1: /* body */
					if(c=='\n'||c=='\r')
					{
						piece++;
						tail_size++;
					}
					else com[i++]=c;
					break;
	
				case 2: /* trailer */
					tail_size++;
					if(tail_size>=head_size) piece++;
					break;

				}

				trys=0;
			}
		}

So this code also sits in a tight loop, waiting for the next character from
the board to become available and then reading it.  This is NOT the way the
stepperMotor record driver support worked. It was interrupt driven.

The problem is now clear:
    set_status() calls send_mess() and then recv_mess(). The CPU will be busy
    during the entire time from the start of sending a message until the
    complete reply is received. This includes the time for the OMS board to
    receive and decode the incoming message, and construct and transmit the
    response string. I would not be very surprised if it took 10 
    milliseconds for the OMS board to do this. If so, polling 5 motors at 10
    Hz would use 50% of the 68040 VME CPU.

    Clearly a better way to do this is to write an interrupt driven routine to
    read each character and to send a response message to a vxWorks message 
    queues) when the complete response from the OMS board has been received.
    set_status() would then just read the message queue with timeout. Note that
    this method will not tie up the 68040. Will it block further record
    processing?


Further performance gains can be realized by polling less frequently (5 Hz?),
but using the end-of-move interrupt to cause a poll to occur whenever a move
completes. This will dramatically reduce the latency for determining when a
move is complete.

____________________________________________________________
Mark Rivers                             (312) 702-2279 (office)
CARS                                    (312) 702-9951 (secretary)
Univ. of Chicago                        (312) 702-5454 (FAX)
5640 S. Ellis Ave.                      (708) 922-0499 (home)
Chicago, IL 60637                       rivers@bnlx26.nsls.bnl.gov (Internet)