TPS6116x 1-wire总线的分析与驱动实现

1-wire总线的特点

1-wire协议是用一条数据线作为总线进行数据通信的协议。

1-wire总线有以下特点:

1. 可以组建网络,个数没有限制。

2. 使用GPIO的特性就可以,不需要专门的控制器。

3. 总线网络中只有一个主动设备,其它设备均为从设备。主设备发起通信,从设备应答。从设备不能发起通信。

4. 属于串行异步通信。

5. 通信时序严格,在操作系统中,必须在数据通信阶段阶段关闭调度(调度带来的延迟可以能有数毫秒,将破坏时序)。

6. 不同的1-wire设备,通信协议和时序很可能不一样。组建网络时,确保使用遵守相同协议和时序的设备。

 

TPS6116x的功能框图

1. 从上电谈起

    上电后,默认工作在PWM模式,参考电压为200mV. 如果要让设备工作在1-wire模式,则要按照时序要求设置CTRL。

    上电的时候,如果CTRL是高电平,对是否1-wire模式的侦测被立即触发。如果CTRL不符合时序要求,则退出侦测。

    任何时候,如果CTRL是低电平,且维持2.5ms以上,则设备关机。

2. 无论是PWM模式,还是1-wire模式,都是在设置参考电压(Reference Control).

    FB的目标值是参考电压(Error Amplier)。FB与参考电压的误差值被输入PWM Control,以修正PWM的有效宽度。

3. Rset电阻用来调整最大亮度。参考电压的最大值为200mV,这样,如果Rset的阻值为10欧姆,那么LED的最大电流是20mA。

4. PWM的频率是600KHz.

5. 设备Shut down的时候(CTRL一直为低),没有PWM输出。Vin可以直接流向LED.所以Vin在设计上要小于LEDs的开启电压。

6. 设备从Shut down状态复位时(CTRL变高触发复位,设备开机)。开机时如果FB寄存器值(用来设置参考电压的寄存器)为0(范围0-31),则FB寄存器被设定为31(200mV)。

    开机时如果FB寄存器不为0,则不会修改FB寄存器的值。Datasheet中指出,不要直接设定FB寄存器值为0,如果想关机,可以令设备Shutdown(CTRL置低2.5ms)。

7. Soft start-up控制电路控制电压一级一级往上升,以避免电流冲击。

 

TPS6116x的时序

 

在TPS6116x的Datasheet中,6.6节详细列出时序要求。

名字含义电平最小值最大值单位
tvalACKNACK准备时间,从设备在此区间准备ACK. TPS6116x只有在数据最高位(RFA)为1时,从设备返回ACK。并且从设备是OpenDrain输出的。 2us
tACKNACK的有效区间。数据线被从设备拉低。 512us
toff设备关机时间。相当于电脑的长按开机键进行强制关机。2500 us
tes_detEasyScale模式侦测的真正开始。260us超过PWM模式的最大低电平宽度(5kHz, 200us). 2602500us
tes_delayTPS6116x从Shutdown状态退出(2.5ms后变高)时开始侦测EasyScale模式的进入。必须维持至少100us的高位。也可能一直高。100 us
tes_winEasyScale模式侦测的总体时间。TPS6116x从Shutdown状态退出(2.5ms后变高)时开始侦测EasyScale模式的进入。包括tes_delay和tes_det。 1000 us
tSTART字节处理的预备时间。也可以理解为字节之间的间隔。2 us
tEOS字节的结束。相当于UART的STOP位。2360us
tH_LB逻辑0的高电平时间2180us
tL_LB逻辑0的低电平时间2 × tH_LB360us
tL_HB逻辑1的低电平时间2180us
tH_HB逻辑1的高电平时间2 × tL_HB360us

 

 

 

 

 

 

 

 

1. 上电

    如果CTRL PIN引脚电平是高,进入tes_win,开始判断是进入EasyScale的1-wire模式,还是进入PWM模式。

    如果CTRL PIN引脚电平是低,2.5ms之后设备shutdown,进入低耗电模式。

2. 进入EasyScale的1-wire模式。

    1. 为了避免不确定的时序状态,先置CTRL PIN引脚电平为低3秒。设备进入shutdown状态。

static void tps6116_shutdown(unsigned int gpio) {
  gpio_set_value(gpio, 0);
  mdelay(3);                                // tps6116 shut down.
}

    2. 置CTRL PIN为高,进入tes_win。tes_win遵循下面的时序要求,以进入EasyScale的1-wire模式。

       

