2021-12-10 03:07 AM
Controller : STM32L031F6P7 custom board.
I2C stops working after exactly 1 minute 6 seconds? I can replicate this every time.
When it stops working, i cannot reset the i2c pheriperal in any way i have found in this forum.
These are attempts i already tried.
static void rtc_reset_i2c_hw(void){
MX_I2C1_Init();
/*
HAL_I2C_DeInit(&hi2c1);
__HAL_RCC_I2C1_FORCE_RESET();
HAL_Delay(5);
__HAL_RCC_I2C1_RELEASE_RESET();
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
Error_Handler();
}
HAL_Delay(100);
*/
//HAL_DMA_DeInit(pDMArx);
//HAL_DMA_DeInit(pDMAtx);
//HAL_DMA_Init(pDMArx);
//HAL_DMA_Init(pDMAtx);
/*
HAL_I2C_DeInit(&hi2c1);
HAL_I2C_Init(&hi2c1);
hi2c1.Instance->CR1 &= ~I2C_CR1_PE; // clear pheripheral enable
hi2c1.Instance->CR1 &= ~I2C_CR1_PE; // clear pheripheral enable
hi2c1.Instance->CR1 &= ~I2C_CR1_PE; // clear pheripheral enable
HAL_Delay(50);
hi2c1.Instance->CR1 |= I2C_CR1_PE; // enable pheripheral enable
*/
i2c_state = i2c_startRx;
}
I have created the project with the absolute minimum pheriperals (IO and I2C), and it keep failing with the HAL library functions.
I use I2C as slave and use a statemachine to organize stuff.
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
i2c_state = i2c_startRx;
interruptcnt = 0;
}
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
i2c_state = i2c_RxCmplt;
interruptcnt = 0;
}
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *I2cHandle)
{
//Error exception callback function
rtc_reset_i2c_hw();
}
void AliveTasks(void){
HAL_StatusTypeDef rel;
switch(i2c_state){
case i2c_startRx:
rel = HAL_I2C_Slave_Receive_IT(&hi2c1, (uint8_t*) i2cbuffer_in,I2C_BUFFER_SIZE);
if (rel != HAL_OK) {
rtc_reset_i2c_hw();
}
tmr_ms_Start(&i2c_tmo, 100);
i2c_state = i2c_waitforRxCmplt;
break;
case i2c_RxCmplt:
tmr_ms_Start(&i2c_tmo, 100);
rtc_process_i2c_cmd();
HAL_I2C_Slave_Transmit_IT(&hi2c1,i2cbuffer_out,I2C_BUFFER_SIZE);
i2c_state = i2c_waitforTxCmplt;
break;
case i2c_waitforRxCmplt:
case i2c_waitforTxCmplt:
if(tmr_ms_Ok(&i2c_tmo)){
faultdetect = 1;
tmr_ms_Start(&i2c_tmo, 100);
rtc_reset_i2c_hw();
}
break;
}
}
This is what i see at the logic analyzer.
Pictures goes from all good -> moment of terror -> continuously terror
What can cause HAL I2C to stop working like this?
How can i do a full reset of HAL I2C ?
Does anyone have a link to non HAL I2C code, or should i write myself? already spend too much time on this issue....
Solved! Go to Solution.
2021-12-10 04:35 AM
Hi,
1 min and 6 seconds sounds a lot like 0xFFFF milliseconds, i.e. an uint16_t overflowing somewhere.
So can you reproduce the problem with just a basic code where the main loop does nothing except an infinite loop and the I2C only acks address and data.
That way you could make sure that the I2C is the problem.
Best regards.
2021-12-10 03:46 AM
How are you clocking your microcontroller? external xtal?
As a long shot.... could your clock drift with time/temperature untill is not usable by i2c anymore?
You could output a very fast hardware pwm and compare freq at the beginning and past 1 min
2021-12-10 03:50 AM
Is everything else working ok? only the i2c peripheral fails?
2021-12-10 04:19 AM
i use the internal HSI clock, there is not much that this chip does, so i cannot give a truthful answer to this..
I expect the HSI clock to be stable? At the master side i also use HSI clock.
2021-12-10 04:35 AM
Hi,
1 min and 6 seconds sounds a lot like 0xFFFF milliseconds, i.e. an uint16_t overflowing somewhere.
So can you reproduce the problem with just a basic code where the main loop does nothing except an infinite loop and the I2C only acks address and data.
That way you could make sure that the I2C is the problem.
Best regards.
2021-12-10 06:01 AM
There was a variable type wrongly defined in my timer function, which caused a continuous I2C reset after 1min and 6 seconds.
But even when i cleared that issue i was not completely out of the woods yet, if i paused the program trough the debugger pause button, i did see the I2C communication was not restoring itself. Once the communication broke, it was broken for good. (endless loop in I2C1_IRQHandler). I know this is not a real life situation, but i do like that communication restores when something goes wrong.
So i looked for a solution and found this one :
At the main program i start a softwaretimer each time HAL_I2C_SlaveTxCpltCallback and HAL_I2C_SlaveRxCpltCallback is called.
in I2C1_IRQHandler i check if the timer elapse , this happen when it's endlessly interrupted , when this happen i reset the I2C module. This seems to do the trick, now i can pauze and run , the I2C communication will always restore itself.
void I2C1_IRQHandler(void)
{
/* USER CODE BEGIN I2C1_IRQn 0 */
/* USER CODE END I2C1_IRQn 0 */
if (hi2c1.Instance->ISR & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) {
HAL_I2C_ER_IRQHandler(&hi2c1);
} else {
HAL_I2C_EV_IRQHandler(&hi2c1);
}
/* USER CODE BEGIN I2C1_IRQn 1 */
if(tmr_us(&intlock_timer){
__HAL_RCC_I2C1_FORCE_RESET();
__HAL_RCC_I2C1_RELEASE_RESET();
}
/* USER CODE END I2C1_IRQn 1 */
}
Thank you for showing me the direction :smiling_face_with_smiling_eyes: