I2C start condition not generating and unknown error interrupts
I am trying to use stm32F446 as a master I2C device with LL library and I have 2 main issues.
1. After sending a couple of messages(always 4 at most) over I2C I get no start condition when setting CR1->START, if I pause the program a couple of seconds later and I inspect the register it is still at 1 and never goes back to 0.
2.I randomly get interrupts on both (Don't know if both at the same time) EVT and ERR with none of the EVT or ERR flags set.
Here is my code if needed:
typedef enum {
TWI_IDLE,
TWI_SENDING,
TWI_RECEIVING,
TWI_BERR,
TWI_AF,
TWI_ARLO,
TWI_OVR,
TWI_UNKNOWN_EVENT,
TWI_UNKNOWN_ERROR,
} TWI_state;
typedef enum {
TWI_SUCCESS,
TWI_FAILURE,
TWI_BUSY,
} TWI_status;
typedef struct {
I2C_TypeDef* I2CxReg;
TWI_state state;
uint8_t totalBytes;
uint8_t bytesDone;
uint8_t* data;
uint8_t sendAddress;
} TWI_interface;
static void resetTWI(TWI_interface* iface);
TWI_status TWIMasterTransmit(TWI_interface* iface, uint8_t address, uint8_t* data, uint8_t length) {
TWI_status status = TWI_SUCCESS;
if (iface->I2CxReg == NULL) {
status = TWI_FAILURE;
}
else if (iface->state == TWI_IDLE) {
iface->totalBytes = length;
iface->bytesDone = 0;
iface->data = data;
iface->sendAddress = address << 1; //addr+w
LL_I2C_GenerateStartCondition(iface->I2CxReg);
iface->state = TWI_SENDING;
}
return status;
}
void TWIEventHandler(TWI_interface* iface) {
//Master transmit
if (LL_I2C_IsActiveFlag_SB(iface->I2CxReg)) {
LL_I2C_TransmitData8(iface->I2CxReg, iface->sendAddress);
}
else if (LL_I2C_IsActiveFlag_ADDR(iface->I2CxReg) || LL_I2C_IsActiveFlag_ADD10(iface->I2CxReg)) {
LL_I2C_ClearFlag_ADDR(iface->I2CxReg);
if (iface->bytesDone == 0) {
LL_I2C_TransmitData8(iface->I2CxReg, iface->data[iface->bytesDone]); //bytesDone=0
iface->bytesDone++;
}
}
else if (LL_I2C_IsActiveFlag_TXE(iface->I2CxReg) || LL_I2C_IsActiveFlag_BTF(iface->I2CxReg)) {
if (iface->bytesDone < iface->totalBytes) {
// Transmit data
LL_I2C_TransmitData8(iface->I2CxReg, iface->data[iface->bytesDone]);
iface->bytesDone++;
}
else if (LL_I2C_IsActiveFlag_BTF(iface->I2CxReg)) {
LL_I2C_GenerateStopCondition(iface->I2CxReg);
// Sometimes it waits forever, so we time out.
uint16_t timeout = 1000;
while (timeout > 0 && (iface->I2CxReg->CR1 & I2C_CR1_STOP)) {
timeout--;
}
if (timeout == 0) {
resetTWI(iface);
}
}
}
else {
iface->state = TWI_UNKNOWN_EVENT;
}
}
void TWIErrorHandler(TWI_interface* iface) {
//Note: State should be reseted to TWI_IDLE manually
// Maybe do fix the i2c issue here
if (LL_I2C_IsActiveFlag_BERR(iface->I2CxReg)) {
iface->state = TWI_BERR;
LL_I2C_ClearFlag_BERR(iface->I2CxReg);
}
else if (LL_I2C_IsActiveFlag_AF(iface->I2CxReg)) {
iface->state = TWI_AF;
LL_I2C_ClearFlag_AF(iface->I2CxReg);
}
else if (LL_I2C_IsActiveFlag_ARLO(iface->I2CxReg)) {
iface->state = TWI_ARLO;
LL_I2C_ClearFlag_ARLO(iface->I2CxReg);
}
else if (LL_I2C_IsActiveFlag_OVR(iface->I2CxReg)) {
iface->state = TWI_OVR;
LL_I2C_ClearFlag_OVR(iface->I2CxReg);
}
else {
iface->state = TWI_UNKNOWN_ERROR;
}
}
static void resetTWI(TWI_interface* iface) {
iface->state = TWI_IDLE;
iface->totalBytes = 0;
iface->bytesDone = 0;
iface->data = NULL;
iface->sendAddress = 0;
LL_I2C_EnableReset(iface->I2CxReg);
LL_I2C_DisableReset(iface->I2CxReg);
}
