0

I use the a40i(arm) processor and read the gpio interrupt flag at the application layer. I read the gpio flag as a character device. The gpio interrupt is given externally and has a stable 4ms period. The kernel has an rt patch, and the interrupt will be threaded. The gpio interrupt has its priority set by renice, and isolated core and core binding processing is also done. However, there will be time fluctuations at the application layer. For example, there is a certain possibility that reading two interrupts will take more than 6ms, but most of the time is still around 4.2ms. Is there any way to optimize this fluctuation?

the driver code of GPIO:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/sys_config.h>
#include <linux/major.h>
#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/pinctrl/pinconf-sunxi.h>
#include <linux/irq.h>
#include <linux/cpumask.h>


static int MajorDevNum = 0;
static int SpiioNum = 0;
static int IrqNum = 0;
static struct class *SpiioClass;
static int IrqOccurred = 0;
static  wait_queue_head_t WaitQueue;
static spinlock_t RWLock;


#define GPIO_PH20 244

static void SetIrqOccurred(int newIrqOccurred)
{
        spin_lock_irq(&RWLock);
        IrqOccurred = newIrqOccurred;
        gpio_set_value(GPIO_PH20, IrqOccurred);
        spin_unlock_irq(&RWLock);
}

static irqreturn_t spiio_irq_handler(int irq, void *dev_id)
{
        if (irq == IrqNum) {
                SetIrqOccurred(1);
        }
        return IRQ_HANDLED;
}

static int spiio_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
        int ret = IrqOccurred;
        if (ret) SetIrqOccurred(0);
        return ret;
}

/* write(fd, &val, 1); */
static int spiio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
   SetIrqOccurred(0);
   return 1;
}

static int spiio_drv_open(struct inode *node, struct file *file)
{
    int err = 0;
    pr_info("this is open for gpio\n");
    return 0;
}

static int spiio_drv_close(struct inode *node, struct file *file)
{
    return 0;
}

static long spiio_drv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
        return 0;
}

static unsigned int spiio_drv_poll(struct file *file, struct poll_table *wait)
{
    return 0;
}


static struct file_operations spiio_drv = {
    .owner = THIS_MODULE,
    .open = spiio_drv_open,
    .read = spiio_drv_read,
    .write = spiio_drv_write,
    .release = spiio_drv_close,
    .unlocked_ioctl = spiio_drv_ioctl,
    .poll = spiio_drv_poll,
};

int spiio_probe(struct platform_device *pdev)
{
    int err = 0;
    struct gpio_config pinConfig;
    char pinName[32] = {0};
    unsigned int config = 0;
    struct device_node *nd = pdev->dev.of_node;
    if (!nd) {
        pr_err("no found device tree node\n");
        return -1;
    }
    if ((of_gpio_named_count(nd, "spiio_gpio") <= 0))
    {
        pr_err("no found spiio_gpio node\n");
        return -1;
    }
    SpiioNum = of_get_named_gpio_flags(nd, "spiio_gpio", 0, (enum of_gpio_flags *)&pinConfig);
    if (!gpio_is_valid(SpiioNum))
    {
        pr_err("gpio isn't valid\n");
        return -1;
    }
    if (gpio_request(SpiioNum, pdev->name) < 0)
    {
        pr_err("gpio request failed, GPIO:%d\n", SpiioNum);
        gpio_free(SpiioNum);
        return -1;
    }
    sunxi_gpio_to_name(pinConfig.gpio, pinName);
    pr_info("pinName = %s\n", pinName);
    pr_info("index = %d\n", pinConfig.gpio);
    pr_info("mul_sel = %d\n", pinConfig.mul_sel);
    pr_info("pull = %d\n", pinConfig.pull);
    pr_info("drv_level = %d\n", pinConfig.drv_level);
    pr_info("data = %d\n", pinConfig.data);
    config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, pinConfig.mul_sel);
    pin_config_set(SUNXI_PINCTRL, pinName, config);
    if (pinConfig.pull != GPIO_PULL_DEFAULT) {
        config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, pinConfig.pull);
        pin_config_set(SUNXI_PINCTRL, pinName, config);
        pr_info("set pull:%d\n", pinConfig.pull);
    }
    if (pinConfig.drv_level != GPIO_DRVLVL_DEFAULT) {
        config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, pinConfig.drv_level);
        pin_config_set(SUNXI_PINCTRL, pinName, config);
        pr_info("set drv_level:%d\n", pinConfig.drv_level);
    }
    if (pinConfig.data != GPIO_DATA_DEFAULT) {
        config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, pinConfig.data);
        pin_config_set(SUNXI_PINCTRL, pinName, config);
        pr_info("set data:%d\n", pinConfig.data);
    }
    if (gpio_direction_input(SpiioNum) < 0)
    {
        pr_err("gpio_direction_input failed %d\n", SpiioNum);
        gpio_free(SpiioNum);
        return -1;
    }
    MajorDevNum = register_chrdev(0, "spiio", &spiio_drv); /* /dev/spiio */
    if (MajorDevNum < 0)
    {
        pr_err("failed to get major device number\n");
        gpio_free(SpiioNum);
        return -1;
    }

    SpiioClass = class_create(THIS_MODULE, "spiio_class");
    if (IS_ERR(SpiioClass))
    {
        pr_err("spiio class has an error\n");
        unregister_chrdev(MajorDevNum, "spiio");
        gpio_free(SpiioNum);
        return PTR_ERR(SpiioClass);
    }
    device_create(SpiioClass, NULL, MKDEV(MajorDevNum, 0), NULL, "spiio%d", 0); /* /dev/100ask_spiio0 */
    pr_info("gpio is ok, spiio num is %d\n", SpiioNum);
