2023-11-28 07:17 AM
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')
}
2023-11-28 07:29 AM
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.
2023-11-28 05:52 PM
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.
2023-11-28 06:00 PM
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.
2023-11-28 06:37 PM
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 ...
2023-11-28 07:08 PM - edited 2023-11-29 12:27 PM
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 */
}
2023-11-28 07:25 PM
thank you so much Karl, looks complicated, i will understand and digest it...
2023-11-29 12:32 AM
This is exactly what I meant ;)
2023-11-29 06:45 AM
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.
2023-11-29 07:42 AM
@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.;)