I/O Hardfault

Hello,
I’m using CMSIS_v2 FreeRTOS on STM32F303. I’ve retargeted I/O to use queue.

int stdout_putchar(int ch)  
{  
   char item = (char)ch;  
      
  osMessageQueuePut(tx_queue, &item, 0U, 0U);  
      
  return ch;  
} 
int stdin_getchar(void)  
{  
  uint16_t        msg;  
  osStatus_t status;  
      
  status = osMessageQueueGet(rx_queue, &msg, NULL, osWaitForever);                    
  if (status == osOK)  
    return((int)msg);  
  else  
    return ((int)NULL);   
}  

This with help of scanf() & printf() i/o data through RS485 and terminal on PC. However, when trying to use printf or scanf program goes into HardFault.
UART is configured to receive through ISR

void UART4_IRQHandler(void)
 {		
   static uint16_t	rx_byte = 0x00;		
   if (USART_GetITStatus(UART4, USART_IT_RXNE) == SET )
   {		
	  rx_byte		=	USART_ReceiveData(UART4);  			    		
      if (USART_GetFlagStatus(UART4, USART_FLAG_ORE) == SET)				
		USART_ClearITPendingBit(UART4, USART_IT_ORE); 					
    }			
	if (rx_byte != NULL)			
	    osMessageQueuePut(rx_queue, &rx_byte, NULL, NULL);    		
 }

And output though low priority thread

void vTransmitUART4(void *argument) 
{
    uint8_t 		UART4_data;

    for(;;)
    {
   	if (osMessageQueueGetCount(tx_queue) == 0)												
		GPIO_ResetBits(GPIOA, GPIO_Pin_12); // Recieve State
																		
	osStatus_t status = osMessageQueueGet(tx_queue, &UART4_data, 0, osWaitForever); 
	if (status == osOK) 
	{		
		GPIO_SetBits(GPIOA, GPIO_Pin_12);	// Output state
		while(USART_GetFlagStatus(UART4, USART_FLAG_TC) == RESET);	
		USART_SendData(UART4, (uint16_t)UART4_data);											
	}					
     }		
}    

How to properly deal with this issue? This is critical to my application.

One big thought is have you made the standard library thread-safe? It is common for printf() to call malloc(), which might not be thread-safe.

Also (not related to this issue) is that your put char has a 0 wait, which means that if the queue fills then you drop characters mid message.

It is hard to provide direct support for third party APIs on top of FreeRTOS, as I would have to go and look up how to use the functions myself. Grateful if you could try using our native API (xQueueSend(), xQueueReceive(), etc.), and if you still have an issue post the code here as you have done above with the CMSIS API.

Just from looking at the code a few suggestions:
Is your implementation of osMessageQueuePut() checking if it is in an ISR or not? If it is it should call xQueueSendFromISR(), if not it should call xQueueSend().

Have you followed the normal set of troubleshooting tips, such as ensuring configASSERT() is defined, you have stack overflow checking on, you are using an up-to-date version of FreeRTOS to ensure you have the maximum number of assert points in the code to help you debug configuration problems, you have followed the instructions to ensure interrupts that use API calls have a setting below configMAX_SYSCALL_INTERRUPT_PRIORITY, on and STM32 you also need to ensure all interrupt priority bits are set to preemption priority, etc. (many of these errors would be caught by asserts if you use up to date FreeRTOS versions).

Yes, I’ve looked over printf(0 from glibc and it calls malloc. I’ve decided to shift away from using queues and rewritten stdin/stdout func to use LL USART commands.

int stdin_getchar(int ch, FILE *f)
{     
  while(USART_GetFlagStatus(UART4, USART_FLAG_RXNE) == RESET);	
   ch		=	USART_ReceiveData(UART4);
   return ch;
}

int stdout_putchar(int ch)
{	
  GPIO_SetBits(GPIOA, GPIO_Pin_12);	

  while(USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);	
  USART_SendData(UART4, (uint16_t)ch);	
  while(USART_GetFlagStatus(UART4, USART_FLAG_TC) == RESET);	

  GPIO_ResetBits(GPIOA, GPIO_Pin_12);

  return ch;
}

It works, but what might be a down side to this approach?

Yes, it checks if app is currently in IRQ and calls SendFromISR API. I’ve checked and ifunctions are IRQ safe. I’ve looked over troubleshooting tips and everything as it should be although configAssert() is a must to add. Can you point me in the direction of CMSIS RTOS support forums if it’s not ot much to ask?

I would say that the big disadvantage of this approach is that your output is now blocking, and calls to printf will take as long as it takes to send the results.

Dumb me, fixed everything by increasing stack of every task.
Runs smooth.
Thank you everybody.

Richard, thank you for this insight. I’m looking into it.