Request printf() to multitask environment
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
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.
Thank you for reply. I can't understand your English correctly,cause i'm not native. What is PR?? What shall i do??
PR is Pull Request. https://help.github.com/en/articles/about-pull-requests
I understood what is PR.
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.
Thanks comment. With esp-idf,printf look like "thread-safe".
Yes but ESP is RTOS oriented while STM32 core not
Thanks. I understood.