[Rtai] Strange comedi command behaviour in RTAI

Jordi Blanch Carles jordi_blanch at encopim.com
Wed Dec 2 11:13:56 CET 2009


Dear Paolo,

>> We need to use a NI PCI-6229 daq card to make acquisitions   
>> asynchronously 2 repeated times on 4 analog channels (comedi comand  
>>  channels list is as follows: 0,1,2,3,0,1,2,3) until we stop it  
>> when  we reach certain condition. We configure the board to wake up  
>> our  task everytime it has finished the acquisition using   
>> rt_comedi_data_wread() method.
>>
>
> The only thing I can verify, as soon as I can get my hands onto a
> board, is the use of a scan with repetition, of the type you used
> above, in user space. The outcome can make me aware if there is a bug
> or a C++ specific coding problem. I let you know when I'll do it.

I think it can be useful for you to know that we have modified the  
code in showroom/v3.x/user/comedi/cmd.c to create a command that makes  
a scan with repetition (as we need in our application) and the  
resulting code is working properly, we get the correct values for each  
sample. So maybe there's something with using C++ that "breaks this  
correct behaviour", but we cannot imagine what, maybe some compilation  
flags must be forbidden?

Thank you for your help.


>
> Paolo
>
>> We have created a task using showroom/v3.x/user/comedi/cmd.c as an   
>> example. We have modified this example to convert it to a C++ class  
>>  to use it in our application.
>>
>> Everything seemed to work properly until we forced different analog  
>>  signals to the AI inputs of the daq card. We realized that,   
>> although we got some values for each channel at each sample, this   
>> values didn't correspond to the value it was supposed to have read   
>> the card. Only the first position of the buffer read with   
>> rt_comedi_data_wread() has a "real" value corresponding to the   
>> voltage forced to the AI pin, the other positions of the buffer   
>> have some values that could seem "real" 0 volts values but they   
>> aren't. Moreover, the 5th position of the buffer should correspond   
>> to the second acquisition of channel 0, and the value read is   
>> always the same and doesn't follow the same values than the first   
>> position of the buffer as it should. If we force an analog signal   
>> to the corresponding pin of any other analog channel, nothing   
>> changes in the values of the corresponding positions of the buffer.
>>
>> We have tried to delete everything else in our code so we only read  
>>  the buffer returned by the rt_comedi_data_wread() method, but   
>> nothing seems to change this strange behaviour. All channels give   
>> values oscillating around what should be 0 volts at the analog   
>> input pin, so it seems that these values are something that must be  
>>  read from wherever. We have also tried to force an analog signal  
>> to  every channel of the board, but nothing changes.
>>
>> The examples found in comedilib/demo and   
>> showroom/v3.x/user/comedi/cmd.c work properly and we can read   
>> analog values for any analog input channel of the board, so we   
>> really don't know what else to try to know where is our error and   
>> why do we have this strange problem.
>>
>> Does anybody have any idea of which could be our problem?
>>
>> I attach the complete code of our C++ classes because we don't know  
>>  where else to search for our error.
>>
>> Thank you very much for your help.
>>
>> ---GestorAdquisicions.h---
>> /*
>> * File:   GestorAdquisicions.h
>> * Author: carlos
>> *
>> * Created on 15 de octubre de 2009, 16:12
>> */
>>
>> #ifndef _GESTORADQUISICIONS_H
>> #define        _GESTORADQUISICIONS_H
>>
>> #include <iostream>
>> #include <rtai_comedi.h>
>>
>> #include "SensorsEncopim.h"
>> #include "Etapa.h"
>>
>> #define NSEGONS_EN_1_SEGON                  1000000
>> #define KHZ_A_NSEGONS(khz)                  (NSEGONS_EN_1_SEGON / khz)
>> #define FREQUENCIA_MAXIMA_TARGA_NS          KHZ_A_NSEGONS(250)
>> #define NS_PER_ADQUISICIO(numCanals,khz)      
>> ((NSEGONS_EN_1_SEGON/khz) / numCanals)
>>
>> #define NUM_MAXIM_TASQUES                   100
>> #define AI_RANGE                            0
>> #define RT_STACK                            4000
>> #define TIMEOUT                             100000000
>>
>> /**
>> *  Clase GestorAdquisicions. Classe encarregada de configurar la targeta
>> *  d'adquisicio per que aquesta funcioni independentment i ens avisi a
>> *  traves d'un trigger cada cop que ha fet una adquisicio.
>> *  Amb aquesta classe els cicles en temps real ja no seran periodics sino
>> *  que s'han de registrar a la classe i cada cop que arribi un trigger
>> *  cridarem els cicles.
>> */
>>
>> class GestorAdquisicions : public Etapa {
>> private:
>>    /** Matriu on guardem les dades de cada escaneig */
>>    double** arrayDades;
>>    /** Array temporal on recollim les dades per posar-les a la matriu */
>>    lsampl_t* arrayTemporalDades;
>>    /** Nombre de overscan que volem fer */
>>    int overscan;
>>    /** Nombre de canals que recollim */
>>    int numCanals;
>>    /** Nombre de encoders que haurem d'agafar a cada callback */
>>    int numEncoders;
>>    /** Nombre de sensors digitals */
>>    int numSensorsDigitals;
>>    /** Array dels valors anteriors dels encoders */
>>    double* valorsAnteriorsEncoders;
>>    /** Array dels valors actuals dels encoders */
>>    double* valorsActualsEncoders;
>>    /** Array dels valors dels sensors digitals */
>>    lsampl_t* valorsSensorsDigitals;
>>    /** Array amb els canals que volem recollir */
>>    int* indexCanals;
>>    /** Array de sensors Analogics que volem fer servir per tractar   
>> les dades recollides
>> */
>>    SensorDecorator** sensorsAnalogics;
>>    /** Array de sensors Digitals que volem fer servir per tractar   
>> les dades recollides */
>>    SensorDecorator** sensorsDigitals;
>>    /** Frequencia del control (sense el overscan) que volem fer   
>> servir (KHz) */
>>    int frequenciaControl;
>>    /** Flag per acabar l'adquisicio en la seguent iteracio */
>>    bool fiAdquisicio;
>>    /** Flag d'estat de l'adquisicio */
>>    bool isAdquirint;
>>    /** Instruccions per fer les adquisicions digitals */
>>    comedi_insn *insn;
>>    /** Puntero para la lista de instrucciones */
>>    comedi_insnlist ilist;
>>
>>    comedi_t *dev;
>>    int subdevAnalogic;
>>    int subdevDigital;
>>    comedi_cmd cmd;
>>
>>    RT_TASK **arrayTasques;
>>    RT_TASK *task;
>>    int numTasques;
>>
>>    void configuraAdquisicio();
>> public:
>>    GestorAdquisicions() {}
>>    GestorAdquisicions(int overscan, int frequenciaControl, SensorDecorator**
>> sensorsAnalogics,
>>            SensorDecorator** sensorsDigitals, int numCanals, int   
>> numEncoders,
>>                        int numSensors, comedi_t* dev);
>>
>>    ~GestorAdquisicions();
>>
>>    int getOverscan() {return this->overscan;}
>>    void setOverscan(int overscan) {this->overscan = overscan;}
>>
>>    int getNumCanals() {return numCanals + numEncoders + numSensorsDigitals;}
>>    void setNumCanals(int numCanals) {this->numCanals = numCanals;}
>>
>>    int getFrequenciaControl() {return this->frequenciaControl;}
>>    void setFrequenciaControl(int frequenciaControl)   
>> {this->frequenciaControl =
>> frequenciaControl;}
>>
>>    int* getIndexCanals() {return this->indexCanals;}
>>    double** getArrayDades() {return this->arrayDades;}
>>    double* getDadesCanal(int i) {return this->arrayDades[i];}
>>    void getDadesScan(int numScan, double* scan);
>>
>>
>>    comedi_t* getDevice() {return this->dev;}
>>    void setDevice(comedi_t* dev) {this->dev = dev;}
>>
>>    RT_TASK* getTasca(int i) {return this->arrayTasques[i];}
>>    void setTasca(int i, RT_TASK* task) {this->arrayTasques[i] = task;}
>>    RT_TASK** getArrayTasques() {return this->arrayTasques;}
>>    void setArrayTasques(RT_TASK** arrayTasques) {this->arrayTasques  
>>  = arrayTasques;}
>>
>>    double getDadaOverscan(int indexDada, int numOverscan);
>>    void arrencaAdquisicio();
>>    void aturaAdquisicio();
>>    void registraTasca(RT_TASK* tasca);
>>    void desregistraTasca(RT_TASK* tasca);
>>
>>        virtual void run();
>> };
>>
>> #endif        /* _GESTORADQUISICIONS_H */
>>
>>
>> ---GestorAdquisicions.cpp---
>> #include "GestorAdquisicions.h"
>>
>> GestorAdquisicions :: GestorAdquisicions(int overscan, int   
>> frequenciaControl,
>> SensorDecorator** sensorsAnalogics,
>>        SensorDecorator** sensorsDigitals, int numCanals, int   
>> numEncoders, int
>> numSensors, comedi_t* dev) {
>>    this->overscan = overscan;
>>    this->numCanals = numCanals;
>>    this->numEncoders = numEncoders;
>>    this->numSensorsDigitals = numSensors - numCanals - numEncoders;
>>    this->valorsAnteriorsEncoders = new double[numEncoders];
>>    this->valorsActualsEncoders = new double[numEncoders];
>>    this->indexCanals = new int[numCanals];
>>    this->sensorsAnalogics = sensorsAnalogics;
>>        this->sensorsDigitals = sensorsDigitals;
>>    this->frequenciaControl = frequenciaControl;
>>    this->dev = dev;
>>    for (int i = 0; i < numCanals; i++) {
>>        //cout << "Sensor " << i << ": " <<   
>> this->sensorsAnalogics[i] << endl;
>>        this->indexCanals[i] = this->sensorsAnalogics[i]->getCanal();
>>        cout << "Canal sensor " << i << ": " <<   
>> this->sensorsAnalogics[i]->getCanal() <<
>> endl;
>>    }
>>
>>    this->arrayDades = new double*[numSensors];
>>    this->arrayDades = new double*[numCanals];
>>    for (int i = 0; i < numSensors; i++) {
>>        this->arrayDades[i] = new double[overscan];
>>    }
>>    this->arrayTemporalDades = new lsampl_t[overscan * numCanals];
>>    this->valorsSensorsDigitals = new lsampl_t[numSensorsDigitals];
>>    this->numTasques = 0;
>>    this->arrayTasques = new RT_TASK*[NUM_MAXIM_TASQUES];
>>    for (int i = 0; i < NUM_MAXIM_TASQUES; i++) {
>>        this->arrayTasques[i] = NULL;
>>    }
>>    this->insn = new comedi_insn[numSensorsDigitals];
>>    this->fiAdquisicio = false;
>> }
>>
>> GestorAdquisicions :: ~GestorAdquisicions() {
>>    delete [] indexCanals;
>>    for (int i = 0; i < (numCanals + numEncoders +   
>> numSensorsDigitals); i++) {
>>        delete arrayDades[i];
>>    }
>>    delete [] arrayDades;
>>    delete [] valorsAnteriorsEncoders;
>>    delete [] valorsActualsEncoders;
>>    delete [] valorsSensorsDigitals;
>>    delete [] arrayTemporalDades;
>>    delete [] insn;
>> }
>>
>> double GestorAdquisicions :: getDadaOverscan(int indexDada, int   
>> numOverscan) {
>>    return arrayDades[indexDada][numOverscan];
>> }
>>
>> void GestorAdquisicions :: configuraAdquisicio() {
>>    unsigned int chanlist[overscan * numCanals];
>>    subdevAnalogic = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_AI, 0);
>>        cout << "Subdev: " << subdevAnalogic << endl;
>>    memset(&cmd, 0, sizeof(cmd));
>>
>>    for (int i = 0; i < (overscan * numCanals); i++) {
>>        chanlist[i] = CR_PACK(indexCanals[i % numCanals], AI_RANGE,   
>> AREF_GROUND);
>>                cout << "Canal " << i << ": " << indexCanals[i %   
>> numCanals] << ", chanlist: " <<
>> chanlist[i] << endl;
>>    }
>>
>>    cmd.subdev = subdevAnalogic;
>>    cmd.flags = TRIG_RT | TRIG_WAKE_EOS;
>>
>>    cmd.start_src = TRIG_NOW;
>>    cmd.start_arg = 0;
>>
>>    cmd.scan_begin_src = TRIG_TIMER;
>>    cmd.scan_begin_arg = KHZ_A_NSEGONS(frequenciaControl);
>>    //cmd.scan_begin_arg = 1000000;
>>        //cout << "Scan begin: " << KHZ_A_NSEGONS(frequenciaControl)  
>>  << ", frequenciaControl: "
>> << frequenciaControl << endl;
>>
>>    cmd.convert_src = TRIG_TIMER;
>>    cmd.convert_arg = NS_PER_ADQUISICIO((overscan * numCanals),   
>> frequenciaControl);
>>    //cmd.convert_arg = 125000;
>>        //cout << "Convert: " << NS_PER_ADQUISICIO((overscan *   
>> numCanals), frequenciaControl) <<
>> ", overscan: " << overscan << ", numCanals: " << numCanals << endl;
>>
>>    cmd.scan_end_src = TRIG_COUNT;
>>    cmd.scan_end_arg = (overscan * numCanals);
>>    //cmd.scan_end_arg = 8;
>>
>>    cmd.stop_src = TRIG_NONE;
>>    cmd.stop_arg = 0;
>>
>>    cmd.chanlist = chanlist;
>>    cmd.chanlist_len = (overscan * numCanals);
>>    //cmd.chanlist_len = 8;
>>
>>    for (int i = 0; i < numCanals; i++) {
>>        sensorsAnalogics[i]->inicialitzaSensor(overscan);
>>    }
>>
>>    // Configurem la llista d'instruccions per fer l'adquisicio dels  
>>  sensors digitals
>>    ilist.n_insns = numSensorsDigitals;
>>    ilist.insns = insn;
>>    // Configurem cada una de les instruccions per l'adquisicio digital
>>    subdevDigital = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_DIO, 0);
>>    for (int i = 0; i < numSensorsDigitals; i++) {
>>        memset(&insn[i], 0, sizeof(insn[i]));
>>        insn[i].insn = INSN_READ;
>>        insn[i].n = 1;
>>        insn[i].data = &valorsSensorsDigitals[i];
>>        insn[i].subdev = subdevDigital;
>>        insn[i].chanspec = CR_PACK(sensorsDigitals[i]->getCanal(), 0, 0);
>>    }
>> }
>>
>> void GestorAdquisicions :: run() {
>>        //cout << "Anem a arrencar l'adquisisio en un thread nou" << endl;
>>    arrencaAdquisicio();
>> }
>>
>> void GestorAdquisicions :: arrencaAdquisicio() {
>>    if (!isAdquirint) {
>>        isAdquirint = true;
>>        configuraAdquisicio();
>>
>>        for (int i = 0; i < numEncoders; i++) {
>>            valorsAnteriorsEncoders[i] = sensorsAnalogics[(numCanals  
>>  + i)]->get();
>>        }
>>
>>        task = rt_task_init_schmod(nam2num("TASCA_ADQUISICIO"), 1,   
>> 0, 0, SCHED_FIFO, 0xF);
>>        mlockall(MCL_CURRENT | MCL_FUTURE);
>>        rt_make_hard_real_time();
>>
>>        rt_comedi_register_callback(dev, subdevAnalogic,   
>> COMEDI_CB_EOS, NULL, task);
>>
>>        int ret = comedi_command_test(dev, &cmd);
>>                //cout << "Comedi commmand test: " << ret << endl;
>>        ret = comedi_command_test(dev, &cmd);
>>                cout << "Comedi commmand test: " << ret << endl;
>>        if (ret == 0) {
>>            ret = comedi_command(dev, &cmd);
>>        } else {
>>            cout << "Error en cmd test: " << ret << endl;
>>            exit(-1);
>>        }
>>
>>        long mask = COMEDI_CB_EOS;
>>                int numDadesLlegir = overscan * numCanals;
>>                int cont;
>>        while(!fiAdquisicio) {
>>            cont = 0;
>>            //cout << "Esperem dades: " << numDadesLlegir << endl;
>>            ret = rt_comedi_command_data_wread(dev, subdevAnalogic,   
>> numDadesLlegir,
>> arrayTemporalDades, &mask);
>>            //cout << "Llegit dades: " << ret << endl;
>>            // Agafem els valors dels encoders
>>            for (int i = 0; i < numEncoders; i++) {
>>                valorsActualsEncoders[i] =   
>> sensorsAnalogics[(numCanals + i)]->get();
>>            }
>>
>>            rt_comedi_do_insnlist(dev, &ilist);
>>
>>            for (int j = 0; j < overscan; j++) {
>>                // Posem els valors que agafem en la callback a   
>> l'array de dades
>>                // passant-los per les operacions dels propis sensors
>>                                //cout << "Agafem les dades,   
>> numCanals: " << numCanals << endl;
>>                for (int i = 0; i < numCanals; i++) {
>>                                        cout << " Dada " << cont <<   
>> ": " << arrayTemporalDades[cont];
>>                    //sensorsAnalogics[i]->setDada(j,   
>> (double)arrayTemporalDades[cont]);
>>                    //sensorsAnalogics[i]->setIndexOverscan(j);
>>                    //sensorsAnalogics[i]->setDada(j,   
>> sensorsAnalogics[i]->get());
>>                    //arrayDades[i][j] = sensorsAnalogics[i]->getDada(j);
>>                    //arrayDades[i][j] = (double)arrayTemporalDades[cont];
>>                    //if (i==0) cout << "GestorAdquisicion::Canal 0   
>> Overscan " << j << ",
>> dada: " << arrayDades[i][j] << endl;
>>                    cont++;
>>                    //sensorsAnalogics[i]->setNovaAdquisicio(1);
>>                }
>>                // Agafem els valors dels encoders
>>                for (int i = 0; i < numEncoders; i++) {
>>                    if (j == overscan) {
>>                        arrayDades[i + numCanals][j] =   
>> valorsActualsEncoders[i];
>>                        valorsAnteriorsEncoders[i] =   
>> valorsActualsEncoders[i];
>>                    } else {
>>                        arrayDades[i + numCanals][j] =   
>> valorsAnteriorsEncoders[i] +
>> ((valorsActualsEncoders[i] - valorsAnteriorsEncoders[i]) / overscan);
>>                    }
>>                }
>>                // Agafem els valors dels sensors digitals
>>                for (int i = 0; i < numSensorsDigitals; i++) {
>>                    arrayDades[i + numCanals + numEncoders][j] =
>> (double)valorsSensorsDigitals[i];
>>                }
>>            }
>>                        cout << endl;
>>            for (int i = 0; i < NUM_MAXIM_TASQUES; i++) {
>>                //cout << "Tasca " << i << ": " << arrayTasques[i] << endl;
>>                if (arrayTasques[i] != NULL) {
>>                    //cout << "GestorAdquisicions::Resume de la tasca: " <<
>> arrayTasques[i] << endl;
>>                    rt_task_resume(arrayTasques[i]);
>>                }
>>            }
>>        }
>>        fiAdquisicio = false;
>>    }
>> }
>>
>> void GestorAdquisicions :: aturaAdquisicio() {
>>    cout << "GestorAdquisicions::Aturar adquisicio" << endl;
>>    if (isAdquirint) {
>>        fiAdquisicio = true;
>>        //cout << "GestorAdquisicions::flag fiAdquisicio aixecat,   
>> esperem" << endl;
>>        while (fiAdquisicio) {
>>            rt_sleep(100000);
>>        }
>>        //cout << "GestorAdquisicions::Adquisicio finalitzada" << endl;
>>        isAdquirint = false;
>>        comedi_cancel(dev, subdevAnalogic);
>>        rt_sleep(100000);
>>        //cout << "GestorAdquisicions::Adquisicio aturada" << endl;
>>        rt_make_soft_real_time();
>>        rt_sleep(100000);
>>        rt_task_delete(task);
>>        //cout << "GestorAdquisicions::Tasca rt esborrada" << endl;
>>    }
>> }
>>
>> void GestorAdquisicions :: registraTasca(RT_TASK* tasca) {
>>    cout << "GestorAdquisicions::Registrem tasca: " << tasca << endl;
>>    for (int i = 0; i < NUM_MAXIM_TASQUES; i++) {
>>        if (this->arrayTasques[i] == NULL) {
>>            cout << "GestorAdquisicions::Tasca registrada a la   
>> posicio " << i << endl;
>>            this->arrayTasques[i] = tasca;
>>            numTasques++;
>>            break;
>>        }
>>    }
>> }
>>
>> void GestorAdquisicions :: desregistraTasca(RT_TASK* tasca) {
>>    cout << "Desregistrem tasca: " << tasca << endl;
>>    for (int i = 0; i < NUM_MAXIM_TASQUES; i++) {
>>        if (this->arrayTasques[i] == tasca) {
>>            cout << "Tasca desregistrada de la posicio: " << i << endl;
>>            this->arrayTasques[i] = NULL;
>>            numTasques--;
>>            break;
>>        }
>>    }
>> }
>>
>> void GestorAdquisicions :: getDadesScan(int numScan, double* scan) {
>>    for (int i = 0; i < numCanals; i++) {
>>        scan[i] = arrayDades[i][numScan];
>>    }
>> }
>>
>>
>> Jordi Blanch Carles
>> Unidad de Ensayo y Control
>>
>> ENCOPIM S.L.
>> C/. del Parc, 5 (nave 13)
>> P.I. Els Pinetons
>> E-08291 RIPOLLET (Barcelona)
>> Tel: (+34) 935 94 23 47
>> Fax: (+34) 935 94 64 15
>>
>> ==========================================================
>> La información contenida en la presente transmisión es confidencial y su
>> uso únicamente está permitido a su(s) destinatario(s). Si Ud. no es la
>> persona destinataria de la presente transmisión, rogamos nos lo
>> comunique de manera inmediata por teléfono (+34 935 942 347) y destruya
>> cualquier copia de la misma (tanto digitales como en papel).
>>
>> The information contained in this transmission is confidential and is
>> intended only for the use of the addressee(s). If you are not the
>> designated recipient of this transmission, please advise us immediately
>> by telephone (+34 935 942 347) and destroy any copies (digital and
>> paper).
>> ======================================================
>> _______________________________________________
>> Rtai mailing list
>> Rtai at rtai.org
>> https://mail.rtai.org/cgi-bin/mailman/listinfo/rtai
>>



Jordi Blanch Carles
Unidad de Ensayo y Control

ENCOPIM S.L.
C/. del Parc, 5 (nave 13)
P.I. Els Pinetons
E-08291 RIPOLLET (Barcelona)
Tel: (+34) 935 94 23 47
Fax: (+34) 935 94 64 15

==========================================================
La información contenida en la presente transmisión es confidencial y su
uso únicamente está permitido a su(s) destinatario(s). Si Ud. no es la
persona destinataria de la presente transmisión, rogamos nos lo
comunique de manera inmediata por teléfono (+34 935 942 347) y destruya
cualquier copia de la misma (tanto digitales como en papel).

The information contained in this transmission is confidential and is
intended only for the use of the addressee(s). If you are not the
designated recipient of this transmission, please advise us immediately
by telephone (+34 935 942 347) and destroy any copies (digital and
paper).
======================================================


More information about the Rtai mailing list