三种方式控制NanoPi2的GPIO

今天药忘吃喽~ 2022-09-21 13:20 328阅读 0赞

首先奉上PDF资料,万变不离其宗,掌握核心科技才是最重要的:

pdf.gif SEC_Users_Manual_S5P4418_Users_Manual_Preliminary_Ver.0.10.pdf (12.59 MB, 下载次数: 37)

我目前找到了三种方式控制NanoPi2的IO口:

  • 通过sysfs(/sys/class/gpio)来操作;
  • 通过内核的gpio_set_value函数来操作;
  • 通过配置寄存器(0xC001X000)来操作。
  1. 通过sysfs来操作

这种方法是官方教程给出的办法,这里只给出链接,不再详细解释。

http://bbs.elecfans.com/jishu_527063_1_1.html

  1. 通过内核函数来操作
    首先,用户层需要和驱动层交流,目前我知道的是两种方式,一种是通过ioctl操作,另一种是基于文件操作。注意,不管是基于ioctl还是文件操作,速度都是在200us这个数量级上,也就是0.2ms。
    2.1 基于ioctl操作
    下面是一段我自己写的内核代码,以及操作这个内核模块的demo。
    2.1.1 内核模块
    这个内核模块控制的是GPIOC11引脚,通过ioctl发送SET_VALUE命令可以设置引脚输出电平的高低,也就是LED的亮灭。使用的函数是:
  1. gpio_request(GPIOC11, “test”);

  2. gpio_direction_output(GPIOC11, 1);

  3. gpio_set_value(GPIOC11, HIGH);

复制代码

下面是全部代码:

  1. #include

  2. #include

  3. #include

  4. #include

  5. #include

  6. #include

  7. #include

  8. #include

  9. #include

  10. #include

  11. #include

  12. #include

  13. #include

  14. #include

  15. #define OUTPUT 1

  16. #define INPUT 0

  17. #define HIGH 1

  18. #define LOW 0

  19. #define SET_VALUE 123

  20. unsigned int GPIOC11 = PAD_GPIO_C + 11;

  21. #define DEVICE_NAME “gpio”

  22. static int gpio_open(struct inode *inode, struct file *file)

  23. {

  24. gpio_request(GPIOC11, “test”);

  25. gpio_direction_output(GPIOC11, 1);

  26. printk(“request GPIOC11\n”);

  27. return 0;

  28. }

  29. static int gpio_close(struct inode *inode, struct file *file){

  30. printk(“gpio_set_value LOW\n”);

  31. gpio_set_value(GPIOC11, LOW);

  32. gpio_free(GPIOC11);

  33. return 0;

  34. }

  35. static long

  36. gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {

  37. if(cmd == SET_VALUE){

  38. if(arg == HIGH){

  39. gpio_set_value(GPIOC11, HIGH);

  40. printk(“gpio_set_value HIGH\n”);

  41. }else if(arg == LOW){

  42. gpio_set_value(GPIOC11, LOW);

  43. printk(“gpio_set_value LOW\n”);

  44. }

  45. }

  46. return -EMSGSIZE;

  47. }

  48. static struct file_operations gpio_fops = {

  49. .owner = THIS_MODULE,

  50. .open = gpio_open,

  51. .release = gpio_close,

  52. .unlocked_ioctl = gpio_ioctl,

  53. };

  54. static struct miscdevice gpio_dev = {

  55. .minor = MISC_DYNAMIC_MINOR,

  56. .name = DEVICE_NAME,

  57. .fops = &gpio_fops,

  58. };

  59. volatile unsigned * GPIOCOUT;

  60. static int gpio_init(void){

  61. int ret = 0;

  62. printk(“init\n”);

  63. ret = misc_register(&gpio_dev);

  64. return ret;

  65. }

  66. static void gpio_exit(void){

  67. misc_deregister(&gpio_dev);

  68. printk(“exit\n”);

  69. }

  70. module_init(gpio_init);

  71. module_exit(gpio_exit);

  72. MODULE_LICENSE(“GPL”);

  73. MODULE_AUTHOR(“YPW”);

