xuexizhe_comput 发表于 2014-09-09 13:46

[求助!!!非标准单总线设备,写数据时使用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_comput 发表于 2014-09-09 16:35

本帖最后由 xuexizhe_computer 于 2014-09-09 16:37 编辑


这是用示波器测得波形,明显时序不对,好像被中断了

蜗牛_1215 发表于 2014-09-10 07:11

spin_lock_irqsave只是防止竞争情况的出现,不能防止一个进程换出CPU。arm Linux内核一般是10ms进行一次进程调度的判断。如果要达到你的要求可以,可以尝试下如下几种方式:
            1、增加该进程的优先级。
            2、在该段代码中禁止进程间的抢占。

xuexizhe_comput 发表于 2014-09-10 11:10

本帖最后由 xuexizhe_computer 于 2014-09-10 15:38 编辑

回复 3# 蜗牛_1215
你好

根据你的两个方案:
1 第一个提高进程优先级,这个该如何提高?

2 第二个是使用disable_preempt()/enable_preempt().
这个我用了,但是不起作用,会出现下图所示现象:


而且这里还有一个问题,整个写数据的过程最短也需要84us,这个是否有些危险?

3 这样一个设备驱动,是否还有其他方式去进行寄存器的操作?例如timer等


   

蜗牛_1215 发表于 2014-09-11 09:59

回复 4# xuexizhe_comput
修改进程优先级可以参考如下代码:

static int touch_event_handler(void *unused)
{
        struct sched_param param = { .sched_priority = RTPM_PRIO_TPD };
        sched_setscheduler(current, SCHED_RR, &param);
        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;
}

蜗牛_1215 发表于 2014-09-11 10:16

回复 5# 蜗牛_1215
我看了一下你的代码,发现传输1与0的数据是通过高低电平的延续时间长短不一来确定1与0。这种传输对于时间的精准度要求比较高,如果你用gpio来模拟时序很容易出现数据出错。

   

xuexizhe_comput 发表于 2014-09-15 17:17

你好
我尝试了一下,但是机子容易挂掉。我又看了一下高精度定时器,这部分,看起来可以实现,
http://blog.csdn.net/droidphone/article/details/8074892
这个具体实现方案该如何做?
回复 6# 蜗牛_1215


   
页: [1]
查看完整版本: [求助!!!非标准单总线设备,写数据时使用spin_lock_irqsave不起作用]