All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sebastian Pavez <sebastian.pavez.t@gmail.com>
To: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
Cc: Xenomai <xenomai@xenomai.org>
Subject: Re: [Xenomai] Doubts about priorities with periodic tasks (Posix Skin)
Date: Tue, 07 May 2013 08:36:22 -0400	[thread overview]
Message-ID: <5188F546.5090001@gmail.com> (raw)
In-Reply-To: <5188E58D.7070304@xenomai.org>

Hi Gilles,

Sorry for the mess :-) I hope this is more clear:

> Hi Gilles,
>
> Thanks for your answer. About the execution time issue I'll explain better:
> - How I see the code works:
>       - I set the period of each thread 'control' and 'pert1'
>       - After the initialization of variables and DAQ card the code
> inside 'while(1)' is executed periodically
>       - I determined the time take it by this 'while(1)' via direct
> measure (activating a signal before the code and disbling it after, and
> measuring the width of the 'pulse')
>       - I get something like 18us for the control thread. So In the pert1
> thread I use a 'for' loop inside the while(1), when I increment the
> interations number I get a higher execution time
> - What I'm trying to test:
>       - For the same period for both tasks and the higher priority for
> the pert1 thread I incremente the number of iterations inside the for loop
>       - I expect, with a execution time of pert1 over 35us, to see a
> malfunctioning in the DC motor following the reference (via some signals
> I get in the oscillo) because the control will not have
>         enough time to be executed properly before the next period in
> wich the pert1 thread will resume his execution ... (is this correct?)
>       - All this is done to confirm the results obtained in simulation
>
> Now, what I'm doing (the structure of my code) is in order with the
> results I would like to test? or I'm misinterpreting something. I would
> like to clarify this in order to know if the problems are about the
> theory or the implementation ... or, sadly, both.
>> I do not see all this in the code you sent to the list, what I see is
>> two threads which sleep on pthread_wait_np and do nothing else. So,
>> execution time virtually 0. You can use rt_timer_spin to simulate some
>> load. Some point you may have missed too, is that Xenomai timer runs in
>> one-shot mode by default, which means the thread periods will not elapse
>> at the same time, except if you synchronize them by using the first
>> argument of pthread_make_periodic_np.
>
Sorry for that, I now attached the code ... It's quite raw at the moment 
but it does what is suppose to, control the DC motor.
Regarding the first argument of pthread_make_periodic_np, I use 
pthread_self() to assign to the calling thread, wht do you precisely 
mean with "using the first
argument of pthread_make_periodic_np"?

>> In general, however, a Xenomai system where a real-time task consumes a
>> lot of cpu does tend to crash, it is recommended to let linux run (by
>> having all your real-time tasks suspended at some point) from time to
>> time. A safe solution is to let it run at least for its timer tick, so
>> every millisecond, 4 milliseconds, or 10 milliseconds depending on
>> CONFIG_HZ value.
>>
>> How could I do this?
> Arrange for every thread to not run more than the time of the period
> corresponding to CONFIG_HZ.
>

This mean, don't set a period more than 4ms for each thread? (I have a 
configuration of 250hz)
I tried to start in text mode by changing "quite splash" to "quite 
splash text" in the grub ... I only get a black screen at the start.

One more question, the results I get with 'cat /proc/xenomai/stat' and 
'cat /proc/xenomai/sched' prove that the threads are being executed in a 
rel-time mode?
or there's something "weird" about them? or That's not enough info?

Best regards,
Seba. P.




-------------- next part --------------
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/io.h>
#include <math.h>
#include <time.h>
#include <sched.h>

// Llamada al archivo de cabecera de los threads de POSIX
#include <pthread.h>

// Llamada al archivo de cabecera que contiene los registros de la tarjeta
#include "REG_PCI1711.h"

// Definición de la dirección base de la tarjeta PCI-1711U
#define PCI_BASE_ADRESS_1711 0xc000

// Se definen los periodos para las dos tareas             
 #define PERIOD  50000            //1000000  
 #define PERIOD2 50000

// Estructura de datos necesarias para la creación de los threads
pthread_t thread_control;
pthread_t thread_pert1;

// Estructura de datos necesarias para la asignación de prioridades
struct sched_param p_control;
struct sched_param p_pert1;