复制代码

下面就是这个模块的Makefile:

  1. obj-m:=gpio.o

  2. mymodule-objs:=gpio

  3. KDIR:=/home/ypw/Desktop/linux-3.4.y/

  4. MAKE:=make

  5. # EXTRA_CFLAGS += -I$(KDIR)arch/arm/mach-s5p4418/prototype/module

  6. default:

  7. $(MAKE) -C $(KDIR) M=$(PWD) modules

  8. clean:

  9. $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean

复制代码

如果你需要编译这个内核模块,你首先需要下载linux内核的源代码:https://github.com/friendlyarm/linux-3.4.y,然后将KDIR修改为你的内核地址,make即可编译出gpio.ko。如果不想自己编译,只想使用GPIOC11,可以下载我编译好的内核模块:gpio\_ioctl.ko
2.1.2 操作demo
安装和删除内核模块的办法:

  1. insmod gpio_ioctl.ko

  2. rmmod gpio_ioctl.ko

复制代码

安装好以后,如何使用呢?

  1. #include

  2. #include

  3. #include

  4. #define HIGH 1

  5. #define LOW 0

  6. #define SET_VALUE 123

  7. int main()

  8. {

  9. int fd = open(“/dev/gpio”, O_RDWR);

  10. int i;

  11. for(i=0;i<3;i++){

  12. ioctl(fd, SET_VALUE, HIGH);

  13. usleep(100000);

  14. ioctl(fd, SET_VALUE, LOW);

  15. usleep(100000);

  16. }

  17. close(fd);

  18. return 0;

  19. }

复制代码

  1. gcc gpio_ioctl.c -o gpio_ioctl

  2. ./gpio_ioctl

复制代码

编译运行,即可看到灯闪三下。
http://yangpeiwen.com/wp-content/uploads/2016/01/gpio.mp4

2.2 基于文件操作
2.2.1 内核代码:

  1. #include

  2. #include

  3. #include

  4. #include

  5. #include

  6. #include

  7. #include

  8. #include

  9. #include

  10. #include

  11. #include

  12. #include

  13. #include

  14. #include

  15. #define OUTPUT 1

  16. #define INPUT 0

  17. #define HIGH 1

  18. #define LOW 0

  19. #define SET_VALUE 123

  20. unsigned int GPIOC11 = PAD_GPIO_C + 11;

  21. #define DEVICE_NAME “gpio”

  22. static int gpio_open(struct inode *inode, struct file *file)

  23. {

  24. gpio_request(GPIOC11, “test”);

  25. gpio_direction_output(GPIOC11, 1);

  26. printk(“request GPIOC11\n”);

  27. return 0;

  28. }

  29. static int gpio_close(struct inode *inode, struct file *file){

  30. printk(“gpio_set_value LOW\n”);

  31. gpio_set_value(GPIOC11, LOW);

  32. gpio_free(GPIOC11);

  33. return 0;

  34. }

  35. static ssize_t

  36. gpio_write(struct file *filp, const char __user *buf,

  37. size_t count, loff_t *f_pos) {

  38. if (count > 1)

  39. return -EMSGSIZE;

  40. if(buf[0] == ‘1’){

  41. gpio_set_value(GPIOC11, HIGH);

  42. printk(“gpio_set_value HIGH\n”);

  43. }else if(buf[0] == ‘0’){

  44. gpio_set_value(GPIOC11, LOW);

  45. printk(“gpio_set_value LOW\n”);

  46. }else{

  47. return -EMSGSIZE;

  48. }

  49. return -EMSGSIZE;

  50. }

  51. static struct file_operations gpio_fops = {

  52. .owner = THIS_MODULE,

  53. .open = gpio_open,

  54. .release = gpio_close,

  55. .write = gpio_write,

  56. };

  57. static struct miscdevice gpio_dev = {

  58. .minor = MISC_DYNAMIC_MINOR,

  59. .name = DEVICE_NAME,

  60. .fops = &gpio_fops,

  61. };

  62. volatile unsigned * GPIOCOUT;

  63. static int gpio_init(void){

  64. int ret = 0;

  65. printk(“init\n”);

  66. ret = misc_register(&gpio_dev);

  67. return ret;

  68. }

  69. static void gpio_exit(void){

  70. iounmap(GPIOCOUT);

  71. misc_deregister(&gpio_dev);

  72. printk(“exit\n”);

  73. }

  74. module_init(gpio_init);

  75. module_exit(gpio_exit);

  76. MODULE_LICENSE(“GPL”);

  77. MODULE_AUTHOR(“YPW”);

