I2C send memory address in read operation

Hello,

I'm trying to implement a comunication with a I2C device. I have a RA6M4 microcontroller and just one slave device on I2C.

The write operation seems to be good, as far the device has a expected behaviour.

But, in read operation, i can not fulfill the sequence of the device. The sequence is like a I2C read memory:

The point is:

- If I execute the read function (R_IIC_MASTER_Read), the start, device address, read bit, and acknoledge is good, but register address is always 0xFF, like a dummy byte.

- If I execute the write function, (R_IIC_MASTER_Write), the start and device address is good, but it sends always the write bit (0).

So, how can I achieve the correct sequence? No examples found that work it.

Thanks.

Parents
  • Hello David,

    Thanks for reaching out Renesas Engineering Community.

    First of all I would suggest to you to advise the documentation of the r_iic_master module in  FSP.

    https://renesas.github.io/fsp/group___i_i_c___m_a_s_t_e_r.html

    There is also an example code.

    Also let me inform you that the IIC driver in FSP is a non blocking driver, which means that  for example if your preform a Write  operation

    the R_IIC_Write() API will return immediately and you should declare a callback as this one shown below to get notified that your operation is actually completed even though it returns FSP_SUCCESS.  

    /* Callback function */
    void g_i2c_master0_callback(i2c_master_callback_args_t *p_args)
    {
        /* TODO: add your own code here */
        i2c_event=p_args->event;
    }
    

    And check the value of the variable i2c_event. And check if it gets one this values below:

    In order to find out what is going wrong we would like to have more information from you like your configurations for I2C and some sample code.

    However let me attach for you an example for I2C that worked for me for reading an I2C temperature sensor. Notice that the example might be forEK-RA2L1 but nothing changes as far as it concerns the code, only set your own slave address and of course change the configurations for EK-RA6M4 for the I2C stack (pins, channels etc.).

    Hope this helps.

    Best Regards,

    IK

    5355.i2c_masterEK_RA2L1.zip

  • Hello,

    i copied the function readReg, and it's the same. In this function, you perform a write, then you are sending a write bit.

    My slave address is 0x30. Then all are going 0's, so bit R/W is W and should be read.

    This function return a value (in output variable) that has no sense.

    My slave device is a led driver KTD2027. I can do a reset of the device, send a control current value, turn on and off the led1. I can assume I2C is working. Driver is my problem when i want to read.

    This is my code that only writes and works:

    void pruebasLED()
    {
        static bool started = 0;
        fsp_err_t err;
    
        if (!started)
        {
            /* Initialize the IIC module */
            err = R_IIC_MASTER_Open (g_i2c_master0.p_ctrl, g_i2c_master0.p_cfg);
            assert(FSP_SUCCESS == err);
    
            // Genera 20 clocks para finalizar cualquier transacción iniciada anteriormente.
            /*for (int i = 0; i < 20; i++)
             {
             g_i2c_master0_ctrl.p_reg->ICCR1_b.CLO = 1;
             while (g_i2c_master0_ctrl.p_reg->ICCR1_b.CLO) { }
             }*/
    
            // Aseguramos que nosotros no tenemos nada a medias.
            R_IIC_MASTER_Abort (g_i2c_master0.p_ctrl);
            started = true;
        }
    
        uint8_t addressToSend = 0x30;
        err = R_IIC_MASTER_SlaveAddressSet (g_i2c_master0.p_ctrl, addressToSend, I2C_MASTER_ADDR_MODE_7BIT);
        assert(FSP_SUCCESS == err);
    
        //Mandamos Reset
        i2c_event = 0;
        uint8_t data[8] =
        { 0, 7, 0, 0, 0, 0, 0, 0 };
        err = R_IIC_MASTER_Write (g_i2c_master0.p_ctrl, data, 2, false);
        uint32_t timeout = 1000;
        while ((i2c_event == 0) && timeout--)
        {
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);
        }
    
        // Después del reset esperamos un tiempo prudencial.
        R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);
    
        // limitamos la corriente del led 1
        i2c_event = 0;
        data[0] = 6;
        data[1] = 20;
        err = R_IIC_MASTER_Write (g_i2c_master0.p_ctrl, data, 2, false);
        timeout = 1000;
        while ((i2c_event == 0) && timeout--)
        {
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);
        }
    
        //Encendemos el led 1
        i2c_event = 0;
        data[0] = 4;
        data[1] = 1;
        err = R_IIC_MASTER_Write (g_i2c_master0.p_ctrl, data, 2, false);
        timeout = 1000;
        while ((i2c_event == 0) && timeout--)
        {
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);
        }
    
        //Apagamos el led 1
        i2c_event = 0;
        data[0] = 4;
        data[1] = 0;
        err = R_IIC_MASTER_Write (g_i2c_master0.p_ctrl, data, 2, false);
        timeout = 1000;
        while ((i2c_event == 0) && timeout--)
        {
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);
        }
    
    
        readReg(0, data);
    
        i2c_event = 0;
        //err = R_IIC_MASTER_Close(g_i2c_master0.p_ctrl);
        //assert(FSP_SUCCESS == err);
    
    }
    
    void i2c_callback(i2c_master_callback_args_t *p_args)
    {
        i2c_event = p_args->event;
    }

    My configuration is:

    Can you confirm that the oscilloscope shows signal that doesn't fit the protocol?

