cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_I2C_Mem_Read disables interrupts

sanju
Senior

Hello all,

I am working on a project which is based on stm32f103cbt7 mcu.

In my project i have two freeRTOS task and 2 timer interrupts and 1 uart interrupt routine.

Task 1:  handles wireless communication (it reads a buffer and if buffer has some valid data then it takes action accordingly). Buffer for which this task checks is filled by uart interrupt, data received on uart is filled to this buffer.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
   HandleRxByte(rdata); // fills task1 buffer by checking received data.
   HAL_UART_Receive_IT(&huart1, &rdata, 1);
}

Task 2: this task reads some data from External RTC over I2C and write some data to SD card over SPI and read analog channels.

Here i am facing a problem that after few minutes (random time) from device power on , buffer of task 1 does not change it's content, i.e. it freezed. For few minutes it works fine , multiple packets are handled by task1 correctly but after random time buffer content stops changing.

after debugging i found that at this moment when problem rise USART1 _> CR1 -> RXNEIE bit becomes 0 , timer and systick interrupts working fine and task 2 also working fine.

only uart interrupt disables.and i think reason is that HAL_I2C_Mem_Read disables and enable interrupts. because of this it disables uart interrupt anddoesn't enable again.

Am i right or please suggest me a solution for this. 

thanks in advance .

 

5 REPLIES 5
Johi
Senior III

Receiving byte by byte is inefficient and can cause overload. Processing your data using HandleRxByte(rdata); might also be not the best choice (if you do serial processing in this part).

It is better to use DMA for serial communication in order reduce load. ( look for HAL_UARTEx_ReceiveToIdle_DMA documentation and use circular receive buffer.)

At least try to read more than 1 byte at a time HAL_UART_Receive_IT(&huart1, &rdata, xxx); if your protocol allows this.

 

  • Receiving byte by byte is inefficient and can cause overload. Processing your data using HandleRxByte(rdata); might also be not the best choice (if you do serial processing in this part).i have to receive byte by byte because length of data to receive is not fixed it's vary with frame type.In HandleRxByte(rdata); it's checks for the frame type or frame error, corresponding data and then fills task1 buffer accordingly.

To demonstrate my problem i have created a sample project  and attached its source files. here i have created two task  and one uart interrupt isr.

uart receive call back just counts number of interrupt occured.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uartRxIntCnt++;
HAL_UART_Receive_IT(&huart1, (uint8_t*)&rData, 1);
}
 
Task1 toggles a led and disable interrupts for some milliseconds then enable again. 
static void task1_handler(void* parameters)
{
while(1)
{
HAL_GPIO_TogglePin(LD4_GPIO_Port, LD4_Pin);
__disable_irq();
for(loop = 0; loop <= 10000; loop++);
__enable_irq();
vTaskDelay(50);
}
}
 
Task 2 reset the uartRxIntCnt if it becomes > 10000 and toggle a led.
static void task2_handler(void* parameters)
{
while(1)
{
if(uartRxIntCnt > 10000)
{
uartRxIntCnt = 0;
}
else;
HAL_GPIO_TogglePin(LD5_GPIO_Port, LD5_Pin);
vTaskDelay(10);
}
}

This code works fine till random time i.e. uartRxIntCnt  goes to 10000 and then 0 so on repeats and both leds LD4 and LD5 toggles fine .

but after some random time uartRxIntCnt stops increasing but both leds LD4 and LD5 toggles fine means both the task are working fine. only uart interrupt stops working.

in order to work uart interrupt fine i have to remove __disable_irq(); and __enable_irq(); from task1.

You can see the complete project in attachment.

Bob S
Principal

You don't say what CPU clock rate and UART baud rate (and I'm not taking the time to look through your project).  So we can't tell how hard you are pushing the CPU.  As @Johi mentioned above, processing byte-by-byte can be expensive (again, depending on your CPU clock and UART baud rates).

You also don't show a HAL_UART_ErrorCallback() implementation.  It is possible (probable) that you are getting some sort of UART error (framing or overrun, for example) which is disabling the interrupt.

Thank you for the reply.

CPU clock frequency is 48 Mhz and UART baud rate is 38400.

I implemented HAL_UART_ErrorCallback() as you guided , here i am getting overrun error.

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
uartErrIntCnt++;
uartErrCode = huart->ErrorCode;
huart->Instance->ICR |= (1<<3);      // Clear overrun error
HAL_UART_Receive_IT(&huart1, (uint8_t*)&rData, 1);
}

But it's still not working fine.

"still not working fine" is not very helpful.  HOW is it still not working?  Are you still getting to a point where the RXInt counter stops incrementing?

Because you are getting overflow errors, that means you are loosing data.  So as long as that happens your code will never work.  At 38400 baud you receive a byte every 260us.  Since your interrupt is unable to keep up with that, perhaps your UART interrupt priority is lower than some other (very long or very frequent) interrupt?  The HAL code is a bit boated, but it should be able to keep up with that baud rate (DISCLAIMER: I have never used the F1xx series and there may be limitations that I am not aware of).

The REAL fix is to stop using interrupts and use DMA in a circular buffer.  See https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx for examples.