Problems with Periodic Timer

Hello,

I am writing a program that does closed loop control on a DC motor at a set sampling interval. I have been using the following code to generate a pulse at a set interval of the timer. When I receive the pulse using MsgReceive(), I perform PID control on the current position of the motor.

My problem is that the timer seems to be going off way before it should. I used the ClockCycles() function, and determined that instead of going off every 442 microseconds, it goes off at random intervals from 1 to 100 microseconds. Am I using the timer improperly?

Any help would be greatly appreciated. Thanks!

/*

  • Initializing the timer
    */

timer_t timerid; // timer ID for timer
struct sigevent event; // event to deliver
struct itimerspec timer; // the timer data struct

// set up the kind of event that we want – a pulse
SIGEV_PULSE_INIT(&event, timCoid,
SIGEV_PULSE_PRIO_INHERIT,CODE_TIMER,10);

// create the timer, binding it to the event
if (timer_create(CLOCK_REALTIME, &event, &timerid)==-1)
printf(“Can’t timer_create, errno %d\n”, errno);

// setup the timer (1ns delay, 442microsec reload)
timer.it_value.tv_sec = 0;
timer.it_value.tv_nsec = 1;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_nsec = 442000;

// and start it!
timer_settime (timerid,0,&timer,NULL);

Timer resolution are by default 1ms I think, so you would have to change with ClockPeriod. Did you do that? The Clock Period should be a multiple of 442 msec.

You set the interval to 442000 ns, but as far as i remember the default system clock period in 6.2.1 is 1000000 ns and the process should not use a timer period shorter than this value.

Both interval values should be divisible without reminder by the current system clock period value.

You can get/set system clock period with a ClockPeriod() call
qnx.com/developers/docs/mome … eriod.html

PS: Last time i tried 10000 ns was the shortest possible value for the system clock period

I didn’t realize that I had to change the Clock Period as well. I will definately try that.

Thanks mario & mezek!

Check out:

qnx.com/developers/articles/ … 834_1.html
qnx.com/developers/articles/ … 826_2.html

The posix timers do not deliver a regular event. They are specified to maintain real time rather than regular events so the events are dithered. And I wouldn’t count on the return value of ClockPeriod() or clock_getres() keeping it completely steady either.

Much better to InterruptAttachEvent() the system tick, ie: IRQ#0, or just go the whole hog and have an ISR using InterruptAttach(). :slight_smile:

I tried the setting ClockPeriod() but it still doesn’t work consistently, as evanh predicted. I need very accurate time events. How do I go about attaching an interrupt to the system tick? I’ve never had to write my own interrupt service routine in QNX before. Please help. Thanx.

Before you go to system interrupt tick, try increasing the priority of the pulse. If you do get delta of less then the ClockPeriod that is mostly because your process is disrupted by higher priority process.

Maybe posix timer rules says the aren’t regular, but if you use them right they will be.

And what is it you do between tick, 442us, have you consider that what you are doing could take more then 442us.

If you weren’t using ClockPeriod before it seems very odd to me that you only got deltas of 1 to 100us since by default the system maximum resolution is 1ms.

If you can avoid interrupt, I suggest you do ;-)

I have changed my ClockPeriod = 10000ns. However, I’m getting pulses from my timer about 340-360us apart now, no matter what my timer interval is (440us to 120us). I increased my priority but the same problem still occurs. I have even commented out everything I usually do after receiving a pulse, except for outputting the time and it makes no difference. I know that ClockCycles isn’t reliable down to the tee, but something weird is definately happening.

I want to try writing a InterruptAttachEvent, but I don’t know how to attach it to system clock.

I would consider the PID in a closed control loop of a motor to be a very time critical application. Only hardware timer gives you required stability, the POSIX timer can give you the time interval not less then requested (though you results look suspiciously to me). Handling of interrupts isn’t very complicated in QNX6 and fortunatelly it is documented very well.
qnx.com/developers/docs/mome … ndler.html

As an alternative to system timer interrupts on IRQ0, you may consider using RTC and its periodic interrupts on IRQ8 (if you’re in x86 land, otherwise your h/w platform may have different RTC hardware and interrupt mapping) . The closest to your requirement period of RTC chip is 488.281us, the faster period is 122.070us. AFAIK, it’s not a big deal to select a slightly different period for PID (you have to recalculate coefficients), but period should be very stable.
My article on using RTC in QNX6 is in russian (I doubt you speak russian), but you can read the documentation it refers to as well as the clock.tgz - fairly simple example.
ed1k.qnx.org.ru/rtc.html
ftp://ftp.qnx.org.ru/pub/projects/ed1k/clock.tgz

How fast is your machine, a clock period of 10us add a lot of overhead. Basicaly now you have 100 000 interrupts a seconds.

ClockCycles IS reliable down to the cpu frequency( on pentium and up). By the way how do you measure time and come up with the value 340-360us?

You mention “outputting the time” what does that mean. Can you post your code? What precision are you looking to get?

Before using interrupt I suggest you get to the bottom of this, there is something not quite right here.

I discovered that my minimum timer interval allowed by my processor is 300us. I output time by keeping track of ClockCycles(), saving the values to a buffer array, and printing out to an output file after its done. I noticed that no matter what I set my SERVO_INT variable to, for the first ~15ms the difference in my timed pulses are around 300us. Then after ~15ms the interval becomes the value of SERVO_INT (like it should be).

When I take out the code that sends a message to my hardware server, I noticed that timed pulses occur at the correct SERVO_INT interval right from time=0. I have concluded that sending messages to my server causes odd behaviour in my timed interrupt. Why is this occurring? And how can I avoid it, besides from creating a delay in my system?

Thank you.

