在我的应用程序中,有一个线程负责处理RESET按钮,按下它的时间和时间;在此基础上我们采取行动。 问题是最小化CPU使用率:
使用此应用程序的{p> 1popen
次使用fp=popen(RESET_GPIO_VALUE,"r");
已75% CPU consumption
。
fopen
使用情况fp=fopen(RESET_GPIO_VALUE,"r");
为87% CPU consumption
。
open
使用情况fd = open(RESET_GPIO_VALUE,O_RDONLY);
为95% CPU consumption
。
是否有任何方法可以使用10-15% of CPU consumption
左右访问GPIO。
目前在我的逻辑中,我通过上面的定义方法检查其值,不断检查RESET GPIO。当按钮按下计时器启动和释放时,停止计时器并计算时间差。这整个动作在无限循环中运行。
答案 0 :(得分:2)
如果(原始)缺少有关"/"
的信息,我们可以提供合理的答案。
显然,您的μC板支持包实现了Linux 用户空间的GPIO Sysfs接口(您应该阅读有关Linux BSP附带的文档)。
基本上(如果电路板和驱动程序支持它),您可以在用户空间中进行GPIO的触发中断。只需将RESET_GPIO_VALUE
,rising
或falling
(字面意思)写入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
AM335x
目标板的终端上键入processID
命令,检查模块是否已插入。 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
发生中断时,该函数将被执行。现在,您可以独立运行应用程序,也可以通过轮询
“这些例子是不言自明的,已经给出了适当的评论”
希望这有助于。