AN4652 I2C Problem

cancel
Showing results for 
Search instead for 
Did you mean: 

AN4652 I2C Problem

Jump to solution
646 Views
jmag99
Contributor II

I am having a problem where this I2C driver will re-start and send 0xFF after a successful write.  The read functions work fine.  I believe the problem is on this line in the ISR for the master:

// ack

if((io_info_ptr->index == io_info_ptr->data_len) && (io_info_ptr->index_repeat_start == REPEAT_INDEX_TX))

The TX function always sets index_repeat_start to REPEAT_INDEX_TX.  So once the data is sent out, it re-starts instead of stopping.

Has anyone else run into this?

How do we know if we have the latest version of the driver?

Tags (2)
1 Solution
254 Views
jia_guo
NXP Employee
NXP Employee

Hi,

The action to restart and send 0xff is just for communication with the slave running the same code on Kinetis MCU.

So, when it is used to write other device, this operation is not necessary.

I just looked into the code to try to modify it to remove the additional sending repeat start and 0xff.

You may try the modification and feedback the result here, then I can know if it works, thanks.

In fact, you just need stop the I2C sequence when it finished the work.

See the following code, focus on the lines with underline, you need not modify any other code.

----------------------------------------------------------------------------------------------------------------------------------------------

static void _isr_ii2c_master(FB_VKI2C_INFO_STRUCT_PTR io_info_ptr)

{

    I2C_MemMapPtr i2c_ptr = io_info_ptr->i2c_ptr;

    int i;

    _clear_int_flag(i2c_ptr);

 

    if (i2c_ptr->C1 & I2C_C1_TX_MASK)

    {

        // tx

        if (i2c_ptr->S & I2C_S_RXAK_MASK)

        {

            // nack

            #ifdef DEBUG_ENABLE

            printf("nack stop.\n");

            #endif

            io_info_ptr->index_rx_tx = io_info_ptr->index;

            _stop(i2c_ptr);

            _lwsem_post((LWSEM_STRUCT_PTR)(&(io_info_ptr->lwsem)));

        }

        else

        {

            // ack

            if((io_info_ptr->index == io_info_ptr->data_len) && (io_info_ptr->index_repeat_start == REPEAT_INDEX_TX))

            {

                // here, please comment the following code to remove the additional restart and sending 0xff

                /*

                #ifdef DEBUG_ENABLE

                printf("ack, sent all, stop -> 0xff, %d \n", io_info_ptr->index);

                #endif

                io_info_ptr->index_rx_tx = io_info_ptr->index;

                io_info_ptr->index = 0;

                io_info_ptr->data = (uchar_ptr)(io_info_ptr->buf_x_stop);

                _repeat_start(i2c_ptr);

                i2c_ptr->D = (io_info_ptr->data[io_info_ptr->index] << 1) | I2C_OPERATION_WRITE;

                */

                // add the following two code line to stop current writing operation.

                // end

                _stop(i2c_ptr);

                _lwsem_post((LWSEM_STRUCT_PTR)(&(io_info_ptr->lwsem)));

            }

            else

            {

                if(io_info_ptr->index == io_info_ptr->index_repeat_start)

                {

                    #ifdef DEBUG_ENABLE

                    printf("repeat start, address, %x\n", (io_info_ptr->data[0] << 1) );

                    #endif

                    _repeat_start(i2c_ptr);

                    i2c_ptr->D = (io_info_ptr->data[0] << 1) | I2C_OPERATION_READ;

                }

                else if(io_info_ptr->index == (io_info_ptr->index_repeat_start + 1) )

                {

                    #ifdef DEBUG_ENABLE

                    printf("change to r mode, %x \n", io_info_ptr->data[io_info_ptr->index]);

                    #endif

                    _to_rx_mode(i2c_ptr);

                    if(io_info_ptr->index == io_info_ptr->data_len)

                        _give_nack(i2c_ptr);

                    else

                        _give_ack(i2c_ptr);

                    // dummy read to start a reading operation

                    io_info_ptr->data[io_info_ptr->index] = i2c_ptr->D;

                }

                else

                {

                    if(io_info_ptr->index == 2)

                    {

                        if(io_info_ptr->data[1] == 0xff)

                        {

                            // end

                            _stop(i2c_ptr);

                            _lwsem_post((LWSEM_STRUCT_PTR)(&(io_info_ptr->lwsem)));

                        }

                    }

                    #ifdef DEBUG_ENABLE

                    printf("continue sending, index = %d, v = %x\n", io_info_ptr->index, io_info_ptr->data[io_info_ptr->index]);

                    #endif

                    i2c_ptr->D = io_info_ptr->data[io_info_ptr->index];

                }

            }

        }

    }

    else

    {

        // rx

        io_info_ptr->index_rx_tx = io_info_ptr->index - 2;

        if(io_info_ptr->index_rx_tx == io_info_ptr->data_len-1)

        {

            _stop(i2c_ptr);

            io_info_ptr->data[io_info_ptr->index_rx_tx] = i2c_ptr->D;

            _lwsem_post((LWSEM_STRUCT_PTR)(&(io_info_ptr->lwsem)));

            #ifdef DEBUG_ENABLE

            printf("read finished, index = %d, v = %x.\n", io_info_ptr->index_rx_tx, io_info_ptr->data[io_info_ptr->index_rx_tx]);

            #endif

        }

        else

        {

            if(io_info_ptr->index_rx_tx == (io_info_ptr->data_len-2) )

                _give_nack(i2c_ptr);

            else

                _give_ack(i2c_ptr);

            io_info_ptr->data[io_info_ptr->index_rx_tx] = i2c_ptr->D;

            #ifdef DEBUG_ENABLE

            printf("continue reading, index = %d, v = %x\n", io_info_ptr->index_rx_tx, io_info_ptr->data[io_info_ptr->index_rx_tx]);

            #endif

        }

    }

    io_info_ptr->index++;

}

