RTX51: Calling PRINTF From Multiple Tasks
Information in this article applies to:
- RTX51 Version 3.10 and Later
SYMPTOMS
I'm trying to call printf from multiple tasks in my RTX51 program.
When I compile and link, I receive the following messages:
*** WARNING 15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?PRINTF?PRINTF
CALLER1: ?PR?TASK_1?MAIN
CALLER2: ?PR?TASK_2?MAIN
*** WARNING 15: MULTIPLE CALL TO SEGMENT
SEGMENT: ?PR?PRINTF?PRINTF
CALLER1: ?PR?TASK_2?MAIN
CALLER2: ?C_C51STARTUP
CAUSE
These warnings are caused because the printf function is invoked
from multiple tasks.
RESOLUTION
Using printf in multiple tasks in RTX51 requires that you do the
following:
-
Remove the printf function from the call tree analysis. Use
the following linker command to do this:
OVERLAY(?PR?PRINTF?PRINTF ! *)
-
Protect the printf function (since it is not reentrant) from
reentrancy. You can use semaphores to do this. For example:
os_wait (K_MBX + SEM_PRINTF, 255, 0); // Wait for printf semaphore
printf ("Task # %d\n", (int) os_running_task_id ());
os_send_token (SEM_PRINTF); // Done with printf semaphore
There is an example program (partially listed below) called
PFSEMA.ZIP that you may download from the Keil website (see More
Information below).
// Task Definitions
#define STARTUP_TASK 3
#define TASK1 1
#define TASK2 2
// Semaphore Definitions
#define SEM_PRINTF 8
/***
make sure to link with...
ol(?PR?PRINTF?PRINTF ! *)
***/
void setup_serial_io (void)
{
SCON = 0x50; /* SCON: mode 1, 8-bit UART, enable rcvr */
TMOD |= 0x20; /* TMOD: timer 1, mode 2, 8-bit reload */
TH1 = 0xF0; /* TH1: reload value */
TR1 = 1; /* TR1: timer 1 run */
TI = 1; /* TI: set TI to send first char of UART */
}
void task_1 (void) _task_ TASK1 _priority_ 0
{
while (1)
{
os_wait (K_IVL, 150, 0); // Delay for 250 ticks
os_wait (K_MBX + SEM_PRINTF, 255, 0); // Wait for printf
printf ("Task # %d\n", (int) os_running_task_id ());
os_send_token (SEM_PRINTF); // Done with printf
}
}
void task_2 (void) _task_ TASK2 _priority_ 1
{
while (1)
{
os_wait (K_IVL, 100, 0); // Delay for 200 ticks
os_wait (K_MBX + SEM_PRINTF, 255, 0); // Wait for printf
printf ("Task # %d\n", (int) os_running_task_id ());
os_send_token (SEM_PRINTF); // Done with printf
}
}
void startup_task (void) _task_ STARTUP_TASK _priority_ 2
{
os_set_slice (1000);
os_create_task (TASK1);
os_create_task (TASK2);
os_send_token (SEM_PRINTF); // Setup printf semaphore
os_delete_task (os_running_task_id ());
while (1)
{
/*** This should never happen ***/
}
}
void main (void)
{
setup_serial_io ();
printf ("Getting ready to start\n\n");
os_start_system (STARTUP_TASK);
while (1)
{
/*** This should never happen ***/
}
}
Download PFSEMA.ZIP from the
Keil website to get this example program.
SEE ALSO
Last Reviewed: Thursday, February 25, 2021