首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在运行安卓的DragonBoard 410 C上访问GPIO低功耗连接器

在运行安卓的DragonBoard 410 C上访问GPIO低功耗连接器
EN

Stack Overflow用户
提问于 2020-08-30 04:10:24
回答 1查看 741关注 0票数 0

我正在使用最近购买的DragonBoard 410 C,运行Android5.1操作系统,并使用Android和Kotlin一起生成一个示例应用程序,该应用程序探索了一些硬件,比如40针低功耗连接器。

我的问题是如何使用Kotlin和Android访问带有GPIO引脚的40针低功耗连接器。

从我到目前为止的研究来看,mraa库似乎是通往成功的道路,但是我没有找到任何关于使用Kotlin库的文档。

如何开始使用Kotlin的mraa库来访问40针低功耗连接器?

还是有不同的方法?

我的第一个例子是一个简单的眨眼LED应用程序,但我不知道如何访问低功耗连接器的引脚使用Kotlin。

备注和资源

mraa文档页面

Libmraa是一个C/C++库,它绑定到Python、Javascript和Java,以便与伽利略、爱迪生和其他平台上的I/O接口,并使用结构化的、合理的API,其中端口名称/编号与您所在的板相匹配。使用libmraa并不会将您绑定到特定的硬件上,在运行时完成板检测,您可以创建跨支持平台工作的可移植代码。

用于mraa GitHub存储库的upm库

UPM存储库为各种常用的传感器和执行器提供软件驱动程序。这些软件驱动程序通过调用MRAA与底层硬件平台(或微控制器)以及附加的传感器进行交互。

哪个Android运行哪个Linux内核?https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel

代码语言:javascript
复制
Android Version    |API Level  |Linux Version in AOSP                    |Header Version
----------------------------------------------------------------------------------------
4.4   Kit Kat      |19, 20     |(3.10)                                   |2.6.18
5.x   Lollipop     |21, 22     |(3.16.1)                                 |3.14.0
6.0   Marshmallow  |23         |(3.18.10)                                |3.18.10

sysfs死了!蜥蜴万岁!( linux和CircuitPython的libgpiod)

这基本上是将取代我们的Python驱动程序的代码,它的优点是可以与运行4.8+内核的任何其他Linux板向前兼容。我们将慢慢地替换其他CircuitPython代码来使用libgpiod,这样我们就可以在Raspberry、BeagleBone或Onion.io上广泛支持CircuitPython。 这里没有很多libgpiod代码,而且libgpiod还没有在Linux发行版上上市,这可能就是为什么它需要一段时间才能流行起来的原因。有C和Python的绑定。下面是一个脚本,可以通过为您编译https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/libgpiod.sh来帮助您入门

DragonBoard 410 C GPIO库是用Java编写的,使用GitHub GpioLibrary的"/sys/class/ GPIO“方法访问GPIO引脚。这看起来像是物联网课程库库中的一个存储库,其中一些使用DragonBoard 410 C。

Linux内核:遗留的GPIO接口

这提供了Linux上GPIO访问约定的概述。 这些调用使用gpio_*命名前缀。任何其他调用都不应使用该前缀或相关的_gpio*前缀。

Android Studio和adb

Android是用于开发Android应用程序的应用程序。可以从https://developer.android.com/studio/releases下载以便安装。

此外,还有Android平台工具,这是一个单独的下载。adb外壳应用程序是这些工具的一部分。这些工具可以从SDK平台工具发布说明下载以进行安装。选择操作系统所需的特定版本(Windows、Linux、MacOS)。

Android Things

虽然安卓系统看起来很有帮助,但它似乎只有几块板实际上是支持的,而DragonBoard 410 C就不是其中之一。而且我也不确定Android系统是否能与Android5.1一起工作。

https://developer.android.com/things/get-started

然而,DragonBoard 410 C https://discuss.96boards.org/t/android-things-on-the-dragonboard/1128有一个Brillo (现在是Android的东西)端口。

Android Developers > Docs > Android Things > Guides > GPIO

为了打开到GPIO端口的连接,您需要知道唯一的端口名。在开发的最初阶段,或者在将应用程序移植到新硬件时,使用PeripheralManager使用getGpioList()发现所有可用的端口名是很有帮助的:

安卓事物GitHub存储库https://github.com/androidthings/

还请参阅下面的堆栈溢出帖子,其中有一些关于这个主题的话要说。参见标记android-堆叠溢出中的东西。

GpioCallback如何连续两次注册"false“?

Android事物销命名约定

