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

Problems with fifos and Doubts about periodic tasks



Hi guys,
 
	I'd like to know if it's possible to change the period of a periodic task
running rt_make_periodic (or pthread_make_periodic_np) more than one time
in the same module. I mean: each time my linux program write to a fifo  a
handler runs in my rt-module with  rt_make_periodic (or
pthread_make_periodic_np) using period values passed through the fifo
(something like frank_app running START_TASK many times, each time with a
"msg.period" different)

	My second question is about the reasons why i can't write to a fifo. I
create the fifos in my rt-module (with rtf_create), but when i run a
monitor program and try write to the fifo the return value is minor than 0
and i can't reinitialize my periodic task.

									thanks in advance,

											Daniela.

P.S.: I'm using the code in attachment. Sorry,  it's really disordered and
ugly  and i hope that someone can urderstand it ?:)  Thanks again, Dani.
#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <rtl_fifo.h>
#include <rtl_time.h>
#include "declaracoes.h"


#define BUFSIZE 70

char buf[BUFSIZE];

int main()
{
	fd_set rfds;
        struct timeval tv;
        int retval;
	int fd0, fd1, ctl;
        int n;
	int i;
	mensagens MSG;

	if ((fd0 = open("/dev/rtf0", O_RDONLY)) < 0) {
		fprintf(stderr, "Error opening /dev/rtf0\n");
		exit(1);
	}

	if ((fd1 = open("/dev/rtf3", O_RDONLY)) < 0) {
		fprintf(stderr, "Error opening /dev/rtf3\n");
		exit(1);
	}

	if ((ctl = open("/dev/rtf4", O_WRONLY)) < 0) {
		fprintf(stderr, "Error opening /dev/rtf4\n");
		exit(1);
	}

	/* now start the tasks */
	MSG.command = START_TASK;
	MSG.tarefa = 0;
	MSG.period = 200000;
	if (write(ctl, &MSG, sizeof(MSG)) < 0) {
	fprintf(stderr, "Can't send a command to START RT-task0\n");
		exit(1);
	}
	MSG.tarefa = 1;
	MSG.period = 200000;
	if (write(ctl, &MSG, sizeof(MSG)) < 0) {
	fprintf(stderr, "Can't send a command to START RT-task1\n");
		exit(1);
	}

	for (i = 0; i < 200; i++) {
	/*	FD_ZERO(&rfds);
		FD_SET(fd0, &rfds);
		FD_SET(fd1, &rfds);
		tv.tv_sec = 1;
		tv.tv_usec = 0;

		retval = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
		if (retval > 0) {
			if (FD_ISSET(fd0, &rfds)) {
				n = read(fd0, buf, BUFSIZE - 1);
				buf[n] = 0;
				printf("FIFO 1: %s\n", buf);
			}
			if (FD_ISSET(fd1, &rfds)) {
				n = read(fd1, buf, BUFSIZE - 1);
				buf[n] = 0;
				printf("FIFO 2: %s\n", buf);
			}
		} */


	}

	fprintf(stderr, "frank_app: now sending commands to stop RT-tasks\n");
	/* stop the tasks */
	MSG.command = STOP_TASK;
	MSG.tarefa = 0;
	if (write(ctl, &MSG, sizeof(MSG)) < 0) {
		fprintf(stderr, "Can't send a command to RT-task\n");
		exit(1);
	}
	MSG.tarefa = 1;
	if (write(ctl, &MSG, sizeof(MSG)) < 0) {
		fprintf(stderr, "Can't send a command to RT-task\n");
		exit(1);
	}
	return 0;
}
# ifndef __PLACA16_H
# define __PLACA16_H

#define LPT 0x378

/***  Variaveis para a Primeira placa DAD1601 ***/

# define AD_BASE	( 0x0300   )			// Endereco base da placa ( default )

# define AD0		( AD_BASE )		// end. LSB do AD + MUX channel
# define AD1		( AD_BASE + 1 )		// end. MSB do AD
# define AD_MUX		( AD_BASE + 2 )		// end. para selecionar canal
# define DIO		( AD_BASE + 3)       		// end. do port i/o digital
# define DA0LB         	 ( AD_BASE + 4)
# define DA0HB          	( AD_BASE + 5)
# define AD_STATUSA	( AD_BASE + 8 )		// end. de status
# define AD_CTRL		( AD_BASE + 9 )		// end. de controle
# define AD_CNTEN	( AD_BASE + 0x0A )		// end. de counter enable
# define AD_GAIN		( AD_BASE + 0x0B )		// end. de ganhos

