ARM Technical Support Knowledge Articles

CALLING PRINTF FROM MULTIPLE TASKS

Applies to: RTX51 Real-time Kernel

Answer


Information in this article applies to:


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
    ", (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
", (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
", (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

");
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

Article last edited on: 2005-09-22 12:28:23

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential