Forum Discussion

MCher6's avatar
MCher6
Icon for New Contributor rankNew Contributor
7 years ago

SoC and i2c read/write transaction without stop in between.

I connect FXOS8700CQ to SoC with Intel FPGA Avalon I2C (Master) Core.

Add to *.dts:

i2c_accelerometer: i2c@0x000010300 {
	compatible = "altr,softip-i2c-v1.0";
	reg = <0x00000000 0x00010300 0x00000040>;
	interrupt-parent = <&hps_0_arm_gic_0>;
	interrupts = <0 51 4>;
	clocks = <&clk_0>;
	clock-frequency = <100000>;
	#address-cells = <1>;
	#size-cells = <0>;
	fifo-size = <32>;
}; //end i2c@0x000010300 (i2c_accelerometer)

Program:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
 
#include <unistd.h>
 
#define I2C_ADAPTER     "/dev/i2c-0"
 
void read_buffer(int fd, unsigned short addr)
{
        struct i2c_rdwr_ioctl_data data;
        struct i2c_msg messages[2];
        unsigned char write_buf[1] = {0x0D}, read_buf[1] = {0x00};
 
        /*
         * .addr - Адрес устройства (датчика)
         * .flags - операция чтения или записи (0 - w, 1 - r)
         * .len - кол-во передаваемых/принимаемых сообщений
         * .buf - буфер на чтение или запись
         */
        messages[0].addr = addr;
        messages[0].flags = 0;
        messages[0].len = 1;
        messages[0].buf = write_buf;
 
        messages[1].addr = addr;
        messages[1].flags = 0x1;
        messages[1].len = 1;
        messages[1].buf = read_buf;
 
        data.msgs = messages;
        data.nmsgs = 2;
 
        ioctl(fd, I2C_TIMEOUT, 2);  // set the timeout
        ioctl(fd, I2C_RETRIES, 4);  // set the retries
 
        if (ioctl(fd, I2C_RDWR, &data) < 0)
        {
                printf("Cant send data!\n");
        }
        else
        {
                printf("ID = 0x%x\n", read_buf[0]);
        }
 
}
 
int main(int argc, char **argv)
{
        int fd;
 
         /*
          * Open I2C file descriptor.
          */
         fd = open(I2C_ADAPTER, O_RDWR);
 
         if (fd < 0) {
                 printf("Unable to open i2c file\n");
                 return 0;
         }
 
         while(1)
         {
         read_buffer(fd, 0x1E);
         sleep(1);
         }
 
         return 0;
 }

I expect to see on i2c bus:

ST-ADDRESS-W-ACK-DATA-ACK-ST-ADDRESS-R-ACK-DATA-ACK-SP

But in reality, I see:

ST-ADDRESS-W-ACK-DATA-ACK-SP-ST-ADDRESS-R-ACK-DATA-ACK-SP

For this reason, reading does not work.

How I can set read/write transaction without stop in between?

4 Replies

  • MCher6's avatar
    MCher6
    Icon for New Contributor rankNew Contributor

    Probably a problem in Linux driver i2c-altera.c

    According to the documentation (Documentation/i2c/dev-interface):

    ioctl (file, I2C_RDWR, struct i2c_rdwr_ioctl_data * msgset)

    Do combined read / write transaction without stop in between.

    Only valid if the adapter has I2C_FUNC_I2C. The argument is

    a pointer to a

    struct i2c_rdwr_ioctl_data {

    struct i2c_msg * msgs; / * ptr to array of simple messages * /

    int nmsgs; / * number of messages to exchange * /

    }

    The msgs [] themselves contain further pointers into data buffers.

    If you’re looking at what I2C_M_RD I’m flag on

    Overlaying the ivectl's

    The i2c-altera.c driver has I2C_FUNC_I2C:

    static u32 altr_i2c_func (struct i2c_adapter * adap)
     
    {
     
    return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
     
    } 

    The driver sets STOP when i2c_msg.len = 1 (last data byte):

    static void altr_i2c_transfer (struct altr_i2c_dev * idev, u32 data)
     
    {
     
    / * On the last byte, send STOP * /
     
    if (idev-> msg_len == 1)
     
    data | = ALTR_I2C_TFR_CMD_STO;
     
    if (idev-> msg_len> 0)
     
    writel (data, idev-> base + ALTR_I2C_TFR_CMD);
     
    } 

    Correctly put STOP after the last byte of the last message.

    Any thoughts on how to fix this?

  • MCher6's avatar
    MCher6
    Icon for New Contributor rankNew Contributor

    I managed!

    The changes are very rough and not entirely correct, but the driver works. I did not completely check, but maybe someone will fall into a similar situation.

  • KennyT_altera's avatar
    KennyT_altera
    Icon for Super Contributor rankSuper Contributor

    ​Hi,

    Do you mind to share with us which coding that you have make the changes for the driver to be working?

    Thanks

  • MCher6's avatar
    MCher6
    Icon for New Contributor rankNew Contributor

    ​Hi, KTan9.

    Yes, a modified driver file has been attached to the previous message. Unfortunately, I am not an expert in creating drivers and my fixes are probably not optimal and need to be corrected. I wrote to the driver author (Thor Thayer from Intel), but I haven’t received a response yet.

    Let me know any news on this issue.

    Thanks.