cancel
Showing results for 
Search instead for 
Did you mean: 

Keyboard Interrupt on UART receive

StanCosgrove
Associate II

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')

}

10 REPLIES 10
SofLit
ST Employee

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.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

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.  

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hi Tesla, thanks for reply, but i still dun understand i m a student working on final year project, could write a simple short C code to further elaborate ... 

Karl Yamashita
Lead III

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 */
}

 

 

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

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

@Karl Yamashita 

This is exactly what I meant ;)

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

HI Karl, where should i place the if (rx_data == 'a') , (rx_data == 'b') and (rx_data =='c'), d,e,f....z statements? All a.....z inside UART_ParseMessage(void) function, if (strncmp(ptr,'A'...) ? Could you show me just 1 example? thanks.  

 

 


@Karl Yamashita wrote:

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.

Really? I would recommend exactly the opposite.;)

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice