哪个是在FriendlyARM board mini2440中编程GPIO的最佳方法?

时间:2013-12-21 17:24:36

标签: c++ qt linux-kernel arm gpio

我有一台带有Linux 2.6的mini2440主板,我必须对其进行编程以控制已安装的太阳能电池板。提供了算法,我需要为ARM板编写代码。 GUI在Qt中完成,我需要编写实际控件的代码。我看到了从用户空间访问GPIO的方法,这很乏味。我质疑PWM的准确度。

我可以使用哪些其他方法为GPIO编程开/关和PWM应用程序?

一些朋友建议将控制代码编程为内核模块,但我不太确定我是否希望进入该模块。

1 个答案:

答案 0 :(得分:4)

  

一些朋友建议将控制代码编程为内核模块,但我不太确定我是否希望进入该模块。

我几乎可以肯定,如果它与硬件没有密切关系,它将在Linux内核中被拒绝。用户空间系统调用和sysfs访问的目的是将您的自定义逻辑放在硬件抽象(OSI模型)之上的Linux中。

您需要做的是首先检查Linux内核是否为您的设备提供所有硬件支持。然后,您可以使用我的中间件类以C ++方式控制GPIO。最后,您可以编写一个小的主应用程序来测试内核和C ++类。该应用程序只会像实例化GPIO类,导出GPIO,然后写入值一样简单。

(这与你的PWM问题有什么关系尚不清楚,但你似乎混淆了两个不同的内核驱动程序区域)

根据sysfs,您可以通过Linux kernel gpio documentation执行以下代码。您当然需要确保Linux内核支持您的硬件gpio。

gpio.h

#ifndef FOOBAR_GENERALPURPOSEIO_H
#define FOOBAR_GENERALPURPOSEIO_H

namespace Foobar
{
   class FOOBAR_EXPORT GeneralPurposeIO
   {
       public:

           enum Direction {
               Input,
               Output
           };

           explicit GeneralPurposeIO(quint32 gpioNumber = 0);
           ~GeneralPurposeIO();

           int gpioExport();
           int gpioUnexport();
           bool isGpioExported();

           quint32 gpioNumber() const;
           void setGpioNumber(quint32 gpioNumber);

           Direction direction() const;
           int setDirection(Direction direction);

           qint32 value() const;
           int setValue(qint32 value);

       private:

           class Private;
           Private *const d;
   };
}

#endif // FOOBAR_GENERALPURPOSEIO_H

gpio.cpp

#include "generalpurposeio.h"

#include <QtCore/QDebug>
#include <QtCore/QFile>

using namespace Foobar;

class GeneralPurposeIO::Private
{
   public:
       Private()
       {
       }

       ~Private()
       {
       }

       static const QString gpioExportFilePath;
       static const QString gpioUnexportFilePath;
       static const QString gpioDirectionFilePath;
       static const QString gpioValueFilePath;
       static const QString gpioFilePath;

       quint32 gpioNumber;
};

const QString GeneralPurposeIO::Private::gpioExportFilePath = "/sys/class/gpio/export";
const QString GeneralPurposeIO::Private::gpioUnexportFilePath = "/sys/class/gpio/unexport";
const QString GeneralPurposeIO::Private::gpioDirectionFilePath = "/sys/class/gpio/gpio%1/direction";
const QString GeneralPurposeIO::Private::gpioValueFilePath = "/sys/class/gpio/gpio%1/value";
const QString GeneralPurposeIO::Private::gpioFilePath = "/sys/class/gpio/gpio%1";

GeneralPurposeIO::GeneralPurposeIO(quint32 gpioNumber)
   : d(new Private)
{
   d->gpioNumber = gpioNumber;
}

GeneralPurposeIO::~GeneralPurposeIO()
{
}

/*
* Exports the desired gpio number.
*
* Note: Unfortunately, it is not possible to just call this method "export"
* since that is a reserved keyword in C++. Systematically the unexport method
* cannot be called "unexport" either for consistency.
*/

