访问GPIO AM335x板作为RESET和最低CPU使用率

时间:2016-03-14 06:58:42

标签: c linux embedded embedded-linux gpio

在我的应用程序中,有一个线程负责处理RESET按钮,按下它的时间和时间;在此基础上我们采取行动。 问题是最小化CPU使用率:

使用此应用程序的{p> 1 popen次使用fp=popen(RESET_GPIO_VALUE,"r");75% CPU consumption

    此应用程序的
  1. fopen使用情况fp=fopen(RESET_GPIO_VALUE,"r");87% CPU consumption

  2. 此应用程序的
  3. open使用情况fd = open(RESET_GPIO_VALUE,O_RDONLY);95% CPU consumption

  4. 是否有任何方法可以使用10-15% of CPU consumption左右访问GPIO。

    目前在我的逻辑中,我通过上面的定义方法检查其值,不断检查RESET GPIO。当按钮按下计时器启动和释放时,停止计时器并计算时间差。这整个动作在无限循环中运行。

2 个答案:

答案 0 :(得分:2)

如果(原始)缺少有关"/"的信息,我们可以提供合理的答案。

显然,您的μC板支持包实现了Linux 用户空间的GPIO Sysfs接口(您应该阅读有关Linux BSP附带的文档)。

基本上(如果电路板和驱动程序支持它),您可以在用户空间中进行GPIO的触发中断。只需将RESET_GPIO_VALUErisingfalling(字面意思)写入both以选择代码想要响应的信号边缘,然后在/sys/class/gpio/gpioN/edge上执行poll()打开文件描述符到/sys/class/gpio/gpioN/value

每次value相应更改时,此轮询都会返回。

答案 1 :(得分:0)

好吧,因为它有点棘手,我会告诉你这样做的步骤是什么。因为它真的很棘手,许多人不愿意给出适当的答案,从来没有这些是你可以遵循的步骤

1.你必须做的是你可以先写一个内核模块。然后您可以编译它以生成.ko文件。哪个是可加载的内核模块。编写一个可加载的内核模块,在该模块中可以保留当任何特定GPIO发生中断时执行的ISR(中断服务程序)。对于您的信息,ISR也是一个在收到特定GPIO中断时自动执行的功能。

在内核模块中保留一个条款,以接受应用程序层Process ID,这样一旦有GPIO的中断,模块就可以从SIGNAL发送ARM target processor内核层到应用层。

2.将其复制到 `insmod <your_module.ko>` ,然后将模块插入内核。您可以通过键入

来插入模块
lsmod
  1. 通过在AM335x目标板的终端上键入processID命令,检查模块是否已插入。
  2. 3.然后,您可以编写用户级应用程序,您可以在进程开始运行时立即将应用程序的ProcessID发送到内核层。因此,您编写的内核模块可以让应用程序层SIGNAL发送32

    注意:由于默认情况下Linux使用第一个SIGNAL SIGNAL,因此您可以使用33 to 64中的SIGNAL Number 44号码来实现您的目的。我们在这里使用#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/gpio.h> //! << Required for the GPIO functions #include <linux/interrupt.h> //! << Required for the IRQ code #include <asm/siginfo.h> //! << siginfo #include <linux/rcupdate.h> //! << rcu_read_lock #include <linux/sched.h> //! << find_task_by_pid_type #include <linux/debugfs.h> #include <linux/uaccess.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sudipta Kumar Sahoo"); MODULE_DESCRIPTION("A SPI GPIO Interrupt driver for the Sitara"); MODULE_VERSION("1.0"); #define SIG_TEST 44 //! << we choose 44 as our signal number //! << (real-time signals are in the range of 33 to 64) struct dentry *file; int gPID = 0; int Return = 0; struct siginfo stGInfo; struct task_struct *stGTask; //static unsigned int resetGPIOInterrupt = 115; //! << hard coding the Delphino Interrupt gpio for this in BB P9_27 (GPIO115) static unsigned int resetGPIOInterrupt = 54; static unsigned int irqNumber; //! << Used to share the IRQ number within this file static unsigned int numberPresses = 0; //! << For information, store the number of times the SIGNAL is high. /********************************************************************************/ /** * \fn write_pid(struct file *file, const char __user *buf, * size_t count, loff_t *ppos) * * @brief The LKM write_pid function * The static keyword restricts the visibility of the function * to within this C file. * * @return returns 0 if successful */ /********************************************************************************/ static ssize_t write_pid(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char mybuf[10]; int pid = 0; int ret; struct siginfo info; struct task_struct *stTask; /* read the value from user space */ if(count > 10) { return -EINVAL; } copy_from_user(mybuf, buf, count); //! << Copy the Process ID from the Application Process /* For Global variables value assignment starts */ /******************************************************************************************/ //! Copy the required information to Global variables to send SIGNAL from ISR sscanf(mybuf, "%d", &gPID); //! << Copy to global PID memset(&stGInfo, 0, sizeof(struct siginfo)); stGInfo.si_signo = SIG_TEST; //! << this is bit of a trickery: SI_QUEUE is normally used by sigqueue from user space, //! << and kernel space should use SI_KERNEL. But if SI_KERNEL is used the real_time data //! << is not delivered to the user space signal handler function. stGInfo.si_code = SI_QUEUE; stGInfo.si_int = 1024; /*For Global variables value assignment Ends */ /******************************************************************************************/ /* send a SIGNAL to the process to intimate that it received the corresponding PID. */ sscanf(mybuf, "%d", &pid); printk("pid = %d\n", pid); memset(&info, 0, sizeof(struct siginfo)); info.si_signo = SIG_TEST; //! << this is bit of a trickery: SI_QUEUE is normally used by sigqueue from user space, //! << and kernel space should use SI_KERNEL. But if SI_KERNEL is used the real_time data //! << is not delivered to the user space signal handler function. info.si_code = SI_QUEUE; info.si_int = 1234; //! << real time signals may have 32 bits of data. rcu_read_lock(); //! << Get the RCU Read lock //t = find_task_by_pid_type(PIDTYPE_PID, pid); //! << find the task_struct associated with this pid stTask = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID); if(stTask == NULL) { printk("no such pid\n"); rcu_read_unlock(); return -ENODEV; } rcu_read_unlock(); //! << Make the RCU Read unlock ret = send_sig_info(SIG_TEST, &info, stTask); //! <<send the signal if (ret < 0) { printk("error sending signal\n"); return ret; } return count; } /********************************************************************************/ /** * @brief The LKM mapping user defiend functions to file_operations structure. */ /********************************************************************************/ static const struct file_operations my_fops = { .write = write_pid, }; /********************************************************************************/ /** * @brief Function prototype for the custom IRQ handler function * see below for the implementation. */ /********************************************************************************/ static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs); /********************************************************************************/ /** * \fn __init ebbgpio_init(void) * * @brief The LKM initialization function. The static keyword restricts the * visibility of the function to within this C file. The __init macro * means that for a built-in driver (not a LKM) the function is only used * at initialization time and that it can be discarded and its memory * freed up after that point. In this example this function sets up the * GPIOs and the IRQ * * @return returns 0 if successful */ /********************************************************************************/ static int __init ebbgpio_init(void) { int result = 0; printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n"); // Is the GPIO a valid GPIO number (e.g., Sitara has 4x32 but not all available) if (!gpio_is_valid(resetGPIOInterrupt)) { printk(KERN_INFO "GPIO_TEST: invalid Button GPIO\n"); return -ENODEV; } //Going to set up the Button. It is a GPIO in input mode and will be zero by default //gpio_set_value(gpioLED, ledOn); //! Not required as set by line above (here for reference) gpio_request(resetGPIOInterrupt, "sysfs"); //! Set up the gpioButton gpio_direction_input(resetGPIOInterrupt); //! Set the resetGPIOInterrupt GPIO to be an input gpio_set_debounce(resetGPIOInterrupt, 200); //! Debounce the resetGPIOInterrupt with a delay of 200ms gpio_export(resetGPIOInterrupt, false); //! Causes gpio115 to appear in /sys/class/gpio //! the bool argument prevents the direction from being changed // Perform a quick test to see that the resetGPIOInterrupt is working as expected on LKM load printk(KERN_INFO "GPIO_TEST: The resetGPIOInterrupt state is currently: %d\n", gpio_get_value(resetGPIOInterrupt)); // GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us irqNumber = gpio_to_irq(resetGPIOInterrupt); printk(KERN_INFO "GPIO_TEST: The resetGPIOInterrupt is mapped to IRQ: %d\n", irqNumber); // This next call requests an interrupt line result = request_irq(irqNumber, //! The interrupt number requested (irq_handler_t) ebbgpio_irq_handler, //! The pointer to the handler function below IRQF_TRIGGER_RISING, //! Interrupt on rising edge (When The Signal is High-1 not at Low-0) "ebb_gpio_handler", //! Used in /proc/interrupts to identify the owner NULL); //! The *dev_id for shared interrupt lines, NULL is okay printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result); /* we need to know the pid of the user space process * -> we use debugfs for this. As soon as a pid is written to * this file, a signal is sent to that pid */ /* only root can write to this file (no read) */ file = debugfs_create_file("signalconfpid", 0200, NULL, NULL, &my_fops); return result; } /********************************************************************************/ /** * \fn __init ebbgpio_init(void) * * @brief The LKM cleanup function Similar to the initialization function, * it is static. The __exit macro notifies that if this code is used for * a built-in driver (not a LKM) that this function is not required. Used * to release the GPIOs and display cleanup messages. * * @return returns NULL */ /********************************************************************************/ static void __exit ebbgpio_exit(void) { printk(KERN_INFO "GPIO_TEST: The resetGPIOInterrupt state is currently: %d\n", gpio_get_value(resetGPIOInterrupt)); printk(KERN_INFO "GPIO_TEST: The resetGPIOInterrupt was received %d times\n", numberPresses); free_irq(irqNumber, NULL); //! << Free the IRQ number, no *dev_id required in this case. gpio_unexport(resetGPIOInterrupt); //! << Unexport the resetGPIOInterrupt GPIO. gpio_free(resetGPIOInterrupt); //! << Free the resetGPIOInterrupt GPIO. debugfs_remove(file); //! << Remove the debugfs file. printk(KERN_INFO "GPIO_TEST: Unloading the GPIO_TEST LKM module!\n"); } /********************************************************************************/ /** * \fn ebbgpio_irq_handler(void) * @brief The GPIO IRQ Handler function. This function is a custom interrupt * handler that is attached to the GPIO above. The same interrupt handler * cannot be invoked concurrently as the interrupt line is masked out * until the function is complete. This function is static as it should * not be invoked directly from outside of this file. * * @param irq the IRQ number that is associated with the GPIO--useful for logging. * * @param dev_id the *dev_id that is provided -- can be used to identify which * device caused the interrupt * (Not used in this case as NULL is passed.) * * @param regs h/w specific register values -- only really ever used for debugging. * * @return returns IRQ_HANDLED if successful -- should return IRQ_NONE otherwise. */ /********************************************************************************/ static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) { printk(KERN_INFO "GPIO_TEST: Interrupt! (resetGPIOInterrupt state is %d)\n", gpio_get_value(resetGPIOInterrupt)); numberPresses++; // Global counter, will be outputted when the module is unloaded /* Sending The Signal to Process Starts */ rcu_read_lock(); stGTask = pid_task(find_pid_ns(gPID, &init_pid_ns), PIDTYPE_PID); printk("sending signal From ISR\n"); if(stGTask == NULL) { printk("no such pid\n"); rcu_read_unlock(); return -ENODEV; } rcu_read_unlock(); //This is the Line Important for You. Where we are sending the Signal to the Application layer Return = send_sig_info(SIG_TEST, &stGInfo, stGTask); //send the signal if (Return < 0) { printk("error sending signal\n"); return Return; } /* Sending The Signal to Process Ends */ return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly } /********************************************************************************/ /// This next calls are mandatory -- they identify the initialization function /// and the cleanup function (as above). /********************************************************************************/ module_init(ebbgpio_init); module_exit(ebbgpio_exit);

    内核模块示例:

    appropriate GPIO

    您可以直接获取代码并生成.ko文件。请注意根据您的要求配置GPIO-54号码。我已配置AM335x该代码仅为.ko处理器编写。如果您不知道如何创建"HOW TO BUILD A KERNEL MODULE"文件,那么只需要很酷并且谷歌/********************************************************************************/ /** * @file userApplication.c * * @author Sudipta Kumar Sahoo * * @brief An Application layer programm implementation to connect with the * kernel layer, That receives the interrupt from the kernel space * once the particular interrupt is received at configured GPIO pin. * * NOTE:: Before executing the program first mount the debugfs if it has * not already mounted to the file system and then execute the application * to receive the interrupt Signal in applicatio layer. * * The copyright notice does not evidence any actual or intended publication. */ /********************************************************************************/ #include <signal.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #define SIG_TEST 44 /* we define our own signal, hard coded since SIGRTMIN is different in user and in kernel space */ #define RUNNING 1 /********************************************************************************/ /** * \fn void signalHandler(int n, siginfo_t *info, void *unused) * * @brief The receiveData function * The function has been registered to the kernel layer debugfs file system * When GPIO gets the interrupt it intimates to appliation process via * signalHandler() function and the appropriate action is taken afterwards. * * @return NULL */ /********************************************************************************/ void signalHandler(int n, siginfo_t *info, void *unused) { printf("Application received value %i\n", info->si_int); /* Do what ever you want to do inside this Function upon the receival of the Interrupt */ } int main ( int argc, char **argv ) { int configfd; char buf[10]; /* setup the signal handler for SIG_TEST * SA_SIGINFO -> we want the signal handler function with 3 arguments */ struct sigaction sig; sig.sa_sigaction = signalHandler; sig.sa_flags = SA_SIGINFO; sigaction(SIG_TEST, &sig, NULL); /* kernel needs to know our pid to be able to send us a signal -> * we use debugfs for this -> do not forget to mount the debugfs! */ configfd = open("/sys/kernel/debug/signalconfpid", O_WRONLY); if(configfd < 0) { printf("Could not Open the File\n"); perror("open"); return -1; } sprintf(buf, "%i", getpid()); //! << Get the process ID. if (write(configfd, buf, strlen(buf) + 1) < 0) //! << Write the details to Kernel Space. { perror("fwrite"); return -1; } /* * Making the Application to run independently */ while(RUNNING) { printf("Waiting for Interrup Signal...\n"); sleep(1); } return 0; } ,您就可以轻松获得。

    最后,您可以编写一个虚拟应用程序来测试它,该应用程序如下所示:

    signalHandler()

    GPIO是应用程序层中的函数,当特定配置的gatttool -b <mac_address> -I //to start the tool in interactive mode. Then connect from the prompt to connect to the device. Then char-write-req <CCC handle> 02 发生中断时,该函数将被执行。现在,您可以独立运行应用程序,也可以通过轮询

    接收中断

    “这些例子是不言自明的,已经给出了适当的评论”

    希望这有助于。