Skip to main content
Visitor II
November 28, 2023
Question

Keyboard Interrupt on UART receive

  • November 28, 2023
  • 2 replies
  • 3639 views

Hi i m using 26 keyboard key to interrupt via UART received, should i coded the 26 interrupt in a single rxcplt callback function or a multiple callback function? Whats the best way? pls advise...

void HAL_UART_RxCpltCallback(UART....)

{

  HAL_UART_Receive_IT(huart, &rx_data....)

  if (rx_data  == 'a')

....

  if (rx_data == 'b')

...

if (rx_data == 'c')

}

    This topic has been closed for replies.

    2 replies

    Technical Moderator
    November 28, 2023

    Hello,

    I didn't understand what do you mean by "multiple callback function"!

    You can manage all received characters inside HAL_UART_RxCpltCallback(). But, it's not recommended to handle the actions inside the callback as it blocks the interrupt for awhile. So save the characters inside a buffer in the callback and treat them outside the IRQ handler.

    Visitor II
    November 29, 2023

    Hi, multiple callback i mean RxCpltCallbackA(), RxCpltCallbackB() C, D....Z. 

    "save the characters inside a buffer in the callback and treat them outside the IRQ handler." ==> could you elaborate further, dun quite understand this, if you can provide a short C code would be better, thx.  

    Graduate II
    November 29, 2023

    It will be called sequentially, the callback occurs under interrupt context, and you will need to return for the next callback or UART IRQ to occur. I would move rx_data to a holding variable on entry.

    Put the new key into a different variable, and process in the main loop. Run code in the call-back if it can be done quickly and not block execution.

    Graduate II
    November 29, 2023

    Don't process any data inside of the interrupt other wise you could miss other interrupts that are happening. Just save the data and set a flag indicating a new byte was received. Enable uart interrupt and exit the callback. Then in a main while loop you can check each character and process it there.

    A better approach is not even having to save the data but just use a ring buffer. Below code has a ring buffer though it's over kill for single characters but it can hold up to 2 characters in a queue which you can increase with the #define. Unless you type like Superman then 2 queues is more than efficient. If you type like a turtle then you don't even need a ring buffer. If you're doing a lot of other things like math calculation, then you can increase the queue so you don't get an overflow.

    Also notice in HAL_UART_RxCpltCallback I don't have to copy received data to another variable. I just increment a pointer and enable the UART interrupt which points the HAL driver to save to the next queue. Then i check if there is a byte available and parse the character.

     

     

     

     

    #include "main.h"
    
    extern UART_HandleTypeDef hlpuart1;
    
    UART_Data_t uartData = {0};
    
    // before main while loop
    void PollingInit(void)
    {
    	UART_EnableInterrupt();
    }
    
    // main while loop
    void PollingRoutine(void)
    {
    	UART_ParseMessage();
    	UART_CheckHalStatus();
    }
    
    void UART_ParseMessage(void)
    {
    	char *ptr;
    
    	if(uartData.ptr.cnt_Handle)
    	{
    		// user can parse the pointer data.
    		ptr = (char*)&uartData.data[uartData.ptr.index_OUT];
    
    		switch(*ptr)
    		{
    			case 'a':
    				GreenLED_Toggle();
    			break;
    			case 'b':
    				HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
    			break;
    			case 'c':
    				HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
    			break;
    		}
    
    		RingBuff_Ptr_Output(&uartData.ptr, DATA_SIZE);
    	}
    }
    
    void UART_EnableInterrupt(void)
    {
    	uartData.HAL_Status = HAL_UART_Receive_IT(&hlpuart1, &uartData.data[uartData.ptr.index_IN], 1); // interrupt on 1 byte
    }
    
    void UART_CheckHalStatus(void)
    {
    	if(uartData.HAL_Status != HAL_OK)
    	{
    		uartData.HAL_Status = HAL_OK;
    		UART_EnableInterrupt(); // try to enable again
    	}
    }
    
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
    	if(huart == &hlpuart1)
    	{
    		RingBuff_Ptr_Input(&uartData.ptr, DATA_SIZE);
    		UART_EnableInterrupt();
    	}
    }
    
    void GreenLED_Toggle(void)
    {
    	HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
    }
    #ifndef INC_POLLINGROUTINE_H_
    #define INC_POLLINGROUTINE_H_
    
    
    #define DATA_SIZE 8
    typedef struct
    {
    	uint8_t data[DATA_SIZE];
    	RING_BUFF_STRUCT ptr;
    	HAL_StatusTypeDef HAL_Status;
    }UART_Data_t;
    
    
    void PollingInit(void);
    void PollingRoutine(void);
    
    void UART_ParseMessage(void);
    void UART_EnableInterrupt(void);
    void UART_CheckHalStatus(void);
    
    void GreenLED_Toggle(void);
    
    
    #endif /* INC_POLLINGROUTINE_H_ */
    #include "main.h"
    #include "ringBuffer.h"
    
    
    void RingBuff_Ptr_Reset(RING_BUFF_STRUCT *ptr) {
    	ptr->index_IN = 0;
    	ptr->index_OUT = 0;
    
    	ptr->cnt_Handle = 0;
    	ptr->cnt_OverFlow = 0;
    }
    
    void RingBuff_Ptr_Input(RING_BUFF_STRUCT *ptr, uint32_t bufferSize) {
    	ptr->index_IN++;
    	if (ptr->index_IN >= bufferSize)
    		ptr->index_IN = 0;
    
    	ptr->cnt_Handle++;
    	if (ptr->index_IN == ptr->index_OUT) {
    		ptr->cnt_OverFlow++;
    		if (ptr->cnt_OverFlow > RING_BUFF_OVERFLOW_SIZE)
    			ptr->cnt_OverFlow = 0;
    		if (ptr->index_IN == 0) {
    			ptr->index_OUT = bufferSize - 1;
    		} else {
    			ptr->index_OUT = ptr->index_IN - 1;
    		}
    		ptr->cnt_Handle = 1;
    	}
    }
    
    void RingBuff_Ptr_Output(RING_BUFF_STRUCT *ptr, uint32_t bufferSize) {
    	if (ptr->cnt_Handle) {
    		ptr->index_OUT++;
    		if (ptr->index_OUT >= bufferSize)
    			ptr->index_OUT = 0;
    		ptr->cnt_Handle--;
    	}
    }
    #ifndef RING_BUFFER_H
    #define RING_BUFFER_H
    
    #include "main.h"
    
    #define RING_BUFF_OVERFLOW_SIZE 100
    
    typedef struct {
    	uint32_t index_IN; // pointer to where the data will be save to
    	uint32_t index_OUT; // pointer to next available data in buffer if cnt_handle is not zero
    	uint32_t cnt_Handle; // if not zero then message available
    	uint32_t cnt_OverFlow; // has overflow if not zero
    }RING_BUFF_STRUCT;
    
    void RingBuff_Ptr_Reset(RING_BUFF_STRUCT *ptr);
    void RingBuff_Ptr_Input(RING_BUFF_STRUCT *ptr, uint32_t bufferSize);
    void RingBuff_Ptr_Output(RING_BUFF_STRUCT *ptr, uint32_t bufferSize);
    
    
    
    #endif // RING_BUFFER_H
    int main(void)
    {
     /* Infinite loop */
     /* USER CODE BEGIN WHILE */
     PollingInit();
     while (1)
     {
    	 PollingRoutine();
     /* USER CODE END WHILE */
    
     /* USER CODE BEGIN 3 */
     }
     /* USER CODE END 3 */
    }

     

     

     

    Visitor II
    November 29, 2023

    thank you so much Karl, looks complicated, i will understand and digest it...