int GeneralPurposeIO::gpioExport()
{
   if (isGpioExported()) {
       // TODO: Proper error mutator mechanism for storing different error
       // enumeration values internally that can be requested by the API user

       qDebug() << "Cannot export the gpio pin since it is already exported:" << d->gpioNumber;
       return -1;
   }

   QFile gpioExportFile(d->gpioExportFilePath);
   if (!gpioExportFile.open(QIODevice::Append)) {
       qDebug() << "Cannot open the gpio export file:" << d->gpioExportFilePath;
       return -1;
   }

   /*
    * Seek to begining of the file
    */

   gpioExportFile.seek(0);

   /*
    * Write our value of "gpioPinNumber" to the file
    */

   if (gpioExportFile.write(QByteArray::number(d->gpioNumber)) == -1) {
       qDebug() << Q_FUNC_INFO << "Error while writing the file:" << d->gpioExportFilePath;
       gpioExportFile.close();

       return -1;
   }

   gpioExportFile.close();

   return 0;
}

int GeneralPurposeIO::gpioUnexport()
{
   if (!isGpioExported()) {
       // TODO: Proper error mutator mechanism for storing different error
       // enumeration values internally that can be requested by the API user

       qDebug() << "Cannot unexport the gpio pin since it is not exported yet:" << d->gpioNumber;
       return -1;
   }

   QFile gpioUnexportFile(d->gpioUnexportFilePath);
   if (!gpioUnexportFile.open(QIODevice::Append)) {
       qDebug() << "Cannot open the gpio export file:" << d->gpioUnexportFilePath;
       return -1;
   }

   /*
    * Seek to begining of the file
    */

   gpioUnexportFile.seek(0);

   /*
    * Write our value of "gpioPinNumber" to the file
    */

   if (gpioUnexportFile.write(QByteArray::number(d->gpioNumber)) == -1) {
       qDebug() << Q_FUNC_INFO << "Error while writing the file:" << d->gpioUnexportFilePath;
       gpioUnexportFile.close();

       return -1;
   }

   gpioUnexportFile.close();

   return 0;
}

bool GeneralPurposeIO::isGpioExported()
{
   if (!QFile(d->gpioFilePath.arg(d->gpioNumber)).exists()) {
       return false;
   }

   return true;
}

quint32 GeneralPurposeIO::gpioNumber() const
{
   return d->gpioNumber;
}

void GeneralPurposeIO::setGpioNumber(quint32 gpioNumber)
{
   d->gpioNumber = gpioNumber;
}

GeneralPurposeIO::Direction GeneralPurposeIO::direction() const
{
   // TODO: Implement me

   return GeneralPurposeIO::Output;
}

int GeneralPurposeIO::setDirection(Direction direction)
{
   if (!isGpioExported()) {
       if (gpioExport() == -1) {
           return -1;
       }
   }

   /*
    * Set the direction
    */

   QFile gpioDirectionFile(d->gpioDirectionFilePath.arg(d->gpioNumber));

   if (!gpioDirectionFile.open(QIODevice::ReadWrite)) {
       qDebug() << "Cannot open the relevant gpio direction file:" << d->gpioDirectionFilePath;
       return -1;
   }

   int retval = 0;

   /*
    * Seek to begining of the file
    */

   gpioDirectionFile.seek(0);

   switch (direction) {

   case Output:
       if (gpioDirectionFile.write("high") == -1) {
           qDebug() << Q_FUNC_INFO << "Error while writing the file:" << d->gpioDirectionFilePath;
           retval = -1;
       }

       break;

   case Input:
       if (gpioDirectionFile.write("low") == -1) {
           qDebug() << Q_FUNC_INFO << "Error while writing the file:" << d->gpioDirectionFilePath;
           retval = -1;
       }

       break;

   default:

       break;

   }

   gpioDirectionFile.close();

   return retval;
}

qint32 GeneralPurposeIO::value() const
{
   // TODO: Implement me

   return 0;
}

int GeneralPurposeIO::setValue(qint32 value)
{
   if (direction() != GeneralPurposeIO::Output) {
       qDebug() << "Cannot set the value for an input gpio pin:" << d->gpioNumber;
       return -1;
   }

   /*
    * Set the value
    */

   QFile gpioValueFile(d->gpioValueFilePath.arg(d->gpioNumber));
   if (!gpioValueFile.open(QIODevice::ReadWrite)) {
       qDebug() << "Cannot open the relevant gpio value file:" << d->gpioValueFilePath.arg(d->gpioNumber);
       gpioValueFile.close();
       return -1;
   }

   /*
    * Seek to begining of the file
    */

   gpioValueFile.seek(0);

   if (gpioValueFile.write(QByteArray::number(value)) == -1) {
       qDebug() << Q_FUNC_INFO << "Error while writing the file:" << d->gpioValueFilePath.arg(d->gpioNumber);
       gpioValueFile.close();
       return -1;
   }

   gpioValueFile.close();

   return 0;
}