Jump to content
babos

Delay Instruction Throught Novo Rtos

Recommended Posts

Sorry sir. a question:

 

During an instruction delay ("es delay_s(3)") Novo RTos polling other task or freeze his status ?

 

thank's

Babos

B)

Share this post


Link to post
Share on other sites

Hi Babos,

 

If your are using Novo RTOS why are you not using Sys_Sleep(x) ?

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites
Hi Babos,

 

If your are using Novo RTOS why are you not using Sys_Sleep(x) ?

 

Cheers

 

Reynard

 

because if I make that the compiler respond with "Error: Can't fit Avoid code boundary code in function:Sys_Yield : failure"

Share this post


Link to post
Share on other sites

Babos,

 

If you are using delay_s(3), then everything (except interrupts) stops for 3 seconds until the delay loop completes. This is not good for an RTOS.

 

Do you have a program space problem with your PIC ?

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

I a "module.c" I had write a subroutine tha referred to main flow as this :

 

// main module

//

#include <novocfg_pic18t6e4ts2.h>

#include <novo.h>

 

....

void pause(unsigned char t)

{

Sys_Sleep(t);

}

.... etc.....

 

// In linked module

//

extern void pause(void);

...

...

pause(t)

 

 

 

This work but I think not elegant..

Sorry for my language.

 

Hi,

Babos

Share this post


Link to post
Share on other sites

This is one way of reducing the number of yield points. Just make sure that only one task is calling the pause() function at any time.

 

Can you write your tasks so that they have a common exit (yield) point reducing the number of yield points.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

I think to have many memory in a 18F8722 but this drive other 4 PIC to move stepper motor. The true problem is this :

I've six task run, one of this is used to moving the four motor trought software SPI unidirectional string commands in a separate pin port.

The program wait "Sys_Sleep(1)" until the control pin (one for motors) indicates that ended his movement in this manner

// example for one motor
motor_move(_X,position,velocity);
while(!x_enable_motor)SysSleep(1);

the same for the Y, Z and R motors. There are several movements of the motors while, if i use this type of code, the compiler

send me the message "Error: Can't fit Avoid code boundary code in function:Sys_Yield"

I did so a single call for each motor

motor_move(_X_position,velocity);
wait_x();

In this manner the compiler say me "Serious Warning: Possible sw stack corruption, function:'wait_x' call".

however, seems to work but for some reason that I can not identify, after some time, seems (indeed do) that the program does not perform

some tasks while keeping active 's interrupt and as one of the tasks and communication with the serial port, remain screwed and I can not work anymore.

I state that I have not understand how to use semaphores or events that could perhaps useful to me.

Any suggestions? better go on horseback?

 

desperate househusband,

Babos.

 

p.s. David or Pavel, if I send you the code , can you take a look ?

Share this post


Link to post
Share on other sites
...

p.s. David or Pavel, if I send you the code , can you take a look ?

The linker serious warning is there because unless you take special precaution you have a chance of corruption, and that seems to be what you are experiencing.

 

If you post the code on the forum, then we all can take a look.

 

Regards

Dave

Share this post


Link to post
Share on other sites
...

p.s. David or Pavel, if I send you the code , can you take a look ?

The linker serious warning is there because unless you take special precaution you have a chance of corruption, and that seems to be what you are experiencing.

 

If you post the code on the forum, then we all can take a look.

 

Regards

Dave

 

I understood the problem but I do not know how to fix it.

I absolutely have to avoid the program remains in the task while waiting for an event it will push ahead.

This is a summary code:

//////////////////////////////////////////////
// Task that processes UART data
//////////////////////////////////////////////
void Task0()
{   
//This take will receive data
while( 1 )
{
	/*
	Wait for serial data to come. This is a blocking
	call that will yield if no data is available
	*/
	unsigned char data = Rx();

	if (rxTail == 4)
	{ 
		nchar = data + 1;		// acquire number of char(s) to read
	}
	//
	if((data == 0x1B) && (nchar == 0x00) ) // wait (esc)
		{	
			// Perform 8bits CRC from received command string
			unsigned char sum = 0;
			bit  crc = 0;	// Set result OK
			unsigned char count_crc = RxBuffer[3]+3;
			for(unsigned char  i=0;i<count_crc;i++)
			{
				sum = (sum + RxBuffer[i]) & 0xFF;
			}
			if(sum != RxBuffer[count_crc])crc = 1;
			switch (crc)
			{
				case 0:
   					// ACK
 					decode_string(); // Decode String from host
 					break;
 				case 1:
 					// NACK
 					send_nak(); // unknowing command or string, send NAK
 			}
			rxTail = 0;
			rxHead = 0;
		}
		nchar--;
}
}

/********************************************************************************/
//						Decoding command string from host						 /
/********************************************************************************/
void decode_string(void)
{
switch (RxBuffer[1])
{
	case 0x00:
		// Send Status IG26
		send_status();
		break;
			/* other CASE */
	// Retrieve parameters information for current analysis i or ii
	case 0xB0:
		// analysis i
		for(i=0;i<48;i++)
			i_analysis_buffer[i] = RxBuffer[i];	// populate parameters buffer i_analysis
		for(i=48;i<62;i++)	
			i_sequence_buffer[i-48] = RxBuffer[i]; // populate sequences buffer i_analysis
		i_start = 1;
		// sound advice 
		acoustic_signal = 0;		// start analysis
		acoustic_signal_start = 1;	// activation of sound
		send_status();
		break;
	case 0xB1:
		// analysis ii
		for(i=0;i<48;i++)
			ii_analysis_buffer[i] = RxBuffer[i];// populate parameters buffer ii_analysis
		for(i=48;i<62;i++)	
			ii_sequence_buffer[i-48] = RxBuffer[i];// populate sequences buffer ii_analysis
		ii_start = 1;
		// sound advice 
		acoustic_signal = 0;		// start analysis
		acoustic_signal_start = 1;	// activation of sound
		send_status();
		break;
}
_asm nop;
}

 

Now there are two task that performing the movement controls and sequence

//////////////////////////////////////////////
// Task Analysis Primary
//////////////////////////////////////////////
void Task1()
{
//
while( 1 )
{
	static unsigned char i_sscan = 0;
	if (i_start)		// Start primary analysis
	{
		flg_switch_analysis = 0;
		i_sequence = i_sequence_buffer[i_sscan];	// load current sequence
		if (i_sequence > 0)	// sequence not zero then perform analysis
		{
			// if the first time, before perform one empty treatment tank
			if(!first_time_analysis)empty_treatment_tank();
			_asm nop;
			switch (i_sequence)
			{
				case 1:
				// Application from parking
					movement = 3;
					while (movement>0)Sys_Sleep(1);
					break;
				case 2:
				// Migration from Application
					movement = 4;
					while (movement>0)Sys_Sleep(1);
					break;					
				case 4:
				// Denaturation from Migration
					movement = 5;
					while (movement>0)Sys_Sleep(1);
					break;
				/* OTHER CASE */						
			}
			i_sscan++;
		}
		else
		{
			i_start = 0;	// end analysis
		}
	}
	else
	{
		i_sequence = 0; // reset i_sequence variable
		purge_buffer(0); // clear session buffer
		i_sscan = 0;	// reset index for sequences buffer
	}
	//	
	Sys_Sleep( 1 );
}
}
//////////////////////////////////////////////
// Task Analysis Secondary
//////////////////////////////////////////////
void Task2()
{
//
while( 1 )
{
	static unsigned char ii_sscan = 0;
	if (ii_start)		// Start secondary analysis
	{
		flg_switch_analysis = 1;
		ii_sequence = ii_sequence_buffer[ii_sscan];	// load current sequence
		if (ii_sequence > 0)	// sequence not zero then perform analysis
		{
			// if the first time, before perform one empty treatment tank
			if(!first_time_analysis)empty_treatment_tank();
			_asm nop;
			switch (ii_sequence)
			{
				case 1:
				// Application from parking
					movement = 3;
					while (movement>0)Sys_Sleep(1);
					break;
				case 2:
				// Migration from Application
					movement = 4;
					while (movement>0)Sys_Sleep(1);
					break;					
				case 4:
				// Denaturation from Migration
					movement = 5;
					while (movement>0)Sys_Sleep(1);
					break;
				/* OTHER CASE */						
			}
			ii_sscan++;
		}
		else
		{
			ii_start = 0;	// end analysis
		}
	}
	else
	{
		ii_sequence = 0; // reset i_sequence variable
		purge_buffer(1); // clear session buffer
		ii_sscan = 0;	// reset index for sequences buffer
	}
	//	
	Sys_Sleep( 1 );
}
}