PeripheralManagerService抛出NoClassDefFoundError

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-02 04:27:23

在回顾了许多替代方案之后,访问运行Android5.1的DragonBoard 410 C的GPIO引脚的最简单方法似乎是使用遗留的sysfs特殊设备文件方法。

我不确定这是否是唯一可行的解决办法。使用Android和libgpiod似乎都需要一个比Android5.1更新的Linux内核。

我写了一篇关于CodeProject.com的文章,详细介绍了如何解决这个问题。见用Windows10forDevelopmentwithDragonBoard 410 C和Android

哪个Android运行哪个Linux内核?https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel

代码语言:javascript
复制
Android Version    |API Level  |Linux Version in AOSP                    |Header Version
----------------------------------------------------------------------------------------
4.4   Kit Kat      |19, 20     |(3.10)                                   |2.6.18
5.x   Lollipop     |21, 22     |(3.16.1)                                 |3.14.0
6.0   Marshmallow  |23         |(3.18.10)                                |3.18.10

这个方法似乎也是最简单的,因为所使用的库也是用Kotlin编写的。

使用遗留的sysfs专用设备GPIO接口

请参阅这篇关于Linux伪文件和特殊设备文件的StackOverFlow文章,以及用于GPIO引脚、什么是/sys/class/gpio/export和`/sys/class/gpio/unexport机制,以及sysfs的基本功能是什么?的遗留sysfs接口。

我找到了一个用Java编写的简单的GPIO库,它提供了必要的源代码。Android有一个将Java转换为Kotlin的工具,我将其包含在我的项目中。源代码在Gpio.kt和GpioProcessor.kt文件中。

但是,为了使这一工作有效,我必须对我的DragonBoard启动脚本进行更改,以确保创建了必要的特殊设备文件并具有适当的权限,从而允许用户程序操作GPIO引脚。

以下过程来自古瑟尔类物联网:设备的感知和执行,第5a课:通过程序(Android)视频#2访问GPIO,修改引导脚本。程序是:

  • 使用亚行将/etc/init.qcom.post_boot.sh的副本从DragonBoard拉到我的PC上
  • 使用记事本修改shell脚本以创建特殊的设备文件
  • 使用亚行将修改后的副本推回Dragonboard
  • 使用adb重新启动DragonBoard

添加到/etc/init.qcom.post_boot.sh底部的附加shell代码如下所示。不过,这些特殊的设备文件只适用于Android5.1。 Linux使用不同的GPIO引脚名。

代码语言:javascript
复制
set -A pins 938 915 1017 926 937 930 914 971 901 936 935
for i in 0 1 2 3 4 5 6 7 8 9 10
do
    echo ${pins[i]} > /sys/class/gpio/export;
    chmod 777 /sys/class/gpio/gpio${pins[i]};
    chmod 777 /sys/class/gpio/gpio${pins[i]}/value;
    chmod 777 /sys/class/gpio/gpio${pins[i]}/direction;
done

--关于sysfs设备属性的一个注记

下面是一些来自用于用户空间的GPIO Sysfs接口的kernel.org文档。除了我使用的两个属性,directionvalue,还有其他几个属性,比如edgeactive_low

“方向”…读为“in”或“out”。此值通常可以写入。以“out”的形式写入默认值为low。为了确保无故障操作,可以编写“低”和“高”值,以便将GPIO配置为具有该初始值的输出。 注意,如果内核不支持更改GPIO的方向,或者它是由内核代码导出的,而内核代码没有显式地允许用户空间重新配置这个GPIO方向,那么这个属性就不存在。 “value”…读取为0(低)或1(高)。如果将GPIO配置为输出,则可以写入此值;任何非零值都被视为高值。 如果引脚可以配置为产生中断的中断,如果它被配置为生成中断(请参阅“edge”的描述),您可以对该文件进行轮询(2),每当中断被触发时,轮询(2)将返回。如果使用轮询(2),则设置事件POLLPRI和POLLERR。如果使用select(2),请将文件描述符设置为“除其他外”。在轮询(2)返回后,要么将After (2)返回sysfs文件的开头并读取新值,要么关闭该文件并重新打开它以读取该值。 “边缘”…读为“无”、“上升”、“下降”或“两者兼而有之”。编写这些字符串以选择将对“value”文件返回进行轮询(2)的信号边缘。 只有当引脚可以配置为生成输入引脚的中断时,此文件才存在。 “active_low”…读取为0 (false)或1 (true)。写入任何非零值,以反转用于读写的value属性。现有的和随后的投票(2)支持配置通过边缘属性的“上升”和“下降”边缘将遵循此设置。

Kotlin使用sysfs的源代码

在我的DragonBoard存储库410 c中有一个完整的测试应用程序,用于探索在Android中使用GitHub 410 C的主题。

文件Gpio.kt源文件

代码语言:javascript
复制
package com.example.myapplication

import java.io.*

/**
 * Created by Ara on 7/21/15.
 * From https://www.instructables.com/id/DragonBoard-How-to-Access-GPIOs-Using-Java/
 *   Java source from the article was converted to Kotlin using Android Studio.
 *
 * See as well https://github.com/IOT-410c/DragonBoard410c_GpioLibrary
 *
 */
class Gpio(pin: Int) {
    private val pin: Int

    /*
     *  The GPIO pins are represented by folders in the Linux file system
     *  within the folder /sys/class/gpio. Each pin is represented by a folder
     *  whose name is the prefix "gpio" followed by the pin number.
     *  Within the folder representing the pin are two files, "value" used to
     *  set or get the value of the pin and "direction" used to set or get
     *  the direction of the pin.
     *
     *  This function creates the path to the Linux file which represents a particular
     *  GPIO pin function, "value" or "direction".
     */
    private fun MakeFileName(pin: Int, op: String): String {
        return "/sys/class/gpio/gpio$pin$op"
    }

    /*
     * Get or set the current direction of a pin.
     * A pin may be either an Input pin or an Output pin.
     */
    var direction: String
        get() {
            println("Getting Direction")
            var line = ""
            try {
                val br = BufferedReader(FileReader(MakeFileName(pin, "/direction")))
                line = br.readLine()
                br.close()
            } catch (e: Exception) {
                println("Error: " + e.message)
            }
            return line
        }
        private set(direction) {
            println("Setting Direction")
            try {
                val out = BufferedWriter(FileWriter(MakeFileName(pin, "/direction"), false))
                out.write(direction)
                out.close()
            } catch (e: IOException) {
                println("Error: " + e.message)
            }
        }

    /**
     * Get or Set pin value.
     * @param value Value of pin.
     * 0 -> Low Level.
     * 1 -> High Level
     */
    var value: Int
        get() {
            println("Getting Value")
            var line = ""
            try {
                val br = BufferedReader(FileReader(MakeFileName(pin, "/value")))
                line = br.readLine()
                br.close()
            } catch (e: Exception) {
                println("Error: " + e.message)
            }
            return line.toInt()
        }
        private set(value) {
            println("Setting Value")
            try {
                val out = BufferedWriter(FileWriter(MakeFileName(pin, "/value"), false))
                out.write(Integer.toString(value))
                out.close()
            } catch (e: IOException) {
                println("Error: " + e.message)
            }
        }

    /**
     * Set pin as high.
     */
    fun pinHigh() {
        value = HIGH
    }

    /**
     * Set pin as low.
     */
    fun pinLow() {
        value = LOW
    }

    /**
     * Set pin as output.
     */
    fun pinOut() {
        direction = "out"
    }

    /**
     * Set pin as input.
     * @param pin - Desirable pin.
     */
    fun pinIn() {
        direction = "in"
    }

    fun exportPin() {
        println("Exporting Ping")
        try {
            val out = BufferedWriter(FileWriter("$PATH/export", false))
            out.write(pin.toString())
            out.close()
        } catch (e: IOException) {
            println("Error: " + e.message)
        }
    }

    /**
     * Disable access to GPIO.
     * @param pin GPIO pin to disable access.
     */
    fun unexportPin() {
        println("unExporting Ping")
        try {
            val out = BufferedWriter(FileWriter("$PATH/unexport", false))
            out.write(pin.toString())
            out.close()
        } catch (e: IOException) {
            println("Error: " + e.message)
        }
    }

    companion object {
        const val HIGH = 1
        const val LOW = 0
        private const val PATH = "/sys/class/gpio"
    }

    /**
     * Set desirable pin for the GPIO class.
     */
    init {
        println("Initializing pin $pin")
        this.pin = pin
    }
}

GpioProcessor.kt的来源

代码语言:javascript
复制
package com.example.myapplication

import java.io.BufferedWriter
import java.io.FileWriter
import java.io.IOException
import java.util.*

/**
 * Created by Ara on 7/21/15.
 * From https://www.instructables.com/id/DragonBoard-How-to-Access-GPIOs-Using-Java/
 *   Java source from the article was converted to Kotlin using Android Studio.
 *
 * See as well https://github.com/IOT-410c/DragonBoard410c_GpioLibrary
 *
 * Simple example main()
 *
 * public class Main {
 *
 * public static void main(String[] args) {
 * int count = 0;
 * int buttonValue = 0;
 *
 * GpioProcessor gpioProcessor = new GpioProcessor();
 *
 * // Get reference of GPIO27 and GPIO29.
 *
 * Gpio gpioPin27 = gpioProcessor.getPin27();
 * Gpio gpioPin29 = gpioProcessor.getPin29();
 *
 * // Set GPIO27 as output.Set GPIO29 as input.
 * gpioPin27.pinOut();
 * gpioPin29.pinIn();
 *
 * while(count<20){
 * count++;
 * // Read value of GPIO29.
 * buttonValue=gpioPin29.getValue();
 *
 * if(buttonValue == 0){
 * // Set GPIO27 as low level.
 * gpioPin27.pinLow();
 * } else{
 * // Set GPIO27 as high level.
 * gpioPin27.pinHigh();
 * }
 *
 * try {
 * Thread.sleep(1000);
 * } catch(InterruptedException e){
 * // TODO Auto-generated catch block
 * e.printStackTrace();
 * }
 * }
 *
 * // Disable access GPIO27 and GPIO29.
 * gpioProcessor.closePins();
 * }
 * }
 */ /*
 This class abstracts the use of the gpio pins. This class can be utilized on any linux operating
 system that has gpio pins defined in the /sys/class/gpio directory. It is required that the gpio
 pins themselves are available for access by the user of this application, and may require a
 change of permissions.
 */
class GpioProcessor {
    private val PATH = "/sys/class/gpio"
    private val pins: MutableList<Int> = ArrayList()

    // mapping of physical pin number to GPIO file number.
    // the mapping varies depending on the operating system
    private val  androidPin23 = 938
    private val  androidPin24 = 914
    private val  androidPin25 = 915
    private val  androidPin26 = 971
    private val  androidPin27 = 1017
    private val  androidPin28 = 901   // GPIO pin borrowed from MPP. supports PWM. support analog I/O.
    private val  androidPin29 = 926   // (input only)
    private val  androidPin30 = 927
    private val  androidPin31 = 937
    private val  androidPin32 = 936
    private val  androidPin33 = 930
    private val  androidPin34 = 935

    private val  linuxPin23 = 36
    private val  linuxPin24 = 12
    private val  linuxPin25 = 13
    private val  linuxPin26 = 69
    private val  linuxPin27 = 115
    private val  linuxPin28 = 4     // GPIO pin borrowed from MPP. supports PWM. support analog I/O.
    private val  linuxPin29 = 24    // (input only)
    private val  linuxPin30 = 25
    private val  linuxPin31 = 35
    private val  linuxPin32 = 34
    private val  linuxPin33 = 28
    private val  linuxPin34 = 33

    private val  physicalPin23 = androidPin23
    private val  physicalPin24 = androidPin24
    private val  physicalPin25 = androidPin25
    private val  physicalPin26 = androidPin26
    private val  physicalPin27 = androidPin27
    private val  physicalPin28 = androidPin28    // GPIO pin borrowed from MPP. supports PWM. support analog I/O.
    private val  physicalPin29 = androidPin29    // (input only)
    private val  physicalPin30 = androidPin30
    private val  physicalPin31 = androidPin31
    private val  physicalPin32 = androidPin32
    private val  physicalPin33 = androidPin33
    private val  physicalPin34 = androidPin34

    /**
     * Get function of specific pin.
     * @param pin Desirable pin.
     */
    fun getPin(pin: Int): Gpio {
        exportPin(pin)
        pins.add(pin)
        return Gpio(pin)
    }

    /**
     * Get pin 23;
     * @returns {Gpio}
     */
    val pin23: Gpio
        get() = getPin(physicalPin23)

    /**
     * Get pin 24.
     * @returns {Gpio}
     */
    val pin24: Gpio
        get() = getPin(physicalPin24)

    /**
     * Get pin 25.
     * @returns {Gpio}
     */
    val pin25: Gpio
        get() = getPin(physicalPin25)

    /**
     * Get pin 26.
     * @returns {Gpio}
     */
    val pin26: Gpio
        get() = getPin(physicalPin26)

    /**
     * Get pin 27.
     * @returns {Gpio}
     */
    val pin27: Gpio
        get() = getPin(physicalPin27)

    /**
     * Get pin 28.
     * @returns {Gpio}
     */
    val pin28: Gpio
        get() = getPin(physicalPin28)

    /**
     * Get pin 29.
     * @returns {Gpio}
     */
    val pin29: Gpio
        get() = getPin(physicalPin29)

    /**
     * Get pin 30.
     * @returns {Gpio}
     */
    val pin30: Gpio
        get() = getPin(physicalPin30)

    /**
     * Get pin 31.
     * @returns {Gpio}
     */
    val pin31: Gpio
        get() = getPin(physicalPin31)

    /**
     * Get pin 32.
     * @returns {Gpio}
     */
    val pin32: Gpio
        get() = getPin(physicalPin32)

    /**
     * Get pin 33.
     * @returns {Gpio}
     */
    val pin33: Gpio
        get() = getPin(physicalPin33)

    /**
     * Get pin 34.
     * @returns {Gpio}
     */
    val pin34: Gpio
        get() = getPin(physicalPin34)

    /**
     * Get all GPIO's pins.
     * @return List of pins.
     */
    val allPins: Array<Gpio?>
        get() {
            val allPins = arrayOfNulls<Gpio>(12)   // android       linux
            allPins[0] = pin23                          // GPIO 938     GPIO 36
            allPins[1] = pin24                          // GPIO 914     GPIO 12
            allPins[2] = pin25                          // GPIO 915     GPIO 13
            allPins[3] = pin26                          // GPIO 971     GPIO 69
            allPins[4] = pin27                          // GPIO 1017    GPIO 115
            allPins[5] = pin28                          // Reserved
            allPins[6] = pin29                          // GPIO 926     GPIO 24 (input only)
            allPins[7] = pin30                          // GPIO 927     GPIO 25
            allPins[8] = pin31                          // GPIO 937     GPIO 35
            allPins[9] = pin32                          // GPIO 936     GPIO 34
            allPins[10] = pin33                         // GPIO 930     GPIO 28
            allPins[11] = pin34                         // GPIO 935     GPIO 33
            return allPins
        }

    /**
     * Enable access to GPIO.
     * @param pin GPIO pin to access.
     */
    private fun exportPin(pin: Int) {
        println("Exporting Ping")
        try {
            val out = BufferedWriter(FileWriter("$PATH/export", false))
            out.write(pin.toString())
            out.close()
        } catch (e: IOException) {
            println("Error: " + e.message)
        }
    }

    /**
     * Disable access to GPIO.
     * @param pin GPIO pin to disable access.
     */
    private fun unexportPin(pin: Int) {
        println("unExporting Ping")
        try {
            val out = BufferedWriter(FileWriter("$PATH/unexport", false))
            out.write(pin.toString())
            out.close()
        } catch (e: IOException) {
            println("Error: " + e.message)
        }
    }

    fun closePins() {
        for (pin in pins) {
            unexportPin(pin)
        }
        pins.clear()
    }

    companion object {
        const val TAG = "GpioProcessor"
    }
}

使用类的GpioProcessor示例源

通过将按钮按下链接到侦听器,我在片段内的Android应用程序中使用了GPIO接口库。我有两个按钮,一个通过驱动一个引脚高开LED,另一个通过把引脚低开来关闭LED。

代码语言:javascript
复制
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    view.findViewById<Button>(R.id.button_second).setOnClickListener {
        findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
    }

    val txtScroll = view.findViewById(R.id.LedStatus) as TextView

    // find the button whose id is button_Location and then set an listener for
    // any clicks on that button. In the following listener we are going to have
    // the "Location" button, defined in the file fragment_first.xml, generate a
    // list of the GPS service providers by creatinga LocationManager object to
    // generate a list.
        val gpioProcessor_x =  GpioProcessor()
        // Get reference of GPIO23.
        val gpioPin23_x = gpioProcessor_x.pin23
        gpioPin23_x.exportPin()

    view.findViewById<Button>(R.id.button_led_off).setOnClickListener {
        val gpioProcessor =  GpioProcessor()
        // Get reference of GPIO27.
        val gpioPin23 = gpioProcessor.pin23

        // Set GPIO23 as output.
        gpioPin23.pinOut()
        gpioPin23.pinLow()    // drive pin low to turn off LED.
        txtScroll.append("LED Off\n")
    }

    view.findViewById<Button>(R.id.button_led_on).setOnClickListener {
        val gpioProcessor =  GpioProcessor()
        // Get reference of GPIO27.
        val gpioPin23 = gpioProcessor.pin23

        // Set GPIO23 as output.
        gpioPin23.pinOut()
        gpioPin23.pinHigh()    // drive pin high to turn on LED
        txtScroll.append("LED On\n")
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63653864

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档