Reply
  • Hello,

    i copied the function readReg, and it's the same. In this function, you perform a write, then you are sending a write bit.

    My slave address is 0x30. Then all are going 0's, so bit R/W is W and should be read.

    This function return a value (in output variable) that has no sense.

    My slave device is a led driver KTD2027. I can do a reset of the device, send a control current value, turn on and off the led1. I can assume I2C is working. Driver is my problem when i want to read.

    This is my code that only writes and works:

    void pruebasLED()
    {
        static bool started = 0;
        fsp_err_t err;
    
        if (!started)
        {
            /* Initialize the IIC module */
            err = R_IIC_MASTER_Open (g_i2c_master0.p_ctrl, g_i2c_master0.p_cfg);
            assert(FSP_SUCCESS == err);
    
            // Genera 20 clocks para finalizar cualquier transacción iniciada anteriormente.
            /*for (int i = 0; i < 20; i++)
             {
             g_i2c_master0_ctrl.p_reg->ICCR1_b.CLO = 1;
             while (g_i2c_master0_ctrl.p_reg->ICCR1_b.CLO) { }
             }*/
    
            // Aseguramos que nosotros no tenemos nada a medias.
            R_IIC_MASTER_Abort (g_i2c_master0.p_ctrl);
            started = true;
        }
    
        uint8_t addressToSend = 0x30;
        err = R_IIC_MASTER_SlaveAddressSet (g_i2c_master0.p_ctrl, addressToSend, I2C_MASTER_ADDR_MODE_7BIT);
        assert(FSP_SUCCESS == err);
    
        //Mandamos Reset
        i2c_event = 0;
        uint8_t data[8] =
        { 0, 7, 0, 0, 0, 0, 0, 0 };
        err = R_IIC_MASTER_Write (g_i2c_master0.p_ctrl, data, 2, false);
        uint32_t timeout = 1000;
        while ((i2c_event == 0) && timeout--)
        {
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);
        }
    
        // Después del reset esperamos un tiempo prudencial.
        R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);
    
        // limitamos la corriente del led 1
        i2c_event = 0;
        data[0] = 6;
        data[1] = 20;
        err = R_IIC_MASTER_Write (g_i2c_master0.p_ctrl, data, 2, false);
        timeout = 1000;
        while ((i2c_event == 0) && timeout--)
        {
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);
        }
    
        //Encendemos el led 1
        i2c_event = 0;
        data[0] = 4;
        data[1] = 1;
        err = R_IIC_MASTER_Write (g_i2c_master0.p_ctrl, data, 2, false);
        timeout = 1000;
        while ((i2c_event == 0) && timeout--)
        {
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);
        }
    
        //Apagamos el led 1
        i2c_event = 0;
        data[0] = 4;
        data[1] = 0;
        err = R_IIC_MASTER_Write (g_i2c_master0.p_ctrl, data, 2, false);
        timeout = 1000;
        while ((i2c_event == 0) && timeout--)
        {
            R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);
        }
    
    
        readReg(0, data);
    
        i2c_event = 0;
        //err = R_IIC_MASTER_Close(g_i2c_master0.p_ctrl);
        //assert(FSP_SUCCESS == err);
    
    }
    
    void i2c_callback(i2c_master_callback_args_t *p_args)
    {
        i2c_event = p_args->event;
    }

    My configuration is:

    Can you confirm that the oscilloscope shows signal that doesn't fit the protocol?