# define AD_TIMER0	( AD_BASE + 0x0C )		// end. de Timer 0
# define AD_TIMER1	( AD_BASE + 0x0D )		// end. de Timer 1
# define AD_TIMER2	( AD_BASE + 0x0E )		// end. de Timer 2
# define AD_TIMERCTL	( AD_BASE + 0x0F )		// end. de ctrol Timer

# define AD_DISARM	( AD_BASE + 0x404 )	// end. de counter dis
# define AD_BMDEN	( AD_BASE + 0x405 )	// end. de Enable busrst

# define AD_M1600	( AD_BASE + 0x406 )		// end. de 1600 mode
# define AD_STATUSB	( AD_BASE + 0x407 )	// end. de status B

# define AD_POL		(2048)  			// Bipolar
// # define AD_POL	(0)  				  // Unipolar

#define AD_CANAL (0x00)		//Sao 16 canais de 0x00 a 0x0F
//#define AD_CANAL (0x0F)

#define AD_INTE (0x00)		//Desabilita (0x00) ou habilita (0x10) interrupcoes da placa AD
//#define AD_INTE (0x10)

#define AD_LEVEL (0x00)		//Define o nível de interrupcao para o processamento das mesmas
//#define AD_LEVEL (0x07)		// vai de (0x00) a (0x07)

#define AD_DMAE (0x00)		//Desabilita (0x00) ou habilita (0x01) DMA
//#define AD_DMAE (0x01)

#define AD_TRIG (0x00)		// Trigger Source. Se 0x00 ou 0x01 eh por software, se 0x02 eh pelo Trig 0
//#define AD_TRIG (0x03)		// e se eh 0x03 pelo timer

#define AD_GANHO (0x00)		//Define o ganho do DA de 1 (0x00) a 500 (0x03)
//#define AD_GANHO (0x03)

#define AD_BRATE (0x00)		//Define a taxa de conversoes durante uma amostragem do tipo Burst.
//#define AD_BRATE (0x1F)		//Esses bits so sao utilizados se o Burst Mode estiver habilitado
				// BURST RATE = 1MHz / ((4 * BURST RATE VALUE) +2)

#define AD_BLEN (0x00)		//Define o número de conversoes durante cada trigger numa aquisicao do tipo Burst
//#define AD_BLEN (0x0F)		// Esses bits so sao utilizados se o Burst Mode estiver habilitado

#define AD_CLOCK (0x00)		//Se 0x00   habilita Contador/Timers.
//#define AD_CLOCK (0x03)		//Se 0x01   habilita Contador/Timers somente se TRG0/IP0 = 0.
				//Se 0x10   habilita clock de 100kHz e Contador/Timers.
				//Se 0x11    habilita clock de 100kHz e Contador/Timers somente se TRG0/IP0 = 0.

#define AD_INICIO (0x00)		//Canal inicial de conversao AD
//#define AD_INICIO (0x03)

#define AD_FIM (0x00)		//Canal final de conversao AD
//#define AD_FIM (0x03)

#define AD_HAB (0x00)		//Habilita (0x00) ou desabilita conversoes (0x40)
//#define AD_HAB (0x40)

/**  Placa DDA-06		****/

/*
# define DA_BASE_DFL	( 0x2E0  )

# define DA0_LOW        ( DA_BASE )
# define DA0_HIGH	( DA_BASE + 1 )

# define DA1_LOW	( DA_BASE + 2)
# define DA1_HIGH	( DA_BASE + 3 )

# define DA2_LOW	( DA_BASE + 4 )
# define DA2_HIGH	( DA_BASE + 5 )

# define DA3_LOW	( DA_BASE + 6 )
# define DA3_HIGH	( DA_BASE + 7 )

# define DA_PA		( DA_BASE + 0xC )
# define DA_PB		( DA_BASE + 0xD )
# define DA_PC		( DA_BASE + 0xE )

# define DA_CTRL	( DA_BASE + 0xF )

# define DA_FAIXA	( 4096 ) // 12 bits
# define DA_POL		( 2048 ) // Bipolar
//				(0)		// Unipolar

# define DA_VMAX		( 5 )
# define DA_VMIN		( 0 )	// Suponhe que todos os DA
					// estam na mesma faixa.
					*/
