首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在linux驱动程序中定期调用spi_write

在linux驱动程序中定期调用spi_write
EN

Stack Overflow用户
提问于 2016-05-10 21:23:30
回答 1查看 1.5K关注 0票数 0

我正在为液晶显示器写一个驱动程序。根据应用程序说明,我需要定期向命令写入一个虚拟SPI,以最大限度地增强其对比度。为此,我设置了一个计时器,并尝试从计时器处理程序中编写对比度最大化的2字节虚拟命令。

但是,由于spi_write函数导致了一个完整的内核崩溃,导致了以下错误,所以出了问题:

代码语言:javascript
运行
复制
BUG: scheduling while atomic: swapper/1/0/0x00000102

基于以下帖子:How to solve "BUG: scheduling while atomic: swapper /0x00000103/0, CPU#0"? in TSC2007 Driver?

“调度而原子”表示您试图睡在您不应该睡的地方,比如在spinlock保护的关键部分或中断处理程序中。

也许对spi_write的调用会触发某种睡眠行为。不允许在这里睡觉是有意义的,因为基于堆栈跟踪,我看到代码处于软IRQ状态:

代码语言:javascript
运行
复制
[<404ec600>] (schedule_timeout) from [<404eac3c>] (wait_for_common+0x114/0x15c)
[<404eac3c>] (wait_for_common) from [<4031c7a4>] (spi_sync+0x70/0x88)
[<4031c7a4>] (spi_sync) from [<3f08a6b0>] (plt_lcd_send_toggle_comin_cmd+0x7c/0x84 [plt_lcd_spi])
[<3f08a6b0>] (plt_lcd_send_toggle_comin_cmd [plt_lcd_spi]) from [<3f08a6c4>] (plt_lcd_timer_handler+0xc/0x2c [plt_lcd_spi])
[<3f08a6c4>] (plt_lcd_timer_handler [plt_lcd_spi]) from [<40058818>] (call_timer_fn.isra.26+0x20/0x30)
[<40058818>] (call_timer_fn.isra.26) from [<40058f30>] (run_timer_softirq+0x1ec/0x21c)
[<40058f30>] (run_timer_softirq) from [<40023414>] (__do_softirq+0xe0/0x1c8)
[<40023414>] (__do_softirq) from [<400236f0>] (irq_exit+0x58/0xac)
[<400236f0>] (irq_exit) from [<4004ee4c>] (__handle_domain_irq+0x80/0xa0)
[<4004ee4c>] (__handle_domain_irq) from [<400085ac>] (gic_handle_irq+0x38/0x5c)
[<400085ac>] (gic_handle_irq) from [<40011740>] (__irq_svc+0x40/0x74)

我的问题是:实现这种周期性行为的正确方法是什么,其中需要周期性地发生SPI事务?

以下是计时器处理程序的摘要(尽管使用了一些手动修改,以使名称更通用-我可能已经在这个过程中插入了一些排印)

代码语言:javascript
运行
复制
static void lcd_timer_handler(unsigned long data)
{
    // priv is a private structure that contains private info for the 
    // driver: timer structure, timer timeout, context for the dummy command
    lcd_priv * const priv = (memlcd_priv *) data;

    unsigned char dummy[2];
    dummy[0] = get_dummy_command_code(priv);
    dummy[1] = 0; // command must be terminated by a 0.

    // This is the call that causes the failure.
    // priv->spi is a struct spi_device *
    spi_write(priv->spi, ((const void *) dummy), 2);

    // Re-arm the timer
    mod_timer(&priv->timer, jiffies + priv->timer_timeout);
}

谢谢!

编辑:下面是我在执行了下面答案中的建议之后提出的建议。工作得很好,但是使用delayed_work需要跳过几圈。

代码语言:javascript
运行
复制
typedef struct lcd_priv {
    /* private stuff: */
    /* ... */

    /* workqueue stuff: */
    struct workqueue_struct * wq;
    struct delayed_work periodic_work;
} lcd_priv;


void lcd_periodic_work(struct work_struct * work_struct_ptr)
{
    /*
     * Old documentation refers to a "data" pointer, but the API
     * no longer supports it. The developer is invited to put the work_struct
     * inside what would have been pointed to by "data" and to use container_of()
     * to recover this master struct.
     * See http://lwn.net/Articles/211279/ for more info.
    */

    struct delayed_work * delayed = container_of(work_struct_ptr, struct delayed_work, work);
    lcd_priv * priv = container_of(delayed, lcd_priv, periodic_work);

    /* (prepare spi buffer in priv->spi_buf) */
    /* ... */

    /* This could be any activity that goes to sleep: */
    spi_write(priv->spi, ((const void *) &priv->spi_buf[0]), 2);

    queue_delayed_work(priv->wq, &priv->periodic_work, TOGGLE_FREQUENCY);
}

static void lcd_start_workqueue(lcd_priv * const priv) {
    priv->wq = create_singlethread_workqueue("lcd_periodic_st_wq");

    INIT_DELAYED_WORK(&priv->periodic_work, lcd_periodic_work);
    queue_delayed_work(priv->wq, &priv->periodic_work, TOGGLE_FREQUENCY);
}

static void lcd_stop_workqueue(lcd_priv * const priv) {
    destroy_workqueue(priv->wq);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-10 22:30:55

如果查看spi_write源代码,它调用spi_sync,如果查看spi_sync -> mutex_lock的第一行,那么spi_write就不能在中断中运行,也不能通过.configsysfs进行修复。

我的问题是:实现这种周期性行为的正确方法是什么?> SPI事务需要定期发生?

答案取决于您的硬件,您希望通过SPI发送数据的频率,您接受的延迟等等。

可以在工作队列回调中使用spi_write,请参阅https://www.safaribooksonline.com/library/view/understanding-the-linux/0596005652/ch04s08.html

专门为这类事情设计的工作队列(运行不能在中断上下文中运行的东西),

此外,您还可以使用spi_async来安排通过spi编写的时间。spy_async可以在中断处理程序中调用。

此外,如果延迟时间不重要,则将东西移动到用户空间,并通过spidev接口写入SPI。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37149212

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档