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 ! *
SEE ALSO
Last Reviewed: Thursday, February 25, 2021