/***  Para a placa mae do PC  ***/

# define CTRL_8259	( 0x0020 )		//  Controle do 8259
# define MASK_8259	( 0x0021 )		//  Mascara do 8259

//  Configuracao de canais da placa A/D
# define	NUM_CANAIS	( 16 )
# define	CANAL_INICIAL	( 15 )
# define	CANAL_FINAL	(  0 )

# define	HARD_INTR	( 7 )


# endif


/* Driver para controle de um duplo integrador. Daniela 16/05/2000 */
/* This program makes the interface between a GUI (not RT) and  AD/DA boards. It looks for work with
     2 kinds of AD/DA boards and V1.1 and V2.2 of RTL, both choosed through #define */

#ifndef MODULE
#define MODULE
#endif

#ifndef __KERNEL__
#define __KERNEL__
#endif

#ifndef __RT__
#define __RT__
#endif

// Define se o drive sera para a versao 1.1 ou 2.2 do RTLinux e se sera para a placa DAS1600 ou AIO (STD)

#define V1  			//Escolhe entre as versoes 1.1 e 2.2 do RTL
//#define V2

//#define AIO		//Escolhe entre as placas AD/DA  AIO(STD) e DAS1601
#define DAS1600

#define OSC			//Define se havera uma onda quadrada na porta paralela para teste

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/cons.h>
#include <linux/ioport.h>
#include <linux/string.h>

#include <pthread.h>

#include <asm/io.h>

#include <rtl_sched.h>
#include <rtl_fifo.h>
#include "declaracoes.h"

#ifdef AIO
#include "placa_ai.h"           // header com os enderecos da placa AD/DA do STD
#endif

#ifdef DAS1600
#include "placa16.h"              // header com os enderecos da placa AD/DA DAS1600
#endif

#ifdef V1
RT_TASK tarefa[2];
#endif

#ifdef V2
pthread_t tarefa[2];
#endif


//Definicao das variaveis de tempo

#ifdef V2
hrtime_t RT_TICKS_CTRL; //Variavel utilizada para determinar o tempo de amostragem para o controle
hrtime_t RT_TICKS_SAVE; //Variavel utilizada para determinar o tempo de amostragem para salvar os dados nas fifos
hrtime_t ONDA_QUADRADA;
hrtime_t ONDA_QUADRADA2;
#endif


#ifdef V1
RTIME  RT_TICKS_CTRL; //Variavel utilizada para determinar o tempo de amostragem para o controle
RTIME  RT_TICKS_SAVE; //Variavel utilizada para determinar o tempo de amostragem para salvar os dados nas fifos
RTIME  ONDA_QUADRADA;
RTIME  ONDA_QUADRADA2;
#endif


parametros_PID PID;  // Ganhos do PID
mensagens MSG;	    // Mensagens de inicializacao e mudanca de periodo
float uf, vf;
int ub;
int valor;
float tensao;
float h;
float ek, pk, dk, otensao, ref;
float ik;
float N=20.0;
float Nh;
float escala; //escala de medicao: VADPP/4095.0 (converte para volts)
int a=1;
int dispara_ad;   //String que dipara o AD
int controle_ad;  //String que controla o funcionamento da placa AD/DA
int range;           // Range de enderecos ocupados pelo AD
//float meio_escala;
//int num_bits;
float FREQHZ;
float VADPP;
int contador; //Contador que controla a onda quadrada
int sinal;  // Sinal da onda quadrada

#ifdef AIO
static int AIO_port_base=0x0300;   //Se zero a base sera lida do arquivo .h
#endif

#ifdef DAS1600
static int das1601_port_base=0;  //Se zero a base sera lida do arquivo .h
#endif




void *lei_controle(void *t)
{
  while (1) {

#ifdef V2
pthread_wait_np(); // Espera a proxima interrupcao
#endif

#ifdef V1
rt_task_wait(); // Espera a proxima interrupcao
#endif

#ifdef DAS1600
valor = ( (inb(AD0) & 0x0F0) >> 4 | ((inb(AD1) & 0x0FF) << 4));  // Aquisicao da posicao
tensao = ((float) (valor - AD_POL))*escala;
#endif

#ifdef AIO
valor = ( (inb(AD0) & 0x0FF) | ((inb(AD1) & 0x00F) << 8));  // Aquisicao da posicao
tensao = ((float) (valor - AD_POL))*escala;
#endif


     // Nao Entendi.Muito complicado

    if (contador > ONDA_QUADRADA2 && contador <= ONDA_QUADRADA)  // Gera um onda quadrada ou retangular?
      sinal = -1;
    else if (contador > ONDA_QUADRADA) {
      sinal = 1;
      contador=0;
    }
   contador++;




    // Lei de controle

    ref = PID.ref + PID.sw_amplitud*sinal;  // A referencia e uma constante mais a amplitude
    					    // da onda quadrada * sinal aplicado

    ek = ref - tensao; //tensao e a leitura atual da posicao (convertida em valores de tensao)

    pk = PID.kp*ek;  //termo proporcional do controle

    dk = PID.kd/(PID.kd+Nh)*(dk - PID.kp*N*(tensao-otensao)); //termo derivativo do controle

    vf = pk + ik + dk; //tensao de controle

    // Saturacao do controle ub \in [0,4095]
    if( vf > 1.0)
      uf=1.0;
    else if (vf < -1.0)
      uf=-1.0;
    else
      uf=vf;

    if (AD_POL==0) {           // a placa do DAS está ajustada para trabalhar de 0 a +10 volts
    ub= (int)uf*4095;}
   else {
    ub = ((int)(uf*2047.0)) + 2048;} // a placa do DAS está ajustada para trabalhar de -10 a +10 volts
					      // Sinal de Controle (+/- 5 volts setados na placa AD/DA)




    // Escreve o controle no DA

#ifdef DAS1600
outb((((ub&0x00F) << 4) & 0xF0), DA0LB);
outb((((ub&0xFF0) >> 4) & 0xFF), DA0HB);
#endif

#ifdef AIO
outb(((ub&0x0FF) & 0xFF), DA0LSB);
outb((((ub&0xF00) >> 8)& 0x0F),DA0MSB);
#endif


   // Calculo dos estados do PID
    ik += PID.kp*PID.ki*h*ek;           //acao integral

    otensao = tensao;                   // prepara a variavel de tensao anterior

#ifdef OSC    		//Produz uma onda quadrada na porta paralela (para teste)
    outb(a, LPT);
    a = ~a & 0x01;
#endif OSC

   // outb(0, AD0);			//dispara o AD para a proxima conversao

#ifdef AIO
dispara_ad = (((AD_GANHO << 5)|AD_CANAL)& 0xFF);
outb(dispara_ad,AD_MUX);
#endif

#ifdef DAS1600
dispara_ad = ((AD_CANAL)& 0x0F);
outb(dispara_ad,AD0);
#endif


  }
}

void *salvar_dados(void *t)
{
  while (1) {

#ifdef V2
pthread_wait_np(); // Espera a proxima interrupcao
#endif

#ifdef V1
rt_task_wait(); // Espera a proxima interrupcao
#endif

    /* Salva posicao e controle nas FIFO */
    rtf_put(0, &tensao, sizeof(float));
    rtf_put(1, &ref,    sizeof(float));
    rtf_put(3, &uf,     sizeof(float));
  }
}


int mod_pid(unsigned int fifo)
{
  rtf_get(fifo, &PID, sizeof(parametros_PID));  //Atualiza a struct PID com os novos dados
  ik=0.0;

  return(0);
}


int comando(unsigned int fifo)
{
  int err;

#ifdef V1
   RTIME now;
#endif

#ifdef V2
  struct sched_param sched_param;
  hrtime_t now;
 #endif


while ((err= rtf_get(fifo, &MSG, sizeof(MSG)))== sizeof(MSG)) {  //Atualiza a struct MSGS com os novos dados

  switch (MSG.command){
	case START_TASK:
			       #ifdef V2
		                 now = gethrtime();
			         pthread_make_periodic_np(tarefa[MSG.tarefa], now + 1 * NSECS_PER_SEC, MSG.period);
 			       #endif
			       #ifdef V1
		                 now = rt_get_time();
				 rt_task_make_periodic(&tarefa[MSG.tarefa], now,MSG.period);
 				#endif

	case STOP_TASK:
			       #ifdef V2
		                 pthread_suspend_np(tarefa[MSG.tarefa]);
 			       #endif
			       #ifdef V1
                                 rt_task_suspend(&tarefa[MSG.tarefa]);
                               #endif

	default:
				return -EINVAL;

		}
    }
    if (err != 0){
        return  -EINVAL;
        }

  return 0;
}