Now perform motor movement as is

//////////////////////////////////////////////
// i Motor Movement
//////////////////////////////////////////////
void Task3()
{ 
while( 1 )
{
	switch(movement)
	{
		case 3:
		/////////////////////////////////////////////////////////////////////////////////
		// Gel Holder Application from Parking
		/////////////////////////////////////////////////////////////////////////////////

			// Reset all Axis (security)
			motor_reset_all();
			if (!busy_migration_group)
			{
				busy_migration_group = 1;	// busy this group !!!
				if(!flg_switch_analysis)gelholder = i_cghld;else gelholder = ii_cghld;
				switch (gelholder - 1)
				{
					case 0:	
					// gelholder 1
					s = _X_GH_PARK1;
					break;
					case 1:
					// gelholder 2
					s = _X_GH_PARK2;
				}
				// Get gelholder from parking 1 or 2
				motor_move(_X,s,0);
				motor_move(_Y,_Y_GH_PARK,0);
				wait_y();
				wait_x();
				motor_move(_Z,_Z_GH_PARK,0);
				wait_z();
				// electromagnet activate
				set_aux(arm_magnet,1);
				Sys_Sleep(100);
				// rotor electromagnet deactivate
				set_aux(rot_magnet,0);
				motor_move(_R,_rot90,0);
				// move gelhoder to load zone
				motor_move(_Z,0,0);
				wait_z();
				motor_move(_X,_X_GH_LOAD,0);
				motor_move(_Y,_Y_GH_LOAD,0);
				wait_x();
				wait_y();
				motor_move(_Z,_Z_GH_LOAD,0);
				wait_z();
				// electromagnet deactivate
				set_aux(arm_magnet,0);
				// reset plotter
				motor_move(_Z,0,0);
				motor_move(_Y,0,0);
				motor_move(_X,0,0);
				motor_reset(_R);
				wait_x();
				wait_r();
				// rotor electromagnet activate
				set_aux(rot_magnet,1);
				// Vacuum pump activate
				if (!flg_switch_analysis)
					set_pump(vacuum,i_pvac,0);
				else
					set_pump(vacuum,ii_pvac,0);
				//
				// [...] test vacuum sensor
				//
				// Get_applicator
				if(!flg_switch_analysis)
				{
					n_applicator = i_apps & 0x1;
					n_applicator += i_apps>>1 & 0x01;
					n_applicator += i_apps>>2 & 0x01;
				}
				else 
				{
					n_applicator = ii_apps & 0x1;
					n_applicator += ii_apps>>1 & 0x01;
					n_applicator += ii_apps>>2 & 0x01;				
				}
				// calculate how much applicator used in current analysis
				// and deposite his samples in accord with number of application
				for(unsigned char i=0;i<n_applicator;i++)
				{
					switch (i)
					{
						case 0:
						// Applicator 1
							motor_move(_X,_X_APPL_PARK1,0);
							// sample 1/13
							d = _X_DRW_POS01;
							break;	
						case 1:
						// Applicator 2
							motor_move(_X,_X_APPL_PARK2,2); 
							// sample 14/26
							d = _X_DRW_POS14;
							break;
						case 2:
						// Applicator 3
							washing_app(0,0); // wash applicator in washing park 1
							motor_move(_X,_X_APPL_PARK3,2);
							// sample 27/39
							d = _X_DRW_POS27;
					}
					_asm nop;
					motor_move(_Y,_Y_APPL_PARK,0);
					wait_y();
					wait_x();
					motor_move(_Z,_Z_APPL_PARK,0);
					wait_z();
					// electromagnet activate
					set_aux(arm_magnet,1);
					Sys_Sleep(100);	
					//
					unsigned char n_appls = 0;
					if(!flg_switch_analysis)n_appls = i_napp;else n_appls = ii_napp;
					while(n_appls>0)
					{
						// start loop for number of application
						motor_move(_Z,_Z_DRW_TRAN,0);
						wait_z();
						motor_move(_Y,_Y_DRW_POS,0);
						motor_move(_X,d,0);
						wait_x();
						wait_y();
						for(unsigned char t=0;t<3;t++)
						{
							motor_move(_Z,_Z_DRW_POS,1);	// insert applicator in sample 3 times
							wait_z();
							motor_move(_Z,_Z_DRW_POS - _Z_DRW_ALT,1);
							wait_z();
						}
						motor_move(_Z,_Z_DRW_POS,1);
						wait_z();
						// in-sample time
						if(!flg_switch_analysis)
						{
							i_time = i_tcp;
							iTime = 1;
							while(iTime)Sys_Sleep(1);
							motor_move(_Z,_Z_DRW_POS - (_Z_DRW_ALT/2),i_vpc);	// out from sample at parameter "VCP"
							wait_z();
							motor_move(_Z,_Z_DRW_POS - _Z_DRW_ALT,0);			// the rest, at full velocity
							wait_z();
							_asm nop;
							// Move to application point
							switch(i)
							{
								case 0:
									// first application point
									motor_move(_X,_X_START_APP - i_pnt0,2);
								break;
								case 1:
									// second application point
									motor_move(_X,_X_START_APP - i_pnt1,2);
								break;
								case 2:
									// third application point
									motor_move(_X,_X_START_APP - i_pnt2,2);
							}
							// application on agarose gel
							motor_move(_Y,_Y_APP_POS,1);
							wait_y();
							wait_x();					// wait for previous movement
							motor_move(_Z,_Z_APP_POS,0);
							wait_z();
							// Time to wait in application "TAP"
							i_time = i_tap;
							iTime = 1;
							while(iTime)Sys_Sleep(1);
							// Up applicator
							motor_move(_Z,_Z_DRW_TRAN + (_Z_DRW_ALT/2),i_vrc); // velocity parameter "VRC"
							wait_z();
							motor_move(_Z,_Z_DRW_TRAN,0); 	 // the rest, at full velocity
							wait_z();
							// Time to wait after application "TADA"
							i_time = i_tada;
							iTime = 1;
							while(iTime)Sys_Sleep(1);

							_asm nop;
						}
						else
						{
							// Secondary analysis

						}
						// Applicator in washing parking
						// _X_APP_WASH_PARK_1
						// _X_APP_WASH_PARK_2 
						// _Y_APP_WASH_PARK   	
						// _Z_APP_WASH_PARK   
						// _Z_APP_WASH_TRAN 
						_asm nop;
						switch(i)
						{
							case 0:;case 2:
							// WASH PARK 1,default OR in the case m_appl [...]
							motor_move(_X,_X_APP_WASH_PARK_1,2);
							motor_move(_Y,_Y_APP_WASH_PARK,0);
							wait_x();
							wait_y();
							motor_move(_Z,_Z_APP_WASH_PARK - _Z_OFS_REL,1);
							wait_z();
							// electromagnet deactivate
							set_aux(arm_magnet,0);	
							motor_move(_Z,_Z_DRW_TRAN,0); 	 // release applicator
							wait_z();
							break;								
							case 1:
							// WASH PARK 2, 
							motor_move(_X,_X_APP_WASH_PARK_2,2);
							motor_move(_Y,_Y_APP_WASH_PARK,0);
							wait_x();
							wait_y();
							motor_move(_Z,_Z_APP_WASH_PARK - _Z_OFS_REL,1);
							wait_z();
							// electromagnet deactivate
							set_aux(arm_magnet,0);		// release applicator
							motor_move(_Z,_Z_DRW_TRAN,0); 	 
							wait_z();
						}

					n_appls--;
					_asm nop;
					// Stop loop for number of application	
					}	
				}
				movement = 0;
			}
			break;
		case 4:
		/////////////////////////////////////////////////////////////////////////////////
		// Migration from application
		/////////////////////////////////////////////////////////////////////////////////
			busy_migration_group = 1;	// busy this group !!!
			// Start Migration 
			motor_move(_R,_rot180,0);
			wait_r();
			// Start E.a.t. 
			eat_init();
			unsigned int v = 0;	 //voltage
			unsigned char e,p,st; // electrode, polarity
			if(!flg_switch_analysis){v = i_tcm; e = i_atec; p = i_apol;st = i_seat;}else{v = ii_tcm; e = ii_atec; p = ii_apol;st = ii_seat;} 
			eat_set(v,st,p,e);
			// Start Migration Time
			if(!flg_switch_analysis)
			{
				i_time = i_tmig*60;
				iTime = 1;
			}
			else
			{
				ii_time = ii_tmig*60;
				iiTime = 1;
			}					
			_asm nop;
			// Applicator washing
			switch (n_applicator)
			{ 
				case 3:
					washing_app(1,2);
					washing_app(0,1);
					break;
				case 2:
					washing_app(0,0);
					washing_app(1,1);
					break;
				case 1:
					washing_app(0,0);
			}
			motor_reset(_Z);
			motor_reset(_Y);
			motor_reset(_X);
			_asm nop;
			if(!flg_switch_analysis)
				{while(iTime)Sys_Sleep(10);}
			else 
				{while(iiTime)Sys_Sleep(10);}
			// Stop E.a.t.
			eat_init();
			// Positioning gel holder at ~100°
			bit skip_tada = 0;
			if(!flg_switch_analysis)
			{
				if(i_tada == 0)skip_tada = 1;
			}
			else
			{
				if(ii_tada == 0)skip_tada = 1;
			}
			if(!skip_tada)
			{
				motor_move(_R,2700,0);
				wait_r();
				// Wait drain pads
				if(!flg_switch_analysis)
				{
					i_time = i_tada;
					iTime = 1;
					while(iTime)Sys_Sleep(1);
				}
				else
				{
					ii_time = ii_tada;
					iiTime = 1;
					while(iiTime)Sys_Sleep(1);
				}
			}
			motor_reset(_R);
			wait_r();
			busy_migration_group = 0;
			movement = 0;
			 break;
	/*OTHER CASE*/								  
	}
	Sys_Sleep( 1 );
}
}

 