Children
  • Hi David,

    Yes, as far I can understand the red line is the SDA and the blue line the SCL.

    I can see from the screenshot you have sent, the start condition and the adress 0x30 but you are right the R/W bit after the address is not set to 1 for read operation.

    But is this screenshot from the read operation? Since to read the contents of Reg0 which is 0x00 you first need to write to the slave the adress of the register you want to read.

    And also according to the datasheet of the Led driver  what are you supposed to read when reading Reg0?

    Also have you tried to read the contents of the ICDRR register? And when calling in your code the Read() API what is the value of the i2c_event variable?

    Regards,

    IK

  • Hello,

    "But is this screenshot from the read operation?" 

    Following your example, in your function readReg you make two "steps". First you call R_IIC_MASTER_Write with some parameters and after you call R_IIC_MASTER_Read. The signals are after the first step.

    "Since to read the contents of Reg0 which is 0x00 you first need to write to the slave the adress of the register you want to read."

    NO. To read I just need to follow what the datasheet says:

    White are signals from Renesas microcontroler.

    Green are signals from Led Driver.

    There is no two step procedure like you say. It's not write the address, then read. Is just all in one. No restart no stops and start again.

    Maybe is a tricky way to do the read? Like I want to write you at this address, then stop with no data and make a read because cursor maybe is changed with the aborted writed?

    I found on the datasheet of ISL12028 (i worked on it in the past) the behaviour your demo is doing:

    In words says:

    Random read operations allow the master to access any location in the ISL12028. Prior to issuing the Slave Address Byte with the R/W bit set to zero, the master must first perform a “dummy” write operation.

    That's ok for ISL12028, but it's not the way that says my led driver.

    Also have you tried to read the contents of the ICDRR register? No, I always supposed that all I need are FSP functions, so no need to know about registers since there is a function for read I2C.

    when calling in your code the Read() API what is the value of the i2c_event variable? Always is I2C_MASTER_EVENT_RX_COMPLETE or I2C_MASTER_EVENT_TX_COMPLETE after power on. After first try, i get some errors I think because i never close I2C. In this case i power off the board and then power on and returns to ok. But never reading ok.

    If a go to the end, the function returns me always a 0xFF.

  • The master receive operation will just send the address bits, the read bit and nothing else. From this moment the master is in receive mode and receiving data from the slave.

    The read operation on your datasheet cannot be implemented with RA.

  • To do a read, you first do a write with restart, then do a read.  This is exactly what your diagram shows

    Dale.

  • Hello David, 

    Apologies for my delayed response.

     You mentioned that:

    ""Since to read the contents of Reg0 which is 0x00 you first need to write to the slave the adress of the register you want to read."

    NO. To read I just need to follow what the datasheet says:"

    Please let me inform you that what you are describing does not comply with what the I2C protocol says.

    Generally to read the contents of a specific register from the slave the write operation to the slave with writing the address of the register you want to get its contents, it is necessary before performing the read operation.

    Please check the screenshot below:

    As you can see from the figure I've send you above. In I2C protocol the steps to read the contents of a register of the slave device are:

    START->7-bit slave Address->R/W=0(Write operation)->ACK->Register Address(1 byte)->ACK->Sr(Repeated Start)->7-bit slave Address->R/W=1 (Read Operation)->ACK->Data from Register-> NACK(from the slave since it does not have any more data to send)->STOP

    And this application note to understand better the I2C:

    Understanding the I2C Bus

    What you are describing is not a read register operation.

    Also the function readReg is made to read 2 bytes from slave have you changed the size to 1?

    Also the Reg0 is the EN/RESET register of your datasheet so I think it's very important here to check what other processes have you done before reading the Reg0. Have you written any data on this register?

    Please try to access the contents of an other register then Reg0 to check  it's contents for example try to read Reg4 

    And see if you get the contents you have written to this register.

    Also let me send you some screenshots from the results I get by using RA6M4 when I want to access register with adress 0x05 to read the raw temperature bytes from MCP9808 which is a temperature sensor.

    As you can see first write is performed , I write to slave 0x05 which is the address of the register I want to read and then after 100 ms approximately since I have also some while loops checking for timeout I have the read process where I read the contents from this register.

    Thank you!

    Best Regards,

    IK

  • didn't catch at first, but yea that sequence isn't valid.  You have to address the slave with the read or write bit.