#if 1
    spin_lock_init(&RWLock);
    init_waitqueue_head(&WaitQueue);
    IrqNum = gpio_to_irq(SpiioNum);
    if (IS_ERR(IrqNum)) {
        pr_err("irqNum is err\n");
        free_irq(IrqNum, NULL);
        gpio_free(SpiioNum);
        unregister_chrdev(MajorDevNum, "spiio");
        return -1;
    }
    if ((err = request_irq(IrqNum, spiio_irq_handler, IRQF_TRIGGER_RISING, "spiio_irq", NULL)) < 0)
    {
        pr_err("requst_irq failed, err = %d\n", err);
        free_irq(IrqNum, NULL);
        gpio_free(SpiioNum);
        unregister_chrdev(MajorDevNum, "spiio");
        return -1;
    }
    pr_info("add irq %d on pin %d success.\n", IrqNum, SpiioNum);
#endif
#if 1
    cpumask_t cpumask;
    cpumask_clear(&cpumask);
    cpumask_set_cpu(2, &cpumask);  // 将中断绑定到CPU2
    err = irq_set_affinity_hint(IrqNum, &cpumask);
    if (err == 0)
    {
        pr_info("set irq cpu to 2 successfully\n");
    }
    else
    {
        pr_err("failed to set irq cpu to 2, err =%d\n", err);
    }
#endif
    if (gpio_request(GPIO_PH20, "PH20_GPIO")) {
        pr_err("failed to request GPIO PH20\n");
    } else {
        gpio_direction_output(GPIO_PH20, 1);
        pr_info("request GPIO PH20 successfully\n");
    }

    return 0;
}

int spiio_remove(struct platform_device *pdev)
{
#if 1
    free_irq(IrqNum, NULL);
#endif
    device_destroy(SpiioClass, MKDEV(MajorDevNum, 0));
    class_destroy(SpiioClass);
    unregister_chrdev(MajorDevNum, "spiio");
    gpio_free(SpiioNum);
    pr_info("gpio remove ...\n");
    return 0;
}

struct of_device_id ids[] = {
    {.compatible = "dobot, spiio"},
    {},
};

static struct platform_driver chip_demo_gpio_driver = {
    .probe = spiio_probe,
    .remove = spiio_remove,
   /* .shutdown = spiio_remove,*/
    .driver = {
        .name = "spiio",
        .of_match_table = ids,
    },
};

static int __init spiio_init(void)
{
    int err;
    err = platform_driver_register(&chip_demo_gpio_driver);
    return err;
}

static void __exit spiio_exit(void)
{
    platform_driver_unregister(&chip_demo_gpio_driver);
}
module_init(spiio_init);
module_exit(spiio_exit);
MODULE_LICENSE("GPL");

According to the test results, the entire ISR is executed with a delay.

static void SetIrqOccurred(int newIrqOccurred)
{
        spin_lock_irq(&RWLock);
        IrqOccurred = newIrqOccurred;
        gpio_set_value(GPIO_PH20, IrqOccurred);
        spin_unlock_irq(&RWLock);
}

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.