wait_x(); is a routine that wait pin event from other PIC that drive motors, equal to wait_y(), wait_z(), wait_r();

in the case of wait_x():

void wait_x()
{
while(!busy_motor_x)Sys_Sleep(1);
}

Furthermore, there are waiting times for certain sequences as above:

						i_time = i_tada;
					iTime = 1;
					while(iTime)Sys_Sleep(1);

this times are decremented in another task:

//////////////////////////////////////////////
// TASK perform ... Timeout
//////////////////////////////////////////////
void Task5()
{

//Update 
while( 1 )
{
				if( 999 == ++nDivider ) // Any seconds - Sys_Sleep(1) = 1millisecond
	{
		/**************************************/
		/* Time Handle for Sequences i and ii */
		/**************************************/
		// i
		if (iTime)if (i_time == 0) iTime = 0;else i_time --;
   }
	Sys_Sleep( 1 );
}
}

 

The problem is only this:

If I lunch only one analysis or sequence (i_sequence) all work fine and that's all right.

If I lunch the second analysis when the first is in progress, the buffer receive the right sequence but

unable to implement other movements of TASK3 because task3

waiting to finish a movement of the motor or get out of a time.

I need to execute a movement independent from the cycle of waiting.

I try to duplicate all movement for the secondary analysis in another task but

the compiler don't support many Sys_Sleep or Sys_Yield.

 

The same program work in a superloop with PicBasicPro but not elegant and whenever any change is there to go nuts.

I do not know if I explained well. is there a way out?

 

very thank's at all.

Babos

Share this post


Link to post
Share on other sites

Do you have a flow chart for what the program is trying to do? Understanding this code without your background in the problem is *difficult*.

 

So far I've gleaned that you have some sort of XYZ robot cell with a magnetic grab and auxiliary equipment including a vacuum pump, one or more washing stations, a treatment tank with automated emptying, three gel applicators and a loading station. You appear to be automating some repetitive laboratory analysis.

 

Looking at the code you have shown us, there are a few *easy* places to reduce the number of separate calls to Sys_xxxxx NOVO yielding functions.

 

In Task1 and Task2 move the repeated line:

while (movement>0)Sys_Sleep(1);

to after the end of the relevant switch (saves 4 yield points)

(If you *ever* need to add a case that needs to exit with movement non zero, you can and a flag with the while condition to skip the sleep. Set it before the switch and clear it in cases that need immediate exit)

 

In Task3 its more difficult...

 

There are 10 calls to Sys_Sleep() and 36 wait_n() calls where wait_n is wait_x, wait_y, wait_z or wait_r. That's at least 14 yield points as I suspect you may have some more in the subroutines you haven't shown us. I guess you had over 46 yield points before you tried to put the wait_n() ones in separate functions.

 

It is STRICTLY ILLEGAL in NOVO RTOS to call any function containing a yield point when another task has called it and hasn't returned yet. This is the cause of your crashes. The warning you had is given whenever the compiler detects more than one task can call the same function containing a yield point. Its a warning not an error because you CAN wrap every call to the function with special code so that only one task at a time can actually call it. That's only for *extreme* experts as it is *FAR* too easy to end up with a deadlock or worse!

 

For your code, you *MUST* have one set of duplicated wait_n() functions for each task that calls them, eg. for Task3 you would have T3wait_x() ... T3wait_r(). Then when you create another secondary analysis task Task4 you will have T4wait_x() ... T4wait_r(). The same will apply to any other function containing a Sys_xxxxxx() call that you use in more than one task.

 

From what I have seen of the code, you need to move to a particular (X,Y) position. then move Z then perform some action. You never perform any actions during an (X,Y) movement. Therefore you can 'fold' wait_x(),wait_y(),wait_z() into a single function T3wait_xyz() saving 2 yield points:

void T3wait_xyz()
{
while(!busy_motor_x && !busy_motor_y && !busy_motor_z) Sys_Sleep(1);
}

You will still need a separate T3wait_r() function. (Unless you *never* rotate(?) during an (X,Y,Z) movement which would let you add '&& !busy_motor_r' to the while condition.)

 

You could write a function to replace the 10 Sys_Sleep() calls in Task3() to save 9 yield points:

void T3sleep(TICK_COUNT sleepTime)
{
 Sys_Sleep(sleepTime);
}

If you use it from any of the T3xxxx functions it would take more SWCS space as that would be an extra level of nesting. As the wait_n() functions already wrap Sys_Sleep(), SWCS usage should remain about the same.

 

You can save 4 yield points in tasks 1 and 2 and 11 in Task 3. That *should* allow you enough to create the Task4 you wanted.

 

Good luck, you are going to need it . . . .

I am *NOT* a NOVO RTOS expert so I may have made some critical mistakes above. Please check my advice by reading the NOVO manual and keep a backup of your code before you start changing it.

Edited by IanM

Share this post


Link to post
Share on other sites
Do you have a flow chart for what the program is trying to do? Understanding this code without your background in the problem is *difficult*.

 

So far I've gleaned that you have some sort of XYZ robot cell with a magnetic grab and auxiliary equipment including a vacuum pump, one or more washing stations, a treatment tank with automated emptying, three gel applicators and a loading station. You appear to be automating some repetitive laboratory analysis.

 

Looking at the code you have shown us, there are a few *easy* places to reduce the number of separate calls to Sys_xxxxx NOVO yielding functions.

 

In Task1 and Task2 move the repeated line:

while (movement>0)Sys_Sleep(1);

to after the end of the relevant switch (saves 4 yield points)

(If you *ever* need to add a case that needs to exit with movement non zero, you can and a flag with the while condition to skip the sleep. Set it before the switch and clear it in cases that need immediate exit)

 

In Task3 its more difficult...

 

There are 10 calls to Sys_Sleep() and 36 wait_n() calls where wait_n is wait_x, wait_y, wait_z or wait_r. That's at least 14 yield points as I suspect you may have some more in the subroutines you haven't shown us. I guess you had over 46 yield points before you tried to put the wait_n() ones in separate functions.

 

