<?xml version="1.0" encoding="ISO-8859-1"?><article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<front>
<journal-meta>
<journal-id>2227-1899</journal-id>
<journal-title><![CDATA[Revista Cubana de Ciencias Informáticas]]></journal-title>
<abbrev-journal-title><![CDATA[Rev cuba cienc informat]]></abbrev-journal-title>
<issn>2227-1899</issn>
<publisher>
<publisher-name><![CDATA[Editorial Ediciones Futuro]]></publisher-name>
</publisher>
</journal-meta>
<article-meta>
<article-id>S2227-18992014000200003</article-id>
<title-group>
<article-title xml:lang="es"><![CDATA[Desarrollo de un driver GNU/Linux para sistemas de adquisición de datos embebidos]]></article-title>
<article-title xml:lang="en"><![CDATA[GNU/Linux driver development for embedded data acquisition systems]]></article-title>
</title-group>
<contrib-group>
<contrib contrib-type="author">
<name>
<surname><![CDATA[Iglesias-Benitez]]></surname>
<given-names><![CDATA[Adrian]]></given-names>
</name>
<xref ref-type="aff" rid="A01"/>
</contrib>
<contrib contrib-type="author">
<name>
<surname><![CDATA[Toledano-Hernández]]></surname>
<given-names><![CDATA[Abel]]></given-names>
</name>
<xref ref-type="aff" rid="A01"/>
</contrib>
<contrib contrib-type="author">
<name>
<surname><![CDATA[Toledo-Enriquez]]></surname>
<given-names><![CDATA[Dainelys]]></given-names>
</name>
<xref ref-type="aff" rid="A01"/>
</contrib>
<contrib contrib-type="author">
<name>
<surname><![CDATA[Gentile Martínez-Casado]]></surname>
<given-names><![CDATA[Jorge]]></given-names>
</name>
<xref ref-type="aff" rid="A01"/>
</contrib>
<contrib contrib-type="author">
<name>
<surname><![CDATA[González-Aguilera]]></surname>
<given-names><![CDATA[Dennys Julián]]></given-names>
</name>
<xref ref-type="aff" rid="A01"/>
</contrib>
</contrib-group>
<aff id="A01">
<institution><![CDATA[,Centro de Inmunoensayo  ]]></institution>
<addr-line><![CDATA[Playa La Habana]]></addr-line>
<country>Cuba</country>
</aff>
<pub-date pub-type="pub">
<day>00</day>
<month>06</month>
<year>2014</year>
</pub-date>
<pub-date pub-type="epub">
<day>00</day>
<month>06</month>
<year>2014</year>
</pub-date>
<volume>8</volume>
<numero>2</numero>
<fpage>35</fpage>
<lpage>51</lpage>
<copyright-statement/>
<copyright-year/>
<self-uri xlink:href="http://scielo.sld.cu/scielo.php?script=sci_arttext&amp;pid=S2227-18992014000200003&amp;lng=en&amp;nrm=iso"></self-uri><self-uri xlink:href="http://scielo.sld.cu/scielo.php?script=sci_abstract&amp;pid=S2227-18992014000200003&amp;lng=en&amp;nrm=iso"></self-uri><self-uri xlink:href="http://scielo.sld.cu/scielo.php?script=sci_pdf&amp;pid=S2227-18992014000200003&amp;lng=en&amp;nrm=iso"></self-uri><abstract abstract-type="short" xml:lang="es"><p><![CDATA[En el presente trabajo se aborda el desarrollo de un driver para el manejo de un sistema de adquisición de datos controlado por la computadora de placa única MINI2440 basada en el procesador RISC de 32 bits S3C2440 de Samsung, equipado con un núcleo ARM920T sobre el cual se ejecuta el sistema operativo embebido GNU/Linux. Se pretende ofrecer una visión global del sistema describiendo sus componentes de hardware y software. Se hace énfasis en la utilización de las estructuras, funciones y primitivas de bloqueo y sincronización que ofrece GNU/Linux para resolver problemas del tipo productor/consumidor.]]></p></abstract>
<abstract abstract-type="short" xml:lang="en"><p><![CDATA[The present work focuses on the development of a driver to handle a data acquisition system controlled by the MINI2440 single board computer based on the S3C2440 RISC processor from Samsung and equipped with an ARM920T 32 bits kernel, in which an embedded GNU/Linux operating system is executed. A global vision of the system is presented and the hardware and software components are described. Emphasis is made in the use of structures, functions and blocking and synchronization primitives GNU/Linux offers to solve problems of the producer´s/consumer´s kind.]]></p></abstract>
<kwd-group>
<kwd lng="es"><![CDATA[Drivers]]></kwd>
<kwd lng="es"><![CDATA[GNU/Linux]]></kwd>
<kwd lng="es"><![CDATA[sistemas embebidos]]></kwd>
<kwd lng="es"><![CDATA[sistemas de adquisición de datos]]></kwd>
<kwd lng="en"><![CDATA[Data acquisition systems]]></kwd>
<kwd lng="en"><![CDATA[drivers]]></kwd>
<kwd lng="en"><![CDATA[embedded systems]]></kwd>
<kwd lng="en"><![CDATA[GNU/Linux]]></kwd>
</kwd-group>
</article-meta>
</front><body><![CDATA[ <div class=Section1>      <p align=right style='text-align:right'><b><span style='font-size:13.5pt; font-family:Verdana'>ARTÍCULO ORIGINAL</span></b></p>      <p align=right style='text-align:right'>&nbsp;</p>      <p><strong><span style='font-size:13.5pt;font-family:Verdana'>Desarrollo de un driver GNU/Linux para sistemas de adquisición de datos embebidos</span></strong></p>      <p>&nbsp;</p>      <p><strong><span lang=EN-GB style='font-family:Verdana'>GNU/Linux driver development for embedded data acquisition systems</span></strong></p>      <p><span lang=EN-GB>&nbsp;</span></p>      <p><span lang=EN-GB>&nbsp;</span></p>      <p><strong><span style='font-size:10.0pt;font-family:Verdana'>AdrianIglesias-Benitez<sup>1*</sup>, Abel Toledano-Hernández<sup>1</sup>, DainelysToledo-Enriquez<sup>1</sup>, Jorge Gentile Martínez-Casado<sup>1</sup>, Dennys Julián González-Aguilera<sup>1</sup></span></strong></p>      <p><sup><span style='font-size:10.0pt;font-family:Verdana'>1</span></sup><span style='font-size:10.0pt;font-family:Verdana'>Centro de Inmunoensayo, Calle 134, Ave. 25, Cubanacán, Playa, La Habana, Cuba. CP.: 11600</span></p>      ]]></body>
<body><![CDATA[<p><span style='font-size:10.0pt;font-family:Verdana'>*Autor para la correspondencia: <a href="mailto:inpipeta1@cie.sld.cu">inpipeta1@cie.sld.cu</a> &nbsp;</span></p>      <div class=MsoNormal align=center style='text-align:center'>  <hr size=2 width="100%" align=center>  </div>      <p><b><span style='font-size:10.0pt;font-family:Verdana'>RESUMEN</span></b> </p>      <p><span style='font-size:10.0pt;font-family:Verdana'>En el presente trabajo se aborda el desarrollo de un driver para el manejo de un sistema de adquisición de datos controlado por la computadora de placa única MINI2440 basada en el procesador RISC de 32 bits S3C2440 de Samsung, equipado con un núcleo ARM920T sobre el cual se ejecuta el sistema operativo embebido GNU/Linux. Se pretende ofrecer una visión global del sistema describiendo sus componentes de hardware y software. Se hace énfasis en la utilización de las estructuras, funciones y primitivas de bloqueo y sincronización que ofrece GNU/Linux para resolver problemas del tipo productor/consumidor.</span> </p>      <p><b><span style='font-size:10.0pt;font-family:Verdana'>Palabras clave: </span></b><span style='font-size:10.0pt;font-family:Verdana'>Drivers, GNU/Linux, sistemas embebidos, sistemas de adquisición de datos. </span></p>      <div class=MsoNormal align=center style='text-align:center'>  <hr size=2 width="100%" align=center>  </div>      <p><b><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>ABSTRACT</span></b><span lang=EN-GB style='font-family:Verdana'> </span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>The present work focuses on the development of a driver to handle a data acquisition system controlled by the MINI2440 single board computer based on the S3C2440 RISC processor from Samsung and equipped with an ARM920T 32 bits kernel, in which an embedded GNU/Linux operating system is executed. A global vision of the system is presented and the hardware and software components are described. Emphasis is made in the use of structures, functions and blocking and synchronization primitives GNU/Linux offers to solve problems of the producer´s/consumer´s kind.</span><span lang=EN-GB style='font-size:10.0pt'> </span></p>      <p><b><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>Key words: </span></b><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>Data acquisition systems, drivers, embedded systems, GNU/Linux<em><span style='font-family:Verdana'>.</span></em></span></p>      <div class=MsoNormal align=center style='text-align:center'>  <hr size=2 width="100%" align=center>  </div>      ]]></body>
<body><![CDATA[<p>&nbsp;</p>      <p>&nbsp;</p>      <p><b><span style='font-family:Verdana'>INTRODUCCIÓN</span></b></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>El Centro de Inmunoensayo, tiene como misión principal la investigación, desarrollo y producción de estrategias y tecnologías que permitan el pesquisaje de forma económica y científicamente sustentable de enfermedades metabólicas, transmisibles y crónicas no transmisibles, a ciclo completo, incluyendo la exportación y asistencia técnica de los laboratorios y personal que las emplean. El Centro de Inmunoensayo y la tecnología SUMA (Sistema Ultra Micro Analítico) se han desarrollado y perfeccionado en función de los requerimientos del Sistema de Salud Cubano, fortaleciendo el esquema de atención primaria al brindar la posibilidad de realizar estudios a escala masiva, cubriendo el cien por ciento de los programas de Pesquisa Neonatal, Certificación de Sangre, Vigilancia Epidemiológica y de Promoción, Prevención y Control de Enfermedades Metabólicas y Crónicas No Transmisibles. La Tecnología SUMA constituye un sistema, a escala de laboratorio, de diagnosticadores y equipamiento instrumental.    <br> Entre los equipos médicos desarrollados para la tecnología SUMA los sistemas de adquisición de datos juegan un papel fundamental. Tradicionalmente los sistemas de adquisición de datos se han desarrollado sobre microcontroladores de 8 bits. Sin embargo, cada vez más, se hace necesario, para la inserción en el mercado internacional de los equipos producidos, tener en cuenta factores como: la conectividad a través de protocolos universales y de alta velocidad, implementar la interacción con el usuario a través de interfaces táctiles, así como aumentar las capacidades para el procesamiento digital de las señales adquiridas. Sin embargo, también es necesario mantener los precios suficientemente bajos de forma que resulten competitivos. Bajo estas imposiciones, el problema está dado porque los recursos de los microcontroladores de 8 bits, aunque son baratos, no resultan suficientes; y los precios de las computadoras tradicionales de propósito general, aunque son muy potentes, resultan excesivos. Hipotéticamente, se puede solucionar este problema migrando los sistemas de adquisición de datos a sistemas embebidos de 32 bits, que al estar destinados a realizar una tarea específica con recursos limitados, se encuentren en un punto medio entre estas dos alternativas y ofrecen las facilidades que se necesitan a precios razonables (<a href="#_ENREF_1" title="Sloss, 2004 #1">Sloss, 2004</a>).</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Los procesadores basados en núcleos ARM (del inglés &#8220;<em><span style='font-family:Verdana'>Advanced RISC Machine</span></em>&#8221;) de 32 bits han tenido gran éxito en el ámbito de los sistemas embebidos (<a href="#_ENREF_1" title="Sloss, 2004 #1">Sloss, 2004</a>). Basan su funcionamiento en una arquitectura, principalmente, RISC donde instrucciones muy simples, pero poderosas, se ejecutan generalmente en un solo ciclo de máquina a altas velocidades. A menudo en los sistemas embebidos, el mismo chip que contiene el núcleo ARM realiza también otras funciones más allá del procesado convencional de instrucciones secuenciales, y se denominan SOC (del inglés &#8220;<em><span style='font-family:Verdana'>Systemon Chip</span></em>&#8221;) (<a href="#_ENREF_2" title="Wolf, 2008 #2">Wolf, 2008</a>). Sin embargo el aumento de las facilidades ofrecidas por el hardware conlleva al aumento de la complejidad para administrar estos recursos, resultando en la necesidad de adopción de algún sistema operativo que sirva de interfaz entre el desarrollador y la plataforma de desarrollo.</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>El sistema operativo GNU/Linux aplicado a sistemas embebidos ha ido ganando progresivamente el interés del sector científico e industrial (<a href="#_ENREF_3" title="Hallinan, 2011 #3">Hallinan, 2011</a>) al ofrecer una alternativa libre y fiable, así como el apoyo de una activa comunidad de programadores. Entre las numerosas ventajas que han popularizado al sistema operativo GNU/Linux para el desarrollo de sistemas embebidos cabe citar la gran variedad de arquitecturas de hardware que soporta, la disponibilidad de un gran número de aplicaciones, bibliotecas de funciones y protocolos de comunicación, la posibilidad de contar con el código fuente, así como su escalabilidad, pudiendo adaptarse tanto a pequeños dispositivos de consumo como a grandes supercomputadoras (<a href="#_ENREF_4" title="Jones, 2012 #11">Jones, 2012a</a>; <a href="#_ENREF_5" title="Sunny, 2012 #18">Sunny, 2012</a>). Sin embargo, a la vez que GNU/Linux administra los recursos del hardware desde un modo privilegiado de ejecución, también los protege de accesos no autorizados (<a href="#_ENREF_6" title="Bhaira, 2013 #20">Bhaira, 2013</a>). Para que las aplicaciones de usuario puedan hacer uso de todas las facilidades que brinda el sistema, es necesario el desarrollo de drivers de dispositivo (<a href="#_ENREF_7" title="Mauerer, 2008 #5">Mauerer, 2008</a>). Puede plantearse entonces, como objetivo central de esta investigación el desarrollo de programas en GNU/Linux para el manejo de tarjetas de adquisición datos como una vía para obtener sistemas embebidos basados en microprocesadores ARM con mayores facilidades de conexión, interfaces más amigables al usuario y mayor potencia de cómputo.</span></p>      <p>&nbsp;</p>      <p><strong><span style='font-family:Verdana'>MATERIALES Y MÉTODOS</span></strong></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Se entiende por sistemas embebidos una combinación de hardware y software diseñado para tener una función específica. Las principales características de un sistema embebido son el bajo costo y consumo de potencia. Generalmente, los sistemas embebidos emplean procesadores muy básicos, relativamente lentos y memorias pequeñas para minimizar los costos. Los sistemas embebidos deben reaccionar ante estímulos provenientes del ambiente, respondiendo, en muchos casos, con fuertes restricciones de tiempo. En el caso de una información que llega de forma periódica, los tiempos de adquisición y tratamiento de la señal deben ser inferiores al período de actualización de dicha información (<a href="#_ENREF_6" title="Bhaira, 2013 #20">Bhaira, 2013</a>).</span></p>      ]]></body>
<body><![CDATA[<p><strong><span style='font-size:10.0pt;font-family:Verdana'>Plataforma MINI2440</span></strong></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>La plataforma MINI2440 está constituida por una computadora de placa única (SBC, del inglés &#8220;<em><span style='font-family:Verdana'>Single Board Computer</span></em>&#8221;) (<a href="#_ENREF_8" title="Abbott, 2011 #13">Abbott, 2011</a>), que representa un excelente compromiso entre costo y desempeño, y la cadena de herramientas necesarias para el desarrollo de aplicaciones que se ejecutan sobre ella. Está basada en el microprocesador de Samsung S3C2440 (<a href="#_ENREF_9" title="Samsung, 2004 #14">Samsung, 2004</a>) equipado con un núcleo ARM9 de 32 bits que opera a una frecuencia de hasta 533MHz y un conjunto de periféricos que la hacen ideal para el desarrollo de sistemas embebidos. En la <a href="#f01">figura 1</a> pueden observarse los principales componentes que la integran. La plataforma MINI2440 está plenamente soportada por las versiones más recientes del &#8220;<em><span style='font-family:Verdana'>kernel</span></em>&#8221; del sistema operativo GNU/Linux (<a href="#_ENREF_10" title="Jones, 2012 #12">Jones, 2012b</a>).</span></p>      <p align=center style='text-align:center'><a name=f01></a><img border=0 width=574 height=463 src="/img/revistas/rcci/v8n2/f0103214.jpg"></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>En general, la SBC MINI2440 presenta interfaces de comunicación que incluyen: un puerto Ethernet RJ45 de 100MBits, 3 puertos serie RS232, 1 puerto USB maestro, 1 puerto USB esclavo, un conector JTAG, soporte para memorias MMC/SD, conexión con otros dispositivos a través los protocolos IIC y SPI, así como facilidades para la integración con un &#8220;<em><span style='font-family:Verdana'>display</span></em>&#8221; gráfico RGB táctil con resolución de hasta 800 por 600 píxeles. El procesador S3C2440 dispone además de un controlador de interrupciones, 4 temporizadores y un bus de expansión que permite la conexión de módulos hardware diseñados a la medida de las necesidades del sistema embebido (<a href="#_ENREF_9" title="Samsung, 2004 #14">Samsung, 2004</a>).</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>La plataforma MINI2440 utiliza 64MB de SDRAM (Memoria dinámica sincrónica de acceso aleatorio) como memoria principal del sistema, distribuidos en dos bancos de memoria de 32MB; y 128MB de memoria <em><span style='font-family:Verdana'>flash</span></em> tipo NAND que puede utilizarse como soporte de almacenamiento masivo. La memoria <em><span style='font-family:Verdana'>flash </span></em>puede verse como un disco duro de estado sólido capaz de almacenar un gran volumen de información en un pequeño encapsulado, que al no contener partes móviles resulta muy robusto e ideal para entornos industriales. La memoria <em><span style='font-family:Verdana'>flash </span></em>se divide de forma que en ella coexisten el cargador del programa de arranque (en inglés &#8220;<em><span style='font-family:Verdana'>bootloader</span></em>&#8221;), el sistema operativo y el sistema de ficheros, como se muestra en la <a href="#f02">figura 2</a>.</span></p>      <p align=center style='text-align:center'><a name=f02></a><img border=0 width=272 height=275 src="/img/revistas/rcci/v8n2/f0203214.jpg" alt=f02></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>En los procesadores ARM, la memoria y los puertos de entrada/salida comparten el mismo espacio de direcciones y son tratados exactamente de la misma forma por el procesador.</span></p>      <p><strong><span style='font-size:10.0pt;font-family:Verdana'>El sistema de adquisición de datos</span></strong><span style='font-size:10.0pt;font-family: Verdana'>    <br> Se define la adquisición de datos como el proceso mediante el cual un fenómeno físico del mundo real es transformado en una señal eléctrica que es medida y convertida a un formato digital para su posterior procesamiento, análisis y almacenamiento. Un sistema de adquisición de datos se construye alrededor de un elemento central de procesamiento, integrando diferentes componentes como por ejemplo: sensores, acondicionadores de señal, convertidores analógicos/digitales y el software de adquisición de datos (<a href="#_ENREF_11" title="Dursun, 2013 #17">Dursun, 2013</a>).</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>En la <a href="#f03">figura 3</a> se muestra el diagrama en bloques de un sistema de adquisición de datos, donde se ha asumido que las señales analógicas de interés ya han sido correctamente filtradas y acondicionadas al rango de entrada del convertidor analógico/digital. En este caso, el convertidor analógico/digital utilizado fue el AD7938 (<a href="#_ENREF_12" title="Analog-Devices, 2011 #15">Analog-Devices, 2011</a>), el cual trabaja por aproximaciones sucesivas y tiene una resolución de 12 <em><span style='font-family:Verdana'>bits</span></em>. El mismo se conectó al bus de expansión del procesador por medio de líneas de direcciones, de datos y de control. Este dispositivo necesita al menos 13 pulsos de una señal de reloj externa para realizar una conversión. Al aplicar un cero lógico al terminal &#8220;CONVST&#8221; se inicia el proceso de conversión y se activa en nivel alto la señal &#8220;BUSY&#8221;, que permanece en este estado hasta que en el bus de datos del convertidor aparece un dato digital válido, regresando nuevamente al nivel lógico cero.</span></p>      ]]></body>
<body><![CDATA[<p align=center style='text-align:center'><a name=f03></a><img border=0 width=565 height=593 src="/img/revistas/rcci/v8n2/f0303214.jpg" alt=f03></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>El flanco de bajada que se produce en el terminal BUSY del convertidor analógico/digital se utiliza para solicitar la atención del procesador a través de una de las líneas de interrupción externa disponibles. Para generar las señales de reloj y los pulsos periódicos que indican el inicio de conversión se utilizan dos de los temporizadores de<em><span style='font-family:Verdana'> hardware</span></em> que vienen integrados junto al procesador. De esta forma se garantiza que la adquisición de los datos se realice a intervalos regulares y uniformes. La estructura de los temporizadores de hardware se muestra en la <a href="#f04">figura 4</a>. Los temporizadores 0 y 1, que fueron los utilizados en el diseño, comparten un pre-escalador de 8 bits y los temporizadores 3, 4 y 5 otro pre-escalador de 8 bits. Cada temporizador presenta un divisor de reloj que puede generar 5 señales diferentes: 1/2, 1/4, 1/8, 1/16 y TCLK. Cada bloque temporizador recibe su propia señal de reloj del divisor de reloj correspondiente, que a su vez la recibe del pre-escalador que le corresponde.</span></p>      <p align=center style='text-align:center'><a name=f04></a><span style='font-size:10.0pt;font-family:Verdana'><img border=0 width=552 height=256 src="/img/revistas/rcci/v8n2/f0403214.jpg" alt=f04></span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>La configuración del pre-escalador y del divisor de reloj se realiza a partir de los registros de funciones especiales TCFG0 y TCFG1. El registro TCNTBn contiene el valor inicial que es cargado en el temporizador cuando es habilitado, mientras el registro TCMPBn contiene el valor inicial que es cargado en el registro de comparación (utilizado para cambiar el ciclo útil de la señal y generar señales moduladas por ancho del pulso). Cuando el contador descendente alcanza el valor de conteo cero, se lanza una solicitud de interrupción indicando que la operación ha concluido y el valor almacenado en el registro TCNTBn es automáticamente recargado.</span></p>      <p><strong><span style='font-size:10.0pt;font-family:Verdana'>Drivers de dispositivo</span></strong><span style='font-size:10.0pt;font-family:Verdana'>    <br> El sistema operativo GNU/Linux se ejecuta en el llamado contexto &#8220;kernel&#8221;, que es un modo de operación privilegiado donde tiene total autoridad sobre todos los recursos, que incluyen la memoria física y los subsistemas de entrada/salida. Una vez que se ha inicializado el<em><span style='font-family:Verdana'> hardware</span></em> y se ha montado el sistema de ficheros raíz, el núcleo Linux ejecuta una aplicación llamada &#8220;init&#8221;. A partir de aquí las aplicaciones se ejecutan en el llamado contexto de usuario. En este estado de operación los procesos tienen acceso restringido y deben utilizar llamadas al sistema para solicitar los servicios del &#8220;kernel&#8221; y los recursos del <em><span style='font-family:Verdana'>hardware </span></em>(<a href="#_ENREF_13" title="Jones, 2010 #9">Jones, 2010</a>). Los procesos de usuario operan en un espacio de direcciones virtuales seleccionado de forma aleatoria y administrada por el &#8220;kernel&#8221;. Cuando un programa de aplicación ejecuta una llamada al sistema se produce una conmutación de contexto y el &#8220;kernel&#8221; ejecuta el código en representación del proceso que la invocó. Por otro lado, las subrutinas de atención a interrupción ejecutan código del &#8220;kernel&#8221; pero no representan a ningún proceso en particular por lo que, cuando se ejecuta código en este contexto se presentan algunas limitaciones: la subrutina de atención a interrupción no puede bloquearse o llamar a ninguna función del &#8220;kernel&#8221; que pueda resultar en un bloqueo.</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Los drivers de dispositivos cumplen una función especial en sistemas GNU/Linux, permiten escribir código de &#8220;Kernel&#8221; para acceder directamente al <em><span style='font-family:Verdana'>hardware</span></em> y brindar una interfaz hacia las aplicaciones de usuario que no cuentan con este privilegio (<a href="#_ENREF_14" title="Corbet, 2005 #6">Corbet, 2005</a>). Los <em><span style='font-family:Verdana'>drivers</span></em> se comportan como cajas negras que hacen a una pieza de <em><span style='font-family:Verdana'>hardware</span></em> responder a una interfaz bien definida. Los drivers esconden completamente los detalles de cómo funciona el dispositivo. Las actividades realizadas por el usuario se realizan a través de un conjunto estandarizado de llamadas al sistema, que son independientes de un <em><span style='font-family:Verdana'>driver</span></em> en específico pero son utilizadas para realizar operaciones específicas del dispositivo. Véase la <a href="#f05">figura 5</a>.</span></p>      <p align=center style='text-align:center'><a name=f05></a><img border=0 width=379 height=352 src="/img/revistas/rcci/v8n2/f0503214.jpg" alt=f05></p>      <p align=center style='text-align:center'>&nbsp;</p>      <p><strong><span style='font-family:Verdana'>RESULTADOS Y DISCUSIÓN</span></strong></p>      ]]></body>
<body><![CDATA[<p><span style='font-size:10.0pt;font-family:Verdana'>Al diseñar un <em><span style='font-family:Verdana'>driver</span></em> para sistemas GNU/Linux debe considerarse el compromiso que se establece entre el tiempo requerido de programación y la flexibilidad del resultado. El término flexible enfatiza el hecho de que un <em><span style='font-family:Verdana'>driver </span></em>debe proveer un mecanismo para interactuar con el dispositivo, no una política en su utilización (<a href="#_ENREF_14" title="Corbet, 2005 #6">Corbet, 2005</a>). Esta distinción entre mecanismo y política es una de las mejores ideas en que se basan los <em><span style='font-family:Verdana'>drivers</span></em> en sistemas tipo Unix. Cada problema se divide en dos partes: primero, qué facilidades debe proveer (mecanismo), y segundo, cómo utilizar esas facilidades (política). El <em><span style='font-family:Verdana'>driver</span></em> debe lidiar con mantener el <em><span style='font-family:Verdana'>hardware</span></em> disponible, pero no forzar la forma de utilizarlo. Esto debe dejarse a las aplicaciones de usuario. <em><span style='font-family:Verdana'>El driver</span></em> puede verse como una capa de <em><span style='font-family:Verdana'>software</span></em> entre la aplicación y el dispositivo.</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Una de las mejores características de GNU/Linux es la posibilidad de extender el conjunto de facilidades que ofrece el &#8220;<em><span style='font-family:Verdana'>kernel</span></em>&#8221; en tiempo de ejecución (<a href="#_ENREF_15" title="Love, 2010 #4">Love, 2010</a>). Esto significa que se pueden agregar (o eliminar) funcionalidades en el núcleo mientras el sistema está activo. Cada pieza de código que se agrega al &#8220;kernel&#8221; en tiempo de ejecución, se denomina módulo. GNU/Linux ofrece una gran variedad de clases de módulos, entre los que se encuentran (pero no se limitan a ellos) los <em><span style='font-family:Verdana'>drivers</span></em> de dispositivo. Cada módulo está constituido por código objeto que se enlaza dinámicamente en tiempo de ejecución utilizando el comando &#8220;insmod&#8221;, y puede ser desenlazado utilizando el comando &#8220;rmmod&#8221;. El código modularizado se ejecuta en el espacio de direcciones del &#8220;kernel&#8221;. Usualmente los <em><span style='font-family:Verdana'>drivers </span></em>de dispositivo realizan dos tareas fundamentales, algunas funciones en el módulo se ejecutan en respuesta a llamadas al sistema y otras se encargan de manejar las solicitudes de interrupción.</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>El modo en que el &#8220;<em><span style='font-family:Verdana'>kernel</span></em>&#8221; Linux clasifica los drivers de dispositivo se divide en tres categorías: <em><span style='font-family:Verdana'>drivers</span></em> de carácter, <em><span style='font-family:Verdana'>drivers </span></em>de bloque y <em><span style='font-family:Verdana'>drivers</span></em> de red. Los <em><span style='font-family:Verdana'>drivers</span></em> de carácter pueden accederse como una secuencia de <em><span style='font-family:Verdana'>bytes</span></em> e implementan al menos cuatro llamadas al sistema: &#8220;<em><span style='font-family:Verdana'>open</span></em>&#8221;, &#8220;<em><span style='font-family:Verdana'>read</span></em>&#8221;, &#8220;<em><span style='font-family:Verdana'>write</span></em>&#8221; y &#8220;<em><span style='font-family:Verdana'>close</span></em>&#8221; (<a href="#_ENREF_7" title="Mauerer, 2008 #5">Mauerer, 2008</a>). Los <em><span style='font-family: Verdana'>drivers</span></em> tipo carácter se acceden a través de nodos en el sistema de ficheros (localizados en el directorio &#8220;/dev&#8221;). La única diferencia entre un fichero regular y un <em><span style='font-family:Verdana'>driver</span></em> tipo carácter es que en los ficheros regulares es permitido el desplazamiento hacia atrás y hacia adelante y los<em><span style='font-family:Verdana'> drivers </span></em>tipo carácter son solo canales de datos que pueden accederse secuencialmente.</span></p>      <p><strong><span style='font-size:10.0pt;font-family:Verdana'>Implementación del driver</span></strong></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Cuando se implementa un <em><span style='font-family:Verdana'>driver </span></em>para sistemas GNU/Linux, generalmente, se incluyen un gran número de ficheros de cabecera que contienen las definiciones de las funciones, tipos de datos y variables. Los ficheros de cabecera incluidos dependen de la aplicación en particular, pero algunos de ellos deben aparecer en cualquier módulo, por ejemplo: &lt;<em><span style='font-family:Verdana'>linux/module.h</span></em>&gt; y &lt;<em><span style='font-family:Verdana'>linux/init.h</span></em>&gt;.</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>En particular, los dispositivos tipo carácter, se identifican utilizando dos números denominados números de identificación mayor y menor. La estructura &#8220;dev_t&#8221; (definida en &lt;<em><span style='font-family:Verdana'>Linux/types.h</span></em>&gt;) se utiliza para almacenar estos números. Si se tienen los números mayor y menor de dispositivo y se quiere obtener la estructura &#8220;dev_t&#8221; asociada, se utiliza la macro:</span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>MKDEV(int major, int minor);</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Una de las primeras operaciones que debe realizar el driver en la función de inicialización es obtener y registrar los números que identifican al dispositivo. La función necesaria para realizar esta tarea está declarada en &lt;linux/fs.h&gt; y se define como:</span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>int register_chrdev_region(dev_t first, unsigned int count, char *name);</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Para liberar los números de dispositivo al desmontar el módulo, se utiliza la función:</span></p>      ]]></body>
<body><![CDATA[<p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>void unregister_chrdev_region(dev_t first, unsigned int count);</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Estas funciones reservan los números de dispositivo pero no le informan al &#8220;kernel&#8221; que hacer realmente con estos números. Antes de que un programa de aplicación de usuario pueda acceder uno de estos números de dispositivo, el <em><span style='font-family:Verdana'>driver</span></em> debe conectarlos a las funciones internas que implementan las operaciones que pueden realizarse sobre él. La estructura &#8220;<em><span style='font-family:Verdana'>file_operations</span></em>&#8221; se utiliza para realizar esta conexión. Esta estructura está definida en el fichero de cabecera &lt;<em><span style='font-family:Verdana'>linux/fs.h</span></em>&gt; y está constituida por una colección de punteros a funciones. Cada fichero abierto es asociado a su propio conjunto de funciones. Las funciones referenciadas por cada puntero se encargan de implementar las llamadas al sistema &#8220;<em><span style='font-family:Verdana'>open</span></em>&#8221;, &#8220;<em><span style='font-family:Verdana'>read</span></em>&#8221;, &#8220;<em><span style='font-family:Verdana'>ioctl</span></em>&#8221;, etc. Cada campo de la estructura, apunta a la función encargada de implementar una operación específica o se pone a NULL para las operaciones no soportadas.</span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>static struct file_operations SAD_fops =     <br> {    <br> .owner = THIS_MODULE,    <br> .read = SAD_read,    <br> .open = SAD_open,     <br> .ioctl = SAD_ioctl,    <br> .release = SAD_release,    <br> };</span></p>      ]]></body>
<body><![CDATA[<p><span style='font-size:10.0pt;font-family:Verdana'>En este caso, solo se implementaron los métodos más importantes con el objetivo de mantener el sistema lo más simple posible.    <br> El &#8220;kernel&#8221; utiliza además la estructura &#8220;cdev&#8221; para representar un dispositivo tipo carácter internamente. Antes de invocar las operaciones del dispositivo, deben declararse una o más de estas estructuras. Para ello debe incluirse el fichero de cabecera &lt;<em><span style='font-family: Verdana'>linux/cdev.h</span></em>&gt; donde están definidas la estructura y las funciones auxiliares necesarias. Sin embargo la mayoría de las veces se embebe la estructura &#8220;cdev&#8221; dentro de una estructura más específica que representa el dispositivo particular para el cual se está desarrollando el <em><span style='font-family:Verdana'>driver</span></em>. </span><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>Por ejemplo:</span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>static struct SAD_dev    <br> {    <br> &nbsp;&nbsp;&nbsp; wait_queue_head_t read_queue;    <br> &nbsp;&nbsp;&nbsp; struct kfifo* read_fifo;    <br> &nbsp;&nbsp;&nbsp; spinlock_t read_lock;    <br> &nbsp;&nbsp;&nbsp; atomic_t is_open;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; struct cdev cdev;    <br> } SAD_dev;.</span></p>      ]]></body>
<body><![CDATA[<p><span style='font-size:10.0pt;font-family:Verdana'>Un sistema de adquisición de datos representa un caso típico de un problema del tipo productor/consumidor donde el <em><span style='font-family:Verdana'>hardware</span></em> produce datos a una razón diferente a la que son consumidos por el <em><span style='font-family:Verdana'>software</span></em> de aplicación. Para dar solución a este problema, en la estructura se incluyen un <em><span style='font-family:Verdana'>buffer</span></em> circular para almacenar los datos leídos, un &#8220;<em><span style='font-family:Verdana'>spinlock</span></em>&#8221; para garantizar la exclusión mutua a la hora de acceder a los datos compartidos por varios hilos de ejecución, una estructura del tipo &#8220;<em><span style='font-family:Verdana'>wait_queue_head_t</span></em>&#8221; para lograr la sincronización del productor y el consumidor, y una variable atómica que permite determinar si el dispositivo ya ha sido abierto para ejecutar la inicialización de las estructuras una sola vez. La función de inicialización quedaría entonces:</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>static int __init SAD_init(void)    <br> {    <br> &nbsp;&nbsp;&nbsp; int result;    <br> &nbsp;&nbsp;&nbsp; dev_t dev;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; // Inicialización de la estructura dev_t     <br> &nbsp;&nbsp;&nbsp; dev = MKDEV(major_number, minor_number);    <br> &nbsp;&nbsp;&nbsp; result = register_chrdev_region(dev, 1, &quot;SAD&quot;);&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; // Inicialización de la estructura &quot;cdev&quot; de SAD_dev     <br> &nbsp;&nbsp;&nbsp; cdev_init(&amp;SAD_dev.cdev, &amp;SAD_fops);    ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp; SAD_dev.cdev.owner = THIS_MODULE;    <br> &nbsp;&nbsp;&nbsp; SAD_dev.cdev.ops = &amp;SAD_fops;    <br> &nbsp;&nbsp;&nbsp; result = cdev_add (&amp;SAD_dev.cdev, dev, 1);    <br> &nbsp;&nbsp;&nbsp; // Inicialización de otros campos de SAD_dev     <br> &nbsp;&nbsp;&nbsp; init_waitqueue_head(&amp;SAD_dev.read_queue);&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; // Inicialización de la FIFO     <br> &nbsp;&nbsp;&nbsp; SAD_dev.read_fifo = kfifo_alloc(read_buffersize * sizeof(SAMPLE_SIZE), GFP_KERNEL, &amp;SAD_dev.read_lock);    <br> &nbsp;&nbsp;&nbsp; atomic_set(&amp;SAD_dev.is_open,-1);&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; // Todo se ejecutó correctamente     <br> &nbsp;&nbsp;&nbsp; #ifdef DEBUG    ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp; printk(KERN_ALERT &quot;El modulo SAD ha sido cargado\n&quot;);    <br> &nbsp;&nbsp;&nbsp; #endif     <br> &nbsp;&nbsp; return 0;    <br> }</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>De forma similar, cualquier módulo no trivial necesita una función encargada de liberar los recursos utilizados y devolverlos al sistema:</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>static void __exit SAD_exit(void)    <br> {&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; dev_t dev;    <br> &nbsp;&nbsp;&nbsp; dev = MKDEV(major_number, minor_number);    <br> &nbsp;&nbsp;&nbsp; unregister_chrdev_region(dev, 1);&nbsp;&nbsp;&nbsp;     ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp; kfifo_free(SAD_dev.read_fifo);    <br> &nbsp;&nbsp;&nbsp; #ifdef DEBUG    <br> &nbsp;&nbsp;&nbsp; printk(KERN_ALERT &quot;El modulo SAD ha sido desmontado\n&quot;);    <br> &nbsp;&nbsp;&nbsp; #endif     <br> }</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Entre las operaciones que pueden realizarse sobre el dispositivo, el método &#8220;<em><span style='font-family:Verdana'>open</span></em>&#8221; se utiliza para inicializar y preparar el dispositivo antes de proceder al resto de las operaciones. En la mayoría de los <em><span style='font-family:Verdana'>drivers </span></em>esta función debe llevar a cabo las siguientes tareas:</span></p>  <ol style='margin-top:0cm' start=1 type=1>  <li class=MsoNormal><span style='font-size:10.0pt;font-family:Verdana'>Chequear      el dispositivo y detectar posibles errores.</span></li>  <li class=MsoNormal><span style='font-size:10.0pt;font-family:Verdana'>Inicializar      el dispositivo si es abierto por vez primera.</span></li>  <li class=MsoNormal><span style='font-size:10.0pt;font-family:Verdana'>Actualizar      los punteros a las operaciones de ser necesario.</span></li>  <li class=MsoNormal><span style='font-size:10.0pt;font-family:Verdana'>Registrar      e inicializar las estructuras de datos.</span></li>     </ol>      <p><span style='font-size:10.0pt;font-family:Verdana'>En este caso, el método &#8220;<em><span style='font-family:Verdana'>open</span></em>&#8221; se implementó como:</span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>static int SAD_open(struct inode *inode, struct file *filp)    <br> {    ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp; int result;&nbsp;     <br> &nbsp;&nbsp;&nbsp; printk (KERN_INFO &quot;opened\n&quot;);&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; if (atomic_inc_and_test (&amp;SAD _dev.is_open)) // Si el dispositivo está siendo utilizado, denegar el acceso.     <br> &nbsp;&nbsp;&nbsp; </span><span style='font-size:10.0pt;font-family:Verdana'>{&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk (KERN_INFO &quot;Inicializado\n&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Configuración del pin GPF0 como entrada de interrupción externa     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s3c2410_gpio_cfgpin (S3C2410_GPF(0), S3C2410_GPF0_EINT0);    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Inicialización de la interrupción externa EXT0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = request_irq (IRQ_EINT0, ext0_isr, IRQ_FLAGS,&quot;SAD&quot;, NULL);&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Obtener acceso a la dirección de memoria del convertidor analógico/digital     ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!request_mem_region (AD_address, 1, &quot;SAD&quot;))    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk (KERN_INFO &quot;No pudo obtenerse la dirección solicitada \n&quot;);    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -ENODEV;    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Obtener la dirección de memoria virtual del convertidor analógico/digital     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vAD_address = (unsignedlong) ioremap (AD_address, 1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Selección de la configuración del convertidor analógico/digital     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iowrite16(0x0001, vAD_address);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_timer0_frequency(TMR0FREQ); // Configuración del timer0     ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk (KERN_INFO &quot;El Timer0 ha sido inicializado\n&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; }    <br> &nbsp;&nbsp;&nbsp; return 0;    <br> }    <br> El método &#8220;<em><span style='font-family:Verdana'>read</span></em>&#8221; copia datos desde el sistema de adquisición de datos hasta el código de aplicación. </span><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>El método &#8220;<em><span style='font-family:Verdana'>read</span></em>&#8221;, puede implementarse como:</span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>static size_t SAD_read(struct file *filp, char __user * buf, size_t count, loff_t *f_pos)    <br> {&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; unsignedint _count;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; _count = kfifo_get(SAD_dev.read_fifo, buf, count *    <br> &nbsp;&nbsp;&nbsp; sizeof(SAMPLE_SIZE));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp; while(_count==0) &nbsp;&nbsp; // Debe bloquearse hasta que hallan datos disponibles para leer     <br> &nbsp;&nbsp;&nbsp; {&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (wait_event_interruptible (SAD_dev.read_queue,(_count = kfifo_get(SAD_dev.read_fifo,    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf, count * sizeof(SAMPLE_SIZE)))))    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -ERESTARTSYS;     <br> &nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; return _count;    <br> }</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>La variable &#8220;<em><span style='font-family:Verdana'>filp</span></em>&#8221;, es el puntero al fichero y &#8220;<em><span style='font-family:Verdana'>count</span></em>&#8221; es el número de <em><span style='font-family:Verdana'>bytes</span></em> que se solicitan transferir. El argumento &#8220;<em><span style='font-family:Verdana'>buf</span></em>&#8221; apunta al <em><span style='font-family:Verdana'>buffer</span></em> del usuario de donde los datos deben leerse o escribirse según sea el caso. Finalmente &#8220;f_pos&#8221; es el puntero que indica la posición a la que el usuario está accediendo. El método &#8220;<em><span style='font-family:Verdana'>read</span></em>&#8221; devuelve un valor negativo si ocurrió algún error. Un valor mayor o igual a cero, indica cuantos <em><span style='font-family:Verdana'>bytes</span></em> fueron transferidos correctamente a la aplicación de usuario. El código de la rutina de atención a la interrupción externa puede implementarse como:</span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>static irqreturn_t ext0_isr(int irq_in, void *dev_id)    ]]></body>
<body><![CDATA[<br> {&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; u16 ad_sample;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; ad_sample = ioread16 (vAD_address) &amp; 0x0FFF;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; if(kfifo_put(SAD_dev.read_fifo,(char*)&amp;ad_sample, 1*sizeof(SAMPLE_SIZE)))&nbsp;     <br> &nbsp;&nbsp;&nbsp; {     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wake_up_interruptible(&amp;SAD_dev.read_queue);     <br> &nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; return IRQ_HANDLED;    <br> }</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Además se puede utilizar el método &#8220;<em><span style='font-family:Verdana'>ioctl</span></em>&#8221; para enviar comandos a la aplicación, como por ejemplo la detención o puesta en marcha del temporizador 1 con el objetivo de detener o reiniciar el proceso de conversión.</span></p>      ]]></body>
<body><![CDATA[<p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>static int SAD_ioctl(structinode *inode, struct file *filp, unsignedint cmd, unsignedlon garg)    <br> {    <br> &nbsp;&nbsp;&nbsp; switch (cmd)     <br> &nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case POT_IOCTL_START:    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk (KERN_INFO &quot;Se ha iniciado el Timer1\n&quot;);&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;set_timer1_frequency(TMR1FREQ);&nbsp;&nbsp;&nbsp; //Iniciar timer 1     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case POT_IOCTL_STOP:    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk (KERN_INFO &quot;Se ha detenido el Timer1\n&quot;);&nbsp;     ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;timer1_stop(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Detener timer1     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;    <br> &nbsp;&nbsp; }    <br> &nbsp;&nbsp; return 0;    <br> }</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>Por último es necesario implementar la llamada al método &#8220;<em><span style='font-family:Verdana'>release</span></em>&#8221; que debe deshacer los efectos producidos por el método &#8220;<em><span style='font-family:Verdana'>open</span></em>&#8221;, dejando listo el sistema para cuando vuelva a ser necesitado por otro proceso de aplicación:</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>static int SAD_release(struct inode *inode, struct file *filp)    <br> {&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp; printk (KERN_INFO &quot;El dispositivos se ha cerrado\n&quot;);    <br> &nbsp;&nbsp;&nbsp; atomic_inc(&amp;SAD_dev.is_open);    ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp; if (atomic_dec_and_test (&amp;SAD_dev.is_open))     <br> &nbsp;&nbsp;&nbsp; {    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk (KERN_INFO &quot;Los recursos se han liberado\n&quot;);&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Detiene el TIMER0 y el TIMER1     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer0_stop(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer1_stop();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Configuración del pin de interrupción como salida digital     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s3c2410_gpio_cfgpin(S3C2410_GPF(0), S3C2410_GPIO_OUTPUT);    <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Libera la interrupción.     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free_irq (IRQ_EINT0, NULL);&nbsp;     ]]></body>
<body><![CDATA[<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Libera las direcciones virtuales del convertidor analógico/digital     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iounmap ((void __iomem *) vAD_address);&nbsp;     <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; release_mem_region (AD_address, 1);&nbsp;     <br> &nbsp;&nbsp;&nbsp; }    <br> &nbsp;&nbsp;&nbsp; atomic_dec(&amp;SAD_dev.is_open);    <br> &nbsp;&nbsp;&nbsp; return 0;    <br> }</span></p>      <p><span style='font-size:10.0pt;font-family:Verdana'>El principal aporte del<em><span style='font-family:Verdana'> driver</span></em> desarrollado y que lo diferencia de forma única del resto, radica en su capacidad para aprovechar las características específicas del <em><span style='font-family:Verdana'>hardware </span></em>de la SBC MINI2440 (temporizadores, controlador de interrupciones, puertos de entrada/salida, buses de expansión, etc.) e integrarlo junto a un convertidor analógico/digital para formar un sistema de adquisición de datos completamente funcional que da solución a un problema real. Además, el sistema tiene a su disposición la gran capacidad de procesamiento que brinda el microprocesador S3C2440 de Samsung y al estar soportado sobre el sistema operativo GNU/Linux permite al desarrollador de la aplicación de usuario contar con todas las ventajas que este ofrece: una gran variedad de librerías de funciones, diversidad en estándares de comunicación y soporte para plataformas orientadas al desarrollo de aplicaciones gráficas enriquecidas en entornos embebidos&nbsp; tales como GTK+ y Qt.</span></p>      <p>&nbsp;</p>      <p><strong><span style='font-family:Verdana'>CONCLUSIONES</span></strong> </p>      ]]></body>
<body><![CDATA[<p><span style='font-size:10.0pt;font-family:Verdana'>En el presente trabajo se ha desarrollado un <em><span style='font-family:Verdana'>driver </span></em>para el sistema operativo GNU/Linux capaz de controlar un sistema de adquisición de datos conectado al bus de expansión de la computadora de tarjeta única MINI2440 como una alternativa a los tradicionales sistemas de adquisición de datos basados en microcontroladores de 8 <em><span style='font-family:Verdana'>bits</span></em> cuyos recursos resultan muchas veces insuficientes. Mediante la utilización de la arquitectura propuesta se amplían las facilidades ofrecidas por el sistema, permitiendo contar con diversas tecnologías de comunicación, una interfaz gráfica enriquecida y más amigable al usuario, así como mayor capacidad de procesamiento. A partir del <em><span style='font-family:Verdana'>driver </span></em>desarrollado se pueden generar por <em><span style='font-family:Verdana'>hardware</span></em> las señales de reloj y de inicio de conversión utilizando los temporizadores 1 y 2 de la SBC MINI2440, y atender el fin de conversión por interrupción, garantizando la adquisición regular y uniforme de las muestras. La propuesta presentada aunque enfocada a un caso particular puede extenderse a otros problemas del tipo productor/consumidor.</span> </p>     <p>&nbsp;</p>     <p><b><span lang=EN-GB style='font-family:Verdana'>REFERENCIAS BIBLIOGRÁFICAS</span></b><span lang=EN-GB> </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>ABBOTT, D. The embedded Linux learning kit version 2 user&#8217;s guide. Silver City: Intellimetrix; 2011. p. 103.     </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>ANALOG-DEVICES. DATASHEET AD7938-6. In: Devices, editor: Analog Devices; 2011. p. 32.     </span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>BHAIRA, A.</span><span lang=EN-GB style='font-size:11.0pt;font-family:Arial;color:gray'> </span><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>2013</span><span lang=EN-GB style='font-size:11.0pt;font-family:Arial;color:gray'> </span><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>Development and implementation of a Linux-Xenomai based hard real-time device driver for PCI data acquisition system (DAS) card. International Journal of Computer Applications. 2013;81(12):24-28. </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>CORBET, J. Linux Device Drivers. Sebastopol: O'Reilly; 2005. p. 636.     </span></p>      ]]></body>
<body><![CDATA[<p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>DURSUN, M. </span><span lang=EN-GB style='font-size:11.0pt;font-family:Arial;color:gray'>2013</span><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>PC-based data acquisition system for PLC-controlled linear switched reluctance motor. Turkish Journal of Electrical Engineering &amp; Computer Sciences. 2013;21:71-80. </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>HALLINAN, C. Embedded Linux primer, a practical real world approach. Boston: Prentice Hall; 2011. p. 652.     </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>JONES, T. Look at Linux, the operating system and universal platform. Colorado: Developers Works IBM; 2012.     </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>JONES, T.Introducing the 3.3 and 3.4 Linux kernels. Colorado: Developers Works IBM; 2012.     </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>JONES, T. Kernel command using Linux system calls. Colorado: Developers Works IBM; 2010.     </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>LOVE, R. Linux kernel development. Boston: Addison-Wisley; 2010. p. 647.    </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>MAUERER, W. Professional Linux kernel architecture. Indianapolis: Wiley Publishing, Inc; 2008. p. 1370.     </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>SAMSUNG. S3C2440A 32-bit RISC microprocessor user's manual. Samsung Electronics; 2004. p. 560.     </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>SLOSS, A. N. ARM system developers guide, designing and optimizing system software. San Francisco: Elsevier; 2004. p. 703.     </span></p>      <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>SUNNY, S. </span><span lang=EN-GB style='font-size:11.0pt;font-family:Arial;color:gray'> </span><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>2012</span><span lang=EN-GB style='font-size:11.0pt;font-family:Arial;color:gray'> </span><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>Data acquisition and control system using embedded web server. International Journal of Engineering Trends and Technology. 2012;3(3):411-414. </span></p>      <!-- ref --><p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>WOLF, W. Computers as components, principles of embedded computing system design. Burlington: Elsevier; 2008. p. 533.     </span></p>     ]]></body>
<body><![CDATA[<p>&nbsp;</p>     <p>&nbsp;</p>     <p><span lang=EN-GB style='font-size:10.0pt;font-family:Verdana'>Recibido: 14/03/2014     <br> Aceptado: 9/04/2014 </span></p>  </div>       ]]></body><back>
<ref-list>
<ref id="B1">
<nlm-citation citation-type="book">
<person-group person-group-type="author">
<name>
<surname><![CDATA[ABBOTT]]></surname>
<given-names><![CDATA[D.]]></given-names>
</name>
</person-group>
<source><![CDATA[The embedded Linux learning kit version 2 user&#8217;s guide.]]></source>
<year>2011</year>
<page-range>103</page-range><publisher-name><![CDATA[Silver City: Intellimetrix]]></publisher-name>
</nlm-citation>
</ref>
<ref id="B2">
<nlm-citation citation-type="book">
<source><![CDATA[ANALOG-DEVICES. DATASHEET AD7938-6]]></source>
<year>2011</year>
<page-range>32</page-range><publisher-name><![CDATA[Devices, editor: Analog Devices]]></publisher-name>
</nlm-citation>
</ref>
<ref id="B3">
<nlm-citation citation-type="book">
<person-group person-group-type="author">
<name>
<surname><![CDATA[BHAIRA]]></surname>
<given-names><![CDATA[A.]]></given-names>
</name>
</person-group>
<article-title xml:lang="en"><![CDATA[Development and implementation of a Linux-Xenomai based hard real-time device driver for PCI data acquisition system (DAS) card]]></article-title>
<source><![CDATA[]]></source>
<year>2013</year>
<volume>81</volume>
<numero>12</numero>
<issue>12</issue>
<page-range>24-28</page-range><publisher-name><![CDATA[International Journal of Computer Applications]]></publisher-name>
</nlm-citation>
</ref>
<ref id="B4">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[CORBET]]></surname>
<given-names><![CDATA[J.]]></given-names>
</name>
</person-group>
<source><![CDATA[Linux Device Drivers. Sebastopol: O'Reilly]]></source>
<year>2005</year>
<page-range>636</page-range></nlm-citation>
</ref>
<ref id="B5">
<nlm-citation citation-type="journal">
<person-group person-group-type="author">
<name>
<surname><![CDATA[DURSUN]]></surname>
<given-names><![CDATA[M.]]></given-names>
</name>
</person-group>
<article-title xml:lang="en"><![CDATA[PC-based data acquisition system for PLC-controlled linear switched reluctance motor.]]></article-title>
<source><![CDATA[Turkish Journal of Electrical Engineering & Computer Sciences]]></source>
<year>2013</year>
<volume>21</volume>
<page-range>71-80</page-range></nlm-citation>
</ref>
<ref id="B6">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[HALLINAN]]></surname>
<given-names><![CDATA[C.]]></given-names>
</name>
</person-group>
<source><![CDATA[Embedded Linux primer, a practical real world approach. Boston: Prentice Hall]]></source>
<year>2011</year>
<page-range>652</page-range></nlm-citation>
</ref>
<ref id="B7">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[JONES]]></surname>
<given-names><![CDATA[T.]]></given-names>
</name>
</person-group>
<source><![CDATA[Look at Linux, the operating system and universal platform. Colorado: Developers Works IBM]]></source>
<year>2012</year>
</nlm-citation>
</ref>
<ref id="B8">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[JONES]]></surname>
<given-names><![CDATA[T.]]></given-names>
</name>
</person-group>
<source><![CDATA[Introducing the 3.3 and 3.4 Linux kernels. Colorado: Developers Works IBM]]></source>
<year>2012</year>
</nlm-citation>
</ref>
<ref id="B9">
<nlm-citation citation-type="book">
<person-group person-group-type="author">
<name>
<surname><![CDATA[JONES]]></surname>
<given-names><![CDATA[T.]]></given-names>
</name>
</person-group>
<source><![CDATA[Kernel command using Linux system calls.]]></source>
<year>2010</year>
<publisher-name><![CDATA[Colorado: Developers Works IBM]]></publisher-name>
</nlm-citation>
</ref>
<ref id="B10">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[LOVE]]></surname>
<given-names><![CDATA[R.]]></given-names>
</name>
</person-group>
<source><![CDATA[Linux kernel development. Boston: Addison-Wisley]]></source>
<year>2010</year>
<page-range>647</page-range></nlm-citation>
</ref>
<ref id="B11">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[MAUERER]]></surname>
<given-names><![CDATA[W.]]></given-names>
</name>
</person-group>
<source><![CDATA[Professional Linux kernel architecture. Indianapolis: Wiley Publishing, Inc]]></source>
<year>2008</year>
<page-range>1370</page-range></nlm-citation>
</ref>
<ref id="B12">
<nlm-citation citation-type="book">
<source><![CDATA[SAMSUNG. S3C2440A 32-bit RISC microprocessor user's manual]]></source>
<year>2004</year>
<page-range>560</page-range><publisher-name><![CDATA[Samsung Electronics]]></publisher-name>
</nlm-citation>
</ref>
<ref id="B13">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[SLOSS]]></surname>
<given-names><![CDATA[A. N.]]></given-names>
</name>
</person-group>
<source><![CDATA[ARM system developers guide, designing and optimizing system software.]]></source>
<year>2004</year>
<page-range>703</page-range><publisher-loc><![CDATA[San Francisco^eElsevier Elsevier]]></publisher-loc>
</nlm-citation>
</ref>
<ref id="B14">
<nlm-citation citation-type="journal">
<person-group person-group-type="author">
<name>
<surname><![CDATA[SUNNY]]></surname>
<given-names><![CDATA[S.]]></given-names>
</name>
</person-group>
<article-title xml:lang="en"><![CDATA[Data acquisition and control system using embedded web server.]]></article-title>
<source><![CDATA[International Journal of Engineering Trends and Technology.]]></source>
<year>2012</year>
<volume>3</volume>
<numero>3</numero>
<issue>3</issue>
<page-range>411-414</page-range></nlm-citation>
</ref>
<ref id="B15">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[WOLF]]></surname>
<given-names><![CDATA[W.]]></given-names>
</name>
</person-group>
<source><![CDATA[Computers as components, principles of embedded computing system design]]></source>
<year>2008</year>
<page-range>533</page-range><publisher-loc><![CDATA[Elsevier^eBurlington Burlington]]></publisher-loc>
</nlm-citation>
</ref>
</ref-list>
</back>
</article>
