EX9: Semaphore example#
This exercise will demonstrate the use of semaphores.
The learning outcome of this problem is to:
Be able to use a semaphore to:
protect a shared resource, and
synchronize to tasks.
Synchronization of tasks#
In the example above the semaphore was used to protect the access to a shared resource. In addition a semaphore can also be used to synchronize the execution of a task with another task or event. In Section 3.6 we implemented interrupt handling for an external push button. In this case we can make use of a semaphore to execture a task every time the push button generates is pressed.
When used for synchronization a semaphore must be initialize to 0, and then made available (posted) from the interrupt handling routine on an active interrupt. The task being synchronized to the interrupt must wait for the semaphore (pend).
Your task will now be to synchronize task1 from the example above with the interrupt generated by the push button. Try to solve the problem by yourself before you look at the solution example below.
Complete code example
#include <stdio.h>
#include "includes.h"
#include <string.h>
#include "altera_avalon_pio_regs.h" //access to PIO macros
#define TASK_STACKSIZE 1024 // Number of 32 bit words (e.g. 8192 bytes)
OS_STK task1_stk[TASK_STACKSIZE];
OS_STK task2_stk[TASK_STACKSIZE];
#define TASK1_PRIORITY 4
#define TASK2_PRIORITY 5
//Semaphore to protect the shared JTAG resource
OS_EVENT *shared_jtag_sem;
//Synchronization semaphore
OS_EVENT *shared_key1_sem;
//Gobal variable to hold the value of the edge capture register.
volatile int edge_capture;
//The interrupt service routine
static void handle_interrupts(void* context)
{
//Cast context to edge_capture's type
//Volatile to avoid compiler optimization
//this will point to the edge_capture variable.
volatile int* edge_capture_ptr = (volatile int*) context;
//Read the edge capture register on the PIO and store the value
//The value will be stored in the edge_capture variable and accessible
//from other parts of the code.
*edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(PIO_IRQ_BASE);
//Write to edge capture register to reset it
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_IRQ_BASE,0);
// Post the semaphore to synchronize with task1
OSSemPost(shared_key1_sem);
}
// Register the interrupt with the CPU
static void init_interrupts()
{
//Recast the edge_capture point to match the
//alt_irq_register() function prototypo
void* edge_capture_ptr = (void*)&edge_capture;
//In this case we enable only the interrupt connected to the push button
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(PIO_IRQ_BASE,0x1);
//Reset the edge capture register
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_IRQ_BASE,0);
//Register the interrupt handler in the system
//The ID and PIO_IRQ number is available from the system.h file.
alt_ic_isr_register(PIO_IRQ_IRQ_INTERRUPT_CONTROLLER_ID,
PIO_IRQ_IRQ, handle_interrupts, edge_capture_ptr, 0x0);
}
void task1(void* pdata)
{
char text[] = "Hello from Task1 on interrupt!\n";
int i;
alt_u8 error_code = OS_ERR_NONE;
while (1)
{
// Wait for the sempahore from interrupt handling routine before executing the task
OSSemPend(shared_key1_sem,0,&error_code);
// Collect semaphore before writing to JTAG UART
OSSemPend(shared_jtag_sem,0,&error_code);
for (i = 0; i < strlen(text); i++){
putchar(text[i]);
}
// Release semaphore
OSSemPost(shared_jtag_sem);
//printf("Hello from task2\n");
// The task will only be exectuted when the semaphore is available.
// The PEND function will make sure that the task is blocked
// and the OSTimeDlyHMSM is no longer needed.
//OSTimeDlyHMSM(0, 0, 0, 20);
}
}
void task2(void* pdata)
{
char text[] = "Hello from Task2\n";
int i;
alt_u8 error_code = OS_ERR_NONE;
while (1)
{
// Collect semaphore before writing to JTAG UART
OSSemPend(shared_jtag_sem,0,&error_code);
for (i = 0; i < strlen(text); i++){
putchar(text[i]);
}
// Release semaphore
OSSemPost(shared_jtag_sem);
//printf("Hello from task2\n");
OSTimeDlyHMSM(0, 0, 0, 4);
}
}
/* The main function creates two task and starts multi-tasking */
int main(void)
{
//create JTAG semaphore and initialize to 1
shared_jtag_sem = OSSemCreate(1);
//create synchronization semaphore and initialize to 0
shared_key1_sem = OSSemCreate(0);
//Initialize interrupt
init_interrupts();
OSTaskCreateExt(task1,
NULL,
(void *)&task1_stk[TASK_STACKSIZE-1],
TASK1_PRIORITY,
TASK1_PRIORITY,
task1_stk,
TASK_STACKSIZE,
NULL,
0);
OSTaskCreateExt(task2,
NULL,
(void *)&task2_stk[TASK_STACKSIZE-1],
TASK2_PRIORITY,
TASK2_PRIORITY,
task2_stk,
TASK_STACKSIZE,
NULL,
0);
OSStart();
return 0;
}