Keil™, An ARM® Company

Technical Support

RTX51 TINY: ADDING SEMAPHORE SUPPORT


Information in this article applies to:

  • C51 All Versions
  • C51 Version 7.04

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

FORUM THREADS

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

Last Reviewed: Sunday, October 29, 2006


Did this article provide the answer you needed?
 
Yes
No
Not Sure