(Sorry, it’s been awhile since I’ve been able to work on this problem.)


#define SERVO_INT 800 //Servo interrupt 800us

// Real-Time Control loop
int controlLoop(void)
{
int i;
int rcvid=0;
ClientMessageT msg;
MessageT timMsg;
uint64_t cps, stClock;
float fTime;
float fBuffer[2000];

//Get the starting time in Clock Cycles
stClock=ClockCycles();
cps = SYSPAGE_ENTRY(qtime)->cycles_per_sec;		

//Process Control Loop
for (i=0;i<=2000;i++)

{
//Receive messages from Timer
rcvid=MsgReceive(timChid,&timMsg,sizeof(MessageT),NULL);
if (rcvid==0)
{
//Send data to Hardware Server for DAC Output
msg.iMsgType = MT_SEND_DAC_OUTPUT;
msg.fMsgData = 20;
if (MsgSend(coid, &msg, sizeof(ClientMessageT),&msg,sizeof(ClientMessageT))==1)
{
printf(“Error during MsgSend\n”);
perror(NULL);
return(-1);
}

//Output data to file
fTime = ((float) (ClockCycles()-stClock)/cps);			
fBuffer[i]=fTime;
    }

}

//Print buffer out to a file
for (i=0;i<=iQueueCtr;i++)
{
fprintf(fptr,"%f \n",fBuffer[i][0]);
}

return (0);

}

/*

  • setupPulseAndTimer
  • This routine is responsible for setting up a pulse so it sends a message
  • with code MT_TIMER. It then sets up a periodic timer that fires once per sec

*/

int SingleMotor::setupPulseAndTimer(void)
{
timer_t timerid; // timer ID for timer
struct sigevent event; // event to deliver
struct itimerspec timer; // the timer data struct
struct _clockperiod clkper; // to control the clock period

 // set up the kind of event that we want -- a pulse
 SIGEV_PULSE_INIT(&event, timCoid, SIGEV_PULSE_PRIO_INHERIT,CODE_TIMER,10);

 // create the timer, binding it to the event
 if (timer_create(CLOCK_REALTIME, &event, &timerid)==-1)
 {
      printf("Can't timer_create, errno %d\n", errno);
      perror(NULL);
      return(-1);
  }

   // setup the timer (1ns delay, SERVO_INT reload)
   timer.it_value.tv_sec = 0;
   timer.it_value.tv_nsec = 1;
   timer.it_interval.tv_sec = 0;
   timer.it_interval.tv_nsec = ((int)SERVO_INT)*1000;
   // and start it!
   timer_settime (timerid,0,&timer,NULL);

   //Set the Clock Period to 100us
   clkper.nsec = 100000;
   clkper.fract = 0;
   ClockPeriod(CLOCK_REALTIME,&clkper,NULL,0);

   return 0;

}

Here’s another question that will probably be easier to answer. Whenever the system receives a timer pulse, there’s a bunch of code that I want it to do in my control loop. What happens when another pulse is received before the code in the control loop is done? Does the pulse simple get ignored until it gets back to the MsgReceive()? If so, how can I detect pulses that are missed?

Thanks.

It is queued. You can’t miss a pulse unless you are running out of ram or accumulating more then kernel can queue.

I read your post yesterday and at first though it was an issue of this sort, but I couldn’t make any sense of it and kept quiet hoping somebody else would understand what is going on.

Thanks mario. For now, all I can do is add a 30ms delay to make sure that the irregularity in the timer interval doesn’t affect my control loop & path planning.

Okay, in order to test to see if my control loop calculations have time to complete before the next pulse occurs, I have attempted to use a separate thread that does my control loop calculations. My problem is that my control calculations are contained in a class function. I can not do it outside of the class. However, QNX doesn’t seem to like this. Is there a different function that I can use that will allow me to use a class function as a separate thread? Why can’t I use a void * return type on a class function?

Thanx.

void myclass::process_pulses()
{

//Create a barrier for threads
pthread_barrier_init (&barrier, NULL, 2);

for (i=0;i<iQueueSize;i++)
{
//Receive messages from Timer
rcvid=MsgReceive(timChid,&timMsg,sizeof(MessageT),NULL);
if (rcvid==0)
{
pthread_create (NULL, NULL, thread_ctrl, (void *) i);
pthread_barrier_wait (&barrier);
}
}

}

void * myclass::thread_ctrl(void * iNum)
{
//Do stuff here then …
pthread_barrier_wait(&barrier);
}

The posix timers just aren’t designed for this. Queuing is not what you want. Responding to superceeded feedback is useless or even detrimental.

If you get behind, the best you can do is measure how far behind and add that in to the servo equations. So, what you would have to do is consume all pulses at once, counting them, and then proceed to do the next round of calculations.

I feel that using InterruptAttachEvent() is the way to go as it doesn’t burden the OS with the posix timer system and it is guaranteed to be regular.

Sure a C++ function member can return a void *. What’s the problem.

A class cannot be a thread, the two concept don’t mtach. However a class method can start a thread, or the thread can instanciate the class. I’m not sure I understand where is your problem.

I think that the error for the void * return type was only showing up because I was trying to use it as a thread. I will try to write an Interrupt to replace the posix timer.

Thanks for the help. Happy Holidays!!

Umm, IAE() is not interrupt coding per se. Think of it as just a message to your thread to say there has been an interrupt some time in the past. After all, that’s all it really is.

If you want to get into real interrupt coding then InterruptAttach() is the mans choice. ;)

Make the thread_ctl method static. You would probably want to somehow pass the address of the instantiated myclass object into the thread so the thread can reference the other non-static class members of my class and use pthread_create(NULL,NULL,myclass::thread_ctl,...