5242 views|3 replies

291

Posts

5

Resources
The OP
 

【i.MX6ULL】Driver Development 7——Key Input Capture [Copy link]

This post was last edited by DDZZ669 on 2021-11-9 00:04

In the previous articles, we have gradually learned about the various lighting principles of embedded Linux development, from the most basic register lighting, to device tree lighting, and then to GPIO subsystem lighting.

The output function of GPIO is used to turn on the lights. In this article, we will learn how to use the GPIO input function by using the buttons .

1 Hardware Introduction

1.1 Schematic diagram of buttons on the board

Let's look at the schematic diagram first . There are 4 buttons sw1~sw4 on my board:

1.1.1 SW1

SW1 is the system reset button of the board and cannot be used programmably

1.1.2 SW2, SW3

  • SW2 : SNVS_TAMPER1, GPIO5_1

    It is usually at a low level, and when pressed it is at a high level.

  • SW3 : ONOFF

    It is also a system-level button used to turn the device on and off by long pressing.

1.1.3 SW4

SW4 is the BOOT_MODE1 pin, which is used to switch the serial burning mode and needs to be used in conjunction with the reset button.

This article only tests the button function, so you can use this button.

1.1.4 Use two of the buttons

The functional characteristics of the four buttons on the board are as follows:

This experiment uses the two buttons SW2 and SW4 to carry out the experiment.

2 Software Writing

2.1 Modify the device tree file

2.1.1 Modify the iomuxc node

Modify imx6ull-myboard.dts and create a child node named pinctrl_key under the imx6ull-evk child node of the iomuxc node. The node content is as follows:

pinctrl_key: keygrp { 
  fsl,pins = < 
    MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01  0x3080 /* SW2 */
    MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11   0xF080 /* SW4 */
  >; 
};

This part configures the pins. The definitions of these two pins are in the imx6ull-pinfunc-snvs.h file:

The value following the pin macro definition is the configuration of the pin function:

SW2: 0x3080, i.e. 0011 0000 1000 0000

SW4: 0xF080, i.e. 1000 0000 1000 0000

Refer to the configuration of the GPIO PAD register explained previously , and configure the pull-up or pull-down according to the actual circuit configuration of the two buttons.

/*
*bit 16:0 HYS关闭
*bit [15:14]: [00]下拉 [01]47k上拉 [10]100k上拉 [11]22k上拉 <---
*bit [13]: [0]kepper功能 [1]pull功能
*bit [12]: [0]pull/keeper-disable [1]pull/keeper-enable
*bit [11]: 0 关闭开路输出
*bit [10:8]: 00 保留值
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 000 输出disable <---
*bit [2:1]: 00 保留值
*bit [0]: 0 低转换率
*/

Note: The GPIO SW4 (MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11) is actually used by another device (spi4) in the device.

At more than 300 lines of imx6ull-myboard.dts, there is:

pinctrl_spi4: spi4grp {
 fsl,pins = <
   MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10    0x70a1
   MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11    0x70a1
   MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07   0x70a1
   MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08   0x80000000
   >;
};

In theory, we should comment out the configuration here, because one IO cannot perform two functions at the same time. Since spi4 is not used in this experiment, ignore it for now and see what impact it will have. If it affects this experiment, comment out the configuration here.

2.1.2 Add key node

Create a key node named key under the root node with the following content:

key { 
  #address-cells = <1>; 
  #size-cells = <1>; 
  compatible = "myboard-key"; 
  pinctrl-names = "default"; 
  pinctrl-0 = <&pinctrl_key>; 
  key1-gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>;  /* SW2 */
  key2-gpio = <&gpio5 11 GPIO_ACTIVE_LOW>;  /* SW4 */
  status = "okay"; 
}; 

2.2 Writing a Key Driver

The key driver also belongs to the character device driver. Like the previous character device driver framework, the main modification points are the hardware initialization configuration of the key and the reading of the key.

Create a new key-Bsp.c

2.2.1 Hardware initialization of buttons

The initialization process is to use the OF function to obtain the key node from the device tree, and then use the API function of the GPIO subsystem to configure the GPIO as input.

static int keyio_init(void)
{
  keydev.nd = of_find_node_by_path("/key");
  if (keydev.nd== NULL) 
   {
    return -EINVAL;
   }

  keydev.key1_gpio = of_get_named_gpio(keydev.nd ,"key1-gpio", 0);
  keydev.key2_gpio = of_get_named_gpio(keydev.nd ,"key2-gpio", 0);
  if ((keydev.key1_gpio < 0)||(keydev.key2_gpio < 0))
   {
    printk("can't get key\r\n");
    return -EINVAL;
   }
  printk("key1_gpio=%d, key2_gpio=%d\r\n", keydev.key1_gpio, keydev.key2_gpio);

  /* 初始化key所使用的IO */
  gpio_request(keydev.key1_gpio, "key1");  /* 请求IO */
  gpio_request(keydev.key2_gpio, "key2");  /* 请求IO */
  gpio_direction_input(keydev.key1_gpio);  /* 设置为输入 */
  gpio_direction_input(keydev.key2_gpio);  /* 设置为输入 */
  return 0;
}

2.2.2 Read the value of a button

The key value is read by the API function of the GPIO subsystem. After reading the key value, the value is passed to the application layer for use. Note that atomic operations atomic_set and atomic_read are used here to implement data writing and reading.

/* 定义按键值 */
#define KEY1VALUE    0X01  /* 按键值    */
#define KEY2VALUE    0X02  /* 按键值    */
#define INVAKEY     0X00  /* 无效的按键值 */

static ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
  int ret = 0;
  int value;
  struct key_dev *dev = filp->private_data;

  if (gpio_get_value(dev->key1_gpio) == 1)     /* key1按下 */
   {
    printk("get key1: high\r\n");
    while(gpio_get_value(dev->key1_gpio));    /* 等待按键释放 */
    atomic_set(&dev->keyvalue, KEY1VALUE);
   }
  else if (gpio_get_value(dev->key2_gpio) == 0)  /* key2按下 */
   {
    printk("get key2: low\r\n");
    while(!gpio_get_value(dev->key2_gpio));   /* 等待按键释放 */
    atomic_set(&dev->keyvalue, KEY2VALUE);
   }
  else
   {
    atomic_set(&dev->keyvalue, INVAKEY);    /* 无效的按键值 */
   }

  value = atomic_read(&dev->keyvalue);
  ret = copy_to_user(buf, &value, sizeof(value));
  return ret;
}

2.3 Writing a Keystroke Application

Create a new key-App.c

The application layer program of the key mainly uses the key reading interface provided by the driver to cyclically read the value of the key and print out the value of the key when the key is pressed.

/* 定义按键值 */
#define KEY1VALUE  0X01
#define KEY2VALUE  0X02
#define INVAKEY   0X00

int main(int argc, char *argv[])
{
  int fd, ret;
  char *filename;
  int keyvalue;

  if(argc != 2)
   {
    printf("Error Usage!\r\n");
    return -1;
   }

  filename = argv[1];

  /* 打开key驱动 */
  fd = open(filename, O_RDWR);
  if(fd < 0)
   {
    printf("file %s open failed!\r\n", argv[1]);
    return -1;
   }

  /* 循环读取按键值数据! */
  while(1)
   {
    read(fd, &keyvalue, sizeof(keyvalue));
    if (keyvalue == KEY1VALUE)
     {
      printf("KEY1 Press, value = %#X\r\n", keyvalue);
     }
    else if (keyvalue == KEY2VALUE)
     {
      printf("KEY2 Press, value = %#X\r\n", keyvalue);
     }
   }

  ret= close(fd); /* 关闭文件 */
  if(ret < 0)
   {
    printf("file %s close failed!\r\n", argv[1]);
    return -1;
   }
  return 0;
}

3 Experimental tests

3.1 Compiler

3.1.1 Compile device tree

Compile the device tree file and copy the compiled dtb file to the startup folder:

Start the development board via the network and view the key node:

3.1.2 Compile the key driver

3.1.3 Compile the button application

3.2 Testing

3.3 Check CPU usage

First, press Ctrl+C to end the key process, and then use the following command to run the key program in the background:

./key-App /dev/key &

Then use the command:

top

To check the CPU usage. As can be seen from the figure below, the CPU usage is 99.8% at this time, which is all occupied by the key check program, because there is a while loop in the key program that keeps reading the key value.

Use the command:

ps

Check the process number of the key, which is 149 in the following figure, and then use:

kill -9 149

To kill the key process, and then use the top command to view, you can see that the CPU usage has returned to 0.

In actual key usage, the method of continuous detection that causes CPU occupancy is generally not used. This article only introduces the use of GPIO input function. Later, a more efficient key detection mechanism will be used to implement the key detection function.

4 Conclusion

This article mainly introduces the use of key detection of i.MX6ULL. The main knowledge points are the modification of device tree, as well as the input configuration of GPIO and the reading of high and low levels.

This post is from ARM Technology

Latest reply

【i.MX6ULL】 Driver development series articles summary entry: 【i.MX6ULL】Driver Development——by DDZZ669 - ARM Technology - Electronic Engineering World - Forum (eeworld.com.cn) Sub-directories: 【i.MX6ULL】Driver Development 1——Character Device Development Template 【i.MX6ULL】Driver Development 2——New Character Device Development Template 【i.MX6ULL】Driver Development 3——GPIO Register Configuration Principle 【i.MX6ULL】Driver Development 4——Light up the LED (Register Version) 【i.MX6ULL】Driver Development 5——Device Tree Principle and Lighting LED 【i.MX6ULL】Driver Development 6——Pinctrl subsystem and GPIO subsystem light up LED 【i.MX6ULL】Driver Development 7——Key Input Capture 【i.MX6ULL】Driver Development 8——Interrupt Method to Detect Buttons 【i.MX6ULL】Driver Development 9——Linux IO Model Analysis 【i.MX6ULL】Driver Development 10——Blocking & Non-blocking Key Detection 【i.MX6ULL】Driver Development 11——LCD Driver Practice 【i.MX6ULL】Driver Development 12——Capacitive Touch Driver Practice (Part 1) 【i.MX6ULL】Driver Development 13——Capacitive Touch Driver Practice (Part 2)   Details Published on 2022-3-21 07:39
 

1w

Posts

203

Resources
From 2
Personal signature

玩板看这里:

https://bbs.eeworld.com.cn/elecplay.html

EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!

 
 

6609

Posts

0

Resources
3
 

The key operation under Linux seems to be more complicated

After the kill command,

If you check the top command again, you can see that the CPU usage has returned to 0. The kill command is equivalent to the termination command.

This post is from ARM Technology

Comments

The keystrokes in Linux can also be interrupted. The reason why this program has a high CPU usage is mainly because the application layer program is constantly reading the keystroke values. The kill command is used to forcibly terminate a process.  Details Published on 2021-11-10 22:58
 
 
 

291

Posts

5

Resources
4
 
Jacktang posted on 2021-11-10 07:16 The key operation under Linux seems to be more complicated. After the kill command, check the top command and you can see that the CPU usage rate has returned to 0. The kill command...

The keystrokes in Linux can also be interrupted. The reason why this program has a high CPU usage is mainly because the application layer program is constantly reading the keystroke values. The kill command is used to forcibly terminate a process.

This post is from ARM Technology
 
 
 

Guess Your Favourite
Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list