Take account of some corner cases in I2C multi-byte read

See https://github.com/geoffreymbrown/STM32-Template/blob/master/Library/i2c.c#L39 and RM0090 p851-853.
This commit is contained in:
Raphael Coeffic
2021-07-11 14:30:43 +02:00
parent 8c7f3cecec
commit 49ae57d370
+93 -13
View File
@@ -512,6 +512,15 @@ void I2C_Init()
GPIO_Init(I2C_GPIO, &GPIO_InitStructure);
}
bool I2C_WaitFlag(uint32_t flag)
{
uint32_t timeout = I2C_TIMEOUT_MAX;
while (!I2C_GetFlagStatus(I2C, flag)) {
if ((timeout--) == 0) return false;
}
return true;
}
bool I2C_WaitEvent(uint32_t event)
{
uint32_t timeout = I2C_TIMEOUT_MAX;
@@ -632,6 +641,10 @@ bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len)
return false;
}
// Enable Acknowledgement, clear POS flag
I2C_AcknowledgeConfig(I2C, ENABLE);
I2C_NACKPositionConfig(I2C, I2C_NACKPosition_Current);
I2C_GenerateSTART(I2C, ENABLE);
if (!I2C_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT))
{
@@ -646,24 +659,91 @@ bool I2C_GT911_ReadRegister(u16 reg, uint8_t * buf, uint8_t len)
return false;
}
if (len > 1) {
I2C_AcknowledgeConfig(I2C, ENABLE);
}
if (len == 1) {
// Clear Ack bit
I2C_AcknowledgeConfig(I2C, DISABLE);
while (len) {
if (len == 1) {
I2C_AcknowledgeConfig(I2C, DISABLE); // Send NACK on last byte
}
if (!I2C_WaitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED))
{
TRACE("I2C READ ERROR: could not read data with %u bytes remaining", len );
// EV6_1 -- must be atomic -- Clear ADDR, generate STOP
__disable_irq();
(void) I2C->SR2;
I2C_GenerateSTOP(I2C,ENABLE);
__enable_irq();
// Receive data EV7
if(!I2C_WaitFlag(I2C_FLAG_RXNE)) {
TRACE("I2C READ ERROR: timeout waiting for RxNE");
I2C_Init();
return false;
}
*buf++ = I2C_ReceiveData(I2C);
len--;
}
else if (len == 2) {
// Set POS flag
I2C_NACKPositionConfig(I2C, I2C_NACKPosition_Next);
// EV6_1 -- must be atomic and in this order
__disable_irq();
(void) I2C->SR2; // Clear ADDR flag
I2C_AcknowledgeConfig(I2C, DISABLE); // Clear Ack bit
__enable_irq();
// EV7_3 -- Wait for BTF, program stop, read data twice
if (!I2C_WaitFlag(I2C_FLAG_BTF)) {
TRACE("I2C READ ERROR: timeout waiting for BTF");
I2C_Init();
return false;
}
__disable_irq();
I2C_GenerateSTOP(I2C,ENABLE);
*buf++ = I2C->DR;
__enable_irq();
*buf++ = I2C->DR;
}
else {
(void) I2C->SR2; // Clear ADDR flag
while (len-- != 3) {
// EV7 -- cannot guarantee 1 transfer completion time, wait for BTF
// instead of RXNE
if (!I2C_WaitFlag(I2C_FLAG_BTF)) {
TRACE("I2C READ ERROR: timeout waiting for BTF");
I2C_Init();
return false;
}
*buf++ = I2C_ReceiveData(I2C);
}
// Data N-2 in DR, data N-1 in shift register,
// SCL stretched low until data N-2 is read
if (!I2C_WaitFlag(I2C_FLAG_BTF)) {
TRACE("I2C READ ERROR: timeout waiting for BTF");
I2C_Init();
return false;
}
I2C_AcknowledgeConfig(I2C, DISABLE); // clear ack bit
*buf++ = I2C_ReceiveData(I2C); // receive byte N-2
// Wait for BTF, program stop, read data twice
if (!I2C_WaitFlag(I2C_FLAG_BTF)) {
TRACE("I2C READ ERROR: timeout waiting for BTF");
I2C_Init();
return false;
}
__disable_irq();
I2C_GenerateSTOP(I2C,ENABLE);
*buf++ = I2C->DR;
__enable_irq();
*buf++ = I2C->DR;
}
I2C_GenerateSTOP(I2C, ENABLE);
return true;
}
@@ -743,7 +823,7 @@ bool touchPanelInit(void)
}
if (!I2C_GT911_ReadRegister(GT_CFGS_REG, tmp, 1))
{
TRACE("GT911 ERROR: configration register read failed");
TRACE("GT911 ERROR: configuration register read failed");
}
TRACE("Chip config Ver:%x", tmp[0]);