int init_ad(unsigned int port, unsigned int range)
{
  int err=0;

  // Verifica se os enderecos necessarios para o AD estao disponiveis
  // Nao entendi check_region e request_region

  if ((err=check_region(port,range)) < 0) return err;         /* busy */
  request_region(port,range,"Placa AD/DA");                 /* always succeeds */

  // Programacao do AD


  // Programacao do AD para a placa DAS1601

#ifdef DAS1600
   controle_ad = (((AD_INTE & 0x01) << 7)| ((AD_LEVEL & 0x07) << 4) | ((AD_DMAE & 0x01) << 2) | (AD_TRIG & 0x03));
   outb(controle_ad, AD_CTRL);   /* 0 		INT
			     xxx 	INT LEVEL = HardInt
			     x 		Doesn't matter
			     0 		DMAE = Desabled
			     0x   	Trigger Source = Timer */

   controle_ad = (((AD_BRATE & 0x1F) << 2) | (AD_GANHO & 0x03));
   outb(controle_ad, AD_GAIN);		/* Seta ganhos */

   controle_ad = (((AD_BLEN & 0x0F) << 4) | (AD_CLOCK & 0x03));
   outb(controle_ad, AD_CNTEN);    /* Contador 1 e 2 habilitados */

   controle_ad = (((AD_FIM & 0x0F) << 4)| (AD_INICIO & 0x0F));
   outb(controle_ad, AD_MUX);   /* Conversao do Canal 0 somente */
  //outb(0x11, AD_MUX);    /*Conversao do Canal 1 somente */

   outb(AD_HAB, AD_DISARM);   /*  Habilita Conversao */

#endif

  //Programacao do AD para a placa AD do STD

#ifdef AIO
controle_ad = (((AD_GANHO << 5)|AD_CANAL)& 0xFF);
outb(controle_ad,AD_MUX);
#endif



  return(err);

}

int init_ctrl(void)
{

  //num_bits = 12;
  //meio_escala = (2^num_bits)/2;
  FREQHZ = 100.0; //Base para a frequencia de amostragem
  h  = 1.0/FREQHZ;
  Nh = N*h;
  escala = VADPP/4095; // Ambas as placas tem 12 bits de resolucao
  ik=0.0;
  contador=0; //Contador que controla a onda quadrada
  sinal = 1;  // Sinal inicial da onda quadrada

//Inicializa as variaveis de tempo

#ifdef V2
  RT_TICKS_CTRL   = HRTICKS_PER_SEC/ FREQHZ;
  RT_TICKS_SAVE   = 4 * RT_TICKS_CTRL;
  ONDA_QUADRADA   = 20 * FREQHZ;
  ONDA_QUADRADA2  = 20 * FREQHZ / 2;
#endif

#ifdef V1
  RT_TICKS_CTRL   = HRTICKS_PER_SEC/ FREQHZ;  //Deve ter que mudar aqui!
  RT_TICKS_SAVE   = 4 * RT_TICKS_CTRL;
  ONDA_QUADRADA   = 20 * FREQHZ;
  ONDA_QUADRADA2  = 20 * FREQHZ / 2;
#endif


// Inicializa as referencias
PID.ref=0;
PID.sw_amplitud=0.5;

  return 0;
}


