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?
Solved! Go to Solution.
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++;
}
Hello Jmag,
Was this suggestion helpful? We'd like to know :smileywink:
Best regards!
Monica.
I can confirm that it works. Both for the version that uses lwsem_post and the version that uses lwevent_set.
Best regards
Sebastian
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++;
}