void * control(void *arg){
unsigned int valor,datos,y,d,beta,N,re;
unsigned long overruns_r;
int out,in,o,outpos;                       // Variables para el control
double t,w,grados,g,m;
float ref,Vtaco,Vpot,err,ctr,ctrpos;
float err0=0.0;
float Vtaco0=0.0;
float Vpot0=0.0;
float ref0=0.0;
float a=0.0737;		            // Constantes del PI para velocidad a=Kp  ;  b=ti
float b=0.0487;
int posicion = 0;                   // Selección de control, 1 = posición ; 0 = velocidad
double referencia=20.2;            // Referencia control de posicion en grado
float x,r,gref;
float h;
float P,I,D, Ppos, Dpos;
float kp=2.88;     // 2.88                    // Constantes del PD para posicion
float td=0.024;   // 0.024
float Dold=0.0;
float Doldpos=0.0;
float Iold=0.0;

// Estructura para el manejo temporal
struct timespec now,period;
int dummy;
w=1.8; // 2rad/s

// Se setean los valores para llevar un conteo del tiempo transcurrido
// Esto se hace según el reloj CLOCK_REALTIME 

       period.tv_sec=0;
       period.tv_nsec=PERIOD;

       clock_gettime  	( CLOCK_REALTIME, &now);
       now.tv_nsec=now.tv_nsec+PERIOD;

// Se marca el thread como uno periodico y se verifica si no se produce algun error
       dummy=pthread_make_periodic_np (pthread_self(), &now,&period);
       switch(dummy){
         case 0 : 
	      break;
         case ESRCH: 
		printf("thread is invalid \n"); 
		pthread_exit ((void *)-1);  
	      break;
         case ETIMEDOUT : 
		printf("the start time has already passed\n"); 
		pthread_exit ((void *)-1); 
	      break;
         default : 
		printf(" output value not defined \n"); 
	        pthread_exit ((void *)-1); 
	}
 
// Se fija la referencia interna de la tarjeta para la salida análoga 0 y 1 en 10[V]
   outw(5,PCI_BASE_ADRESS_1711 + PCI171x_DAREF); 

// Se selecciona el modo del funcionamiento de la tarjeta y se limpia la
// información que pueda quedar en el buffer. Se inicializa el conversor A/D
   outw(Control_CNT0|Control_SW, PCI_BASE_ADRESS_1711+PCI171x_CONTROL);
   outb(0, PCI_BASE_ADRESS_1711+PCI171x_CLRFIFO);
   outb(0, PCI_BASE_ADRESS_1711+PCI171x_CLRINT);

   outw(1, PCI_BASE_ADRESS_1711+PCI171x_CONTROL);
   outb(0, PCI_BASE_ADRESS_1711+PCI171x_CLRFIFO);
   outb(0, PCI_BASE_ADRESS_1711+PCI171x_CLRINT);

// Se selecciona la ganancia del amplificador, así como el canal de entrada, AI0
   outw(0, PCI_BASE_ADRESS_1711+PCI171x_RANGE);


while(1) {

if(posicion == 1){ // Control de posicion, lectura desde la entrada AI1
   outb(1, PCI_BASE_ADRESS_1711+PCI171x_MUX_sta);  // Empezar en el canal AI0
   outb(1, PCI_BASE_ADRESS_1711+PCI171x_MUX_sto);  // Terminar en el canal AI0   
		

		clock_gettime(CLOCK_REALTIME,&now);     // Variacion de la referencia en el tiempo
		t=(double)now.tv_nsec*1.0E-9+(double)now.tv_sec;
		r=(double)2+(double)2*sin( w*t);		
                if(r<2){
		grados=referencia;
		}
		if(r>2){
		grados=referencia+18.09;
		}

// Conversion de grados en tension
if((0<=grados)&&(grados<160)){
 gref=grados*0.0553-0.1255;
// printf("x: %f[V]  ", x);
}
if((215<grados)&&(grados<360)){
gref=grados*0.0555-20.161;
}

// Zona muerta del potenciometro
if((160<=grados)&&(grados<=215)){
gref=-0.1255;
}

// Conversion de la tension para la salida de la tarjeta considerando la etapa de adaptacion de niveles
if((-10<=gref)&&(gref<0)){
in=(gref+10)/0.00488;
}
if((0<=gref)&&(gref<=10)){
in=gref/0.00244;
}

// Limitacion del valor de la salida
if(in<0){
in=0;
}else if(in>4095){
in=4095;
}

// Se saca la señal de referencia por la salida DA0
outw(in,PCI_BASE_ADRESS_1711 + PCI171x_DA0);

// Lectura de la salida
    valor=1;        

//Comenzar el proceso de conversión
    outw(0, PCI_BASE_ADRESS_1711+PCI171x_SOFTTRG);

    while (valor) {
// Verificar si la conversión ha finalizado
    valor=(inb(PCI_BASE_ADRESS_1711+PCI171x_STATUS) & Status_FE);
	        }
// Leer los datos
    datos=inw(PCI_BASE_ADRESS_1711+PCI171x_AD_DATA); // Obtener datos de la cola
    d=datos&0x0fff;

// Transformacion en tension de la lectura
Vpot=d*0.002442;
Vpot=(Vpot-5)*2;

// COnversion de la tension en grados
if((-0.1255<=Vpot)&&(Vpot<8.68)){
g=(Vtaco+0.1255)/0.0553;
}
if((-8.25<Vpot)&&(Vpot<-0.1255)){
g=(Vpot+20.161)/0.0555;
}

// Algoritmo del PD para control de posición
beta=1;
N=10;
h=PERIOD*0.000000001;
Ppos=kp*(beta*gref-Vpot);
Dpos=td/(N*h+td)*Dold + N*kp*td/(N*h+td)*(Vpot0-Vpot);
ctrpos = Ppos + Dpos;
Doldpos = Dpos;
Vpot0 = Vpot;

// Limitacion en tension de la señal de control
if(ctrpos>10){
ctrpos=10;
}
if(ctrpos<-10){
ctrpos=-10;
}

// Conversion de la señal de control para ser escrita en la tarjeta
if((-10<=ctrpos)&&(ctrpos<0)){
outpos=(ctrpos+10)/0.00488;
}
if((0<=ctrpos)&&(ctrpos<=10)){
outpos=ctrpos/0.00488+2046;
}

// Limitacion de la salida
if(outpos<0){
outpos=0;
}else if(outpos>4095){
outpos=4095;
}

// Se saca la señal de control por la salida analoga DA1 y se aplica al puente H del motor
outw(outpos,PCI_BASE_ADRESS_1711 + PCI171x_DA1);


}else if(posicion == 0){ // Control de velocidad, lectura desde la entrada AI0
   outb(0, PCI_BASE_ADRESS_1711+PCI171x_MUX_sta);  // Empezar en el canal AI0
   outb(0, PCI_BASE_ADRESS_1711+PCI171x_MUX_sto);  // Terminar en el canal AI0  

		clock_gettime(CLOCK_REALTIME,&now);     // Variacion de la referencia en el tiempo
		t=(double)now.tv_nsec*1.0E-9+(double)now.tv_sec;
		x=(double)2+(double)2*sin( w*t);
		if(x<2){
		x=0.5;
		}
		if(x>2){
		x=1.5;
		}
		if((0<=x)&&(x<=10)){  // Conversion de la tension en valores de la tarjeta
                in=x/0.00244;
                }
                outw(in,PCI_BASE_ADRESS_1711 + PCI171x_DA0); // Se saca la referencia por el canal DA0

// Lectura de la salida
    valor=1;        

//Comenzar el proceso de conversión
    outw(0, PCI_BASE_ADRESS_1711+PCI171x_SOFTTRG);

    while (valor) {
// Verificar si la conversión ha finalizado
    valor=(inb(PCI_BASE_ADRESS_1711+PCI171x_STATUS) & Status_FE);
	        }
// Leer los datos
    datos=inw(PCI_BASE_ADRESS_1711+PCI171x_AD_DATA); // Obtener datos de la cola
    y=datos&0x0fff;

// Transformacion en tension de la lectura
Vtaco=y*0.00244;
Vtaco=(Vtaco-5)*2;

// Algoritmo del PI para control de velocidad
beta=1;
N=10;
h=PERIOD*0.000000001;
P=a*(beta*x-Vtaco);
I=Iold;
ctr = P+I;
Iold = Iold + a*h/b*(x-Vtaco);
Vtaco0 = Vtaco;

// Limitacion en tension de la señal de control
if(ctr>10){
ctr=10;
}
if(ctr<-10){
ctr=-10;
}

// Conversion de la señal de control para ser escrita en la tarjeta
if((-10<=ctr)&&(ctr<0)){
out=(ctr+10)/0.00488;
}
if((0<=ctr)&&(ctr<=10)){
out=ctr/0.00488+2046;
}

// Limitacion de la salida
if(out<0){
out=0;
}else if(out>4095){
out=4095;
}

// Se saca la señal de control por la salida analoga DA1 y se aplica al puente H del motor
     outw(out,PCI_BASE_ADRESS_1711 + PCI171x_DA1);

}

// Pausar la ejecución hasta el próximo periodo
  pthread_wait_np (&overruns_r);
  
}

// Señala el termino del thread
 pthread_exit ((void *)0);
}


