[求助!!!非标准单总线设备,写数据时使用spin_lock_irqsave不起作用]
各位高手:本人目前在写一个操作led灯的IC驱动,但是在使用GPIO模拟时序时,会被打断,使用spin_lock_irqsave也不起作用,代码如下:
#define DELAY_TDS udelay(10)
#define DELAY_THLBudelay(2)
#define DELAY_TLLBudelay(4)
#define DELAY_THHBudelay(4)
#define DELAY_TLHBudelay(2)
#define DELAY_TEODL udelay(2)
#define DELAY_TEODH udelay(400)
#define DELAY_TSD mdelay(2)
void ktd202x_send_bit(struct ktd202x_data *data,int bit_data)
{
if (bit_data == 0) {
gpio_set_value(data->ctrl_gpio, 0);
DELAY_TLLB;
gpio_set_value(data->ctrl_gpio, 1);
DELAY_THLB;
} else {
gpio_set_value(data->ctrl_gpio, 0);
DELAY_TLHB;
gpio_set_value(data->ctrl_gpio, 1);
DELAY_THHB;
}
}
/* Write a complete command including address, data and EOD */
void ktd202x_send_data(struct ktd202x_data *data,unsigned char byte_address, unsigned char byte_data)
{
int n;
unsigned long flags;
printk(KERN_ERR"address = %d,data = %d\n" ,byte_address,byte_data);
spin_lock_irqsave(&data->led_lock, flags);
/* Set Ctrl High */
gpio_set_value(data->ctrl_gpio, 1);
DELAY_TDS;
/* Write Byte Address (only 4 bits) */
/* MSB first, start at xxxx 1xxx */
for (n = 0; n < 4; n++) {
ktd2024_send_bit(data,(byte_address & 0x08) ? 1 : 0);
byte_address = byte_address << 1;
}
/* Write Byte Data (8 bits) */
/* MSB first, start at 1xxx xxxx */
for (n = 0; n < 8; n++) {
ktd2024_send_bit(data,(byte_data & 0x80) ? 1 : 0);
byte_data = byte_data << 1;
}
/* Write EOD */
gpio_set_value(data->ctrl_gpio, 0);
DELAY_TEODL;
gpio_set_value(data->ctrl_gpio, 1);
spin_unlock_irqrestore(&data->led_lock, flags);
DELAY_TEODH;
}
这个应该如何解决,是否还有其他方式去写这个IC的寄存器?请高手指点. 本帖最后由 xuexizhe_computer 于 2014-09-09 16:37 编辑
这是用示波器测得波形,明显时序不对,好像被中断了 spin_lock_irqsave只是防止竞争情况的出现,不能防止一个进程换出CPU。arm Linux内核一般是10ms进行一次进程调度的判断。如果要达到你的要求可以,可以尝试下如下几种方式:
1、增加该进程的优先级。
2、在该段代码中禁止进程间的抢占。 本帖最后由 xuexizhe_computer 于 2014-09-10 15:38 编辑
回复 3# 蜗牛_1215
你好
根据你的两个方案:
1 第一个提高进程优先级,这个该如何提高?
2 第二个是使用disable_preempt()/enable_preempt().
这个我用了,但是不起作用,会出现下图所示现象:
而且这里还有一个问题,整个写数据的过程最短也需要84us,这个是否有些危险?
3 这样一个设备驱动,是否还有其他方式去进行寄存器的操作?例如timer等
回复 4# xuexizhe_comput
修改进程优先级可以参考如下代码:
static int touch_event_handler(void *unused)
{
struct sched_param param = { .sched_priority = RTPM_PRIO_TPD };
sched_setscheduler(current, SCHED_RR, ¶m);
do
{
mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
set_current_state(TASK_INTERRUPTIBLE);
wait_event_interruptible(waiter, tpd_flag != 0);
mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM);
tpd_flag = 0;
TPD_DEBUG_SET_TIME;
set_current_state(TASK_RUNNING);
gsl_report_work();
} while (!kthread_should_stop());
return 0;
}
回复 5# 蜗牛_1215
我看了一下你的代码,发现传输1与0的数据是通过高低电平的延续时间长短不一来确定1与0。这种传输对于时间的精准度要求比较高,如果你用gpio来模拟时序很容易出现数据出错。
你好
我尝试了一下,但是机子容易挂掉。我又看了一下高精度定时器,这部分,看起来可以实现,
http://blog.csdn.net/droidphone/article/details/8074892
这个具体实现方案该如何做?
回复 6# 蜗牛_1215
页:
[1]