ARM Technical Support Knowledge Articles

ADDING SEMAPHORE SUPPORT

Applies to: RTX51 Tiny Real-time Kernel

Answer


Information in this article applies to:


SYMPTOM

RTX51 Tiny Version 2 does not include binary semaphore or counting semaphore support. However, with a little work, you can add support for semaphores using the existing functions in the kernel.

RESOLUTION

Basically, you need a structure for each semaphore as well as a setup, get, and put function. You must define the maximum number of semaphores in MAX_SEMAPHORES.

/*---------------------------------------------------------
---------------------------------------------------------*/
#include <rtx51tny.h>

#define MAX_SEMAPHORES 4

struct sem_st
  {
  unsigned char max_count;
  unsigned char count;
  unsigned waiting_task_bits;
  };

static struct sem_st sem_tab[MAX_SEMAPHORES];

/*---------------------------------------------------------
---------------------------------------------------------*/
#pragma disable
void init_semaphore (
  unsigned char semaphore_id,
  unsigned char max_count,
  unsigned char count)
{
if (semaphore_id >= MAX_SEMAPHORES) return;

sem_tab[semaphore_id].max_count = max_count;
sem_tab[semaphore_id].count = count;
sem_tab[semaphore_id].waiting_task_bits = 0;
}

/*---------------------------------------------------------
---------------------------------------------------------*/
#pragma disable
static char _Xget_semaphore (
  unsigned char semaphore_id)
{
if (sem_tab[semaphore_id].count > 0)
  {
  --sem_tab[semaphore_id].count;
  return (-1);
  }

sem_tab[semaphore_id].waiting_task_bits |=
  (1 << os_running_task_id());

return (0);
}

/*---------------------------------------------------------
---------------------------------------------------------*/
void get_semaphore (
  unsigned char semaphore_id)
{
if (semaphore_id >= MAX_SEMAPHORES) return;

if (_Xget_semaphore (semaphore_id) == 0)
  {
  while (os_wait (K_TMO, 255, 0) != RDY_EVENT);
  }
}

/*---------------------------------------------------------
---------------------------------------------------------*/
#pragma disable
static char _Xput_semaphore (
  unsigned char semaphore_id)
{
unsigned char i;

if ((sem_tab[semaphore_id].count > 0) ||
    (sem_tab[semaphore_id].waiting_task_bits == 0))
  {
  ++sem_tab[semaphore_id].count;
  return (-1);
  }

for (i = 0; i < (sizeof(sem_tab[0].waiting_task_bits)*8); i++)
  {
  if (sem_tab[semaphore_id].waiting_task_bits & (1 << i))
    {
    sem_tab[semaphore_id].waiting_task_bits &= ~(1 << i);
    return (i);
    }
  }

return (-1);  /*** This should NEVER happen ***/
}

/*---------------------------------------------------------
---------------------------------------------------------*/
void put_semaphore (
  unsigned char semaphore_id)
{
unsigned char i;

if (semaphore_id >= MAX_SEMAPHORES) return;

if ((i=_Xput_semaphore (semaphore_id)) != -1)
  {
  os_set_ready (i);
  os_switch_task ();
  }
}

/*---------------------------------------------------------
---------------------------------------------------------*/

In your RTX51 Tiny program, you must initialize each semaphore with a maximum count and a starting count. Then, call get_semaphore to get the semaphore--your task will be blocked if no semaphore is available. Call put_semaphore when you are done with a semaphore--tasks waiting on a semaphore will be readied.

The following example shows how multiple tasks in an RTX51 Tiny program can share the 8051 on-chip UART.

/*---------------------------------------------------------
---------------------------------------------------------*/
#define USE_SEMAPHORES 1

#include <rtx51tny.h>
#include <stdio.h>
#include <reg51.h>

/*---------------------------------------------------------
---------------------------------------------------------*/
extern void get_semaphore (unsigned char);
extern void put_semaphore (unsigned char);

extern void init_semaphore (
  unsigned char semaphore_id,
  unsigned char max_count,
  unsigned char count);

/*---------------------------------------------------------
---------------------------------------------------------*/
void task_0 (void) _task_ 0
{
SCON  = 0x50;     /* SCON: mode 1, 8-bit UART, enable rcvr      */
TMOD |= 0x20;     /* TMOD: timer 1, mode 2, 8-bit reload        */
TH1   = 221;      /* TH1:  reload value for 1200 baud @ 16MHz   */
TR1   = 1;        /* TR1:  timer 1 run                          */
TI    = 1;        /* TI:   set TI to send first char of UART    */

#if USE_SEMAPHORES
init_semaphore (0, 1, 1); /*** Semaphore ID 0, Max 1, Count 1 ***/
#endif

os_create_task (1);

while (1)
  {
#if USE_SEMAPHORES
  get_semaphore (0);
#endif

  puts ("This is task 0");

#if USE_SEMAPHORES
  put_semaphore (0);
#endif
  }
}

/*---------------------------------------------------------
---------------------------------------------------------*/
void task_1 (void) _task_ 1
{
while (1)
  {
#if USE_SEMAPHORES
  get_semaphore (0);
#endif

  puts ("This is task 1");

#if USE_SEMAPHORES
  put_semaphore (0);
#endif
  }
}

/*---------------------------------------------------------
---------------------------------------------------------*/

Change the USE_SEMAPHORES macro to a value of 0 to see what happens when semaphores are not used.

Additionally, you'll have to specify the following overlay information to the BL51 Linker.

?PR?__XPUT_SEMAPHORE?SEMAPHORE ! *

MORE INFORMATION

SEE ALSO

Article last edited on: 2006-10-29 19:01:56

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