天天看点

L3总线协议及时序示意代码

    CODEC目前实现内部寄存器的操作一般有SPI、IIC和L3.这里介绍L3.

    L3接口实际上是一种串行接口,它由3根信号线组成,完成处理器和C0DEC之间的数据和控制信号交换.DAl341TS就是采用L3接口.

    L3DATA:处理器接口数据线; 

    L3MODE:处理器接口模式信号线;

    L3CLOCK:处理器接口时钟信号线.

    一般而言,一款CPU的硬件音频系统一般带有L3接口,否则只能用GPIO模拟了.

    L3总线有写地址和数据之分,对于写地址L3MODE为L(0),写数据L3MODE为H(1),时钟和模式开始都应该为1,数据线开始为0.先写地址在些数据,先发低位在发高位.

     当发起数据通讯时,一般选选定地址模式,接下来就是数据传输.

    以UDA1341TS为例,地址模式:

L3总线协议及时序示意代码

        下面根据此时序图写出示意代码.根据时序图写代码,首先要学会看时序图.因此,需要注意下面的知识点:       

1.时序图从左到右看,有箭头的地方表示有时序的要求,即需要写代码;
2.每一次电平变化都应该有时序的要求;
3.箭头都是匹对的,左右对向为一组,两箭头之间便是状态保持时间,这对应代码适当的延时;
           

        根据上述三点,从左到右,成对看箭头.

        首先L3CLOCK为高电平,L3MODE为高电平;L3MODE变为低之前,必须保持th时间段的状态保持:

L3CLOCK = 1;
L3MODE = 1;
udelay(th);
L3MODE = 0;
           

        L3MODE拉低之后,L3CLOCK不能立马拉低,还需要保持tsu时间段的状态保持:

udelay(tsu);
L3CLOCK = 0;
           

        与此同时,L3DATA输出一个位的数据.此时L3CLOCK要变成高电平之前,需要保持tsu时间段的状态保持,数据才稳定:

L3DATA = X(X = 0,1);
udelay(tsu);
L3CLOCK = 1;
           

        L3CLOCK变成高电平后,需要保持th时间段的状态,保证数据被读取:

udelay(th);
           

        当一个字节被传输完之后,L3MODE被拉高之前,L3CLOCK需要th时间段的高电平状态保持:

L3CLOCK = 1;
L3MODE = 1;
           

        当L3MODE被拉高之后,L3CLOCK不能立马拉氏.还需要tsu时间段的高电平状态保持:

udelay(tsu);
           

        至此,形成了1Byte的周期.

       因此,完整的时序示意代码如下:

L3CLOCK = 1;
L3MODE = 1;
udelay(th);
L3MODE = 0;
udelay(tsu);

for(i = 0; i < 8; ++i)
{
    L3CLOCK = 0;
    L3DATA = X(X = 0,1);
    udelay(tsu);
    L3CLOCK = 1;
    udelay(th);
}
    L3MODE = 1;
    udelay(tsu);
           

       对应内核代码sound/soc/codecs/l3.c:

int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
{
	adap->setclk(1);
	adap->setmode(1);
	udelay(adap->mode);

	adap->setmode(0);
	udelay(adap->mode_setup);
	sendbyte(adap, addr);
	udelay(adap->mode_hold);

}
           

        其中,sendbyte()函数如下:

static void sendbyte(struct l3_pins *adap, unsigned int byte)
{
	int i;

	for (i = 0; i < 8; i++) {
		adap->setclk(0);
		udelay(adap->data_hold);
		adap->setdat(byte & 1);
		udelay(adap->data_setup);
		adap->setclk(1);
		udelay(adap->clock_high);
		byte >>= 1;
	}
}
           

        l3_write()函数在接下来的sendbytes()函数完成了示意代码中L3MODE = 1;udelay(tsu);因此,没有在上述分析中表现出这样的代码.

        数据模式:

L3总线协议及时序示意代码

    当然,可以将地址后地址后面紧随的数据一并批量传输:

L3总线协议及时序示意代码

        大体讲述此时序图的意义.L3MODE为低时L3DATA传输的是地址数据;当L3MODE为高时,L3DATA传输的是数据信息.每8个bit之间需要tstp时间段的延时.可以一次性完成2个Byte的数据传输.

        对应sound/soc/codecs/l3.c:

/*
 * Send a set of bytes to the chip.  We need to pulse the MODE line
 * between each byte, but never at the start nor at the end of the
 * transfer.
 */
static void sendbytes(struct l3_pins *adap, const u8 *buf,
		      int len)
{
	int i;

	for (i = 0; i < len; i++) {
		if (i) {
			udelay(adap->mode_hold);
			adap->setmode(0);
			udelay(adap->mode);
		}
		adap->setmode(1);
		udelay(adap->mode_setup);
		sendbyte(adap, buf[i]);
	}
}
           

继续阅读