BF706 UART Driver Callback is not invoked

I am running UART Driver for ADI BF706 with FreeRTOS.

I ported the ADI sample code for UART DMA option and the initialization and TX works fine on my board when I run the code in the main() function before all my FreeRTOS tasks are created. The UART TX can submit buffer and enable TX, the callback is invoked with success event and my transmission completed successfully.

However, if I move the same code under a task created with:
xTaskCreate(vUARTTask, “UART_Handling_task”, 4000, (void*) xV1, 2, &xUARTTask_HANDLE);

The UART callback is no longer invoked and thus my UART TX is not successful.

Does anyone know what could be the issue for this?

Thanks,
Jonathan

Hello @wu_yongjian
You should add some more context information others should know to give an answer.
What’s your MCU and which FreeRTOS port ? Which FreeRTOS version ? Maybe which SDK/3rd party libraries ?
Just a wild guess: Is xUARTTask_HANDLE a local/stack variable in main ?
In case it’s e.g. a Cortex-M MCU this won’t work because the main stack is re-used as ISR stack after starting the scheduler and all main local stack data is discarded.
You might change it to a static variable and retry.
Edit See this page: https://www.freertos.org/FAQHelp.html and search for “main() stack” for details.

Thank you Hartmut for the response. Here is more details about the background of my FreeRTOS port:

MCU: Analog Device Blackfin 706 come with the FreeRTOS port with Analog Device Cross Core Embedded Studio v2.10.0.0
FreeRTOS: FreeRTOS Kernel V10.0.0

static xUARTTask_HANDLE is defined as static local global variable
TaskHandle_t xUARTTask_HANDLE = NULL;

