Hi Gabor, Hoffman and all,

        First, i'd like to apologize come back to this point now but in the last
days i've been trying to understand (trough your e-mails) and testing my
program to learn how can i use FP in my own programs, but to be honest some
things, even now, aren't clear for me.
          Before talk about my doubts i'd like to thank Gabor for his help
about rtl_printf: I changed all  printk with rtl_printf and my system began
work better although it still freeze sometimes. I'd like to thank Hoffman
too and everybody that sended e-mails about this point. 
        After my mail talking about my "system freezing" Hoffman asked me if the
floating point reference ("10.0") in my init_module() code couldn't be
causing the crash. Well, when he asked this i really didn't know the
answer, now (after many mails) seems to me that it could be the problem but
my practice results are bring me doubts.

        To test my module i removed all the rtl_printf calls. Now my program seems
work very well, without crashs. Important points: I'm still using FP in my
init_module() and fifo handlers and i don't call pthread_setfp_np (or
something like that) in any point of my code.

        Hoping you can help me to understand this,
                                                                                   
Daniela.     

P.S.: My module is attached. Sorry but i didn't have time to translate the
comments.
/* Driver para controle de um duplo integrador. Daniela Almeida 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 range;           // Range de enderecos ocupados pelo AD
int dispara_ad;   //String que dipara o AD
int controle_ad;  //String que controla o funcionamento da placa AD/DA

float FREQHZ;
float VADPP;
int contador; //Contador que controla a onda quadrada
int sinal;  // Sinal da onda quadrada

int count=0;

#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) {
if (count < 100)          //rotina para teste
{
//rtl_printf("Lei de controle Chamada,count= %i\n",count);
count = count+1;
}

#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


     // Rotina para gerar a onda quadrada

    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 eh 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;

    ub = ((int)(uf*2047.0)) + 2048; // Sinal de Controle (Limites setados na placa 
AD/DA. Verificar Header)



    // 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


//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

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

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


  }
}

void *salvar_dados(void *t)
{
  while (1) {
 if (count < 100)          //rotina para teste
{
//rtl_printf("Salvar Dados Chamado, count= %i\n",count);
count = count+1;
}
    //ref = 1.0;

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

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

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

  }
}


int mod_pid(unsigned int fifo)
{
  //rtl_printf("mod_pid chamado\n");
  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;
//pthread_wakeup_np(tarefa[MSG.tarefa]);
hrtime_t now;
#endif

//rtl_printf("Handler Comando Chamado\n");
//while ((err= rtf_get(fifo, &MSG, sizeof(MSG)))== sizeof(MSG)) {  //Atualiza a struct 
MSGS com os novos dados
  err= rtf_get(fifo, &MSG, sizeof(MSG));
  switch (MSG.command){
        case START_TASK:
         //rtl_printf("Comando: %d, Tarefa: %d, Periodo: %g\n", 
MSG.command,MSG.tarefa,MSG.period);
               #ifdef V2
               now = gethrtime();
               pthread_wakeup_np(tarefa[MSG.tarefa]);
               err=pthread_make_periodic_np(tarefa[MSG.tarefa], now, 
HRTICKS_PER_SEC*MSG.period);
               //if (err<0) { rtl_printf("Erro fazendo a tarefa %d periodica, err= 
%i\n",MSG.tarefa,err);} else {//rtl_printf("Sucesso fazendo a tarefa %d periodica, 
err= %i\n",MSG.tarefa,err);}
               #endif
               #ifdef V1
                now = rt_get_time();
                err=rt_task_make_periodic(&tarefa[MSG.tarefa], now,MSG.period);
                //if (err<0) { rtl_printf("Erro fazendo a tarefa %d periodica, err= 
%i\n",MSG.tarefa,err);} else {//rtl_printf("Sucesso fazendo a tarefa %d periodica, 
err= %i\n",MSG.tarefa,err);}
                #endif
          break;
        case STOP_TASK:
         //rtl_printf("Comando: %d, Tarefa: %d, Periodo: %g\n", 
MSG.command,MSG.tarefa,MSG.period);
               #ifdef V2
               err=pthread_suspend_np(tarefa[MSG.tarefa]);
               //if (err<0) { rtl_printf("Erro suspendedo a tarefa %d periodica, err= 
%i\n",MSG.tarefa,err);} else {//rtl_printf("Sucesso suspendendo a tarefa %d periodica, 
err= %i \n",MSG.tarefa,err);}
               #endif
               #ifdef V1
               err=rt_task_suspend(&tarefa[MSG.tarefa]);
               //if (err<0) { rtl_printf("Erro suspendedo a tarefa %d periodica, err= 
%i\n",MSG.tarefa,err);} else {//rtl_printf("Sucesso suspendendo a tarefa %d periodica, 
err= %i \n",MSG.tarefa,err);}
               #endif
               count =0;
           break;
        default:
        //rtl_printf("Dados errados\n");
        //rtl_printf("Comando: %d, Tarefa: %d, Periodo: %d\n", 
MSG.command,MSG.tarefa,MSG.period);
        return -EINVAL;

//              }
    }
    //    if (err != 0){
    //    return  -EINVAL;
    //    }
//rtl_printf("Handler Comando Finalizado\n");
  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)
{
  FREQHZ = 50.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;        // Periodo em nanosegundos
  RT_TICKS_SAVE   = 1 * RT_TICKS_CTRL;            // Periodo em nanosegundos
  ONDA_QUADRADA   = 10 * FREQHZ;
  ONDA_QUADRADA2  = 10 * FREQHZ / 2;
#endif

#ifdef V1
  RT_TICKS_CTRL   = RT_TICKS_PER_SEC/ FREQHZ;       //Periodo em Ticks do 8254
  RT_TICKS_SAVE   = 4 * RT_TICKS_CTRL;             //Periodo em Ticks do 8254
  ONDA_QUADRADA   = 20 * FREQHZ;
  ONDA_QUADRADA2  = 20 * FREQHZ / 2;
#endif


// Inicializa as referencias
PID.ref=0.0;
PID.sw_amplitud=0.0;

  return 0;
}


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


#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;
#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;
#endif


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



 /* //rtl_printf(KERN_INFO "di.c:2.0 09/05/00 [EMAIL PROTECTED]\n"); */


