STM32FreeRTOS icon indicating copy to clipboard operation
STM32FreeRTOS copied to clipboard

Request printf() to multitask environment

Open nopnop2002 opened this issue 6 years ago • 8 comments

My environment: Arduino-IDE(Ver1.8.5) + stm32duino + nucleo F103RB

Source code:

	#include <STM32FreeRTOS.h>
	#include <stdarg.h>

	SemaphoreHandle_t xSemaphore;

	void _printf(const char *format, ...) {
	    xSemaphoreTake(xSemaphore, portMAX_DELAY);
	    va_list va;
	    va_start(va, format);
	//    TickType_t _nowTick = xTaskGetTickCount();
	//    char * _taskName = pcTaskGetTaskName( NULL );
	//    printf("[%s:%d] ",_taskName, _nowTick);    
	    vprintf(format, va); 
	    va_end(va);
	    xSemaphoreGive(xSemaphore);
	}

	// 時間稼ぎ(Gain time)
	void ConsumptionTick(int delay) {
	    TickType_t startTick;
	    TickType_t endTick;
	    TickType_t nowTick;
	    startTick = xTaskGetTickCount();
	    endTick = startTick + delay;
	    //printf("startTick=%d endTick=%d\n",startTick,endTick);
	    while(1) {
	      nowTick = xTaskGetTickCount();
	      if (nowTick > endTick) break;
	    }
	}

	// Task Body
	void task(void *pvParameters)
	{
	    UBaseType_t prio;
	    TickType_t nowTick;

	    prio = uxTaskPriorityGet( NULL );
	    nowTick = xTaskGetTickCount();
	    printf("[%s:%d] start Priority=%d\n",pcTaskGetName(0),nowTick,(int)prio);
	//    _printf("[%s:%d] start Priority=%d\n",pcTaskGetName(0),nowTick,(int)prio);
	    ConsumptionTick(200);
	    nowTick = xTaskGetTickCount();
	    printf("[%s:%d] end\n",pcTaskGetName(0),nowTick);
	//    _printf("[%s:%d] end\n",pcTaskGetName(0),nowTick);
	    vTaskDelete( NULL );
	}


	//------------------------------------------------------------------------------
	void setup() {
	  portBASE_TYPE xTask1, xTask2, xTask3, xTask4;

	  Serial.begin(115200);
	  Serial.println("setup() start");
	  Serial.print("configTICK_RATE_HZ:");
	  Serial.println(configTICK_RATE_HZ);
	  Serial.print("portTICK_PERIOD_MS:");
	  Serial.println(portTICK_PERIOD_MS);
	  Serial.print("freeRTOS version:");
	  Serial.println(tskKERNEL_VERSION_NUMBER);

	#if 1
	// Task1 is started in priority=2
	// Task2 is started in priority=2
	// Task3 is started in priority=2
	// Task4 is started in priority=2
	  xTask1 = xTaskCreate(task, "Task1", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
	  xTask2 = xTaskCreate(task, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
	  xTask3 = xTaskCreate(task, "Task3", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
	  xTask4 = xTaskCreate(task, "Task4", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
	#endif

	#if 0
	// Task1 is started in priority=2
	// Task2 is started in priority=3
	// Task3 is started in priority=4
	// Task4 is started in priority=5
	  xTask1 = xTaskCreate(task, "Task1", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
	  xTask2 = xTaskCreate(task, "Task2", configMINIMAL_STACK_SIZE, NULL, 3, NULL);
	  xTask3 = xTaskCreate(task, "Task3", configMINIMAL_STACK_SIZE, NULL, 4, NULL);
	  xTask4 = xTaskCreate(task, "Task4", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
	#endif

	  /* Check everything was created. */
	  configASSERT( xTask1 );
	  configASSERT( xTask2 );
	  configASSERT( xTask3 );
	  configASSERT( xTask4 );

	  /* Create Mutex for printf */
	  xSemaphore = xSemaphoreCreateMutex();
	  /* Check everything was created. */
	  configASSERT( xSemaphore );
	  
	  // start scheduler
	  Serial.println("Start Scheduler.....");
	  vTaskStartScheduler();

	#if 1
	  while (1) {
	    Serial.println("setup alive...");
	    delay(1000);
	  }
	#endif
	}

	//------------------------------------------------------------------------------
	// WARNING loop() called from vApplicationIdleHook(), so don't use this function.
	// loop must never block
	void loop() {
	  // Not used.
	}

When i used prinf(),Indication is confused.

setup() start configTICK_RATE_HZ:1000 portTICK_PERIOD_MS:1 freeRTOS version:V9.0.0 Start Scheduler..... 0] start Priority=2 rity=2 0] start Priority=2 rity=2 0] start Priority=2 0] start Priority=2 rity=2 rity=2 [Task3:218] end [Task4:225] end [Task1:230] end [Task2:238] end

When i used _print(),Indication is not confused.

setup() start configTICK_RATE_HZ=1000 portTICK_PERIOD_MS=1 Start Scheduler..... [Task1:0] start Priority=2 [Task2:1] start Priority=2 [Task3:1] start Priority=2 [Task4:1] start Priority=2 [Task1:211] end [Task2:214] end [Task3:222] end [Task4:233] end

nopnop2002 avatar Mar 22 '19 00:03 nopnop2002

Hi @nopnop2002 I guess it could be redefined for FreeRTOS. The used one is the one from newlib nano. Do not hesitate to provide a PR.

fpistm avatar Mar 22 '19 07:03 fpistm

Thank you for reply. I can't understand your English correctly,cause i'm not native. What is PR?? What shall i do??

nopnop2002 avatar Mar 22 '19 07:03 nopnop2002

PR is Pull Request. https://help.github.com/en/articles/about-pull-requests

fpistm avatar Mar 22 '19 08:03 fpistm

I understood what is PR.

nopnop2002 avatar Mar 22 '19 08:03 nopnop2002

Actually the C runtime library is not "thread-safe". When you use a shared resource, like the serial interface you use for printf() output, you have to provide your own locking/mutex mechanism to prevent this kind of issues.

And I think it might go even worse than that when multiple tasks use an MCU peripheral: the HAL framework has its "lock" mechanism but I don't know how it performs with an RTOS.

ppescher avatar Jul 18 '19 10:07 ppescher

Thanks comment. With esp-idf,printf look like "thread-safe".

nopnop2002 avatar Jul 18 '19 12:07 nopnop2002

Yes but ESP is RTOS oriented while STM32 core not

fpistm avatar Jul 18 '19 12:07 fpistm

Thanks. I understood.

nopnop2002 avatar Jul 19 '19 00:07 nopnop2002