It is STRICTLY ILLEGAL in NOVO RTOS to call any function containing a yield point when another task has called it and hasn't returned yet. This is the cause of your crashes. The warning you had is given whenever the compiler detects more than one task can call the same function containing a yield point. Its a warning not an error because you CAN wrap every call to the function with special code so that only one task at a time can actually call it. That's only for *extreme* experts as it is *FAR* too easy to end up with a deadlock or worse!

 

For your code, you *MUST* have one set of duplicated wait_n() functions for each task that calls them, eg. for Task3 you would have T3wait_x() ... T3wait_r(). Then when you create another secondary analysis task Task4 you will have T4wait_x() ... T4wait_r(). The same will apply to any other function containing a Sys_xxxxxx() call that you use in more than one task.

 

From what I have seen of the code, you need to move to a particular (X,Y) position. then move Z then perform some action. You never perform any actions during an (X,Y) movement. Therefore you can 'fold' wait_x(),wait_y(),wait_z() into a single function T3wait_xyz() saving 2 yield points:

void T3wait_xyz()
{
while(!busy_motor_x && !busy_motor_y && !busy_motor_z) Sys_Sleep(1);
}

You will still need a separate T3wait_r() function. (Unless you *never* rotate(?) during an (X,Y,Z) movement which would let you add '&& !busy_motor_r' to the while condition.)

 

You could write a function to replace the 10 Sys_Sleep() calls in Task3() to save 9 yield points:

void T3sleep(TICK_COUNT sleepTime)
{
 Sys_Sleep(sleepTime);
}

If you use it from any of the T3xxxx functions it would take more SWCS space as that would be an extra level of nesting. As the wait_n() functions already wrap Sys_Sleep(), SWCS usage should remain about the same.

 

You can save 4 yield points in tasks 1 and 2 and 11 in Task 3. That *should* allow you enough to create the Task4 you wanted.

 

Good luck, you are going to need it . . . .

I am *NOT* a NOVO RTOS expert so I may have made some critical mistakes above. Please check my advice by reading the NOVO manual and keep a backup of your code before you start changing it.

 

 

Ok. IanM I try to save all possible yield point , thank's, Babos

Share this post


Link to post
Share on other sites

I think that even with a duplicate secondary analysis task as Task4, you will have problems. It will be possible to write it so it compiles without any warnings or errors, but you are going to have to master semaphores as from the moment your arm moves down and activates its grab till it has transported the object to its destination and released it and returned to an up position, it must be exclusively reserved by one task. It makes no sense for the other task to tell it to go somewhere else if it is already holding something. Until the arm is free, the other task must block. To avoid contention each task will probably need to reserve the arm from the start of the (X,Y) movement with the grab empty to the position the grab will be activated in.

 

You will probably also need some sort of reservation system. If there is a 10 second duration arm sequence that *must* occur in 35 seconds, then it is no good starting a 40 second sequence in the other task.

 

It may be easier if you write a single arm control task that each analysis task passes a command list giving actions, positions and delays. Once the arm has a command list, it performs them in a single continuous sequence, queuing other requests till its done.

 

It would help us advise you if you listed the steps and delay times in between with maximum and minimum durations to manually process a single sample and indicated which steps are 'bulk' actions that apply to all the samples at once and which are individual for each sample.

 

Lastly, if you quote me or anyone else just to add "OK ... Thanks", the topic gets full of repeated stuff and is much harder to read. PLEASE edit out any part of the quote you don't actually need to ask questions about or add something to. It is often helpful to indicate where you remove stuff by putting '...' and of course you shouldn't alter the meaning of someone else's words. If you use the 'add reply' button instead of the ' " reply' button on the individual post, it doesn't give you the quote in the first place. You could use '+edit' NOW to go back and delete everything from

where you quoted me unnecessarily. The thanks are appreciated however.

Share this post


Link to post
Share on other sites

Sorry IanM,

if I try to regroup Sys_Sleep like you suggested, I get a compiler error which does not have sufficient resources.

but I made some progress.

for example I've modified this task without Sys_Sleep, because not necessary.

//////////////////////////////////////////////
// Task Analysis Primary
//////////////////////////////////////////////
void Task1()
{
//Update 
while( 1 )
{
	if (i_start)		// Start primary analysis
	{
		flg_switch_analysis = 0;
		i_sequence = i_sequence_buffer[i_sscan];	// load current sequence
		if (i_sequence > 0)	// sequence not zero then perform analysis
		{
			// if the first time, before perform one empty treatment tank
			if(!first_time_analysis)empty_treatment_tank();
			_asm nop;
			switch (i_sequence)
			{
				case 1:
				// Application from parking
					movement = 3;
					while (movement>0)goto exit1;
					break;
				case 2:
				// Migration from Application
					movement = 4;
					while (movement>0)goto exit1;
					break;					
				case 4:
				// Denaturation from Migration
					movement = 5;
					while (movement>0)goto exit1;
					break;
				case 6:
				// Staining from denaturation
					movement = 6;
					while (movement>0)goto exit1;
					break;
				case 7:
				// Destaining from Staining
					movement = 7;
					while (movement>0)goto exit1;
					break;	
				case 8:
				// Destaining from destain
					movement = 8;
					while (movement>0)goto exit1;
					break;
				case 10:
				// Drying from destain/wash
					movement = 10;
					while (movement>0)goto exit1;
					break;
				case 11:
				// Scan from drying
					movement = 11;
					while (movement>0)goto exit1;
					break;	
				case 30:
				// Scan from drying
					movement = 30;
					while (movement>0)goto exit1;
					break;											
			}
		}
		else
		{
			i_start = 0;	// end analysis
		}
	}
	else
	{
		i_sequence = 0; // reset i_sequence variable
		purge_buffer(0); // clear session buffer
		i_sscan = 0;	// reset index for sequences buffer
	}
exit1:
	//	
	Sys_Sleep( 1 );
}
}

well now I try to replicate an analysis secondary in another task but I think that the resources are few.

Let you know. Regards.

Share this post


Link to post
Share on other sites

in fact I can avoid Sys_Sleep engines, waiting to do their movements and with a simple "while (! motor_busy);" but the computer requires the machine status every 500ms;during which I was lacking.

Share this post


Link to post
Share on other sites
in fact I can avoid Sys_Sleep engines, waiting to do their movements and with a simple "while (! motor_busy);"...

Yes you mentioned you had it working in Basic as a superloop.

... but the computer requires the machine status every 500ms;during which I was lacking.

*HOW* does the PIC report to the computer? It *may* be possible to put the reporting in an interrupt routine and avoid the need for NOVO at all!

What's the interface and the message format?

Share this post


Link to post
Share on other sites
in fact I can avoid Sys_Sleep engines, waiting to do their movements and with a simple "while (! motor_busy);"...

Yes you mentioned you had it working in Basic as a superloop.

... but the computer requires the machine status every 500ms;during which I was lacking.

*HOW* does the PIC report to the computer? It *may* be possible to put the reporting in an interrupt routine and avoid the need for NOVO at all!

What's the interface and the message format?

pic transmint a status of 64 byte @115200b/s any 250/500ms

Share this post


Link to post
Share on other sites

OK, a 64 byte status block is a little bigger than I had hoped.

 

It's still doable. The problem is:

Use a timer or trigger off any RTC code to: Every 500 ms (or a little bit sooner - you said 250 ms was the MINIMUM interval) call a Message init routine that reset a message counter and transmits the first character.

Then when the TXIF interrupt happens and the message counter is under 64, either read from a buffer or calculate on the fly the next byte of the message. transmit it and increment the counter.

 

If you are using a buffer, it gets filled from your status variables in the message init routine. If you are calculating the message the variables are copied in the init routine so you dont change messages half way.

 

The *other* approach if you haven't finalised your hardware is to stick in the serial line back to the PC something like a PIC16F88 to buffer the message and re-transmit it until it either gets a new one or a hardware error signal on one of it's spare pins. If this is a one-off or limited series production the cost of an extra PIC is negligible compared to the development time. You would need to double buffer the message. i.e. transmit from one buffer while receiving in the other. When transmit finishes, swap to the other buffer if its complete.

Share this post


Link to post
Share on other sites

The problem remain.

when I have few Sys_Sleep to wait an event as

// motor move
motor_move(_X,position,velocity);
// wait end of movement for motor X
while(!x_busy)Sys_Sleep(1);

During this wait, the processor send his status to serial port, fill the treatment tank, decrement any elapsed time for process. I can't block these flows

All work fine but not is possible increment Sys_Sleep infinity and, in my program, there are many calls to the motors.

we need an alternative to handle this problem, use other tasks, use semaphores or some other devilish otherwise be forced to return to superloop and I would not.

I need a council resolution, and I thank those who cooperated and who gives me any other one.

 

Babos

Share this post


Link to post
Share on other sites
we need an alternative to handle this problem, use other tasks, use semaphores or some other devilish otherwise be forced to return to superloop and I would not.

I need a council resolution, and I thank those who cooperated and who gives me any other one.

 

Babos

 

 

It may well be possible to redesign the analysis task so it can handle multiple samples in parallel and write a motor control task that runs a tight control loop that executes high level commands passed to it in a buffer by the analysis task, which would reduce your need for separate yield points or there may be another approach to simplifying the program till it fits OR it *might* be the case that your total project is just too big for the PIC18 you are using.

 

You are the only person here who has the overall picture. Without a clear description of the whole process we are not able to give you good advice.

If the process is confidential, then do not tell us *WHAT* it does, but just the steps it takes to do it. e.g.

 

1 take sample

2 immerse in reagent A for 3 minutes

3 drain for 30 seconds

4 apply gel reagent B

5 dry for 10 minutes *

6 immerse and agitate in reagent C for 70 seconds

7 drain for 5 seconds

8 rinse for 3 minutes

9 drain for 30 seconds

10 dry for 5 minutes. *

* indicates the arm is free for other duties

 

We would also need to know which steps are time critical and must be exactly as specified and which can be delayed and for how long. (e.g. step 3: can we drain for longer while applying reagent B (step 4) to another sample?)

 

If you *still* have confidentiality problems, add a couple of dummy steps and dummy reagents you can remove later and multiply or divide all the times that you give us by the same factor. Even if someone was able to trace you back to your company (unlikely), without knowing what the process is for, genuine timings, stages and reagents, the information you give us would be of no use to a competitor

 

We would also need to know something about the physical handling of the samples. Are they in separate containers or are they in wells in a single sample plate? This affects which steps *have* to be done for all samples simultaneously and which steps leave the arm free to do something else, which also depends on if the arm has to hold the sample in the tank or whether it locks into place freeing the arm. In between the steps there may be extra processes like applicator filling and cleaning and tank emptying but they can be fitted in more easily once we have the general picture.

 

If it is *NOT* confidential, can you direct us to any internet resources describing the process?

 

I know you have a lot of work invested in this project as it is nearly a year since your first NOVO question here and you probably do not want to be forced into a major redesign at this stage . . .

 

It is really up to you how much you allow us to help you . . .

 

Best wishes

 

Ian M.

Share this post


Link to post
Share on other sites

The biggest problem is that I can not speak well's English.I try to explain:

 

* equipment has more groups: washing, serum application, drying, treatment tank, ecc.

* The motors are used to move on accessories for various groups' analysis.

* From computer via USB port sending the parameters that I need for a specific method

* Send also (every 500ms) a request to state that allows me to display temperature, time in progression, etc.

* Together with the parameters of methods, including sending the sequences of movements of the motors.

* equipment is started and I could also disconnect the USB because the process can be completed alone, but I need to display as I explained the state.

* Not only that, there are methods that require outside processing then, the machine is retired, the signals and allows you to restart the method after performing the external work manual.

* The various groups of markers (flags) that alert you if they are busy. This is because I can send a 'parallel other analysis and sharing groups with different sequences. Maximum of two simultaneously.

* If the second analysis, must use a group busy, waiting for free.

* Like I said, the device functions as two years without major problems but uses superloop written PicBasicPro and most of the work is done during 'single Timer1 interrupt

 

A typical flow for a single analysis could be this:

 

1) Send the parameters for analysis and the sequence of executing via USB.

2) the equipment send me an acoustic signal that advice me wich is in start.

3) The plotter X,Y,Z gets a support and move this in a washin tank for (es. 3 minutes)

4) During this time moves to do other tasks meanwhile sends me the state with the time spent washing, the temperatures of the liquid, etc.

5) Continues to support other groups of workers through the plotter.

6) If I wanted to send another way I could do it because the group was released after 3 minutes of washing.

7) ... ...

 

 

I practically two buffers where to send the analysis parameters and sequences to be carried.

4 motors to move (one-way communication) command telling them where to go and at what speed.

That's where the problem arises!!For example, I have to wait for X to finish the movement, before launching Y or Z, and use a pin that I got up to a high level when the engine started has finished processing the motion.During the waiting however, I still perform other tasks and this, with novo, I can not do.

 

If I use

 while(busy_x_motor);

other tasks are blocked waiting to exit the loop

 

if I use

 while(busy_x_motor)Sys_Sleep(1);

all work, but adding movements also group calls Sys_Sleep, the compiler will not let me because it exceeds its parameters.If it solves this problem , I solved everything.

 

I hope that I explained sufficiently

 

The mcu is PIC18F8722. isn't enoght?

Share this post


Link to post
Share on other sites

Your English is far better than my non-existant Italian. It would be as much as I could do to manage "Quanto è il costo?" in a shop and I'd need the answer written in numbers! ;-(

 

If you are not certain of the English for a phrase or word, put what you think is correct but also put the Italian in brackets so we can look up your word.

 

I still think your problem is mostly due to having the Task3 'i Motor Movement' task controlling the motors individually in so many places and performing all the parts of one of your numbered movements in a single pass through its outer loop. This means it needs to yield in too many places for NOVO to fit the task switching code in one page. I suspect if you redesigned this task so it does only a small part of the movement in each pass, it would work better.

 

You would need another variable to track which stage of the current movement you have reached and put the stages for each movement in a switch so that it skips the stages already done and the ones that are in the future. Near the end of the Task3 main loop you would have a single Sys_Sleep in a while loop testing the motor running flags you have specified earlier so it does not carry on until the current stage is finished. This should keep the system responsive and let all other tasks run often enough.

 

It would be helpful if you could show us ALL your C program code for this project and the working superloop code you have written in PicBasicPro which would help us understand how the C is meant to work.

 

Ian

Edited by IanM

Share this post


Link to post
Share on other sites
Your English is far better than my non-existant Italian. It would be as much as I could do to manage "Quanto è il costo?" in a shop and I'd need the answer written in numbers! ;-(

 

If you are not certain of the English for a phrase or word, put what you think is correct but also put the Italian in brackets so we can look up your word.

 

I still think your problem is mostly due to having the Task3 'i Motor Movement' task controlling the motors individually in so many places and performing all the parts of one of your numbered movements in a single pass through its outer loop. This means it needs to yield in too many places for NOVO to fit the task switching code in one page. I suspect if you redesigned this task so it does only a small part of the movement in each pass, it would work better.

 

You would need another variable to track which stage of the current movement you have reached and put the stages for each movement in a switch so that it skips the stages already done and the ones that are in the future. Near the end of the Task3 main loop you would have a single Sys_Sleep in a while loop testing the motor running flags you have specified earlier so it does not carry on until the current stage is finished. This should keep the system responsive and let all other tasks run often enough.

 

It would be helpful if you could show us ALL your C program code for this project and the working superloop code you have written in PicBasicPro which would help us understand how the C is meant to work.

 

Ian

 

the source is for commercial use, dear Ian;

I have some security that is not made public? And if so, where it posted?

Thanks for everything.

Share this post


Link to post
Share on other sites
It would be helpful if you could show us ALL your C program code for this project and the working superloop code you have written in PicBasicPro which would help us understand how the C is meant to work.

 

Ian

 

the source is for commercial use, dear Ian;

I have some security that is not made public? And if so, where it posted?

Thanks for everything.

 

In which case it would be unwise to discuss it in more detail or show any more of it to anyone unless you have them under contract with a signed non-disclosure agreement. Before you do that, you would of course need to see that they had done a realtime project of a similar size to your own. I am just a hobby user and am NOT the right person if you need someone under contract.

 

You might be able to tell us how many lines of code you have, the number of Sys_xxxxx functions your code has in total, and maybe show us the call tree annotated with the number of bytes of variables and yield points per function without compromising confidentiality. That might give one of the experts here

