9 years, 6 months ago.

STM32F401-Serial Interrupt handler with C++ interface not getting called

Hello,

I am working on STM32F401RE board and using a serial port Serial bt_uart(PA_9, PA_10);

And using the below initialisation

bt_uart.baud(115200);

bt_uart.format(8, Serial::Even, 1);

bt_uart.attach(&UART_RX_IRQHandler,Serial::RxIrq);

With the above C++ initialisation my Interrupt handler is never getting called.

However when I tried using the C interface as below (from the standard serial_api.c) my interrupt handler is called,

serial_t test;

SerialParity x=ParityEven;

SerialIrq z=RxIrq;

serial_init(&test,PA_9,PA_10);

serial_baud(&test,115200);

serial_format(&test,8,x,1);

serial_irq_handler(&test,UART_RX_IRQHandler,1);

serial_irq_set(&test,z,1);

I want to use the standard C++ API interface due to project needs and not C API. Does the C++ interface has some problem ?

-ykd

Are you using RTOS also or other relevant code?

posted by Erik - 22 Jun 2015

Yes RTOS is used (RTX rtos).

posted by yogesh kulkarni 22 Jun 2015

2 Answers

9 years, 6 months ago.

When using RTOS the serial IRQ will block indefinately on getc(), locking your program. This is because it uses stdio, which places a mutex on getc/putc, which is not allowed within interrupt context.

The solution to this is using RawSerial, which is (almost) the same as Serial, but does not use stdio, thereby circumventing those mutexes.

Hi Erik, thanks for your inputs. yes i tried with RawSerial but the result is the same. My Rx interrupt handler is never called. As you suggested i changed Serial to RawSerial as below when I declare the object.

So now instead of Serial bt_uart(PA_9, PA_10);

I now have RawSerial bt_uart(PA_9, PA_10);

Hope I have understood you correctly. Is there any other change that i must do along with this ?

Regards Ykd

posted by yogesh kulkarni 23 Jun 2015

No, that should do the trick. Which code is in your UART_RX_IRQHandler?

posted by Erik - 23 Jun 2015

Hi Erik, UART_Rx_IRQHandler() is as below. It reads a byte.

void UART_RX_IRQHandler(void)

{

pc.printf(" In ...UART_RX_IRQHandler\n");

if(bt_uart.readable())

{

uint8_t byte = bt_uart.getc();

if (byte == 0xC0)

{

if(rx_frame == 0)

{

rx_frame = 1;

}

else if(rx_frame == 1)

{

rx_frame = 2;

}

}

}

}

posted by yogesh kulkarni 23 Jun 2015
9 years, 6 months ago.

Hi Yogesh,

How do you know that your interrupt handler is never called? Maybe it is called and then hangs somewhere inside?

Try your UART_RX_IRQHandler like this:

very simple IRQ routine

...
uint8_t rx_byte;
...
void UART_RX_IRQHandler(void)
{
   rx_byte = bt_uart.getc();
}

and then output rx_byte outside UART_RX_IRQHandler() using printf. Check if this works, i.e. if received character is printed.

  • If yes, expand your IRQHandler line-by-line and check where the problem occurs.
  • If no, then program probably doesn't enter the IRQHandler(). :( Then it would be good if you can post your C++ code, at least the basic things you wrote regarding serial port operations.

Regards, Miloje

i tried as you said , but rx_byte is not getting any data. I can say it is never called because with serial_api.c interface it works fine and i got the print statement always coming inside the ISR . With C++ interface code it did not work (even with rawSerial). I will post my C++ code related to serial port settings below.

RawSerial bt_uart(PA_9, PA_10);

static uint8_t rx_frame = 0;

static uint16_t rx_frame_count = 0;

void UartInit(void) {

bt_uart.baud(115200); 115200

bt_uart.format(8, Serial::Even, 1);

bt_uart.attach(&UART_RX_IRQHandler,Serial::RxIrq); Interrupt callback func

printf("UART init OK\n");

}

void Tx_Data_send(void) {

uint8_t i=0;

uint8_t CmdBuffer[10] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};

for (i = 0; i < 10; i++) {

while(bt_uart.writeable() == 0) {}

bt_uart.putc(CmdBuffer[i]);

}

}

void UART_RX_IRQHandler(void)

{

static uint8_t isRxBufferFull = 0; if(bt_uart.readable() && (isRxBufferFull == 0))

{ uint8_t byte = bt_uart.getc();

/* Token detector */ if (byte == 0xC0)

{

if(rx_frame == 0) {

rx_frame = 1;

} else if(rx_frame == 1) { rx_frame = 2;

}

} rx_frame_count++;

if (rx_frame_count >= UART_RX_BUFFER_SIZE)

{

isRxBufferFull = 1;

}

if (rx_frame == 2)

{ rx_frame_count = 0; rx_frame = 0; }

}

}

Sorry for the brackets (the code is not looking properly indented after i pasted it here) but I tried to be as clear as possible . I will try with another hardware and see if the problem occurs.

posted by yogesh kulkarni 25 Jun 2015

Hi Yogesh,

Just a small hint - when you post some code, use word "code" within << >> to format it in a more readable way (in a right bottom corner of message window there is "Editing tips" help).

Code from Yogesh

RawSerial bt_uart(PA_9, PA_10);

static uint8_t rx_frame = 0;
static uint16_t rx_frame_count = 0;

void UartInit(void)
{
	bt_uart.baud(115200); // 115200
	bt_uart.format(8, Serial::Even, 1);
	bt_uart.attach(&UART_RX_IRQHandler,Serial::RxIrq); //Interrupt callback func
	printf("UART init OK\n");
}

void Tx_Data_send(void)
{
	uint8_t i = 0;
	uint8_t CmdBuffer[10] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
	
	for (i = 0; i < 10; i++)
	{
		while(bt_uart.writeable() == 0) {}
		bt_uart.putc(CmdBuffer[i]);
	}
}

void UART_RX_IRQHandler(void)
{
	static uint8_t isRxBufferFull = 0;
	
	if(bt_uart.readable() && (isRxBufferFull == 0))
	{
		uint8_t byte = bt_uart.getc();
		
		/* Token detector */
		if (byte == 0xC0)
		{
			if(rx_frame == 0)
			{
				rx_frame = 1;
			}
			else if(rx_frame == 1)
			{
				rx_frame = 2;
			}
		}
		
		rx_frame_count++;
		
		if (rx_frame_count >= UART_RX_BUFFER_SIZE)
		{
			isRxBufferFull = 1;
		}
		
		if (rx_frame == 2)
		{
			rx_frame_count = 0; rx_frame = 0;
		}
	}
}

Try to write very simple program to test if C++ api is a problem. Something similar like the code you posted and execute it without RTOS - just initialize uart, attach IRQHandler and see if it works.

posted by Miloje Zecevic 25 Jun 2015