Keil Logo

RTX51 TINY: Adding Semaphore Support


Information in this article applies to:

  • C51 Version 7.04 and later

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

#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
#include
#include

/*---------------------------------------------------------
---------------------------------------------------------*/
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


Last Reviewed: Thursday, February 25, 2021


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.