gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 10:36:37 37 4
gpt4 key购买 nike

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

但是,由于 spi_write 函数导致内核完全崩溃并出现以下错误,出现了问题:

BUG: scheduling while atomic: swapper/1/0/0x00000102

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

"Scheduling while atomic" indicates that you've tried to sleep somewhere that you shouldn't - like within a spinlock-protected critical section or an interrupt handler.

也许对 spi_write 的调用会触发某种 sleep 行为。禁止在这里休眠是有意义的,因为根据堆栈跟踪,我看到代码处于软 IRQ 状态:

[<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 事务需要定期发生的情况下,实现这种周期性行为的正确方法是什么?

以下是计时器处理程序的摘要(尽管进行了一些手动修改以使名称更通用——我可能在此过程中插入了一些拼写错误)

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 需要跳过几个环节。

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);
}

最佳答案

如果看spi_write源码,它会调用spi_sync,如果看第一行spi_sync -> mutex_lock,所以spi_write不能在中断内运行,并且无法通过 .configsysfs 修复。

My question is: what is the right way to implement such periodic behavior, where > an SPI transaction needs to occur periodically?

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

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

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

您还可以使用 spi_async 通过 spi 安排写入。 spy_async 可以在中断处理程序中调用。

如果延迟无关紧要,您还可以将内容移至用户空间,并通过 spidev 接口(interface)写入 SPI。

关于在 linux 驱动程序中定期调用 spi_write,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37149212/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com