View solution in original post

0 Kudos
3 Replies
254 Views
Monica
Senior Contributor III

Hello Jmag,

Was this suggestion helpful? We'd like to know :smileywink:

Best regards!

Monica.

0 Kudos
254 Views
sholmgren
Contributor I

I can confirm that it works. Both for the version that uses lwsem_post and the version that uses lwevent_set.

Best regards

Sebastian

255 Views
jia_guo
NXP Employee
NXP Employee

Hi,

The action to restart and send 0xff is just for communication with the slave running the same code on Kinetis MCU.

So, when it is used to write other device, this operation is not necessary.

I just looked into the code to try to modify it to remove the additional sending repeat start and 0xff.

You may try the modification and feedback the result here, then I can know if it works, thanks.

In fact, you just need stop the I2C sequence when it finished the work.

See the following code, focus on the lines with underline, you need not modify any other code.

----------------------------------------------------------------------------------------------------------------------------------------------

static void _isr_ii2c_master(FB_VKI2C_INFO_STRUCT_PTR io_info_ptr)

{

    I2C_MemMapPtr i2c_ptr = io_info_ptr->i2c_ptr;

    int i;

    _clear_int_flag(i2c_ptr);

 

    if (i2c_ptr->C1 & I2C_C1_TX_MASK)

    {

        // tx

        if (i2c_ptr->S & I2C_S_RXAK_MASK)

        {

            // nack

            #ifdef DEBUG_ENABLE

            printf("nack stop.\n");

            #endif

            io_info_ptr->index_rx_tx = io_info_ptr->index;

            _stop(i2c_ptr);

            _lwsem_post((LWSEM_STRUCT_PTR)(&(io_info_ptr->lwsem)));

        }

        else

        {

            // ack

            if((io_info_ptr->index == io_info_ptr->data_len) && (io_info_ptr->index_repeat_start == REPEAT_INDEX_TX))

            {

                // here, please comment the following code to remove the additional restart and sending 0xff

                /*

                #ifdef DEBUG_ENABLE

                printf("ack, sent all, stop -> 0xff, %d \n", io_info_ptr->index);

                #endif

                io_info_ptr->index_rx_tx = io_info_ptr->index;

                io_info_ptr->index = 0;

                io_info_ptr->data = (uchar_ptr)(io_info_ptr->buf_x_stop);

                _repeat_start(i2c_ptr);

                i2c_ptr->D = (io_info_ptr->data[io_info_ptr->index] << 1) | I2C_OPERATION_WRITE;

                */

                // add the following two code line to stop current writing operation.

                // end

                _stop(i2c_ptr);

                _lwsem_post((LWSEM_STRUCT_PTR)(&(io_info_ptr->lwsem)));

            }

            else

            {

                if(io_info_ptr->index == io_info_ptr->index_repeat_start)

                {

                    #ifdef DEBUG_ENABLE

                    printf("repeat start, address, %x\n", (io_info_ptr->data[0] << 1) );

                    #endif

                    _repeat_start(i2c_ptr);

                    i2c_ptr->D = (io_info_ptr->data[0] << 1) | I2C_OPERATION_READ;

                }

                else if(io_info_ptr->index == (io_info_ptr->index_repeat_start + 1) )

                {

                    #ifdef DEBUG_ENABLE

                    printf("change to r mode, %x \n", io_info_ptr->data[io_info_ptr->index]);

                    #endif

                    _to_rx_mode(i2c_ptr);

                    if(io_info_ptr->index == io_info_ptr->data_len)

                        _give_nack(i2c_ptr);

                    else

                        _give_ack(i2c_ptr);

                    // dummy read to start a reading operation

                    io_info_ptr->data[io_info_ptr->index] = i2c_ptr->D;

                }

                else

                {

                    if(io_info_ptr->index == 2)

                    {

                        if(io_info_ptr->data[1] == 0xff)

                        {

                            // end

                            _stop(i2c_ptr);

                            _lwsem_post((LWSEM_STRUCT_PTR)(&(io_info_ptr->lwsem)));

                        }

                    }

                    #ifdef DEBUG_ENABLE

                    printf("continue sending, index = %d, v = %x\n", io_info_ptr->index, io_info_ptr->data[io_info_ptr->index]);

                    #endif

                    i2c_ptr->D = io_info_ptr->data[io_info_ptr->index];

                }

            }

        }

    }

    else

    {

        // rx

        io_info_ptr->index_rx_tx = io_info_ptr->index - 2;

        if(io_info_ptr->index_rx_tx == io_info_ptr->data_len-1)

        {

            _stop(i2c_ptr);

            io_info_ptr->data[io_info_ptr->index_rx_tx] = i2c_ptr->D;

            _lwsem_post((LWSEM_STRUCT_PTR)(&(io_info_ptr->lwsem)));

            #ifdef DEBUG_ENABLE

            printf("read finished, index = %d, v = %x.\n", io_info_ptr->index_rx_tx, io_info_ptr->data[io_info_ptr->index_rx_tx]);

            #endif

        }

        else

        {

            if(io_info_ptr->index_rx_tx == (io_info_ptr->data_len-2) )

                _give_nack(i2c_ptr);

            else

                _give_ack(i2c_ptr);

            io_info_ptr->data[io_info_ptr->index_rx_tx] = i2c_ptr->D;

            #ifdef DEBUG_ENABLE

            printf("continue reading, index = %d, v = %x\n", io_info_ptr->index_rx_tx, io_info_ptr->data[io_info_ptr->index_rx_tx]);

            #endif

        }

    }

    io_info_ptr->index++;

}

View solution in original post

0 Kudos