enough information to tell you if your project is too big for NOVO on a PIC18F8722.

 

Finally have you built a custom version of NOVO yet? If not, I presume you are using 'novolib_pic18t6e4ts2.lib' which supports 4 events (semaphores). I understand you are not yet using semaphores and if you have fewer than 6 tasks as well, *maybe* you could save enough resources if you were to build, for example, 'novolib_pic18t5e2ts2.lib'.

 

I am sorry I don't have any other suggestions to help you.

 

Ian M.

Share this post


Link to post
Share on other sites
It would be helpful if you could show us ALL your C program code for this project and the working superloop code you have written in PicBasicPro which would help us understand how the C is meant to work.

 

Ian

 

the source is for commercial use, dear Ian;

I have some security that is not made public? And if so, where it posted?

Thanks for everything.

 

In which case it would be unwise to discuss it in more detail or show any more of it to anyone unless you have them under contract with a signed non-disclosure agreement. Before you do that, you would of course need to see that they had done a realtime project of a similar size to your own. I am just a hobby user and am NOT the right person if you need someone under contract.

 

You might be able to tell us how many lines of code you have, the number of Sys_xxxxx functions your code has in total, and maybe show us the call tree annotated with the number of bytes of variables and yield points per function without compromising confidentiality. That might give one of the experts here

enough information to tell you if your project is too big for NOVO on a PIC18F8722.

 

Finally have you built a custom version of NOVO yet? If not, I presume you are using 'novolib_pic18t6e4ts2.lib' which supports 4 events (semaphores). I understand you are not yet using semaphores and if you have fewer than 6 tasks as well, *maybe* you could save enough resources if you were to build, for example, 'novolib_pic18t5e2ts2.lib'.

 

I am sorry I don't have any other suggestions to help you.

 

Ian M.

I'll let you know how it ends. For now, a big thanks.

Share this post


Link to post
Share on other sites
Your English is far better than my non-existant Italian. It would be as much as I could do to manage "Quanto è il costo?" in a shop and I'd need the answer written in numbers! ;-(

 

If you are not certain of the English for a phrase or word, put what you think is correct but also put the Italian in brackets so we can look up your word.

 

I still think your problem is mostly due to having the Task3 'i Motor Movement' task controlling the motors individually in so many places and performing all the parts of one of your numbered movements in a single pass through its outer loop. This means it needs to yield in too many places for NOVO to fit the task switching code in one page. I suspect if you redesigned this task so it does only a small part of the movement in each pass, it would work better.

 

You would need another variable to track which stage of the current movement you have reached and put the stages for each movement in a switch so that it skips the stages already done and the ones that are in the future. Near the end of the Task3 main loop you would have a single Sys_Sleep in a while loop testing the motor running flags you have specified earlier so it does not carry on until the current stage is finished. This should keep the system responsive and let all other tasks run often enough.

 

It would be helpful if you could show us ALL your C program code for this project and the working superloop code you have written in PicBasicPro which would help us understand how the C is meant to work.

 

Ian

 

Ian wrote:

"You would need another variable to track which stage of the current movement you have reached and put the stages for each movement in a switch so that it skips the stages already done and the ones that are in the future. Near the end of the Task3 main loop you would have a single Sys_Sleep in a while loop testing the motor running flags you have specified earlier so it does not carry on until the current stage is finished. This should keep the system responsive and let all other tasks run often enough."

 

Can you explain with an example the above concept ?

regards,

Babos.

Share this post


Link to post
Share on other sites

....

You would need another variable to track which stage of the current movement you have reached and put the stages for each movement in a switch so that it skips the stages already done and the ones that are in the future. Near the end of the Task3 main loop you would have a single Sys_Sleep in a while loop testing the motor running flags you have specified earlier so it does not carry on until the current stage is finished. This should keep the system responsive and let all other tasks run often enough."

 

Can you explain with an example the above concept ?

regards,

Babos.

Possibly. However I will have to write it all from a blank sheet to a finished, built and tested program if I am to be certain it works. I am not charging for my time (nor would I want to) so the example project must interest, entertain and educate me or I will not do it. I am away for a few days and if I can think of an idea I like that needs this level of complexity, I will start work on it, but no promises.

 

To modify your code you have shown us to make an example would be non trivial and I would not be able to run it without either the rest of the project and its hardware or a software test harness controlled by a script on a PC. I do not like posting bad code here, and I would not like to spend hours working on code I couldn't test.

 

If I may tell you a little story, you may understand me better:

 

Many years ago, just out of University, I was given a contract to rewrite a PC based medical instrument display. After some weeks I came to the conclusion that salvaging the display routine was impossible in the time available and I would need to rewrite it. It had to scroll a trace smoothly while displaying various cursor lines and timing marks on it.

 

8 weeks in, I had a prototype I was happy with and my boss took the demo to his boss. Unfortunately I was developing on a 286 PC with Hercules Mono graphics and the head of department had a 386 with an EGA card that his secretary used for word-processing and he only used to play cards on at lunchtime. I had auto detected the graphics correctly and my demo ran on the EGA, but it was compiled for a 286 and with three colour bit planes to scroll, it couldn't keep up, and worse, the graphics library did not interleave the scrolling, but scrolled R then G then B.

 

The result was a rainbow coloured mush on the screen instead of a nice sharp trace and an error after a few seconds when my code detected it could not maintain a realtime display. The head of department was NOT happy.

 

About a fortnight later, I was ready for another demo. My boss had given me access after hours to his machine for testing and I had built seperate 286 and 386 versions. All worked well, scrolled smoothly and kept up with realtime. My boss said 'I like the green trace." and I replied "Yes, it looks better than red or blue.". He asked me why red or blue and I explained that I could only scroll ONE colour smoothly in the time available :-). The horizontal cursors could be multicoloured as they did not have to scroll but all moving time marks had to be dotted green . . . The boss couldn't stop laughing. We took it to the head of department and the demo was successful. Our team went to the bar afterwards and I spent the last couple of weeks tidying up the documentation and packaging the code for the research team to hook up to.

 

That was two weeks of 16 to 18 hour days of coding grief just because the secretary had a better PC than the programmer or any of the engineers. Afterwards, it took about a month for my health to recover and I vowed I'd never take another contract that was mainly software development.

 

I have a couple of personal projects I have been putting off all summer with the intention of doing them this winter. One is generating a compensated pulse train from a sensor that is non-linear. It will involve sampling the incoming pulse and generating the same waveform at a different frequency with the ratio adjusted slightly by number of other external factors AND a correction derived from the period of the original waveform. Owing to the speed of the pulse train, this is going to be interrupt driven hard realtime stuff possibly with external hardware assistance for the waveform generation.

 

The other is instrumentation, fault monitoring and data logging for an engine. It will probably fit fairly well with NOVO in a 16F887 or maybe I'll have to go PIC18. I don't think it will have anywhere near the complexity of your project even if I put in all the performance monitoring and data collection I can think of. If I wanted to add a realtime PC USB interface, it *might* come close, but I think I'd be more likely to break it up into separate logger and measurement / UI processors communicating serially and a RS232 link to the PC.

 

I also have a lot of database and web stuff to do for work and as a volunteer

 

Please don't wait for me to come up with an example. If I start work on something that uses the technique I suggested I will send you a PM. Meanwhile, best wishes and good luck . . .

 

Yours Sincerely

 

Ian M.

Share this post


Link to post
Share on other sites

....

You would need another variable to track which stage of the current movement you have reached and put the stages for each movement in a switch so that it skips the stages already done and the ones that are in the future. Near the end of the Task3 main loop you would have a single Sys_Sleep in a while loop testing the motor running flags you have specified earlier so it does not carry on until the current stage is finished. This should keep the system responsive and let all other tasks run often enough."

 

Can you explain with an example the above concept ?

regards,

Babos.

Possibly. However I will have to write it all from a blank sheet to a finished, built and tested program if I am to be certain it works. I am not charging for my time (nor would I want to) so the example project must interest, entertain and educate me or I will not do it. I am away for a few days and if I can think of an idea I like that needs this level of complexity, I will start work on it, but no promises.

 

To modify your code you have shown us to make an example would be non trivial and I would not be able to run it without either the rest of the project and its hardware or a software test harness controlled by a script on a PC. I do not like posting bad code here, and I would not like to spend hours working on code I couldn't test.

 

If I may tell you a little story, you may understand me better:

 

Many years ago, just out of University, I was given a contract to rewrite a PC based medical instrument display. After some weeks I came to the conclusion that salvaging the display routine was impossible in the time available and I would need to rewrite it. It had to scroll a trace smoothly while displaying various cursor lines and timing marks on it.

 

8 weeks in, I had a prototype I was happy with and my boss took the demo to his boss. Unfortunately I was developing on a 286 PC with Hercules Mono graphics and the head of department had a 386 with an EGA card that his secretary used for word-processing and he only used to play cards on at lunchtime. I had auto detected the graphics correctly and my demo ran on the EGA, but it was compiled for a 286 and with three colour bit planes to scroll, it couldn't keep up, and worse, the graphics library did not interleave the scrolling, but scrolled R then G then B.

 

The result was a rainbow coloured mush on the screen instead of a nice sharp trace and an error after a few seconds when my code detected it could not maintain a realtime display. The head of department was NOT happy.

 

About a fortnight later, I was ready for another demo. My boss had given me access after hours to his machine for testing and I had built seperate 286 and 386 versions. All worked well, scrolled smoothly and kept up with realtime. My boss said 'I like the green trace." and I replied "Yes, it looks better than red or blue.". He asked me why red or blue and I explained that I could only scroll ONE colour smoothly in the time available :-). The horizontal cursors could be multicoloured as they did not have to scroll but all moving time marks had to be dotted green . . . The boss couldn't stop laughing. We took it to the head of department and the demo was successful. Our team went to the bar afterwards and I spent the last couple of weeks tidying up the documentation and packaging the code for the research team to hook up to.

 

That was two weeks of 16 to 18 hour days of coding grief just because the secretary had a better PC than the programmer or any of the engineers. Afterwards, it took about a month for my health to recover and I vowed I'd never take another contract that was mainly software development.

 

I have a couple of personal projects I have been putting off all summer with the intention of doing them this winter. One is generating a compensated pulse train from a sensor that is non-linear. It will involve sampling the incoming pulse and generating the same waveform at a different frequency with the ratio adjusted slightly by number of other external factors AND a correction derived from the period of the original waveform. Owing to the speed of the pulse train, this is going to be interrupt driven hard realtime stuff possibly with external hardware assistance for the waveform generation.

 

The other is instrumentation, fault monitoring and data logging for an engine. It will probably fit fairly well with NOVO in a 16F887 or maybe I'll have to go PIC18. I don't think it will have anywhere near the complexity of your project even if I put in all the performance monitoring and data collection I can think of. If I wanted to add a realtime PC USB interface, it *might* come close, but I think I'd be more likely to break it up into separate logger and measurement / UI processors communicating serially and a RS232 link to the PC.

 

I also have a lot of database and web stuff to do for work and as a volunteer

 

Please don't wait for me to come up with an example. If I start work on something that uses the technique I suggested I will send you a PM. Meanwhile, best wishes and good luck . . .

 

Yours Sincerely

 

Ian M.

 

 

apologize if I've had you to be dried in the last email you sent me but it was not my intention.

However I solved the problem and wanted to show you how, if you like:

			/////////////////////////////////////////////////////////////////////////////////
		// Gel Holder Application from Parking
		/////////////////////////////////////////////////////////////////////////////////
			if (ii_busy_migration_group)break; // if ii_analysis is in migration group, wait 
			i_busy_migration_group = 1; // busy migration group
			switch(i_reg_step_sequence) // remember what precedent step
			{
				case 0:
					// Start sequence
					gelholder = i_cghld;								// get selected gel holder
					if (gelholder = 1)s=_X_GH_PARK1;else s=_X_GH_PARK2;	// set it position
					motor_move(_X,s,0);									// get gel holder form parking
					motor_move(_Y,_Y_GH_PARK,0);	 					//  "   "	"	  "	 "
					i_reg_step_sequence++;break;	 					// increment for next step
				case 1:													// step 1
					if(!busy_y)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 2:													// step 2
					if(!busy_x)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 3:													// step 3
					motor_move(_Z,_Z_GH_PARK,0);	 					// move z in position for bring frame
					i_reg_step_sequence++;break;						// increment for next step
				case 4:													// step 4
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 5:													// step 5
					set_aux(arm_magnet,1);								// activate arm electromagnet
					Sys_Sleep(100);										// pause 100ms
					set_aux(rot_magnet,0);								// deactivate rotor electromagnet
					Sys_Sleep(100);										// stabilization
					motor_move(_R,_rot90,0);							// move rotor il load position
					motor_move(_Z,0,0);									// set z position to up frame
					i_reg_step_sequence++;break;						// increment for next step
				case 6:													// step 6
					if(!busy_z)break;									// if morot busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 7:													// step 7
					motor_move(_X,_X_GH_LOAD,0);						// move x to load frame 
					motor_move(_Y,_Y_GH_LOAD,0);						// move y to load frame
					i_reg_step_sequence++;break;						// increment for next step
				case 8:													// step 8
					if(!busy_x)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 9:													// step 9
					if(!busy_y)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 10:												// step 10	
					motor_move(_Z,_Z_GH_LOAD,0);						// move to release frame
					i_reg_step_sequence++;break;						// increment for next step
				case 11:												// step 11
					if(!busy_z)break;									// if morot busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 12:												// step 12
					set_aux(arm_magnet,0);								// deactivate arm magnet
					motor_move(_Z,0,0);									// home motor z
					motor_move(_Y,0,0);									// home motor y
					motor_move(_X,0,0);									// home motor x
					motor_reset(_R);									// reset rotor motor
					i_reg_step_sequence++;break;						// increment for next step
				case 13:												// step 13
					if(!busy_x)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 14:												// step 14
					if(!busy_r)break;									// if motor busy, switch other task
					set_aux(rot_magnet,1);								// activate rotor magnet
					set_pump(vacuum,i_pvac,0);							// activate vacuum pump
					// here [test vacuum sensor ...]					// to do
					n_applicator  = i_apps & 0x01;						// get number of used applicator	
					n_applicator += i_apps>>1 & 0x01;					//  "	"		"		"
					n_applicator += i_apps>>2 & 0x01;					//	"	"		"		"
					/* calculate how much applicators 
					   are used in current analysis,
					   and deposite it samples in accord
					   with number of applications
					*/
					i_reg_step_sequence++;break;						// increment for next step
				case 15:												// step 15
					static unsigned char i = 0;							// verify how applicator currente is used
next_applicator:
					switch(i)											// bring current applicator
					{													// to pick samples
						case 0:											//
							// Applicator 1							
							motor_move(_X,_X_APPL_PARK1,0);				// move x to applicator parking
							d = _X_DRW_POS01;							// for samples 1÷13
							break;
						case 1:
							// Applicator 2
							motor_move(_X,_X_APPL_PARK2,2);				// move x to applicator parking
							d = _X_DRW_POS14;							// for samples 14÷26
							break;
						case 2:
							// Applicator 3
							washing_app(0,0);							// wash applicator in washing park 1
							motor_move(_X,_X_APPL_PARK3,2);				// move x to applicator parking
							d = _X_DRW_POS27;							// for samples 27÷39
					}													//
					motor_move(_Y,_Y_APPL_PARK,0);						// move y to applicator parking
					i_reg_step_sequence++;break;						// increment for next step
				case 16:												// step 16
					if(!busy_x)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 17:												// step 17
					if(!busy_y)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step						 
				case 18:												// step 18
					motor_move(_Z,_Z_APPL_PARK,0);						// move z to applicator parking
					i_reg_step_sequence++;break;						// increment for next step
				case 19:												// step 19
					if(!busy_z)break;									// if morot busy, switch other task
					set_aux(arm_magnet,1);								// activate arm magnet to pick applicator						
					Sys_Sleep(100);										// stabilization
					unsigned char n_appls = i_napp;						// number of application for any applicator
					i_reg_step_sequence++;break;						// increment for next step
				case 20:												// step 20

					/* next_application */								// recursive
					motor_move(_Z,_Z_DRW_TRAN,0);						// up applicator to transition
					i_reg_step_sequence++;break;						// increment for next step
				case 21:												// step 21
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 22:												// step 22
					motor_move(_Y,_Y_DRW_POS,0);						// move to samples
					motor_move(_X,d,0);									//
					i_reg_step_sequence++;break;						// increment for next step
				case 23:												// step 23	
					if(!busy_x)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 24:												// step 24
					if(!busy_y)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step						 
				case 25:												// step 25
					static unsigned char t = 0;							// number of samples soak 
					/* next_insertion */								// recursive from step 29
					motor_move(_Z,_Z_DRW_POS,1);						// insert applicator in samples well
					i_reg_step_sequence++;break;						// increment for next step
				case 26:												// step 26
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 27:												// step 27
					motor_move(_Z,_Z_DRW_POS - _Z_DRW_ALT,1);			// insert applicator in samples well
					i_reg_step_sequence++;break;						// increment for next step
				case 28:												// step 28
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 29:												// step 29	
					t++;												// increment number of samples soak
					if (t<4){i_reg_step_sequence = 25;break;}			// recursive for all three soak
					t = 0;												// reset number of soak
					i_reg_step_sequence++;break;						// increment for next step
				case 30:												// step 30
					motor_move(_Z,_Z_DRW_POS,1);							// last soak
					i_reg_step_sequence++;break;						// increment for next step
				case 31:												// step 31
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 32:												// step 32	
					i_time_set = i_tcp;
					i_time = i_time_set;								// Wait time insert in samples from parameter
					iTime = 1;											// start time
					while(iTime)Sys_Sleep(1);							// leave resource for other task
					motor_move(_Z,_Z_DRW_POS - (_Z_DRW_ALT/2),i_vpc);	// out from samples with parametrized velocity
					i_reg_step_sequence++;break;						// increment for next step
				case 33:												// step 33
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 34:												// step 34	
					motor_move(_Z,_Z_DRW_POS - _Z_DRW_ALT,0);			// out remain at max velocity
					i_reg_step_sequence++;break;						// increment for next step
				case 35:												// step 35
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 36:												// step 36
					switch(i)											// select application point position
					{													// from parameters
						case 0:
							// first application point
						 	motor_move(_X,_X_START_APP - i_pnt0,2);
						 	break;
						case 1:
							// second application point
						 	motor_move(_X,_X_START_APP - i_pnt1,2);
						 	break;								
						case 2:
							// third application point
						 	motor_move(_X,_X_START_APP - i_pnt2,2);						
					}
					motor_move(_Y,_Y_APP_POS,1);
					i_reg_step_sequence++;break;						// increment for next step
				case 37:												// step 37
					if(!busy_y)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 38:												// step 38
					if(!busy_x)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step						 
				case 39:												// step 39
					motor_move(_Z,_Z_APP_POS,0);						// down to application point
					i_reg_step_sequence++;break;						// increment for next step
				case 40:												// step 40
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 41:												// step 41
					i_time_set = i_tap;
					i_time = i_time_set;								// wait in application position from parameter time
					iTime = 1;											// start time
					while(iTime)Sys_Sleep(1);							// leave resource for other task
					motor_move(_Z,_Z_DRW_TRAN + (_Z_DRW_ALT/2),i_vrc);	// Up applicator at parametrized velocity
					i_reg_step_sequence++;break;						// increment for next step
				case 42:												// step 42	
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 43:												// step 43
					motor_move(_Z,_Z_DRW_TRAN,0);						// out remain at max velocity
					i_reg_step_sequence++;break;						// increment for next step	
				case 44:												// step 44
					if(!busy_z)break;									// if motor busy, switch other task
					i_reg_step_sequence++;break;						// increment for next step
				case 45:												// step 45
					i_time_set = i_tada;
					i_time = i_time_set;								// wait after application from parameter time
					iTime = 1;											// start time
					while(iTime)Sys_Sleep(1);							// leave resource for other task
					if(n_appls>0)goto next_application;
					if ((i==0) || (i==2))
					{
						// wash park 1 for default
						motor_move(_X,_X_APP_WASH_PARK_1,2);
						motor_move(_Y,_Y_APP_WASH_PARK,0);
					}			
					else
					{
						// wash park 2
						motor_move(_X,_X_APP_WASH_PARK_2,2);
						motor_move(_Y,_Y_APP_WASH_PARK,0);
					}
					wait_x();
					wait_y();
					motor_move(_Z,_Z_APP_WASH_PARK - _Z_OFS_REL,1);
					wait_z();
					set_aux(arm_magnet,0);							// deactivate arm magnet
					motor_move(_Z,_Z_DRW_TRAN,0);					// up applicator
					wait_z();
next_application:												
					n_appls--;
					if(n_appls>0){i_reg_step_sequence = 20;break;}	// number of application from parameters
					n_appls = i_napp;
					i_reg_step_sequence++;break;
				case 46:
					n_applicator--;
					if(n_applicator>0){i_reg_step_sequence = 15;i++;break;}
					_asm nop;

 

I store sequence at the point where it is and if I find an motor busy, free to other task.

When I am again in this task, I go straight to the point where I was and continues.

I am again in this task, I go straight to the point where I was and continues.

Works fine even handle a lot of rom .. but I have enough

What do you think?

Cheers. :D Babos

Share this post


Link to post
Share on other sites

Looking good. Its more or less as I was suggesting.

 

You can save a few instructions if you alter the tests for motor busy which you have many of:

case 4:	 // step 4
 if(!busy_z)break;   // if motor busy, switch other task
 i_reg_step_sequence++; 
 break;  // increment for next step

is your current code.

Invert the if() condition and use it to control incrementing i_reg_step_sequence and you save a NOT in the expression and a break. Depending on how far it is to the end of the switch, this could save several program memory words.

case 4:	 // step 4
 if(busy_z) i_reg_step_sequence++; // if motor not busy, increment for next step   
 break;  //  switch other task

but that is just style and efficiency.

 

Also I was proposing to move busy testing out of the switch with flags set in the various cases to decide which tests to use and which to ignore which would save even more code and probably make it easier to understand.

 

If it works and you have enough ROM, it will do for now though . You can always rewrite it smaller when you need to.

 

It is more important to make the same routine handle the i_ and ii_ sequences *WITHOUT* duplicating the actual step code.

 

e.g. i_reg_step_sequence and ii_reg_step_sequence would be combined as a two element array as would the other simple i_ and ii_ variables with another variable to toggle between them

//Declarations
int reg_step_sequence[2];
int cghld[2];
...
int toggle_i_ii=0; // 0 for i_, 1 for ii_
int can_swap=1;  // 0 for stay in same analysis, 1 for swappable 
...
// Your code, slightly adjusted!
			switch(reg_step_sequence[toggle_i_ii]) // remember what precedent step
			{
				case 0:
					// Start sequence
					gelholder = cghld[toggle_i_ii];								// get selected gel holder
					if (gelholder = 1)s=_X_GH_PARK1;else s=_X_GH_PARK2;	// set it position
					motor_move(_X,s,0);									// get gel holder form parking
					motor_move(_Y,_Y_GH_PARK,0);						 //  "   "	"	  "	 "
					reg_step_sequence[toggle_i_ii]++;break;						 // increment for next step
...
...
//at end of outer loop
If(can_swap) toggle_i_ii=!toggle_i_ii; // swap to other analysis
...

 

You will need to wrap access to the buffers in conditional code:

if (toggle_i_ii)
 sequence[1] = i_sequence_buffer[sscan[1]];
else
 sequence[0] = i_sequence_buffer[sscan[0]];

as if you combined the buffer arrays I think they would be too large for the compiler to handle.

 

can_swap is cleared for any analysis steps that *MUST* be continuous without the other analysis running and set when you can allow the other analysis to run. It is not a two element array as it communicates with the other analysis to agree sharing the arm.

 

There is plenty there to keep you busy and I look forward to reading your progress report towards the end of the week.

 

P.S Please *DONT* quote my whole post. This topic is getting far too big and it is awkward to scroll down through so many repeats of my own words. Obviously if you are asking me a question about something I have said, quote the bit you are asking about.

 

Ian M.

Share this post


Link to post
Share on other sites

Your content will need to be approved by a moderator

Guest
You are commenting as a guest. If you have an account, please sign in.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×