void * pert1(void *arg){
unsigned int valor,lect,lt;
int i,j,k;
double u;
unsigned long overruns_r;
struct timespec now,period;
int dummy;

       period.tv_sec=0;                //Inicializo los contadores del tiempo transcurrido
       period.tv_nsec=PERIOD2;          // en 0.001 seg
       clock_gettime  	( CLOCK_REALTIME, &now);
       now.tv_nsec=now.tv_nsec+PERIOD2;
       dummy=pthread_make_periodic_np (pthread_self(), &now,&period);
       switch(dummy){
         case 0 : 
	      break;
         case ESRCH: 
		printf("thread is invalid \n"); 
		pthread_exit ((void *)-1);  
	      break;
         case ETIMEDOUT : 
		printf("the start time has already passed\n"); 
		pthread_exit ((void *)-1); 
	      break;
         default : 
		printf(" output value not defined \n"); 
	        pthread_exit ((void *)-1); 
	}

   while (1) {

	for(i=0;i<210;i++){
//        for(j=0;j<100;j++){
        k++;
	u=sin((double)k);
//        }
    }

    pthread_wait_np (&overruns_r);
    	}
 pthread_exit ((void *)0);
}

int main(int argc, char* argv[]){

// Reserva de memoria y permiso para acceso a la tarjeta
    mlockall(MCL_CURRENT|MCL_FUTURE);
    ioperm(PCI_BASE_ADRESS_1711,50,2);    

// Crea el thread "control" y se le asigna su prioridad    
    pthread_create (&thread_pert1, NULL, pert1, 0);
    p_pert1.sched_priority = 1;
    pthread_setschedparam (thread_pert1, SCHED_FIFO, &p_pert1);    

// Crea el thread "control" y se le asigna su prioridad  
    pthread_create (&thread_control, NULL, control, 0);
    p_control.sched_priority = 2;
    pthread_setschedparam (thread_control, SCHED_FIFO, &p_control); 

// Coordina el termino de la ejecución de los threads
    pthread_join   (thread_control,NULL);
    pthread_join   (thread_pert1,NULL);

    return(0);
}

  reply	other threads:[~2013-05-07 12:36 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-05-06 17:14 [Xenomai] Doubts about priorities with periodic tasks (Posix Skin) Sebastian Pavez
2013-05-06 18:17 ` Gilles Chanteperdrix
2013-05-06 19:15   ` Sebastian Pavez
2013-05-06 19:33     ` Gilles Chanteperdrix
2013-05-06 21:12       ` Sebastian Pavez
2013-05-07 11:29         ` Gilles Chanteperdrix
2013-05-07 12:36           ` Sebastian Pavez [this message]
2013-05-08 13:19             ` Gilles Chanteperdrix
2013-05-08 18:39               ` Sebastian Pavez
2013-05-08 18:49                 ` Gilles Chanteperdrix
2013-05-08 18:50                   ` Gilles Chanteperdrix
2013-05-08 19:42                   ` Sebastian Pavez
2013-05-08 20:05                     ` Gilles Chanteperdrix

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5188F546.5090001@gmail.com \
    --to=sebastian.pavez.t@gmail.com \
    --cc=gilles.chanteperdrix@xenomai.org \
    --cc=xenomai@xenomai.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.