This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320DM368:关于i2c_davinci.c

Other Parts Discussed in Thread: TVP5150

我在使用TVP5150的时候,最原始的IPNC_RDK5.0,就可以对5150进行i2c读写操作,但ADV7441A只能进行i2c写操作,不能进行读操作。

在参考对比TVP51501和ADV7441数据手册中关于i2c时序的时候,发现TVP5150的读操作中在主机发送从机寄存器之后,等待从机应答,主机会紧接着发送一个STOP信号,但ADV7441却没有这个STOP信号。

TVP5150和ADV7441的i2c时序如下:

另外,我在进行i2c的内核调试时候,发现应用层的i2c读写函数,都会调用文件Source\dvsdk_ipnctools\ipnc_psp_03_21_00_04\kernel\drivers\i2c\busses\i2c_davinci.c中的函数i2c_davinci_xfer_msg。

所以,想请教一下,怎样去掉函数i2c_davinci_xfer_msg中关于STOP信号的代码?

  • 你好,

    下面e2e论坛的讨论的问题和你是类似的,请参考下面面的解决方法:

    https://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/100/p/8015/32357#32357

  • Chris Meng,

    你好,谢谢您的回复。

    我根据您给的链接,参照修改了Source\ipnc_rdk\av_capture\framework\drv\kermod\src目录下的文件dev_i2c.c。

    将代码:

    int I2C_read(I2C_Obj *pObj, uint8_t *reg, uint8_t *buffer, uint8_t count, uint8_t dataSize)
    {
    uint8_t i;
    int err;
    struct i2c_client *client;
    struct i2c_msg msg[1];
    unsigned char data[1];

    if(pObj==NULL){
    return -ENODEV;
    }

    client = &pObj->client;
    if(!client->adapter){
    return -ENODEV;
    }

    if(dataSize<=0||dataSize>4){
    return -1;
    }

    for(i=0; i<count; i++) {
    msg->addr = client->addr;
    msg->flags = 0;
    msg->len = 1;
    msg->buf = data;
    data[0] = reg[i];
    err = i2c_transfer(client->adapter, msg, 1);
    if(err<0) {
    printk( KERN_ERR " i2c_transfer(0x%x, 0x%x)\n", msg->addr, msg->buf[0]);
    }

    if (err >= 0)
    {
    msg->flags = I2C_M_RD;
    msg->len = dataSize;
    err = i2c_transfer(client->adapter, msg, 1);
    if (err >= 0)
    {
    if(dataSize==1) {
    buffer[i] = data[0];
    } else
    if(dataSize==2) {
    buffer[2*i] = data[1];
    buffer[2*i+1] = data[0];
    }
    }
    }
    if (err<0)
    return -ENODEV;
    }

    return 0;
    }

    修改成:

    int I2C_read(I2C_Obj *pObj, uint8_t *reg, uint8_t *buffer, uint8_t count, uint8_t dataSize)
    {
    uint8_t i;
    int err;
    struct i2c_client *client;
    unsigned char data[2];
    struct i2c_msg msg[2] = {
    { client->addr, 0, 1, &data[0] },
    { client->addr, I2C_M_RD, 1, &data[1] },
    };

    if(pObj==NULL){
    return -ENODEV;
    }

    client = &pObj->client;
    if(!client->adapter){
    return -ENODEV;
    }

    if(dataSize<=0||dataSize>4){
    return -1;
    }

    for(i=0; i<count; i++) {
    data[0] = reg[i];
    data[1] = 0xff;
    err = i2c_transfer(client->adapter, msg, 2);
    if(err<0) {
    printk( KERN_ERR " i2c_transfer(0x%x, 0x%x)\n", msg->addr, msg->buf[0]);
    }

    if (err >= 0)
    {
    buffer[i] = data[0];
    }
    if (err<0)
    return -ENODEV;
    }

    return 0;
    }

    但是,在运行之后的结果却是这样:

    而未修改前的运行结果是这样的:

    请问:我的代码还需要哪些修改?

  • 你好,

    你不是说你用的是psp目录kernel下的驱动么? 你为什么要去改IPNC软件里面的i2c驱动呢?

  • Chris Meng,

    你好!

    因为我理解的dm368的整个i2c调用流程是:Source\ipnc_rdk\av_capture\framework\drv\usermod\src\drv_i2c.c中的i2c读函数会进入文件Source\ipnc_rdk\av_capture\framework\drv\kermod\src\dev_i2c.c中的I2C_read函数,然后进入文件Source\dvsdk_ipnctools\ipnc_psp_03_21_00_04\kernel\drivers\i2c\i2c-core.c中的函数i2c_transfer,最后才会进入文件Source\dvsdk_ipnctools\ipnc_psp_03_21_00_04\kernel\drivers\i2c\busses\i2c-davinci.c。

    所以,我参考您给的链接对dev_i2c.c中的I2C_read函数(如果我没找错地方的话)进行修改,但我不知道我哪里修改不正确,导致上面的问题出现?

    以下是我参考的部分:

    Problem solved! No driver changes necessary. See below for details....

    Although most of the drivers don't seem to do this for their xxx_i2c_read functions (I guess because most i2c slave devices don't seem to care about the stop in between a write/read pair), you can actually pass multiple i2c_msg structures to a singe i2c_transfer() call and the stop bit will only be sent on the last command. For example, this is how I got the read to work fr this device:

        unsigned char data[2];
        struct i2c_msg msg[2] = {
            { client->addr, 0,  1, &data[0] },
            { client->addr, I2C_M_RD, 1, &data[1] },
        };

        data[0] = reg;
        data[1] = 0xff; /* just init to some value */
        err = i2c_transfer(client->adapter, msg, 2);
        if (err >= 0) {
            *val = data[1];
        }

     

    Instead of doing this (2 separate calls, which is the code prevalent in most of the drivers):

        struct i2c_msg msg[1];
        unsigned char data[1];

            msg->addr = client->addr;
            msg->flags = 0;
            msg->len = 1;
            msg->buf = data;
            data[0] = reg;
            err = i2c_transfer(client->adapter, msg, 1);
            if (err >= 0) {
                msg->flags = I2C_M_RD;
                msg->len = 1;
                err = i2c_transfer(client->adapter, msg, 1);
                if (err >= 0) {
                    *val = data[0];
                }
            }
        }

  • malik 说:
    if (err >= 0)
    {
    buffer[i] = data[0];
    }

    这里是否应该是

    buffer[i] = data[1];

  • Chris Meng ,

    你好!

    我按照您说的修改以后,发现程序还是相同的错误。

    另外我在跟踪程序的时候,发现程序根本未进入dev_i2c.c的i2c_read函数,而是在drv_i2c.c中就出现了错误。

    具体是在:

    但程序上我只修改了dev_i2c.c文件的i2c_read函数,未修改前是能进入这个函数的。

  • Chris Meng,

    您好!

    我已经把程序修改完了,./i2crw.out程序能够正常结束,而不是出现内存错误,但读出来的值还是最初写入的值,即data[1]的0xff。

    您能给我一些建议,关于这个问题?

  • 你好,

    请问你还修改了什么解决的之前的问题?

    如果修改data【1】的值为其他值(不是0xff),最后你读到的还是data【1】的值么?

    如果是,你能否测量下I2C上的信号,看看读的时候返回的值是否正确?

  • Chris Meng ,

    您好!

    我的问题已经解决了!谢谢您的帮助!

  • 你好,

    很高兴问题已经解决!

    能否告知一下修改代码后的问题是如何解决的?谢谢!

  • Chris Meng,

    您好!

    您的建议是没问题的,是代码中我把第二次msg的data[1]写成了data[0]。

    再次感谢您的帮助!

    但是,虽然问题解决了,我发现在对i2c_msg定义的时候就初始化会发生内存错误,而对其中每个成员单独进行赋值时就没这个问题。