(reference_desing documentation here)
Creating an application using GeMRTOS follows a process familiar to developers experienced with uniprocessor projects in Intel’s Quartus Prime and Platform Designer tools. The journey begins by setting up a Quartus Prime project, using the “New Project Wizard…” to simplify configuration and define essential parameters such as the target FPGA device, project directory, and top-level entity.
Alternatively, developers can leverage an existing project provided with the target FPGA development board, streamlining the setup further. This tutorial will modify an existing Platform Designer project based on Nios II or Nios V, included with the FPGA board.
The following steps assume the prerequisites are met:
- Quartus Prime installed.
- Platform Designer project with Nios II or Nios V processors targeted for the FPGA board.
These prerequisites ensure the development environment is properly set up for working with GeMRTOS and Intel’s design tools. It is important to note that configuring a system for any board simply requires specific information about that board. To avoid error-prone configurations, it is best to start development from a pre-configured design aimed at the specific board, including all necessary settings in the project.
Step 1: Check for the existence of a Quartus Prime project folder containing the GeMRTOS IP components. #
To begin the design of a GeMRTOS application using Intel’s Platform Designer within the Quartus Prime project directory, the following files and directories must be included:
The /ip subfolder contains the necessary directories including the GeMRTOS IP components required by Platform Designer (The GeMRTOS component and license can be freely downloaded here).
The essential Quartus Prime project and Platform Designer project files include:
- <quartus_project_name>.qpf: The Quartus Project file.
- <quartus_project_name>.qsf: The Quartus Project Settings file.
- <top_level_entity_file>.v or .vhd: The hardware description file containing the design description. This file can be added after the project has been created, but its association must be established during the generating process. It is typical to instantiate the embedded system created using the Platform Designer tool, including the GeMRTOS IP component, within this file.
- <platform_designer_project_name>.qsys: The Platform Designer project file.
Step 2: Modify a Platform Designer project, incorporating the GeMRTOS IP component. #
While the Quartus Prime project is active, navigate to Tools -> Platform Designer to initiate the Intel’s Platform Designer tool. This utility facilitates the creation or modification of an embedded system tailored for Intel’s FPGA devices.
Note: It is imperative that the Quartus Prime project remains open within Quartus Prime to establish the working directory as the current Quartus Prime project directory. This ensures that the Platform Designer project will be located in the designated folder. This same principle applies to executing commands in the command shell: all commands should be executed from the Quartus Prime project directory.
When “Platform Designer” is open, the GeMRTOS_Multiprocessor component is available in the GeMRTOS group in the IP Catalog Library. This integration streamlines the process and empowers you to harness the capabilities of GeMRTOS effortlessly.
The GeMRTOS_Multiprocessor component simplifies the configuration of multiprocessor system features. Aspects such as the number of processors, processor type, and processor parameters easily converge within the GeMRTOS component’s user-friendly GUI parameter setup. This consolidation captures all of the complicated features inherent in the design of a sophisticated multiprocessor system, effectively addressing problems that would otherwise necessitate much knowledge and effort.
Note: The fields labeled as "Quartus Prime project name" and "Platform Designer project name" enable the selection of default values for constructing the entire design flow using the gemrtos_build.sh script. Therefore, it is advisable to initially save the Platform Designer project and subsequently verify the chosen project names to ensure accuracy in the process.
Within the “System Contents” window, a distinctive characteristic of the GeMRTOS_Multiprocessor becomes evident. It is seamlessly interconnected, much like a “conventional” processor, featuring multiple memory buses that establish connections to various peripherals within the system. This integration facilitates a smooth and familiar interaction with peripherals, despite the underlying complexity of the GeMRTOS_Multiprocessor’s functionality.
Note: The GeMRTOS IP component offers the flexibility of utilizing two different clocks. It's crucial to ensure that all components connected to the GeMRTOS IP component share the same clock, which is connected to the "clk_external_bus" port. However, it is possible to connect the GeMRTOS processors to a different clock through the "clk_processors" port, providing an additional layer of configurability.
The GeMRTOS framework smoothly integrates interrupt handling, matching the approach of a normal uniprocessor architecture. This unique perspective enables GeMRTOS to simplify the development of multiprocessor architectures within FPGA devices, providing an intuitive avenue for implementation.
For a more beginner-friendly introduction to GeMRTOS, a direct port can be effortlessly exported to connect inputs and outputs directly to the GeMRTOS memory map registers. These outputs can serve practical purposes, such as controlling LEDs to visually represent the execution of system tasks. This approach obviates the need for intricate PIO device configuration.
To bring the entire system to life,it is imperative to initiate the generation of the “Platform Designer” project. This can be achieved by selecting the “Generate HDL…” button located in the bottom-left corner of the “System Contents” window or selecting “Generate ->Generate HDL…” from the Platform Designer menu. This project generation culminates in the creation of a component that can be seamlessly instantiated within your Quartus Prime hardware project, solidifying the integration of GeMRTOS into your FPGA design. The instantiation template for the Platform Designer system can be readily obtained by navigating to “Generate -> Show Instantiation Template…” from the Platform Designer menu.
When the Platform Designer project containing the GeMRTOS IP component is generated, the gemrtos_build.sh script is automatically generated and placed within the Quartus Prime project directory.
Step 3: Instantiate the GeMRTOS Platform Designer component into the existing Quartus Prime project. #
To prepare for hardware compilation, the Platform Designer Instantiation Template must be instantiated in the Quartus Prime project. This stage should be carried out in the same way as any other Platform Designer project to ensure a smooth integration into the Quartus Prime project.
The exported signals from the Platform Designer component must be meticulously linked to the appropriate signals in the Quartus Prime project, aligning them with the specific FPGA pins connected to the corresponding on-board devices. For instance, memory signals should be accurately assigned to the FPGA pins that interface with the memory device on the board. This meticulous signal mapping is vital to ensure proper functionality and connectivity with the hardware.
Once the Platform Designer component has been instantiated, the Quartus Prime project can be compiled by selecting “Processing -> Start Compilation” from the Quartus Prime menu. Upon completion of the compilation process, the <quartus_project_name>.sof file is generated. This file serves as the configuration hardware file for the FPGA device.
Note: To ensure the successful operation of the gemrtos_build.sh script, it is imperative to specify the output file directory as "<quartus_project_name>/output_files" subdirectory. This configuration can be achieved through the "Assignments -> Settings..." menu, where you should set the "Directory name" field to "output_files" within the "Compilation Process Settings" category in the settings window. This precise configuration is vital for the script's functionality.
Step 4: Build all the application through the gemrtos_build.sh script. #
A Platform Designer project’s generation process includes multiple configuration steps. A GeMRTOS-based system’s build flow is similar to that of any other Platform Designer project, with the addition of configuring reset and exception memory settings for the system processors. This particular setting is required to ensure appropriate operation.
As a result of the introduction of the Nios V command shell, which is based on the Windows Console, all the design flow for Nios V processor requires executing the gemrtos_build.bat script. #
The gemrtos_build.sh script automates all of the essential operations for building a GeMRTOS application, which simplifies these stages, especially for those new to GeMRTOS, and improves efficiency during the development of GeMRTOS applications. This automation simplifies the procedure and decreases the complexity of manual configuration.
The gemrtos_build.sh should be executed from the command line of the Nios Command shell from the <quartus_prime_directory_name> directory.
XXXX@XXXX:/mnt/<quartus_prime_directory_name>$ bash gemrtos_build.sh
The “gemrtos_build.sh” file is a bash script that executes all the essential steps to build a GeMRTOS application via the command line in the command shell. By default, it is set up with the parameters derived from the GeMRTOS module configuration.
- Platform Designer Project Name: The GeMRTOS component should be integrated into a Platform Designer project, and the associated .qsys file must reside in the main directory of the Quartus Prime project. The Platform Designer project name may be specified through the “Platform Designer project name” parameter in the GeMRTOS IP component’s parameter window.
- Quartus Prime Project Name: This designation identifies the Quartus Prime project in which the Platform Designer project, containing the GeMRTOS IP component, is instantiated. The Quartus Prime project name can be designated via the “Quartus Prime project name” parameter in the GeMRTOS IP component’s parameter window.
- Application project name: This determines the name of the application that the GeMRTOS multiprocessor architecture will execute. By default, a “hellogemrtos” project is created or considered within the “./software” directory, using a “hellogemrtos.c” template.
- BSP Project Name: This establishes the name for the Board Support Package (BSP) associated with the application. By default, it is produced and stored in the “hellogemrtos_bsp” subdirectory within the “./software” directory.
The execution of the “gemrtos_build” script encompasses the following steps:
- Generates the Platform Designer system, incorporating the GeMRTOS component.
- Compiles the Quartus Prime project that instantiates the Platform Designer system, leading to the creation of the “<quartus_project_name>.sof” file.
- Generates the BSP setting file and the BSP project directory, configuring memory sections for GeMRTOS processors.
- Establishes the “./software/hellogemrtos” directory, and if absent, includes the “hellogemrtos.c” template file.
- Compiles both the BSP and application projects, resulting in the creation of “hellogemrtos.elf.”
- Transfers the “<quartus_project_name>.sof” file to the FPGA utilizing the Quartus Prime Programmer tool.
- Opens terminals to establish connections with the GeMRTOS JTAG UARTs within the GeMRTOS component, encompassing a default STDIO, a default STDERR, and a JTAG UART for each system processor.
- Downloads and initiates the execution of “hellogemrtos.elf” on the target hardware.
Following these procedures, a multiprocessor application commences its execution on the FPGA device, and the connected terminals begin displaying welcome messages.
Congratulations! Your first GeMRTOS implementation is up and running successfully. This achievement marks a significant milestone in your project. If you have any further questions or require assistance with anything else, please feel free to ask.
Some final remarks: the application code. #
By default, the gemrtos_build.sh script generates two projects: “hellogemrtos” and “hellogemrtos_bsp.” These projects are located within the /software subdirectory of the <quartus_project_directory_name> directory.
The “hellogemrtos_bsp” project includes the Board Support Package (BSP) required to build the system’s Hardware Abstraction Layer (HAL).
The “hellogemrtos” project, on the other hand, is started with a template C code file called “hellogemrtos.c.” This code can be changed to meet the specific functionality of your project and serves as a starting point for an initial GeMRTOS application. You are free to edit this source file to meet your needs.
The original code within this template source file contains the following program:
/**
* \file
* \author Ricardo Cayssials
* \brief GeMRTOS dining philosophers example
* \version 0.9a
* \date 2015-2023
* \bug None known
* \copyright Ricardo Cayssials (rcayssials@gemrtos.com)
* \copyright All rights reserved.
* \copyright Copyright (c) 2013-2020
* \warning This product was produced by Ricardo Cayssials in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* \warning DISCLAIMER OF WARRANTY. THIS PRODUCT IS LICENSED "AS IS." YOU BEAR THE RISK OF USING IT.
* \warning RICARDO CAYSSIALS GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS.
* TO THE EXTENT PERMITTED UNDER APPLICABLE LAWS, RICARDO CAYSSIALS EXCLUDES ALL IMPLIED WARRANTIES,
* INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
*/
/******************************************************************************
* *
* License Agreement *
* Copyright (c) Ricardo L. Cayssials *
* All rights reserved. *
* *
******************************************************************************/
/* Include the GeMRTOS library */
#include <gemrtos.h>
// ####################################################################################
// Defining system parameters
#define NUMBER_PHILOSOPHERS 30
// ####################################################################################
// Global structure for task information storage
t_semaphore_resource *leds_sem;
/* Semaphore to exclude forks variable access */
t_semaphore_resource *forks[NUMBER_PHILOSOPHERS];
#define left_fork(i) (i)
#define right_fork(i) ((i + 1) % NUMBER_PHILOSOPHERS)
/* leds variable retains the current value written to GeMRTOS outputs */
volatile unsigned int leds;
/* Producer consumer queue for jtag_uart output*/
G_RCB *pqueue_out;
/* Producer consumer queue for jtag_uart input*/
G_RCB *pqueue_in;
/* Trigger for jtag output server */
G_RCB *jtag_uart_0_out;
/* Trigger for jtag input server */
G_RCB *jtag_uart_0_in;
/******************************************************************/
/* Signal function when task is aborted (the deadline is missed) */
/******************************************************************/
void sig_aborted_task_generic(int pdata)
{
gu_printf("\nTASK %u ABORTED\n", (unsigned int) pdata);
}
/******************************************************************/
/* Signal function when system goes to frozen mode */
/******************************************************************/
void sig_frozen_mode(int pdata)
{
gu_printf("\nSYSTEM IN FROZEN MODE %u\n", (unsigned int) pdata);
}
/******************************************************************/
/* generic task function */
/******************************************************************/
void task_philosopher(void* pdata)
{
unsigned int i = (unsigned int) pdata;
/* get the pointer to the TCB of the current task */
GS_TCB *ptcb = gu_TaskGetCurrentTCB();
/* get the semaphores in order */
if (( i & 1) == 0) { // philosopher is even
gu_SemaphoreWait(forks[left_fork(i)], (int) G_TRUE);
gu_SemaphoreWait(forks[right_fork(i)], (int) G_TRUE);
} else { // philosopher is odd
gu_SemaphoreWait(forks[right_fork(i)], (int) G_TRUE);
gu_SemaphoreWait(forks[left_fork(i)], (int) G_TRUE);
}
/* change the leds value using exclusion */
gm_SchedulingListExclusionSectionEnter;
leds = leds + 1;
/* write the value in leds variable to the GeMRTOS output port */
gm_WriteOutputs(leds);
gm_SchedulingListExclusionSectionExit;
gu_printf("%s is eating in processor %u\n", ptcb->TCB_description, (unsigned int) gm_ProcessorId);
if (i > NUMBER_PHILOSOPHERS / 2)
gu_MessageQueuePrintf(pqueue_out,"%s is eating in processor %d\n", ptcb->TCB_description, (int) gm_ProcessorId);
/* release the semaphore in order */
gu_SemaphorePost((G_RCB *) forks[left_fork(i)]);
gu_SemaphorePost((G_RCB *) forks[right_fork(i)]);
}
struct jtag_uart_info {
unsigned int trigger_out;
unsigned int trigger_in;
G_RCB *pqueue_out;
G_RCB *pqueue_in;
unsigned int buffer_length_out;
unsigned int buffer_length_in;
unsigned int jtag_base;
};
#ifdef JTAG_UART_0_BASE
void *GRTOS_IRQ_READ_SERVER_ENABLE(void * pdata)
{
PRINT_ASSERT((gm_ProcessorId == GRTOS_MTX_PRC_GRANTED), "ERROR MTX not proc=%d, mtx=%d\n",(int) gm_ProcessorId, (int) GRTOS_MTX_PRC_GRANTED);
// Enable interrupt in JTAG UART component
unsigned int status = IORD_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE);
IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE, status | ALTERA_AVALON_JTAG_UART_CONTROL_RE_MSK);
return ((void *) 0);
}
void *GRTOS_IRQ_READ_SERVER_DISABLE(void *pdata)
{
PRINT_ASSERT((gm_ProcessorId == GRTOS_MTX_PRC_GRANTED), "ERROR MTX not proc=%d, mtx=%d\n",(int) gm_ProcessorId, (int) GRTOS_MTX_PRC_GRANTED);
// Disable interrupt in JTAG UART component
unsigned int status = IORD_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE);
IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE, status & ~(ALTERA_AVALON_JTAG_UART_CONTROL_RE_MSK));
return ((void *) 0);
}
void GRTOS_IRQ_READ_SERVER(void *pdata)
{
struct jtag_uart_info * jtag_uart_0_info = (struct jtag_uart_info *) pdata;
unsigned int index_msg = 0;
unsigned int uart_data;
char *buffer_msg = (char *) malloc(jtag_uart_0_info->buffer_length_in);
PRINT_ASSERT(((unsigned int) buffer_msg % 4 == 0), "ERROR memory is not alligned");
PRINT_ASSERT(((unsigned int) buffer_msg != 0), "ERROR no memory available");
/* Get the pointer to the TCB of the current task */
GS_TCB *ptcb = gu_TaskGetCurrentTCB();
/* Define this task as an ISR associated to trigger_out jtag_uart_0_in */
gu_TriggerRegisterTask(ptcb, (G_INT32) jtag_uart_0_info->trigger_in);
while (1) {
/* wait for trigger to read the jtag buffer */
gu_TriggerWait();
while ((uart_data = IORD_ALTERA_AVALON_JTAG_UART_DATA(JTAG_UART_0_BASE)) & ALTERA_AVALON_JTAG_UART_DATA_RVALID_MSK) {
char data = (char) (uart_data & ALTERA_AVALON_JTAG_UART_DATA_DATA_MSK) >> ALTERA_AVALON_JTAG_UART_DATA_DATA_OFST;
buffer_msg[index_msg] = data;
index_msg++;
if ((data == '\r') || (data == '\n') || (index_msg >= jtag_uart_0_info->buffer_length_in - 2)) {
buffer_msg[index_msg] = '\0'; // end of string
/* Produce the message received to the queue_in */
gu_fprintf("\nINPUT FROM JTAG-UART = %s\n", buffer_msg);
gu_MessageQueuePrintf(jtag_uart_0_info->pqueue_in,"%s", buffer_msg);
index_msg = 0;
break;
}
}
}
}
void *GRTOS_IRQ_WRITE_SERVER_ENABLE(void * pdata)
{
PRINT_ASSERT((gm_ProcessorId == GRTOS_MTX_PRC_GRANTED), "ERROR MTX not proc=%d, mtx=%d\n",(int) gm_ProcessorId, (int) GRTOS_MTX_PRC_GRANTED);
// Enable interrupt in JTAG UART component
unsigned int status = IORD_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE);
IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE, status | ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK);
return ((void *) 0);
}
void *GRTOS_IRQ_WRITE_SERVER_DISABLE(void *pdata)
{
PRINT_ASSERT((gm_ProcessorId == GRTOS_MTX_PRC_GRANTED), "ERROR MTX not proc=%d, mtx=%d\n",(int) gm_ProcessorId, (int) GRTOS_MTX_PRC_GRANTED);
// Disable interrupt in JTAG UART component
unsigned int status = IORD_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE);
IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE, status & ~(ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK));
return ((void *) 0);
}
void GRTOS_IRQ_WRITE_SERVER(void *pdata)
{
struct jtag_uart_info * jtag_uart_0_info = (struct jtag_uart_info *) pdata;
/* Get a buffer to store the messaje to send to the jtag-uart */
char *buffer_msg = (char *) malloc(jtag_uart_0_info->buffer_length_out);
PRINT_ASSERT(((unsigned int) buffer_msg % 4 == 0), "ERROR memory is not alligned");
PRINT_ASSERT(((unsigned int) buffer_msg != 0), "ERROR no memory available");
int size;
unsigned int index_msg;
/* Get the pointer to the TCB of the current task */
GS_TCB *ptcb = gu_TaskGetCurrentTCB();
/* Define this task as an ISR associated to trigger_out jtag_uart_0_out */
gu_TriggerRegisterTask(ptcb, (G_INT32) jtag_uart_0_info->trigger_out);
while (1) {
/* receive next message from producer/consumer queue */
size = gu_MessageQueueReceive(jtag_uart_0_info->pqueue_out, (void *) buffer_msg, jtag_uart_0_info->buffer_length_out);
/* Iterate for each character of the message, but the ending '\0' */
index_msg = 0;
while (index_msg < size-1)
{
// int space_fifo;
/* Get the available space in jtag uart buffer */
int space_fifo = (((G_INT32) IORD_ALTERA_AVALON_JTAG_UART_CONTROL(jtag_uart_0_info->jtag_base)) & ((G_INT32) ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK )) >> ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_OFST;
// if (space_fifo > size) space_fifo = size - 2;
/* Send as many characters up to the end of message or as possible to jtag uart */
while (space_fifo > 0 && index_msg < size-1)
{
PRINT_ASSERT((buffer_msg[index_msg] != '\0'), "Error char zero=%d", (int) buffer_msg[index_msg]);
/* write next message character to jtag uart output fifo */
IOWR_ALTERA_AVALON_JTAG_UART_DATA(jtag_uart_0_info->jtag_base, buffer_msg[index_msg]);
/* Update iteration variables */
index_msg++;
space_fifo--;
}
/* There exist more character to send, so wait to next trigger_out from jtag device */
if (index_msg < size-1) {
gu_TriggerWait();
}
}
};
}
/* This function is the ISR for the jtag uart named "jtag_uart_0_out" */
void jtag_irq_manager(int pdata)
{
/* Read the state of interrupt flags from the JTAG UART status register */
volatile G_INT32 uart_ctrl_register = (G_INT32) IORD_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE);
/* Get the state of the write interrupt (output buffer empty) */
volatile G_INT32 write_interrupt = (uart_ctrl_register & ((G_INT32) ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK )) >> ALTERA_AVALON_JTAG_UART_CONTROL_WI_OFST;
/* Get the state of the read interrupt (input buffer full) */
volatile G_INT32 read_interrupt = (uart_ctrl_register & ((G_INT32) ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK )) >> ALTERA_AVALON_JTAG_UART_CONTROL_RI_OFST;
/* If write interrupt is on, the release the output server trigger_out */
if ((write_interrupt == (G_INT32) 1) && (jtag_uart_0_out->trigger.TRG_Enabled == G_TRUE)) {
PRINT_ASSERT((jtag_uart_0_out->trigger.TRG_Enabled == G_TRUE),"ERROR trigger write is not enabled\n");
gu_TriggerRelease ((int) jtag_uart_0_out);
}
/* If write interrupt is on, the release the output server trigger_in */
if ((read_interrupt == (G_INT32) 1) && (jtag_uart_0_in->trigger.TRG_Enabled == G_TRUE)) {
PRINT_ASSERT((jtag_uart_0_in->trigger.TRG_Enabled == G_TRUE),"ERROR trigger read is not enabled\n");
gu_TriggerRelease ((int) jtag_uart_0_in);
}
PRINT_ASSERT(((write_interrupt == (G_INT32) 1) || (read_interrupt == (G_INT32) 1)),"ERROR not interrupt triggering");
}
#endif
int main(void)
{
/* ################################################### */
/* main variable definition */
/* ################################################### */
GS_TCB *ptcb;
/* Create a semaphore for LEDS */
leds_sem = gu_SemaphoreCreate((int) 1);
/* Create semaphores for forks */
for (int i = 0; i < NUMBER_PHILOSOPHERS; i++) {
forks[i] = gu_SemaphoreCreate((int) 1);
}
// Create the philosopher
for (unsigned int i = 0; i < NUMBER_PHILOSOPHERS; i++)
{
/* Create a new Task */
ptcb = gu_TaskCreate((void *) task_philosopher, ///< Pointer to the task code
(void *) i, ///< Pointer to the argument of first call
"task %d", i);
if (ptcb != (void *) 0) { /* Task was created successfully */
/* Set the task as periodic */
gu_TaskTypeSet(ptcb, G_TCBType_PERIODIC);
/* Set the task priority equal to the task index plus one */
gu_TaskReadyPrioritySet(ptcb, (G_INT64) i+1);
gu_TaskRunPrioritySet(ptcb,(G_INT64) i+1);
/* Set the period equal to the task index plus one in seconds */
gu_TaskPeriodSet(ptcb, 0, 0, 1, (i+1) * 100);
/* Start execution of task with an offset equal to five seconds */
gu_TaskStartWithOffset(ptcb, 0, 0, 5, 0);
// Signal when task is aborted because of deadline
gu_SignalCreate(G_SCBType_TCB_ABORTED, 0, (void *) ptcb, (void *) sig_aborted_task_generic, (void *) i);
}
else {
gu_printf("Error when creating task\n");
while(1);
}
}
gu_SignalCreate(G_SCBType_FROZEN_MODE, 0, (void *) 0, (void *) sig_frozen_mode, (void *) 0);
#ifdef JTAG_UART_0_BASE
/* Create a message queue for JTAG-UART jtag_uart_0 output */
pqueue_out = gu_MessageQueueCreate();
/* Create a message queue for JTAG-UART jtag_uart_0 input */
pqueue_in = gu_MessageQueueCreate();
/* Create a trigger_out for JTAG UART writting */
/* -1 because it is not associated with hardware interrupt */
jtag_uart_0_out = gu_TriggerCreate(-1);
PRINT_ASSERT((gkm_RCB_IsValid(jtag_uart_0_out) == G_TRUE),"ERROR ECB not valid\n");
/* Create a trigger_in for JTAG UART reading */
/* -1 because it is not associated with hardware interrupt */
jtag_uart_0_in = gu_TriggerCreate(-1);
PRINT_ASSERT((gkm_RCB_IsValid(jtag_uart_0_in) == G_TRUE),"ERROR ECB not valid\n");
/* create a jtag_uart_info structure to store the information for output server consumer */
struct jtag_uart_info *jtag_uart_0_info = (struct jtag_uart_info *) malloc(sizeof(struct jtag_uart_info));
/* set the parameter for jtag output server configuration.
The pointer to this structure is pass as reference to the task */
jtag_uart_0_info->pqueue_out = pqueue_out;
jtag_uart_0_info->pqueue_in = pqueue_in;
jtag_uart_0_info->trigger_out = (unsigned int) jtag_uart_0_out;
jtag_uart_0_info->trigger_in = (unsigned int) jtag_uart_0_in;
jtag_uart_0_info->buffer_length_in = 100;
jtag_uart_0_info->buffer_length_out = 100;
jtag_uart_0_info->jtag_base = JTAG_UART_0_BASE;
/* Creatse task for jtag output server */
ptcb = gu_TaskCreate((void *) GRTOS_IRQ_WRITE_SERVER,
(void *) jtag_uart_0_info,
"GRTOS_IRQ_WRITE_SERVER");
if (ptcb != (void *) 0)
{
gu_TaskTypeSet(ptcb, G_TCBType_OneShot);
// gu_SchedulingListAssociateTask(ptcb, (struct gs_lcb *) pedf_list);
gu_TaskReadyPrioritySet(ptcb, (G_INT64) 0);
gu_TaskRunPrioritySet(ptcb, (G_INT64) 0);
gu_TaskPeriodSet(ptcb, 0, 0, 1, 1);
/* Start execution of task with an offset */
gu_TaskStartWithOffset(ptcb, 0, 0, 5, 0);
}
/* suscribe task as consumer to the consumer/producer queue */
gu_MessageQueueSubscribe(ptcb, pqueue_out);
/* Set the jtag output server hooks */
gu_TriggerEnableHook((int) jtag_uart_0_out, (void *) GRTOS_IRQ_WRITE_SERVER_ENABLE, (void *) NULL);
gu_TriggerDisableHook((int) jtag_uart_0_out, (void *) GRTOS_IRQ_WRITE_SERVER_DISABLE, (void *) NULL);
/* Creatse task for jtag output server */
ptcb = gu_TaskCreate((void *) GRTOS_IRQ_READ_SERVER,
(void *) jtag_uart_0_info,
"GRTOS_IRQ_READ_SERVER");
if (ptcb != (void *) 0)
{
gu_TaskTypeSet(ptcb, G_TCBType_OneShot);
// gu_SchedulingListAssociateTask(ptcb, (struct gs_lcb *) pedf_list);
gu_TaskReadyPrioritySet(ptcb, (G_INT64) 0);
gu_TaskRunPrioritySet(ptcb, (G_INT64) 0);
gu_TaskPeriodSet(ptcb, 0, 0, 1, 1);
/* Start execution of task with an offset */
gu_TaskStartWithOffset(ptcb, 0, 0, 5, 0);
}
/* Set the jtag output server hooks */
gu_TriggerEnableHook((int) jtag_uart_0_in, (void *) GRTOS_IRQ_READ_SERVER_ENABLE, (void *) NULL);
gu_TriggerDisableHook((int) jtag_uart_0_in, (void *) GRTOS_IRQ_READ_SERVER_DISABLE, (void *) NULL);
// 22-03-2024 ####################################
// #################################
/* Create a ISR task for jtag uart hardware interrupt */
ptcb = gu_TaskCreate((void *) jtag_irq_manager,
(void *) 5,
"jtag_irq_manager");
PRINT_ASSERT((gkm_TCB_IsValid(ptcb) == G_TRUE),"ERROR TCB is not valid\n");
if (ptcb != (void *) 0)
{
gu_TaskTypeSet(ptcb, G_TCBType_OneShot);
// gu_SchedulingListAssociateTask(ptcb, (struct gs_lcb *) pedf_list);
gu_TaskReadyPrioritySet(ptcb, (G_INT64) 0);
gu_TaskRunPrioritySet(ptcb, (G_INT64) 0);
gu_TaskPeriodSet(ptcb, 0, 0, 1, 1);
}
/* Associate the task to be triggered with the jtag uart interrupt */
gu_TriggerRegisterTask(ptcb, (int) JTAG_UART_0_IRQ);
gu_TriggerEnable((int) JTAG_UART_0_IRQ);
#endif
return (0);
}