Keil Logo

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:

  1. Remove the printf function from the call tree analysis. Use the following linker command to do this:
    OVERLAY(?PR?PRINTF?PRINTF ! *)
    
  2. 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 ***/
  }
}

MORE INFORMATION

Download PFSEMA.ZIP from the Keil website to get this example program.

SEE ALSO

FORUM THREADS

The following Discussion Forum threads may provide information related to this topic.

Last Reviewed: Thursday, September 22, 2005


Did this article provide the answer you needed?
 
Yes
No
Not Sure
 
  Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.

Change Settings

Privacy Policy Update

Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.