The main() and UARTTask code are below. I am currently enabled the UART code in main thread and it is working. As soon as I move to UART task (by switching the #if 1/0 in the code), it stops working due to transmission done interrupt callback is no longer invoked.

Do you have some more suggestions?

Thanks,
Jonathan

int main( void )
{
	int16_t outputCount;
    uint32_t numCallbacks;

	/* Initialize managed drivers and/or services */
	adi_initComponents();

	/* The queue is created to hold a maximum of 5 long values. */
    xQueue = xQueueCreate( 5, sizeof( int32_t ) );
    xUARTReceivingQueue = xQueueCreate( 20, sizeof( int32_t ) );	// Create the UART receiving queue.

	if ((xQueue != NULL) && (xUARTReceivingQueue != NULL))
	{
		//
		// QUEUE TRANSMITS INTERUPT VECTOR TABLE  OFFSET
		vPrintString("Periodic tasks created\r\n");
		xTaskCreate(vUARTTask, "UART_Handling_task", 4000, (void*) xV1, 2, &xUARTTask_HANDLE); // UART RX/TX
	}
	else
		 vPrintString("Queue could not be created\r\n");

#if 1
	 usart_init( 9600 );
	// Sample transmission on UART0
	usart_tx(0, testdata, 10);
	/* End of testing UART transmission */

	usart_tx(0, testdata, 10);
	/* End of testing UART transmission */

	usart_tx(0, testdata, 10);
	/* End of testing UART transmission */
#endif

	Create_Task();
	/* End of ADI sample code invoke */

	/* Start the scheduler so the created tasks start executing. */
	    vPrintString("Scheduler started\r\n");
		vTaskStartScheduler();
		
	for( ;; ) // INFINITE LOOP
	return 0;
}

static void vUARTTask( void *pvParameters )
{
	int16_t outputCount = 10;
	BaseType_t xStatus;
	int32_t lReceivedValue; // value to br recieved from Queue

#if 0
	 usart_init( 9600 );
	// Sample transmission on UART0
	usart_tx(0, testdata, 10);
	/* End of testing UART transmission */

	usart_tx(0, testdata, 10);
	/* End of testing UART transmission */

	usart_tx(0, testdata, 10);
	/* End of testing UART transmission */
#endif

	for( ;; ) // INFINITE LOOP
	{
		// Block on the receive for 1 second
		xStatus = xQueueReceive( xUARTReceivingQueue, &lReceivedValue, pdMS_TO_TICKS( 1000UL ) );

		if (xStatus == pdPASS) // QUEUE PEND OVER AND SUCCESSFUL
		{
			// Perform action to send the string to UART output.
			// vPrintStringAndNumber("UART Task Received = ", lReceivedValue); // successful read
			vPrintString( messageBuffer[lReceivedValue]);
		}
	}
}

I guess also xUARTReceivingQueue and xQueue are static or global variables, right ?
What about the local variables on main stack ?

int16_t outputCount;
uint32_t numCallbacks;

As mentioned those variables are probably not longer valid and might get overwritten after starting the scheduler. Even though I’m not familiar with the ADI Blackfin port I found that it supports a user and and a supervisor stack pointer similar to the Cortex-M CPUs. Hence I guess also with this port the main (or supervisor stack) gets reused, too.
Do you have a debugger attached to verify that the ISR (callback) is not longer invoked or do you verify that by checking the numCallbacks variable ?
I’d propose to make also those variables static or global and retry.
BTW are you familiar with FreeRTOS or is it your 1st FreeRTOS application ?

Thanks you Hartmut.

First of all, this is indeed my first application with FreeRTOS. So it is bit challenging for me even though I have couple other RTOS experiences. FreeRTOS is first one.

I did move:
int16_t outputCount;
uint32_t numCallbacks;
to static global and that didn’t help. I am still facing the same issue that the UARTcallback is not invoked.

I have JTAG debugger attached and I can watch break point hit (for both ADI_UART_EVENT_TX_BUFFER_PROCESSED and ADI_UART_EVENT_TX_COMPLETE) in UARTCallback while executing in main(). When in UART task, the break point hit once for ADI_UART_EVENT_TX_BUFFER_PROCESSED. but the ADI_UART_EVENT_TX_COMPLETE event never come back.

I wonder if it is true that the main() executes in supervisor mode and the created task such as UART Task executes in user mode? If that is the case, should I get an error in UART driver calls for accessing supervisor privileged registers?

Thanks again for your suggestions.

Best,
Jonathan

So at least there is an (1) interrupt invoking the callback :slight_smile:
Usually there is no difference running code from main or from task context. But I’m not familiar with the vendor specific ADI Blackfin port…
When in doubt that the UART HW is properly setup when done in task context I’d compare the HW settings when done in main against the status after invoking usart_init in task context using the debugger. I guess it’s possible to view the UART controller registers.
Or just step through the usart_init code (in main and in task) to see what’s going on and compare and also the ISR/callback code. Given the uart driver is known to work seamlessly with FreeRTOS.
I hope you get some support and documentation from ADI regarding their Blackfin port or have access to a demo application to get your application running, too :+1:

1 Like

Can you compare the callstack in both the cases? Also, can this be related - https://ez.analog.com/dsp/software-and-development-tools/cces/f/q-a/67637/uart-api-driver-for-bf70x-callback-events?

Thanks Hartmut.

Yes, this looks like very specific to Analog Device’s Blackfin port. I am contacting their Tech support and hope to get a solution soon.

Best,
Jonathan

Thank you Gaurav:

Yeah, it sounds similar to what is described in your link.

I am contacting Analog Device to get help. It is more likely that specific port has some subtle difference when UART is executing in main thread and a FreeRTOS task.

Thanks,
Jonathan

unlikely, imho. I would focus on what Hartmut suggested earlier, ie a race condition in the init sequence that leaves the peripheral in a different state. Remember that the second task you dispatch runs concurrently with the task that dispatched it, so if all of a sudden two init sequences interleave instead of running sequentially, everything can happen.

The usual strategy to debug this is is to compare the SFR register sets in both scenarios and then look closer at what instruction sequence can account for the deltas. Also, if it happens that a long delay at the beginning of your secondary thread solves the problem, it is a strong hint towards that (not that I would ever recommend delays for working code, only for debugging aids).