/*#ifdef DEBUG
  //rtl_printf(KERN_INFO "di.c: Sampling time: %i*nanoseg \n", RT_TICKS_CTRL);
  //rtl_printf(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)
  c[5] = rtf_create(5, 1000); //Teste de Funcionamento guarda o valor  de count

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


  // Le o status do AD

#ifdef DAS1600
adstatus = inb(AD_STATUSA);
AD_POL= ((adstatus & 0x40) >> 6);

if (AD_POL==0) {
 VADPP  = 20.0;
 AD_POL = 2048;}  // a placa do DAS esta ajustada para trabalhar de -10 a +10 volts
else if (AD_POL==1){
 VADPP  = 10.0;
AD_POL = 0;} // a placa do DAS esta ajustada para trabalhar de 0 a +10 volts
else{
 //rtl_printf("Erro lendo o status do AD\n");
 return (-1);
}
#endif

#ifdef AIO
  VADPP = 5.0;          // a placa AIO trabalha somente de 0 a +5 Volts (AD e DA)
  adstatus = (inb(AD1));
  adstatus = (((adstatus & 0xC0) >> 5)|AD_POL);

 if (AD_POL==0) {
  AD_POL = 2048;}                // A planta de controle tem saida bipolar
 else if (AD_POL==1){
 AD_POL = 0;}           // A planta de controle tem saida unipolar
 else{
  //rtl_printf("Erro lendo o status do AD\n");
  return (-1);
 }

#endif

  rtf_put(1, &adstatus, sizeof(int));  //Grava o status do AD na rtf1

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


  // Cria as threads

#ifdef V2
  err=pthread_create(&tarefa[0], NULL,lei_controle, (void *)1);
  //if (err<0) {rtl_printf("Erro iniciando a tarefa 0\n");} else {rtl_printf("Tarefa 0 
inicializada corretamente\n");}
  sched_param.sched_priority = 1;
  pthread_setschedparam (tarefa[0],  SCHED_FIFO, &sched_param);

  err=pthread_create (&tarefa[1], NULL,salvar_dados, (void *)1);
  //if (err<0) {rtl_printf("Erro iniciando a tarefa 1\n");} else {rtl_printf("Tarefa 1 
inicializada corretamente\n");}
  sched_param.sched_priority = 4;
  pthread_setschedparam (tarefa[1],  SCHED_FIFO, &sched_param);

 now = gethrtime();

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

err=pthread_make_periodic_np(tarefa[0], now + 1 * NSECS_PER_SEC, RT_TICKS_CTRL);
//if (err<0) {rtl_printf("Erro fazendo a tarefa 0 periodica\n");} else 
{rtl_printf("Sucesso fazendo a tarefa 0 periodica\n");}
err=pthread_make_periodic_np(tarefa[1], now + 2 * NSECS_PER_SEC, RT_TICKS_SAVE);
//if (err<0) {rtl_printf("Erro fazendo a tarefa 1 periodica\n");} else 
{rtl_printf("Sucesso fazendo a tarefa 1 periodica\n");}

#endif



#ifdef V1

err = rt_task_init(&tarefa[0],(void *)lei_controle,1,3000,1);
//if (err<0) {rtl_printf("Erro iniciando a tarefa 0\n");} else {rtl_printf("Tarefa 0 
inicializada corretamente\n");}
err = rt_task_init(&tarefa[1],(void *)salvar_dados,1,3000,4);
//if (err<0) {rtl_printf("Erro iniciando a tarefa 1\n");} else {rtl_printf("Tarefa 1 
inicializada corretamente\n");}

//rtl_printf("Tarefas inicializadas\n");

now = rt_get_time();


err=rt_task_make_periodic(&tarefa[0], now, RT_TICKS_CTRL);  // Ha 1193180 Ticks em 1 
segundo (Era 120000)
//if (err<0) {rtl_printf("Erro fazendo a tarefa 0 periodica\n");} else 
{rtl_printf("Sucesso fazendo a tarefa 0 periodica\n");}
err=rt_task_make_periodic(&tarefa[1], now + 3000,RT_TICKS_SAVE);  // Ha 1193180 Ticks 
em 1 segundo (Era 120000)
//if (err<0) {rtl_printf("Erro fazendo a tarefa 1 periodica\n");} else 
{rtl_printf("Sucesso fazendo a tarefa 1 periodica\n");}
#endif

  // Cria o handler de modificacao dos parametros do PID

err=rtf_create_handler(2,&mod_pid); //Toda vez que ha uma modificacao da fifo 2 
mod_pid eh chamada
//if (err<0) {rtl_printf("Erro criando o handler 1\n");} else {rtl_printf("Sucesso 
criando o handler 1\n");} 
err=rtf_create_handler(4,&comando); //A rotina comando le a fifo 4 e determina o 
inicio e o fim das tarefas
//if (err<0) {rtl_printf("Erro criando o handler 2\n");} else {rtl_printf("Sucesso 
criando o handler 2\n");}

  return 0;
}


void cleanup_module(void)
{

  /* 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;
        float period;
}mensagens ;

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

Reply via email to