复制代码

2.2.2 DEMO代码

  1. #include

  2. int main()

  3. {

  4. FILE *p = fopen(“/dev/gpio”, “w”);

  5. int i;

  6. for(i=0;i<3;i++){

  7. fprintf(p, “1”);fflush(p);

  8. usleep(100000);

  9. fprintf(p, “0”);fflush(p);

  10. usleep(100000);

  11. }

  12. fclose(p);

  13. return 0;

  14. }

复制代码

这个比较简单,跟上面的一样,我就不过多讲了。如果不想自己编译,可以下载我编译好的内核模块:gpio_file.ko

不过有一点我想说的就是,可以通过寄存器加速控制IO口的速度,这里仅贴一个代码片段,只能在内核中操作,这种操作方式最快可以达到20ns:

  1. #include

  2. volatile unsigned * GPIOCOUT;

  3. GPIOCOUT = ioremap(0xC001C000, 4);

  4. *GPIOCOUT = 0xFFFF;

  5. *GPIOCOUT = 0;

  6. iounmap(GPIOCOUT);

复制代码

  1. 通过配置寄存器来操作
    下面这个程序在用户层即可操作寄存器,原理是通过mmap将寄存器的地址通过映射到用户层,然后控制方法参考三星PDF即可。
  1. #include

  2. #include

  3. #include

  4. #include

  5. #include

  6. #include

  7. #include

  8. #define GPIOC_BASE_ADDRESS (0xC001C000)

  9. #define MAP_SIZE 40

  10. static int dev_fd;

  11. int main(int argc, char **argv)

  12. {

  13. dev_fd = open(“/dev/mem”, O_RDWR | O_NDELAY);

  14. if (dev_fd < 0)

  15. {

  16. printf(“open(/dev/mem) failed.”);

  17. return 0;

  18. }

  19. unsigned int base = (unsigned int)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, GPIOC_BASE_ADDRESS );

  20. #define GPIOCOUT *(unsigned int *)base

  21. #define GPIOCOUTENB *(unsigned int *)(base+0x04)

  22. #define GPIOCALTFN0 *(unsigned int *)(base+0x20)

  23. GPIOCALTFN0 &= ~(3<<22);

  24. GPIOCALTFN0 |= (1<<22);

  25. GPIOCOUTENB |= (1<<11);

  26. GPIOCOUT |= (1<<11);

  27. sleep(1);

  28. GPIOCOUT &= ~(1<<11);

  29. if(dev_fd)

  30. close(dev_fd);

  31. munmap((unsigned int *)base,MAP_SIZE);

  32. return 0;

  33. }

复制代码

效果是灯亮一秒,然后熄灭。这种方法操作速度很快,可以在80ns级别控制,而且很方便,不需要内核级的代码。

发表评论

表情:
评论列表 (有 0 条评论,328人围观)

还没有评论,来说两句吧...

相关阅读

    相关 NanoPi 2 GPIO使用

            在嵌入式设备中对 GPIO 的操作,一般的做法是写一个单独驱动程序。其实 linux 下面有一个通用的 GPIO 操作接口,那就是  “/sys/class/g