如何在非Android Things的Android系统中通过NDK访问GPIO/SPI/I2C接口
树莓派LineageOS下NDK访问GPIO/SPI/I2C方案
接口底层运行逻辑
- GPIO:Android基于Linux内核,和树莓派OS逻辑一致,GPIO通过sysfs节点(默认路径
/sys/class/gpio/)控制,核心操作就是导出引脚、设置输入输出方向、读写电平值,你之前的理解完全正确。你所用的LineageOS16对应树莓派4.9版本以上内核,默认已经开启GPIO的sysfs支持。 - I2C:内核加载i2c-dev驱动模块后,会生成
/dev/i2c-*格式的字符设备文件,树莓派3B+默认启用的I2C总线对应/dev/i2c-1,操作时直接打开对应设备文件,通过ioctl系统调用指定从设备地址,即可完成数据读写。 - SPI:内核启用spidev驱动后,会生成
/dev/spidevX.Y格式的设备文件,X是总线编号、Y是片选编号,树莓派3B+默认SPI0总线的两个片选对应/dev/spidev0.0和/dev/spidev0.1。SPI的4引脚时序逻辑完全由内核驱动处理,不需要单独操作单个GPIO引脚,直接对设备文件做读写、通过ioctl配置时钟频率、极性、相位等参数即可完成通信。
树莓派LineageOS16前置配置
你所用的第三方编译版LineageOS已经默认把上述驱动编译进内核,只需要修改启动参数开启接口即可:
- 把树莓派的SD卡插到电脑上,打开boot分区的
config.txt文件,添加以下配置:
dtparam=i2c_arm=on dtparam=spi=on dtparam=gpio_in_pull=up
- 保存文件后插回树莓派开机,通过adb shell进入系统目录,查看
/dev/路径下有没有i2c-1、spidev0.0类文件,存在即说明接口启用成功。 - 权限配置:默认这些设备文件只有root权限可访问,调试阶段可以临时执行
chmod 666 /dev/i2c-1 /dev/spidev0.0 /sys/class/gpio/export /sys/class/gpio/unexport开放权限,长期使用可以修改系统ueventd规则实现开机自动配置权限。
NDK调用示例
不需要移植第三方库,直接在native层操作对应设备文件即可:
GPIO操作示例
// 导出GPIO18引脚 int export_fd = open("/sys/class/gpio/export", O_WRONLY); write(export_fd, "18", 2); close(export_fd); // 设置引脚为输出模式 int dir_fd = open("/sys/class/gpio/gpio18/direction", O_WRONLY); write(dir_fd, "out", 3); close(dir_fd); // 输出高电平 int val_fd = open("/sys/class/gpio/gpio18/value", O_WRONLY); write(val_fd, "1", 1); close(val_fd);
I2C操作示例
#include <linux/i2c-dev.h> #include <sys/ioctl.h> int fd = open("/dev/i2c-1", O_RDWR); // 设置通信的从设备地址为0x48 ioctl(fd, I2C_SLAVE, 0x48); // 读取2字节传感器数据 unsigned char buf[2]; read(fd, buf, 2); close(fd);
SPI操作示例
#include <linux/spi/spidev.h> #include <sys/ioctl.h> int fd = open("/dev/spidev0.0", O_RDWR); // 配置SPI模式0 uint8_t mode = SPI_MODE_0; ioctl(fd, SPI_IOC_WR_MODE, &mode); // 配置最大通信时钟为1MHz uint32_t speed = 1000000; ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); // 半双工收发3字节数据 unsigned char tx_buf[3] = {0x01, 0x02, 0x03}; unsigned char rx_buf[3]; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx_buf, .rx_buf = (unsigned long)rx_buf, .len = 3, .speed_hz = speed, .bits_per_word = 8, }; ioctl(fd, SPI_IOC_MESSAGE(1), &tr); close(fd);
如果对GPIO操作性能有要求,可以替换为更高效的gpiochar驱动方案,对应/dev/gpiochip*设备,操作逻辑和上述示例一致,调用内核对应ioctl指令即可。
内容的提问来源于stack exchange,提问作者odieatla
相关产品推荐
相关产品推荐