int init_module(void)
{
  int adstatus;
  int err;
  int c[5];

#ifdef V1
  RTIME now;
#endif

//#ifdef V2
 // struct sched_param sched_param;
 // hrtime_t now;
 //#endif


#ifdef DAS1600
int base = das1601_port_base ? das1601_port_base : AD_BASE;  //Determina se o endereco base sera o mesmo do arquivo .h
range=0x20;
if (AD_POL==0) {
 VADPP  = 10.0;}  // a placa do DAS está ajustada para trabalhar de 0 a +10 volts
else {
 VADPP  = 20.0;} // a placa do DAS está ajustada para trabalhar de -10 a +10 volts
#endif

#ifdef AIO
int base = AIO_port_base ? AIO_port_base : AD_BASE;        //Determina se o endereco base sera o mesmo do arquivo .h
range=0x20;
VADPP=5.0;       // a placa do STD trabalha de 0 a 5 volts
#endif


  if((err=init_ad(base, 0x20)) != 0 ) {         //Se o AD nao puder ser inicializado retorna uma mensagem de erro
    printk(KERN_INFO "I/O Address already used\n");
    printk("I/O Address already used\n");
    return(-1);
  }

  init_ctrl(); //Inicializa as variaveis de tempo, frequencia, escala, etc.

  printk(KERN_INFO "di.c:2.0 09/05/00 fernando@coep.ufrj.br\n");


#ifdef DEBUG
  printk(KERN_INFO "di.c: Sampling time: %i*nanoseg \n", RT_TICKS_CTRL);
  printk(KERN_INFO "di.c: Saving interval: %i*nanoseg \n", RT_TICKS_SAVE);
#endif

  // Nao exporta as variaveis globais para o kernel
  //register_symtab(0);



  // Cria as FIFOs

  c[0] = rtf_create(0, 1000);  // y
  c[1] = rtf_create(1, 1000);  // status ad
  c[2] = rtf_create(2, 1000);  // parametros PID
  c[3] = rtf_create(3, 1000);  // u
  c[4] = rtf_create(4, 1000); //comandos para o tarefa0 (lei_controle) e para o tarefa1 (salvar_dados)

  printk("Fifo return 0=%d 1=%d 2=%d 3=%d 4=%d\n",c[0],c[1],c[2],c[3],c[4]);




  // Le o status do AD

#ifdef DAS1600
  adstatus = inb(AD_STATUSA);
#endif

#ifdef AIO
  adstatus = (inb(AD1));
  adstatus = ((adstatus & 0xC0) >> 6);
#endif

  //rtf_put(1, &adstatus, sizeof(int));
  rtf_put(1, &FREQHZ, sizeof(float));




  // Cria as threads

#ifdef V2
  pthread_create(&tarefa[0], NULL,lei_controle, (void *)1);
  sched_param.sched_priority = 1;
  pthread_setschedparam (tarefa[0],  SCHED_FIFO, &sched_param);

  pthread_create (&tarefa[1], NULL, &salvar_dados, (void *)1);
  sched_param.sched_priority = 4;
  pthread_setschedparam (tarefa[1],  SCHED_FIFO, &sched_param);

 now = gethrtime();

  /* the 2 tarefas run periodically with an offset of 100 time units -> Nao entendi o comentario */

 pthread_make_periodic_np(tarefa[0], now + 1 * NSECS_PER_SEC, RT_TICKS_CTRL);
 pthread_make_periodic_np(tarefa[1], now + 2 * NSECS_PER_SEC, RT_TICKS_SAVE);
#endif



#ifdef V1

rt_task_init(&tarefa[0],(void *)lei_controle,1,3000,1);
rt_task_init(&tarefa[1],(void *)salvar_dados,1,3000,4);

printk("Tarefas inicializadas\n");

now = rt_get_time();

  /* the 2 tasks run periodically with an offset of 100 time units */

rt_task_make_periodic(&tarefa[0], now,120000);
rt_task_make_periodic(&tarefa[1], now + 3000,120000);
#endif

  // Cria o handler de modificacao dos parametros do PID

  rtf_create_handler(2,&mod_pid); //Toda vez que ha uma modificacao da fifo 2 mod_pid eh chamada

  rtf_create_handler(4,&comando); //A rotina comando le a fifo 4 e determina o inicio e o fim das tarefas




  return 0;
}


void cleanup_module(void)
{
  //  int r[2];

  /* release adc  region.
     Before that write zero to the DA */

#ifdef DAS1600
outb(0x00,DA0LB);
outb(0x00,DA0HB);
#endif

#ifdef AIO
outb(0x00,DA0LSB);
outb(0x00,DA0MSB);
#endif

  rtf_destroy(0);
  rtf_destroy(1);
  rtf_destroy(2);
  rtf_destroy(3);
  rtf_destroy(4);

#ifdef V2
  pthread_delete_np(tarefa[0]);
  pthread_delete_np(tarefa[1]);
#endif

#ifdef V1
rt_task_delete(&tarefa[0]);
rt_task_delete(&tarefa[1]);
#endif


release_region(AD_BASE, range);
}

//#define COMMAND_FIFO 4

#define START_TASK	1
#define STOP_TASK	2

typedef struct {
	int command;
	int tarefa;
	int period;
}mensagens ;

typedef struct 		
{
  float kd; 
  float kp; 
  float ki; 
  float ref;
  float sw_amplitud;
}parametros_PID;