static void tps6116_reset(unsigned int gpio){
  gpio_set_value(gpio, 0);
  mdelay(3);                                // tps6116 shut down.
  gpio_set_value(gpio, 1);                  // reset, FB = 200mv. start EasyScale detection window.
  usleep(500);                              // tes_delay. min 100us
  preempt_disable();                        // avoid the possbile shutdown. let me do it over.
  gpio_set_value(gpio, 0);  
  usleep(300);                              // tes_det, min 260us
  gpio_set_value(gpio, 1);
  preempt_enable();
  usleep(500);                              // tes_win, min 1000us. 500 + 300 + 500 = 1300 > 1000
}

    3. 发送字符1。

 

static void tps6116_send_bit_1(unsigned int gpio){
  gpio_set_value(gpio, 0);
  udelay(20);                                // pull low for 20us
  gpio_set_value(gpio,1);
  udelay(80);                                // pull high for 80us
}

    4. 发送字符0。

static void tps6116_send_bit_0(unsigned int gpio){
  gpio_set_value(gpio, 0);
  udelay(80);                                // pull low for 80us
  gpio_set_value(gpio,1);
  udelay(20);                                // pull high for 20us

   5. 发送字节。

static void tps6116_send_byte(unsigned int gpio, unsigned char value){
  int i;
  int bit; 

  udelay(50);                                  // start
  for (i = 7; i >= 0; i--){
      bit = value & (1 << i);                  // High bit first
      if (bit){
          tps6116_send_bit_1(gpio);
      }
      else{
          tps6116_send_bit_0(gpio);
      }
  }
  gpio_set_value(gpio, 0);                    // End of start
  udelay(50);
  gpio_set_value(gpio, 1);                    // idle
}

 

   6. 发送帧。 

       数据帧包含两个字节,第一个字节是地址0x72(固定的)。第二个地址是数据,bit[0-4]是FB寄存器值(0-31),bit[5-6]是设备地址(0),bit[7]是RFA,表示是否希望设备传回ACK。使用RFA,通信会更复杂,驱动还要改变GPIO方向,并且由于设备CTRL是OpenDrain的,主机端要加4.7K的上拉电阻。

// irq code running time is very short, assume it does not effect the timming here.
// if disable irq, the performance of the system will be effected.
static void tps6116_set_fb_value(unsigned int gpio, unsigned char value){
  value = value & 0x1F;                     // RFA: 0, A1=A0=0
  preempt_disable();                        // let me do it over. 
  tps6116_send_byte(gpio, 0x72);            // address: 0x72
  tps6116_send_byte(gpio, value);
  preempt_enable();
}

 

 

TPS6116x的Linux驱动的其它部分

1. 设置好平台驱动的数据结构。

static struct platform_driver tps6116_bl_driver = {
    .driver        = {
        .name    = "tps6116-bl",
        .pm        = &tps6116_bl_pm_ops,
        .of_match_table    = of_match_ptr(tps6116_bl_of_match),
    },
    .probe        = tps6116_bl_probe,
    .remove        = tps6116_bl_remove,
    .shutdown    = tps6116_bl_shutdown,
};

module_platform_driver(tps6116_bl_driver);

 

2. probe的工作

   1. 分配设备私有数据。

   2. 从dts中获取必要的信息: default-brightness, max_brightness, gpio。

   3. 初始化gpio。

   4. 注册背光驱动。

   5. 初始设置背光。

   6. 设置平台驱动数据。 这样,从平台设备可以得到背光设备结构,从背光设备结构可以得到设备数据。这对应那些回调函数是很有必要的。

    struct backlight_device *bl = platform_get_drvdata(pdev);
    struct tps6116_bl *tps6116_bl = bl_get_data(bl);

 

  最快的方法是找一个相似的背光驱动,比如pwm_bl.c,看它是怎么与驱动框架交互的。

 

后语

  看Data sheet或者看别人写的示例代码,会忽略很多细节。而在整理资料的过程当中,为了把内容细致、逻辑地呈现出来,就会反复阅读和理解手头的资料,很多细节就被挖掘出来。所以养成资料整理的习惯是很有必要的。

 

转载于:https://www.cnblogs.com/zjsxdmif/p/10144800.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值