# Assignment 1 - Embedded Systems Design

# Takes from Assignment 1 brief

# Introduction

A frequency relay is a device designed to accurately detect abnormal power frequency and react quickly by tripping or reconnecting loads in an attempt to maintain a stable network frequency.


A low-cost frequency relay (LCFR), which is the target of this assignment, is aimed at smaller individual consumers. It is capable of measuring the frequency in real-time and tripping or reconnecting the loads within the consumer scope, for example by controlling all individual sub-circuits in the home.

# Objective

The LCFR is a system that interfaces directly with the power network to measure current frequency and is able to switch on and off loads by using triacs (Triode for Alternating Current).


A part of the device must use digital signal processing algorithms to prepare information for frequency and its rate of change calculation. This can be done by the use of these algorithms implemented in digital hardware or by using very fast and expensive processors. In our case, we opted for a hardware-implemented unit for frequency calculation. The remaining tasks of the LCFR are performed using software running on an embedded processor.


The assignment is focused on the integration of the hardware part into the software environment and then the implementation of all functions of the LCFR that can be implemented in software.


The aim of this assignment is the implementation of the application software of a frequency relay, targeted for use in normal households. The software will control load tripping according to the measured frequency of the power network.

# Conceptual design

  1. Hardware Interface: The hardware interface consists of the FPGA on the DE2-115 development board and the LCFR circuitry. The FPGA is responsible for implementing digital signal processing algorithms to measure the frequency and rate of change of the power supply. The LCFR circuitry is responsible for switching loads on and off using triacs based on the measured frequency.

ASS1

  1. Software Interface: The software interface consists of the FreeRTOS real-time operating system and the application software written in C. The FreeRTOS provides a multitasking environment for the concurrent execution of tasks, while the application software performs the load-tripping control based on the measured frequency.

  2. Task Partitioning: The application software is partitioned into concurrent tasks, each with a specific purpose. The tasks can be divided as follows:

  • Frequency Measurement Task: This task is responsible for continuously measuring the frequency and rate of change of the power supply using the digital signal processing algorithms implemented in hardware.

  • Tripping Control Task: This task is responsible for monitoring the frequency measurements and controlling the triacs to switch loads on and off based on the measured frequency.

  • User Interface Task: This task is responsible for providing a user interface to interact with the system, such as displaying the measured frequency and load status.


ASS1

  1. Synchronization and Communication: The tasks need to communicate and synchronize with each other to ensure the proper functioning of the system. For example, the Tripping Control Task needs to communicate with the Frequency Measurement Task to obtain the measured frequency, and with the User Interface Task to display the load status.

  2. Memory-Mapped Devices: The system also needs to interface with memory-mapped devices to access physical inputs and outputs. For example, the system can interface with a temperature sensor to monitor the temperature of the system, or with a relay to control the power supply.

Overall, this conceptual design demonstrates the integration of hardware and software components to achieve a functional real-time embedded system for load control frequency relay.

Frequency analyzer

For the frequency analyzer part we can use the example given by the LAB here.

# Literature review

# Background

Based on simulated frequency responses (shown in Fig. 1), [1] demonstrates that the system response is not significantly degraded by the delay inherent in the frequency measurement algorithm, assuming instantaneous load shedding or load shedding delayed by the measurement algorithm, with a 100 ms allowance for relay operation. Therefore we can assume the reliability of the system based on the measurements made with an FPGA, which with faster than a single-chip microcomputer used by [1]. His device could be used to shed off-peak load, thus replacing expensive emergency reserves over the corresponding periods.


 D. J. Morrow, B. Fox and P. T. Toner

In his relay schematic diagram, [1] includes a stage for "Signal isolation and conditioning" (refer to Fig. 2). We believe that having an isolation and conditioning phase in the design is crucial, even if it results in higher system costs.


 D. J. Morrow, B. Fox and P. T. Toner

# Design


VIEIRA et al.: PERFORMANCE OF FREQUENCY RELAYS

# References

[1] - D. J. Morrow, B. Fox and P. T. Toner, "Low-cost under-frequency relay for distributed load shedding," 1991 Third International Conference on Power System Monitoring and Control, London, UK, 1991, pp. 273-275.

[2] - J. C. M. Vieira, W. Freitas, Wilsun Xu and A. Morelato, "Performance of frequency relays for distributed generation protection," in IEEE Transactions on Power Delivery, vol. 21, no. 3, pp. 1120-1127, July 2006, doi: 10.1109/TPWRD.2005.858751.

[3] - Z. Salcic, S. Kiong Nguang and Y. Wu, "An Improved Taylor Method for Frequency Measurement in Power Systems," in IEEE Transactions on Instrumentation and Measurement, vol. 58, no. 9, pp. 3288-3294, Sept. 2009, doi: 10.1109/TIM.2009.2022377.

# Class 7 - Wed 22 March 2023

# Assignment


 Assignment 1

Frequency delays connect and disconnect devices automatically. It is disconnecting the load and in that way helps the overall network to reduce the load and increase the frequency in the network.

The first major problem is measuring frequency in power systems.


Period is 150Mhz=20ms\frac{1}{50Mhz} = 20 ms


Voltage changes with time and is not just represented by sine waveforms, which is ideal.


Below 49 shed some loads, reinstated above 49.5 connect loads. Also, rate of change.


 Assignment 1

Hard real-time requirements:

  • The frequency relay must shed load within 200 ms since the detection of violation of frequency level of rate of change.

Other ideas for the project

other functions useful: a push button to change between modes

normal mode which measures the frequencies sheds the loads and so on

maintenance mode

# ISRs

peaks of the sources of interacts

keyboard - enter values of threshold - frequency and rate of change

push button, which changes the mode


 Assignment 1

# Implementation

# Implementation Plan

To implement the described frequency relay system on the DE2-115 board, you can follow these steps:

  1. Set up the DE2-115 board and connect the required peripherals (switches, LEDs, VGA display, and push button).

  2. Create a main.c file and include the necessary libraries for the DE2-115 board, such as Altera's libraries for I/O, VGA display, timer, etc., and FreeRTOS libraries.

  3. Define global variables and shared resources, such as:

    • Instantaneous frequency
    • Rate of change of frequency
    • Load status
    • Network stability status
    • Relay state (normal, managing, or maintenance)
    • Timing measurements
    • Mutexes for shared resources
  4. Implement tasks and ISRs:

    • Task 1: Monitor frequency and rate of change of frequency
    • Task 2: Manage loads based on network stability and priority
    • Task 3: Update VGA display with frequency relay information
    • ISR 1: Handle user inputs (slide switches and push button)
    • ISR 2: Timer interrupt for measuring time intervals
  5. In the main function:

    • Initialize the board, peripherals, and FreeRTOS components (tasks, ISRs, mutexes, etc.).
    • Start the FreeRTOS scheduler.
  6. Implement Task 1 to monitor the frequency and rate of change of frequency:

    • Continuously measure the instantaneous frequency and rate of change of frequency.
    • Update the global variables for instantaneous frequency and rate of change of frequency.
    • Signal the other tasks or ISRs if the network status changes (e.g., using FreeRTOS event groups).
  7. Implement Task 2 to manage loads:

    • Monitor network stability status and relay state.
    • Perform load shedding or reconnection based on the network stability, priority, and relay state.
    • Update the LED states according to the load status and relay state.
  8. Implement Task 3 to update the VGA display:

    • Periodically read the shared variables and display the relay information on the VGA screen.
    • Use mutexes for accessing shared resources to ensure mutual exclusion.
  9. Implement ISR 1 to handle user inputs:

    • Detect slide switch position changes and update the corresponding load status.
    • Detect push button press to toggle the relay state between normal and maintenance.
    • Use mutexes for accessing shared resources to ensure mutual exclusion.
  10. Implement ISR 2 for timer interrupt:

    • Use the FreeRTOS timer service to generate periodic interrupts for measuring time intervals.
    • Update the timing measurements in the ISR.
    • Signal the other tasks or ISRs if a timing-related event occurs.
  11. Compile the code, load it onto the DE2-115 board, and test the implemented frequency relay system.

Following these steps should provide a functional implementation of the described frequency relay system on the DE2-115 board using FreeRTOS. Remember to use FreeRTOS features for task synchronization and communication, such as mutexes, event groups, and queues, and justify their use in your design.

# 1. Set up the DE2-115 board and connect the required peripherals (switches, LEDs, VGA display, and push button).✅

The digital design is provided in the form of a .sof programming file To program the Cyclone IV on the DE2 115, start Quartus from the Altera submenu of the Start menu. Connect the DE2 115 board with power and ensure the USB cable is connected to the port labeled “BLASTER” on the board. Select “Programmer” from the “Tools” menu to open up the programmer as shown below.


DE2-115-LAB

Click the “Hardware Setup” button to make sure the currently selected hardware is USB Blaster as shown in Figure 1 2. If this is not the case, select USB Blaster from the Available hardware items list, click the “Add Hardware” button and close the dialog. If USB Blaster is not present in the list, then the board may not be connected properly or your computer may not have the correct drivers installed.


DE2-115-LAB

Click on the “Add File” or “Change File” button on the left of the Programmer dialog to include freq_relay_controller.sof and tick the box under "Program/Configure”. Then click the Start button to download the hardware design to the DE2 115 board. The progress of the download is displayed on the progress bar. Now you are ready to start the software implementation of the Nios II system.


DE2-115-LAB

# 2. Create a main.c file and include the necessary libraries for the DE2-115 board, such as Altera's libraries for I/O, VGA display, timer, etc., and FreeRTOS libraries. ✅

Create a new Nios II application project (called frequency_relay ) in addition to an associated BSP - Board Support Package (called frequency_relay_bsp). Make sure you remove any C files that may be generated for you in the application project directory to prevent errors due to an existing definition of a main function.

Starting with the BSP we upload the "nios2.sopcinfo" file.


Frequency-Relay


Frequency-Relay

Now we create the project based on the BSP created before.


Frequency-Relay

Now we create the main.c file and copy the freertos folder to the project folder.


Frequency-Relay

Pass the code below to the main.c file, refresh the project and build.

Graphviz
digraph frequency_relay_system {
    rankdir=LR;
    node [shape=box, style="rounded,filled", fillcolor=white];

    subgraph cluster_tasks {
        label = "Tasks";
        task1 [label="Task 1:\nMonitor frequency\nand RoC"];
        task2 [label="Task 2:\nManage loads"];
        task3 [label="Task 3:\nUpdate VGA display"];
    }

    subgraph cluster_isrs {
        label = "Interrupt Service Routines";
        isr1 [label="ISR 1:\nHandle user inputs"];
        isr2 [label="ISR 2:\nTimer interrupt"];
    }

    subgraph cluster_shared_resources {
        label = "Shared Resources";
        inst_freq [label="Instantaneous frequency"];
        roc_freq [label="Rate of change of frequency"];
        load_status [label="Load status"];
        net_stability [label="Network stability status"];
        relay_state [label="Relay state"];
        timing_meas [label="Timing measurements"];
        mutexes [label="Mutexes"];
    }

    subgraph cluster_peripherals {
        label = "Peripherals";
        switches [label="Slide switches"];
        leds [label="Red/Green LEDs"];
        vga_display [label="VGA display"];
        push_button [label="Push button"];
    }

    task1 -> inst_freq [label="read/write"];
    task1 -> roc_freq [label="read/write"];
    task1 -> net_stability [label="read/write"];

    task2 -> net_stability [label="read"];
    task2 -> relay_state [label="read"];
    task2 -> load_status [label="read/write"];
    task2 -> leds [label="control"];

    task3 -> inst_freq [label="read"];
    task3 -> roc_freq [label="read"];
    task3 -> load_status [label="read"];
    task3 -> net_stability [label="read"];
    task3 -> relay_state [label="read"];
    task3 -> timing_meas [label="read"];
    task3 -> vga_display [label="control"];

    isr1 -> switches [label="read"];
    isr1 -> push_button [label="read"];
    isr1 -> relay_state [label="read/write"];
    isr1 -> load_status [label="read/write"];

    isr2 -> timing_meas [label="read/write"];

    inst_freq -> mutexes [label="protected"];
    roc_freq -> mutexes [label="protected"];
    load_status -> mutexes [label="protected"];
    net_stability -> mutexes [label="protected"];
    relay_state -> mutexes [label="protected"];
    timing_meas -> mutexes [label="protected"];
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

Frequency-Relay-System

Here's the rest of the C program using FreeRTOS to implement the frequency relay system on the DE2-115 board:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "altera_avalon_pio_regs.h"

// Constants and hardware definitions
#define THRESHOLD_FREQ 50 // Set your threshold frequency
#define THRESHOLD_ROC 5 // Set your threshold rate of change of frequency

// Shared resources
SemaphoreHandle_t xMutex;
float inst_freq = 0;
float roc_freq = 0;
int load_status[5] = {0};
int net_stability = 1;
int relay_state = 0;
int timing_meas[5] = {0};

// Function prototypes
void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);
void ISR1(void *context, alt_u32 id);
void ISR2(TimerHandle_t xTimer);

int main() {
    // Initialize hardware, peripherals, and shared resources
    // ...

    // Create the tasks
    xTaskCreate(task1, "Monitor frequency and RoC", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task2, "Manage loads", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task3, "Update VGA display", configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    // Create the mutex for shared resources
    xMutex = xSemaphoreCreateMutex();

    // Set up timer interrupt for ISR2
    TimerHandle_t xTimer = xTimerCreate("TimerISR", pdMS_TO_TICKS(200), pdTRUE, 0, ISR2);
    xTimerStart(xTimer, 0);

    // Set up user input interrupt for ISR1
    // ...

    // Start the scheduler
    vTaskStartScheduler();

    // The program should not reach this point, as the scheduler takes control
    while(1);
    return 0;
}

void task1(void *pvParameters) {
    while(1) {
        // Measure inst_freq and roc_freq using appropriate sensors or methods
        float measured_inst_freq;
        float measured_roc_freq;
        // ...

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}


void task2(void *pvParameters) {
    while(1) {
        // Check network stability and relay state
        // ...

        // Manage loads based on network stability and relay state
        // ...

        // Update LED states according to load status and relay state
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void task3(void *pvParameters) {
    while(1) {
        // Read shared variables
        // ...

        // Update VGA display with frequency relay information
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void ISR1(void *context, alt_u32 id) {
    // Handle user input (slide switches and push button)
    // ...

    // Update shared resources (load_status and relay_state)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update load_status based on the slide switches
    // Update relay_state based on the push button
    xSemaphoreGiveFromISR(xMutex, 0);
}

void ISR2(TimerHandle_t xTimer) {
    // Measure the time intervals and update timing measurements
    // ...

    // Update shared resources (timing_meas)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update timing_meas array
    xSemaphoreGiveFromISR(xMutex, 0);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

The provided code is a high-level implementation of the frequency relay system using FreeRTOS, and you will need to adjust it according to your specific hardware and peripherals. Make sure to include the appropriate libraries and initialize the hardware correctly.

Please note that while this code should give you a rough idea of how to structure your program, it is crucial to test and debug it on your specific hardware to ensure it functions as expected. Also, consider optimizing the task delays and other parameters to meet the real-time requirements of your system.

# Shared Resources

In the provided code, shared resources are variables that are accessed or modified by multiple tasks or interrupt service routines (ISRs). Since tasks and ISRs can run concurrently, it is important to protect shared resources from unpredictable concurrent access, which can lead to race conditions or inconsistencies.


The shared resources in this code are:

  1. inst_freq: Represents the instantaneous frequency of the system. Task 1 updates this value, and Task 3 reads it to display it on the VGA screen.
  2. roc_freq: Represents the rate of change of frequency in the system. Task 1 updates this value, and Task 3 reads it to display it on the VGA screen.
  3. load_status: Represents the status of each load (on or off). Task 2 updates this value based on the network stability and relay state, ISR 1 updates it based on user inputs (slide switches), and Task 3 reads it to display it on the VGA screen.
  4. net_stability: Represents the network stability status (stable or unstable). Task 1 updates this value based on the instantaneous frequency and rate of change of frequency, and Task 2 reads it to manage the loads.
  5. relay_state: Represents the state of the frequency relay (normal operation or maintenance mode). ISR 1 updates this value based on the push button input, and Task 2 reads it to manage the loads.
  6. timing_meas: Represents the timing measurements for the system, such as the time taken from detecting a deviation of frequency or rate of change of frequency to the first load shed. ISR 2 updates this value, and Task 3 reads it to display it on the VGA screen.

To protect shared resources from concurrent access, a mutex (short for "mutual exclusion") is used. A mutex ensures that only one task or ISR can access the shared resource at a time, preventing race conditions and data inconsistencies.


In the code, a mutex called xMutex is created using xSemaphoreCreateMutex(). When a task or ISR wants to access a shared resource, it first takes the mutex using xSemaphoreTake() or xSemaphoreTakeFromISR(). Once the shared resource has been accessed or modified, the mutex is released using xSemaphoreGive() or xSemaphoreGiveFromISR(). This process ensures that shared resources are accessed sequentially, even if tasks or ISRs run concurrently.

Possible problems

This code is working but #include "FreeRTOS.h" had to be changed to #include "freertos/FreeRTOS.h".

Also, the numbers had to be set in the code below:

#define THRESHOLD_FREQ 50 // Set your threshold frequency
#define THRESHOLD_ROC 5 // Set your threshold rate of change of frequency
1
2

before, it doesn't work

#define THRESHOLD_FREQ // Set your threshold frequency
#define THRESHOLD_ROC  // Set your threshold rate of change of frequency
1
2

Create a new configuration and run


Frequency-Relay-System


Frequency-Relay-System

# 3. Define global variables and shared resources ✅

  1. Instantaneous frequency
  2. Rate of change of frequency
  3. Load status
  4. Network stability status
  5. Relay state (normal, managing, or maintenance)
  6. Timing measurements
  7. Mutexes for shared resources
// Shared resources
float inst_freq = 0;
float roc_freq = 0;
int load_status[5] = {0};
int net_stability = 1;
int relay_state = 0;
int timing_meas[5] = {0};
SemaphoreHandle_t xMutex;
1
2
3
4
5
6
7
8

# 4. Implement tasks and ISRs ✅

// Function prototypes
void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);
void ISR1(void *context, alt_u32 id);
void ISR2(TimerHandle_t xTimer);
1
2
3
4
5
6

Basic functions implementation


void task1(void *pvParameters) {
    while(1) {
        // Measure inst_freq and roc_freq using appropriate sensors or methods
        float measured_inst_freq;
        float measured_roc_freq;
        // ...

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}


void task2(void *pvParameters) {
    while(1) {
        // Check network stability and relay state
        // ...

        // Manage loads based on network stability and relay state
        // ...

        // Update LED states according to load status and relay state
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void task3(void *pvParameters) {
    while(1) {
        // Read shared variables
        // ...

        // Update VGA display with frequency relay information
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void ISR1(void *context, alt_u32 id) {
    // Handle user input (slide switches and push button)
    // ...

    // Update shared resources (load_status and relay_state)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update load_status based on the slide switches
    // Update relay_state based on the push button
    xSemaphoreGiveFromISR(xMutex, 0);
}

void ISR2(TimerHandle_t xTimer) {
    // Measure the time intervals and update timing measurements
    // ...

    // Update shared resources (timing_meas)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update timing_meas array
    xSemaphoreGiveFromISR(xMutex, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

# 5. In the main function: ✅

  • Initialize the board, peripherals, and FreeRTOS components (tasks, ISRs, mutexes, etc.). ✅
  • Start the FreeRTOS scheduler.✅

int main() {
    // Initialize hardware, peripherals, and shared resources
    // ...

    // Create the tasks
    xTaskCreate(task1, "Monitor frequency and RoC", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task2, "Manage loads", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task3, "Update VGA display", configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    // Create the mutex for shared resources
    xMutex = xSemaphoreCreateMutex();

    // Set up timer interrupt for ISR2
    TimerHandle_t xTimer = xTimerCreate("TimerISR", pdMS_TO_TICKS(200), pdTRUE, 0, ISR2);
    xTimerStart(xTimer, 0);

    // Set up user input interrupt for ISR1
    // ...

    // Start the scheduler
    vTaskStartScheduler();

    // The program should not reach this point, as the scheduler takes control
    while(1);
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 6. Implementing task1 - Measure inst_freq and roc_freq using appropriate sensors or methods ✅

  • Continuously measure the instantaneous frequency and ✅
  • rate of change of frequency. ✅
  • Update the global variables for instantaneous frequency and rate of change of frequency. ✅
  • Signal the other tasks or ISRs if the network status changes (e.g., using FreeRTOS event groups). ✅

This code reads a frequency signal from a frequency analyzer module and prints the frequency in Hz on the console.


The function task1 reads the frequency signal from the frequency analyzer module using the IORD function and calculates the frequency in Hz using a formula. The frequency value is printed on the console using printf.


The alt_irq_register function is used to register an interrupt handler function freq_relay for the frequency analyzer interrupt. This means that function task1 will be called every time the frequency analyzer module generates an interrupt.**









































 



















 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 




















































#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "altera_avalon_pio_regs.h"
#include <stdlib.h>


// Constants and hardware definitions
#define THRESHOLD_FREQ 50 // Set your threshold frequency
#define THRESHOLD_ROC 5 // Set your threshold rate of change of frequency

// Shared resources
float inst_freq = 0;
float roc_freq = 0;
int load_status[5] = {0};
int net_stability = 1;
int relay_state = 0;
int timing_meas[5] = {0};
SemaphoreHandle_t xMutex;


// Function prototypes
void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);
void ISR1(void *context, alt_u32 id);
void ISR2(TimerHandle_t xTimer);

int main() {
    // Initialize hardware, peripherals, and shared resources
    // ...

    // Create the tasks
    xTaskCreate(task1, "Monitor frequency and RoC", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task2, "Manage loads", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task3, "Update VGA display", configMINIMAL_STACK_SIZE, NULL, 1, NULL);


    alt_irq_register(FREQUENCY_ANALYSER_IRQ, 0, (void (*)(void *, alt_u32))task1);

    // Create the mutex for shared resources
    xMutex = xSemaphoreCreateMutex();

    // Set up timer interrupt for ISR2
    TimerHandle_t xTimer = xTimerCreate("TimerISR", pdMS_TO_TICKS(200), pdTRUE, 0, ISR2);
    xTimerStart(xTimer, 0);

    // Set up user input interrupt for ISR1
    // ...

    // Start the scheduler
    vTaskStartScheduler();

    // The program should not reach this point, as the scheduler takes control
    while(1);
    return 0;
}

void task1(void *pvParameters) {
    while(1) {
    	printf("Task 1 - Frequency measurement: \n");
        // Measure inst_freq and roc_freq using appropriate sensors or methods
        float measured_inst_freq;
        float measured_roc_freq;

        measured_inst_freq = IORD(FREQUENCY_ANALYSER_BASE, 0);
		printf("%f Hz\n", 16000/(double)measured_inst_freq);
		return;
        // ...

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}


void task2(void *pvParameters) {
    while(1) {
        // Check network stability and relay state
        // ...

        // Manage loads based on network stability and relay state
        // ...

        // Update LED states according to load status and relay state
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void task3(void *pvParameters) {
    while(1) {
        // Read shared variables
        // ...

        // Update VGA display with frequency relay information
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void ISR1(void *context, alt_u32 id) {
    // Handle user input (slide switches and push button)
    // ...

    // Update shared resources (load_status and relay_state)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update load_status based on the slide switches
    // Update relay_state based on the push button
    xSemaphoreGiveFromISR(xMutex, 0);
}

void ISR2(TimerHandle_t xTimer) {
    // Measure the time intervals and update timing measurements
    // ...

    // Update shared resources (timing_meas)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update timing_meas array
    xSemaphoreGiveFromISR(xMutex, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

Results


Frequency-Relay-System

Eliminating warnings

The following warning were happening:








 
 










 
 











make all 
Info: Building ../frequency_relay_bsp/
C:/intelFPGA_lite/17.0/nios2eds/bin/gnu/H-x86_64-mingw32/bin/make --no-print-directory -C ../frequency_relay_bsp/
[BSP build complete]
Info: Compiling main.c to obj/default/main.o
nios2-elf-gcc -xc -MP -MMD -c -I../frequency_relay_bsp//HAL/inc -I../frequency_relay_bsp/ -I../frequency_relay_bsp//drivers/inc  -pipe -D__hal__ -DALT_NO_INSTRUCTION_EMULATION -DALT_SINGLE_THREADED    -O0 -g -Wall   -mhw-div -mhw-mul -mno-hw-mulx -mgpopt=global  -o obj/default/main.o main.c
main.c: In function 'main':
main.c:39:49: warning: passing argument 3 of 'alt_irq_register' from incompatible pointer type [-Wincompatible-pointer-types]
     alt_irq_register(FREQUENCY_ANALYSER_IRQ, 0, task1);
                                                 ^
In file included from ../frequency_relay_bsp//HAL/inc/sys/alt_irq.h:218:0,
                 from freertos/portmacro.h:77,
                 from freertos/portable.h:94,
                 from freertos/FreeRTOS.h:104,
                 from main.c:2:
../frequency_relay_bsp//HAL/inc/priv/alt_legacy_irq.h:61:12: note: expected 'alt_isr_func {aka void (*)(void *, long unsigned int)}' but argument is of type 'void (*)(void *)'
 extern int alt_irq_register (alt_u32 id, 
            ^
main.c: In function 'task1':
main.c:75:59: warning: implicit declaration of function 'abs' [-Wimplicit-function-declaration]
         net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
                                                           ^
Info: Linking frequency_relay.elf
nios2-elf-g++  -T'../frequency_relay_bsp//linker.x' -msys-crt0='../frequency_relay_bsp//obj/HAL/src/crt0.o' -msys-lib=hal_bsp -L../frequency_relay_bsp/   -Wl,-Map=frequency_relay.map   -O0 -g -Wall   -mhw-div -mhw-mul -mno-hw-mulx -mgpopt=global  -o frequency_relay.elf obj/default/freertos/croutine.o obj/default/freertos/event_groups.o obj/default/freertos/heap.o obj/default/freertos/list.o obj/default/freertos/port.o obj/default/freertos/queue.o obj/default/freertos/tasks.o obj/default/freertos/timers.o obj/default/main.o obj/default/freertos/port_asm.o -lm -msys-lib=m
nios2-elf-insert frequency_relay.elf --thread_model hal --cpu_name nios2 --qsys true --simulation_enabled false --id 7 --sidp 0x430f0 --timestamp 1393900972 --stderr_dev jtag_uart --stdin_dev jtag_uart --stdout_dev jtag_uart --sopc_system_name nios2 --sopcinfo C:/compsys723/lab/software/frequency_relay_bsp/../../nios2.sopcinfo
Info: (frequency_relay.elf) 609 KBytes program size (code + initialized data).
Info:                       130561 KBytes free for stack + heap.
Info: Creating frequency_relay.objdump
nios2-elf-objdump --disassemble --syms --all-header frequency_relay.elf >frequency_relay.objdump
[frequency_relay build complete]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

and here is the solution to eliminate the warnings:

The warnings that you see are not critical, and the program should still work properly. However, it's always a good idea to try to resolve any warnings or errors to improve the quality and maintainability of your code.

The first warning indicates that there's an incompatible pointer type in the alt_irq_register function call. Specifically, it's a warning about passing a function pointer of type void (*)(void ) to a function that expects a function pointer of type void ()(void *, long unsigned int). This warning is likely caused by a change in the function signature of the alt_irq_register function.

To resolve this warning, you can cast the task1 function pointer to the expected function signature like this:

alt_irq_register(FREQUENCY_ANALYSER_IRQ, 0, (void (*)(void *, alt_u32))task1);
1

from

alt_irq_register(FREQUENCY_ANALYSER_IRQ, 0, task1);
1

This cast tells the compiler to interpret the function pointer as having the expected type.

The second warning is related to an implicit declaration of the abs function. This warning is caused by not including the stdlib.h header file, which contains the declaration of the abs function.

To resolve this warning, you can include the stdlib.h header file at the top of your main.c file like this:

#include <stdlib.h>
1

Once you make these changes, you can rebuild your project and check if the warnings are resolved.

# implementing the rate of change

To implement the rate of change calculation in the task1 function, you need to measure the frequency at two different times and calculate the difference between these measurements. Here's one way you can modify the function to calculate the rate of change of frequency:

void task1(void *pvParameters) {
    // Variables for frequency measurement and rate of change calculation
    float prev_freq = 0;
    float curr_freq = 0;
    TickType_t prev_time = 0;
    TickType_t curr_time = 0;
    float measured_inst_freq;
    float measured_roc_freq;

    while(1) {
        // Measure inst_freq using appropriate sensors or methods
        measured_inst_freq = IORD(FREQUENCY_ANALYSER_BASE, 0);
        printf("Task 1 - Frequency measurement: %f Hz\n", 16000/(double)measured_inst_freq);

        // Calculate rate of change of frequency
        curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS;
        curr_freq = measured_inst_freq;
        measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time) * 1000;
        prev_freq = curr_freq;
        prev_time = curr_time;

        printf("Task 1 - Rate of frequency change: %f Hz/ms\n", measured_roc_freq);

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

In this modified function, we first declare variables to hold the previous and current frequency values (prev_freq and curr_freq) and the previous and current time values (prev_time and curr_time). We then measure the frequency using the appropriate sensors or methods and print the result to the console.

After measuring the frequency, we calculate the rate of change of frequency by dividing the difference between the current and previous frequency values by the difference between the current and previous time values. We then update the shared resources with the new frequency and rate of change values, using the same code as before.

Finally, we sleep for a while to give other tasks a chance to run and repeat the process indefinitely. Note that the delay between frequency measurements may need to be adjusted depending on the requirements of your application.

Result:

Why i'm getting Task 1 - Frequency measurement: 48.338369 Hz
Task 1 - Rate of frequency change: inf Hz/ms„‡
1
2

inf result

You are getting an "inf" result for the rate of frequency change because you are dividing by a very small time interval. In your code, you are measuring the time interval in milliseconds using xTaskGetTickCount() * portTICK_PERIOD_MS, and then dividing the frequency difference by this value to get the rate of change in Hz/ms. However, in some cases, the time interval may be very small (e.g. 0 ms), which causes the division to result in an "inf" value.

To fix this, you can check if the time interval is non-zero before calculating the rate of change. If the time interval is zero, you can set the rate of change to zero as well. Here's an updated version of the code that implements this check:

# Refactoring to clear the inf result

void task1(void *pvParameters) {

    // Variables for frequency measurement and rate of change calculation
    float prev_freq = 0;
    float curr_freq = 0;
    float prev_time = 0;
    float curr_time = 0;
    float measured_inst_freq;
    float measured_roc_freq;

    while(1) {

        printf("Task 1 - Frequency measurement: \n");
        // Measure inst_freq using appropriate sensors or methods
        measured_inst_freq = IORD(FREQUENCY_ANALYSER_BASE, 0);
        printf("%f Hz\n", 16000/(double)measured_inst_freq);

        // Calculate rate of change of frequency
        curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS;
        curr_freq = measured_inst_freq;
        if (curr_time != prev_time) { // Check if time interval is non-zero
            measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time);
        } else {
            measured_roc_freq = 0; // Set rate of change to zero
        }
        prev_freq = curr_freq;
        prev_time = curr_time;

        printf("Task 1 - Rate of frequency change: \n");
        printf("%f Hz/ms\n",(double)measured_roc_freq);

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# Refactoring to reflect rate of change in Hz/s

Here's an updated version of task1() that calculates the rate of frequency change in Hz/s:

void task1(void *pvParameters) {
    // Variables for frequency measurement and rate of change calculation
    float prev_freq = 0;
    float curr_freq = 0;
    float prev_time = 0;
    float curr_time = 0;
    float measured_inst_freq;
    float measured_roc_freq;

    while (1) {
        printf("Task 1 - Frequency measurement: \n");
        // Measure inst_freq using appropriate sensors or methods
        measured_inst_freq = IORD(FREQUENCY_ANALYSER_BASE, 0);
        printf("%f Hz\n", 16000 / (double)measured_inst_freq);

        // Calculate rate of change of frequency in Hz/s
        curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000.0; // Convert ms to s
        curr_freq = measured_inst_freq;
        measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time);
        prev_freq = curr_freq;
        prev_time = curr_time;

        printf("Task 1 - Rate of frequency change: \n");
        printf("%f Hz/s\n", (double)measured_roc_freq);

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

Note that we divide curr_time by 1000.0 to convert milliseconds to seconds, and we print the rate of change in Hz/s instead of Hz/ms.

# refactoring to eliminate inf results from rof.

It's possible that you are still getting "inf" as the result because the measured frequency is too close to zero, causing the denominator (curr_time - prev_time) to become very small or zero. To avoid this issue, you could add a check to ensure that the time interval is not zero before calculating the rate of change:

// Calculate rate of change of frequency in Hz/s
curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000.0; // Convert ms to s
curr_freq = measured_inst_freq;
if (curr_time != prev_time) { // Check if the time interval is not zero
    measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time);
} else {
    measured_roc_freq = 0; // Set rate of change to 0 if time interval is zero
}
prev_freq = curr_freq;
prev_time = curr_time;
1
2
3
4
5
6
7
8
9
10

With this check, the calculated rate of change will be set to 0 if the time interval is zero, avoiding division by zero and resulting in a valid output.

results:


Frequency-Relay-System

# refactoring warning Symbol 'FREQUENCY_ANALYSER_IRQ' could not be resolved

#include "system.h"

# Final code after task1 complete

#include <stdio.h>
#include <stdlib.h>

#include "system.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "altera_avalon_pio_regs.h"



// Constants and hardware definitions
#define THRESHOLD_FREQ 50 // Set your threshold frequency
#define THRESHOLD_ROC 5 // Set your threshold rate of change of frequency

// Shared resources
float inst_freq = 0;
float roc_freq = 0;
int load_status[5] = {0};
int net_stability = 1;
int relay_state = 0;
int timing_meas[5] = {0};
SemaphoreHandle_t xMutex;


// Function prototypes
void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);
void ISR1(void *context, alt_u32 id);
void ISR2(TimerHandle_t xTimer);

int main() {
    // Initialize hardware, peripherals, and shared resources
    // ...

    // Create the tasks
    xTaskCreate(task1, "Monitor frequency and RoC", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task2, "Manage loads", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task3, "Update VGA display", configMINIMAL_STACK_SIZE, NULL, 1, NULL);


    alt_irq_register(FREQUENCY_ANALYSER_IRQ, 0, (void (*)(void *, alt_u32))task1);

    // Create the mutex for shared resources
    xMutex = xSemaphoreCreateMutex();

    // Set up timer interrupt for ISR2
    TimerHandle_t xTimer = xTimerCreate("TimerISR", pdMS_TO_TICKS(200), pdTRUE, 0, ISR2);
    xTimerStart(xTimer, 0);

    // Set up user input interrupt for ISR1
    // ...

    // Start the scheduler
    vTaskStartScheduler();

    // The program should not reach this point, as the scheduler takes control
    while(1);
    return 0;
}

void task1(void *pvParameters) {
    // Variables for frequency measurement and rate of change calculation
    float prev_freq = 0;
    float curr_freq = 0;
    float prev_time = 0;
    float curr_time = 0;
    float measured_inst_freq;
    float measured_roc_freq;

    while (1) {
        printf("Task 1 - Frequency measurement: \n");
        // Measure inst_freq using appropriate sensors or methods
        measured_inst_freq = IORD(FREQUENCY_ANALYSER_BASE, 0);
        printf("%f Hz\n", 16000 / (double)measured_inst_freq);

        // Calculate rate of change of frequency in Hz/s
        curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000.0; // Convert ms to s
        curr_freq = measured_inst_freq;
        if (curr_time != prev_time) { // Check if the time interval is not zero
            measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time);
        } else {
            measured_roc_freq = 0; // Set rate of change to 0 if time interval is zero
        }
        prev_freq = curr_freq;
        prev_time = curr_time;

        printf("Task 1 - Rate of frequency change: \n");
        printf("%f Hz\n", (double)measured_roc_freq);

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void task2(void *pvParameters) {
    while(1) {
        // Check network stability and relay state
        // ...

        // Manage loads based on network stability and relay state
        // ...

        // Update LED states according to load status and relay state
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void task3(void *pvParameters) {
    while(1) {
        // Read shared variables
        // ...

        // Update VGA display with frequency relay information
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void ISR1(void *context, alt_u32 id) {
    // Handle user input (slide switches and push button)
    // ...

    // Update shared resources (load_status and relay_state)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update load_status based on the slide switches
    // Update relay_state based on the push button
    xSemaphoreGiveFromISR(xMutex, 0);
}

void ISR2(TimerHandle_t xTimer) {
    // Measure the time intervals and update timing measurements
    // ...

    // Update shared resources (timing_meas)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update timing_meas array
    xSemaphoreGiveFromISR(xMutex, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

# Testing task1 ❌

DETAILS

Didn't work with https://github.com/ThrowTheSwitch/Unity

Download the unit test framework here, and clone it into the project folder.


Frequency-Relay-System

To write a unit test for task1, we need to test the functionality of the frequency measurement and rate of change calculation. We can simulate the frequency analyzer output by passing a range of values as the measured instantaneous frequency in measured_inst_freq. We can then test if the calculated rate of change of frequency measured_roc_freq matches our expected output based on the input values.

Here is an example unit test for task1:

void test_task1() {
    float expected_inst_freq;
    float expected_roc_freq;

    // Test 1: Instantaneous frequency is 60 Hz, no change in frequency
    expected_inst_freq = 266;
    expected_roc_freq = 0;
    IORD_ExpectAndReturn(FREQUENCY_ANALYSER_BASE, 0, expected_inst_freq);
    task1(NULL);
    TEST_ASSERT_EQUAL_FLOAT(expected_inst_freq, inst_freq);
    TEST_ASSERT_EQUAL_FLOAT(expected_roc_freq, roc_freq);

    // Test 2: Instantaneous frequency increases to 70 Hz in 100 ms
    expected_inst_freq = 229;
    expected_roc_freq = 1000 * (70 - 60) / 100;
    IORD_ExpectAndReturn(FREQUENCY_ANALYSER_BASE, 0, expected_inst_freq);
    task1(NULL);
    TEST_ASSERT_EQUAL_FLOAT(expected_inst_freq, inst_freq);
    TEST_ASSERT_EQUAL_FLOAT(expected_roc_freq, roc_freq);

    // Test 3: Instantaneous frequency decreases to 50 Hz in 200 ms
    expected_inst_freq = 320;
    expected_roc_freq = 1000 * (50 - 70) / 200;
    IORD_ExpectAndReturn(FREQUENCY_ANALYSER_BASE, 0, expected_inst_freq);
    task1(NULL);
    TEST_ASSERT_EQUAL_FLOAT(expected_inst_freq, inst_freq);
    TEST_ASSERT_EQUAL_FLOAT(expected_roc_freq, roc_freq);
}

int main() {
    // Initialize hardware and shared resources
    // ...

    // Run unit tests
    UNITY_BEGIN();
    RUN_TEST(test_task1);
    UNITY_END();

    // Start the scheduler
    vTaskStartScheduler();

    // The program should not reach this point, as the scheduler takes control
    while(1);
    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# Complete code after task1 working

#include <stdio.h>
#include <stdlib.h>

#include "system.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "altera_avalon_pio_regs.h"



// Constants and hardware definitions
#define THRESHOLD_FREQ 50 // Set your threshold frequency
#define THRESHOLD_ROC 5 // Set your threshold rate of change of frequency

// Shared resources
float inst_freq = 0;
float roc_freq = 0;
int load_status[5] = {0};
int net_stability = 1;
int relay_state = 0;
int timing_meas[5] = {0};
SemaphoreHandle_t xMutex;


// Function prototypes
void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);
void ISR1(void *context, alt_u32 id);
void ISR2(TimerHandle_t xTimer);

int main() {
    // Initialize hardware, peripherals, and shared resources
    // ...

    // Create the tasks
    xTaskCreate(task1, "Monitor frequency and RoC", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task2, "Manage loads", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task3, "Update VGA display", configMINIMAL_STACK_SIZE, NULL, 1, NULL);


    alt_irq_register(task1, 0, (void (*)(void *, alt_u32))task1);

    // Create the mutex for shared resources
    xMutex = xSemaphoreCreateMutex();

    // Set up timer interrupt for ISR2
    TimerHandle_t xTimer = xTimerCreate("TimerISR", pdMS_TO_TICKS(200), pdTRUE, 0, ISR2);
    xTimerStart(xTimer, 0);

    // Set up user input interrupt for ISR1
    // ...

    // Start the scheduler
    vTaskStartScheduler();

    // The program should not reach this point, as the scheduler takes control
    while(1);
    return 0;
}

void task1(void *pvParameters) {
    // Variables for frequency measurement and rate of change calculation
    float prev_freq = 0;
    float curr_freq = 0;
    float prev_time = 0;
    float curr_time = 0;
    float measured_inst_freq;
    float measured_roc_freq;

    while (1) {
        printf("Task 1 - Frequency measurement: \n");
        // Measure inst_freq using appropriate sensors or methods
        measured_inst_freq = IORD(FREQUENCY_ANALYSER_BASE, 0);
        printf("%f Hz\n", 16000 / (double)measured_inst_freq);

        // Calculate rate of change of frequency in Hz/s
        curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000.0; // Convert ms to s
        curr_freq = measured_inst_freq;
        if (curr_time != prev_time) { // Check if the time interval is not zero
            measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time);
        } else {
            measured_roc_freq = 0; // Set rate of change to 0 if time interval is zero
        }
        prev_freq = curr_freq;
        prev_time = curr_time;

        printf("Task 1 - Rate of frequency change: \n");
        printf("%f Hz\n", (double)measured_roc_freq);

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void task2(void *pvParameters) {
    while(1) {
        // Check network stability and relay state
        // ...

        // Manage loads based on network stability and relay state
        // ...

        // Update LED states according to load status and relay state
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void task3(void *pvParameters) {
    while(1) {
        // Read shared variables
        // ...

        // Update VGA display with frequency relay information
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void ISR1(void *context, alt_u32 id) {
    // Handle user input (slide switches and push button)
    // ...

    // Update shared resources (load_status and relay_state)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update load_status based on the slide switches
    // Update relay_state based on the push button
    xSemaphoreGiveFromISR(xMutex, 0);
}

void ISR2(TimerHandle_t xTimer) {
    // Measure the time intervals and update timing measurements
    // ...

    // Update shared resources (timing_meas)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update timing_meas array
    xSemaphoreGiveFromISR(xMutex, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

# Testing with googletest

To use Google Test with this code, you will need to first integrate the Google Test framework into your project. You can download the Google Test framework from the official GitHub repository: https://github.com/google/googletest.

Once you have downloaded and extracted the Google Test framework, you will need to add the framework to your project by following these steps:

  1. Create a gtest directory in your project directory.
  2. Copy the entire googletest directory from the extracted Google Test framework to your gtest directory.
  3. In your project directory, create a test directory.
  4. Create a new file test_task1.cpp in the test directory.
  5. In test_task1.cpp, add the following code:
#include "gtest/gtest.h"
#include "main.h"

TEST(task1, test_frequency_measurement) {
    // Set up test input values
    float expected_inst_freq = 100.0;

    // Set up expected output values
    float expected_net_stability = true;
    float expected_inst_freq_output = expected_inst_freq;
    float expected_roc_freq_output = 0;

    // Call the task1 function with the test input values
    task1(&expected_inst_freq);

    // Check the output values against the expected values
    EXPECT_EQ(expected_net_stability, net_stability);
    EXPECT_EQ(expected_inst_freq_output, inst_freq);
    EXPECT_EQ(expected_roc_freq_output, roc_freq);
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

This code defines a test for task1 that sets up input values, calls the task1 function with the input values, and checks the output values against the expected values.

  1. Modify the task1 function to take a float pointer parameter:
void task1(void *pvParameters) {
    float *inst_freq_ptr = (float *)pvParameters;

    // Variables for frequency measurement and rate of change calculation
    float prev_freq = 0;
    float curr_freq = 0;
    float prev_time = 0;
    float curr_time = 0;
    float measured_inst_freq;
    float measured_roc_freq;

    printf("Task 1 - Frequency measurement: \n");
    // Measure inst_freq using appropriate sensors or methods
    measured_inst_freq = *inst_freq_ptr;
    printf("%f Hz\n", 16000 / (double)measured_inst_freq);

    // Calculate rate of change of frequency in Hz/s
    curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000.0; // Convert ms to s
    curr_freq = measured_inst_freq;
    if (curr_time != prev_time) { // Check if the time interval is not zero
        measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time);
    } else {
        measured_roc_freq = 0; // Set rate of change to 0 if time interval is zero
    }
    prev_freq = curr_freq;
    prev_time = curr_time;

    printf("Task 1 - Rate of frequency change: \n");
    printf("%f Hz\n", (double)measured_roc_freq);

    // Update shared resources
    xSemaphoreTake(xMutex, portMAX_DELAY);
    inst_freq = measured_inst_freq;
    roc_freq = measured_roc_freq;
    net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
    xSemaphoreGive(xMutex);

    // Sleep for a while (adjust the delay as needed)
   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

Graphviz of task 1

Graphviz Code
// digraph task1 {
//     graph [rankdir=LR, nodesep=1.5, ranksep=1.5];
//     node [shape=box, style=rounded];

//     A [label="Read frequency"];
//     B [label="Calculate rate of change"];
//     C [label="Update shared resources"];
//     D [label="Sleep"];

//     A -> B;
//     B -> C;
//     C -> D;
//     D -> A [style=dashed];
// }

digraph Task1 {
  rankdir=LR;
  node [shape=rectangle, fontname="Arial", fontsize=12];
  edge [fontname="Arial", fontsize=10];

  // Nodes
  task1 [label="Task 1\nFrequency measurement and RoC calculation", style=filled, fillcolor=lightblue];
  freq_sens [label="Frequency sensor"];
  roc_calc [label="Rate of change of frequency\n(Hz/s)"];
  shared_res [label="Shared resources", style=filled, fillcolor=lightblue];
  inst_freq [label="Instantaneous frequency (Hz)"];
  roc_freq [label="Rate of change of frequency (Hz/s)"];
  net_stability [label="Network stability"];
  threshold_freq [label="Threshold frequency"];
  threshold_roc [label="Threshold rate of change of frequency"];
  delay [label="Delay (adjustable)"];
  tick_count [label="Tick count (ms)"];
  time_interval [label="Time interval (s)"];

  // Edges
  freq_sens -> task1 [label="Measure", fontsize=10];
  task1 -> inst_freq [label="Update shared resources", fontsize=10];
  roc_calc -> task1 [label="Calculate", fontsize=10];
  task1 -> roc_freq [label="Update shared resources", fontsize=10];
  threshold_freq -> net_stability [label="Compare", fontsize=10];
  threshold_roc -> net_stability [label="Compare", fontsize=10];
  inst_freq -> roc_calc [label="Input", fontsize=10];
  tick_count -> time_interval [label="Conversion", fontsize=10];
  time_interval -> roc_calc [label="Input", fontsize=10];
  task1 -> delay [label="Sleep", fontsize=10];
  delay -> task1 [label="Repeat", fontsize=10];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

Frequency-Relay-System


Frequency-Relay-System

# 7. Implement Task 2 to manage loads: ✅

  • Monitor network stability status and relay state.
  • Perform load shedding or reconnection based on the network stability, priority, and relay state.
  • Update the LED states according to the load status and relay state.

To implement Task 2 to manage loads in the given code, follow these steps:

  1. Add the necessary constants and variables related to load management at the beginning of the file:
...
#define MAX_LOADS 5 // maximum number of loads
#define PRIORITY_HIGH 2
#define PRIORITY_MEDIUM 1
#define PRIORITY_LOW 0

int load_priority[MAX_LOADS] = {PRIORITY_HIGH, PRIORITY_MEDIUM, PRIORITY_LOW, PRIORITY_LOW, PRIORITY_LOW};
int load_status[MAX_LOADS] = {0};
int relay_state = 0;
int net_stability = 0;

// Shared resources
float inst_freq = 0;
float roc_freq = 0;
int timing_meas[5] = {0};
SemaphoreHandle_t xMutex;
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

The MAX_LOADS constant specifies the maximum number of loads that can be managed. The PRIORITY_HIGH, PRIORITY_MEDIUM, and PRIORITY_LOW constants represent the priority levels of loads. The load_priority array holds the priority of each load, and the load_status array holds the current status (on/off) of each load. The relay_state variable holds the current state of the relay (on/off), and the net_stability variable holds the current stability status of the network.

  1. Modify the task2 function to perform load management based on the network stability, relay state, and load priorities:
void task2(void *pvParameters) {
    while(1) {
        // Check network stability and relay state
        xSemaphoreTake(xMutex, portMAX_DELAY);
        int net_stability_local = net_stability;
        int relay_state_local = relay_state;
        xSemaphoreGive(xMutex);

        // Perform load shedding or reconnection based on the network stability, priority, and relay state
        for (int i = 0; i < MAX_LOADS; i++) {
            if (load_priority[i] == PRIORITY_HIGH && net_stability_local == 0) {
                load_status[i] = 0; // shed high priority load if network is unstable
            } else if (load_priority[i] == PRIORITY_LOW && relay_state_local == 0) {
                load_status[i] = 0; // shed low priority load if relay is off
            } else {
                load_status[i] = 1; // reconnect load if conditions are met
            }
        }

        // Update LED states according to load status and relay state
        for (int i = 0; i < MAX_LOADS; i++) {
            // Set LED state according to load status
            if (load_status[i] == 1) {
                IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LEDS_BASE, (1 << i));
            } else {
                IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LEDS_BASE, ~(1 << i));
            }
        }

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));

        // Print load status
        printf("Task 2 - Manage Loads: \n");
		for (int i = 0; i < MAX_LOADS; i++) {
			printf("Load %d = %d\n", i + 1, load_status[i]);
		}

        // Sleep for a while (adjust the delay as needed)
		vTaskDelay(pdMS_TO_TICKS(1000));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

The first part of the function reads the current values of net_stability and relay_state from the shared resources using a semaphore. Then, it loops through all the loads and performs load shedding or reconnection based on the network stability, priority, and relay state. For high priority loads, it checks if the network is stable, and if not, it sheds the load. For low priority loads, it checks if the relay is off, and if so, it sheds the load. For medium priority loads, it does not perform any action. Finally, it updates the load_status array accordingly. The second part of the function updates the LED states according to the load_status array. The last part of the function sleeps for a while before repeating the process.

# Complete code after task2 working

#include <stdio.h>
#include <stdlib.h>

#include "system.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "altera_avalon_pio_regs.h"



// Constants and hardware definitions
#define THRESHOLD_FREQ 50 // Set your threshold frequency
#define THRESHOLD_ROC 5 // Set your threshold rate of change of frequency

#define MAX_LOADS 5 // maximum number of loads
#define PRIORITY_HIGH 2
#define PRIORITY_MEDIUM 1
#define PRIORITY_LOW 0

int load_priority[MAX_LOADS] = {PRIORITY_HIGH, PRIORITY_MEDIUM, PRIORITY_LOW, PRIORITY_LOW, PRIORITY_LOW};
int load_status[MAX_LOADS] = {0};
int relay_state = 0;
int net_stability = 0;

// Shared resources
float inst_freq = 0;
float roc_freq = 0;
int timing_meas[5] = {0};
SemaphoreHandle_t xMutex;



// Function prototypes
void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);
void ISR1(void *context, alt_u32 id);
void ISR2(TimerHandle_t xTimer);

int main() {
    // Initialize hardware, peripherals, and shared resources
    // ...

    // Create the tasks
    xTaskCreate(task1, "Monitor frequency and RoC", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task2, "Manage loads", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task3, "Update VGA display", configMINIMAL_STACK_SIZE, NULL, 1, NULL);


    alt_irq_register(task1, 0, (void (*)(void *, alt_u32))task1);

    // Create the mutex for shared resources
    xMutex = xSemaphoreCreateMutex();

    // Set up timer interrupt for ISR2
    TimerHandle_t xTimer = xTimerCreate("TimerISR", pdMS_TO_TICKS(200), pdTRUE, 0, ISR2);
    xTimerStart(xTimer, 0);

    // Set up user input interrupt for ISR1
    // ...

    // Start the scheduler
    vTaskStartScheduler();

    // The program should not reach this point, as the scheduler takes control
    while(1);
    return 0;
}

void task1(void *pvParameters) {
    // Variables for frequency measurement and rate of change calculation
    float prev_freq = 0;
    float curr_freq = 0;
    float prev_time = 0;
    float curr_time = 0;
    float measured_inst_freq;
    float measured_roc_freq;

    while (1) {
        printf("Task 1 - Frequency measurement: \n");
        // Measure inst_freq using appropriate sensors or methods
        measured_inst_freq = IORD(FREQUENCY_ANALYSER_BASE, 0);
        printf("%f Hz\n", 16000 / (double)measured_inst_freq);

        // Calculate rate of change of frequency in Hz/s
        curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000.0; // Convert ms to s
        curr_freq = measured_inst_freq;
        if (curr_time != prev_time) { // Check if the time interval is not zero
            measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time);
        } else {
            measured_roc_freq = 0; // Set rate of change to 0 if time interval is zero
        }
        prev_freq = curr_freq;
        prev_time = curr_time;

        printf("Task 1 - Rate of frequency change: \n");
        printf("%f Hz\n", (double)measured_roc_freq);

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void task2(void *pvParameters) {
    while(1) {
        // Check network stability and relay state
        xSemaphoreTake(xMutex, portMAX_DELAY);
        int net_stability_local = net_stability;
        int relay_state_local = relay_state;
        xSemaphoreGive(xMutex);

        // Perform load shedding or reconnection based on the network stability, priority, and relay state
        for (int i = 0; i < MAX_LOADS; i++) {
            if (load_priority[i] == PRIORITY_HIGH && net_stability_local == 0) {
                load_status[i] = 0; // shed high priority load if network is unstable
            } else if (load_priority[i] == PRIORITY_LOW && relay_state_local == 0) {
                load_status[i] = 0; // shed low priority load if relay is off
            } else {
                load_status[i] = 1; // reconnect load if conditions are met
            }
        }

        // Update LED states according to load status and relay state
        for (int i = 0; i < MAX_LOADS; i++) {
            // Set LED state according to load status
            if (load_status[i] == 1) {
                IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LEDS_BASE, (1 << i));
            } else {
                IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LEDS_BASE, ~(1 << i));
            }
        }

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));

        // Print load status
        printf("Task 2 - Manage Loads: \n");
		for (int i = 0; i < MAX_LOADS; i++) {
			printf("Load %d = %d\n", i + 1, load_status[i]);
		}

        // Sleep for a while (adjust the delay as needed)
		vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void task3(void *pvParameters) {
    while(1) {
        // Read shared variables
        // ...

        // Update VGA display with frequency relay information
        // ...

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void ISR1(void *context, alt_u32 id) {
    // Handle user input (slide switches and push button)
    // ...

    // Update shared resources (load_status and relay_state)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update load_status based on the slide switches
    // Update relay_state based on the push button
    xSemaphoreGiveFromISR(xMutex, 0);
}

void ISR2(TimerHandle_t xTimer) {
    // Measure the time intervals and update timing measurements
    // ...

    // Update shared resources (timing_meas)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update timing_meas array
    xSemaphoreGiveFromISR(xMutex, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

results:


Frequency-Relay-System

# 8. Implement Task 3 to update the VGA display ✅

Task3 (Update VGA display): Reads shared variables and updates the VGA display with the frequency and relay information.


Frequency-Relay-System

Final code with this phase complete

#include <stdio.h>
#include <stdlib.h>

#include "system.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "altera_avalon_pio_regs.h"

#include "altera_up_avalon_video_character_buffer_with_dma.h"
#include "altera_up_avalon_video_pixel_buffer_dma.h"




// an LED for each task
#define LED_TASK1_BASE 0x42020
#define LED_TASK2_BASE 0x42030
#define LED_TASK3_BASE 0x42040



// Constants and hardware definitions
#define THRESHOLD_FREQ 50 // Set your threshold frequency
#define THRESHOLD_ROC 5 // Set your threshold rate of change of frequency

#define MAX_LOADS 5 // maximum number of loads
#define PRIORITY_HIGH 2
#define PRIORITY_MEDIUM 1
#define PRIORITY_LOW 0

int load_priority[MAX_LOADS] = {PRIORITY_HIGH, PRIORITY_MEDIUM, PRIORITY_LOW, PRIORITY_LOW, PRIORITY_LOW};
int load_status[MAX_LOADS] = {0};
int relay_state = 0;
int net_stability = 0;

// Shared resources
float inst_freq = 0;
float roc_freq = 0;
int timing_meas[5] = {0};
SemaphoreHandle_t xMutex;



// Function prototypes
void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);
void ISR1(void *context, alt_u32 id);
void ISR2(TimerHandle_t xTimer);


///VGA

#include "altera_up_avalon_video_character_buffer_with_dma.h"

#define VGA_CHAR_BUFFER_BASE 0x40000
#define VGA_CHAR_CONTROL_BASE 0x430e8



int main() {
    // Initialize hardware, peripherals, and shared resources
    // ...


    // Create the tasks
    xTaskCreate(task1, "Monitor frequency and RoC", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task2, "Manage loads", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(task3, "Update VGA display", configMINIMAL_STACK_SIZE * 2, NULL, 2, NULL);


    alt_irq_register(task1, 0, (void (*)(void *, alt_u32))task1);

    // Create the mutex for shared resources
    xMutex = xSemaphoreCreateMutex();

    // Set up timer interrupt for ISR2
    TimerHandle_t xTimer = xTimerCreate("TimerISR", pdMS_TO_TICKS(200), pdTRUE, 0, ISR2);
    xTimerStart(xTimer, 0);

    // Set up user input interrupt for ISR1
    // ...

    // Start the scheduler
    vTaskStartScheduler();

    // The program should not reach this point, as the scheduler takes control
    while(1);
    return 0;
}

void task1(void *pvParameters) {

	// Blink LED for Task 1
	IOWR_ALTERA_AVALON_PIO_DATA(LED_TASK1_BASE, 0x1);
	vTaskDelay(pdMS_TO_TICKS(100));
	IOWR_ALTERA_AVALON_PIO_DATA(LED_TASK1_BASE, 0x0);
	vTaskDelay(pdMS_TO_TICKS(100));


    // Variables for frequency measurement and rate of change calculation
    float prev_freq = 0;
    float curr_freq = 0;
    float prev_time = 0;
    float curr_time = 0;
    float measured_inst_freq;
    float measured_roc_freq;

    while (1) {
        printf("Task 1 - Frequency measurement: \n");
        // Measure inst_freq using appropriate sensors or methods
        measured_inst_freq = IORD(FREQUENCY_ANALYSER_BASE, 0);
        printf("%f Hz\n", 16000 / (double)measured_inst_freq);

        // Calculate rate of change of frequency in Hz/s
        curr_time = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000.0; // Convert ms to s
        curr_freq = measured_inst_freq;
        if (curr_time != prev_time) { // Check if the time interval is not zero
            measured_roc_freq = (curr_freq - prev_freq) / (curr_time - prev_time);
        } else {
            measured_roc_freq = 0; // Set rate of change to 0 if time interval is zero
        }
        prev_freq = curr_freq;
        prev_time = curr_time;

        printf("Task 1 - Rate of frequency change: \n");
        printf("%f Hz\n", (double)measured_roc_freq);

        // Update shared resources
        xSemaphoreTake(xMutex, portMAX_DELAY);
        inst_freq = measured_inst_freq;
        roc_freq = measured_roc_freq;
        net_stability = (inst_freq >= THRESHOLD_FREQ) && (abs(roc_freq) <= THRESHOLD_ROC);
        xSemaphoreGive(xMutex);

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void task2(void *pvParameters) {
    while(1) {

    	// Blink LED for Task 2
		IOWR_ALTERA_AVALON_PIO_DATA(LED_TASK2_BASE, 0x1);
		vTaskDelay(pdMS_TO_TICKS(100));
		IOWR_ALTERA_AVALON_PIO_DATA(LED_TASK2_BASE, 0x0);
		vTaskDelay(pdMS_TO_TICKS(100));


        // Check network stability and relay state
        xSemaphoreTake(xMutex, portMAX_DELAY);
        int net_stability_local = net_stability;
        int relay_state_local = relay_state;
        xSemaphoreGive(xMutex);

        // Perform load shedding or reconnection based on the network stability, priority, and relay state
        for (int i = 0; i < MAX_LOADS; i++) {
            if (load_priority[i] == PRIORITY_HIGH && net_stability_local == 0) {
                load_status[i] = 0; // shed high priority load if network is unstable
            } else if (load_priority[i] == PRIORITY_LOW && relay_state_local == 0) {
                load_status[i] = 0; // shed low priority load if relay is off
            } else {
                load_status[i] = 1; // reconnect load if conditions are met
            }
        }

        // Update LED states according to load status and relay state
        for (int i = 0; i < MAX_LOADS; i++) {
            // Set LED state according to load status
            if (load_status[i] == 1) {
                IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LEDS_BASE, (1 << i));
            } else {
                IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LEDS_BASE, ~(1 << i));
            }
        }

        // Sleep for a while (adjust the delay as needed)
        vTaskDelay(pdMS_TO_TICKS(100));

        // Print load status
        printf("Task 2 - Manage Loads: \n");
		for (int i = 0; i < MAX_LOADS; i++) {
			printf("Load %d = %d\n", i + 1, load_status[i]);
		}

        // Sleep for a while (adjust the delay as needed)
		vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

// VGA

void custom_char_buffer_clear_line(alt_up_char_buffer_dev *char_buf, int line) {
    for (int i = 0; i < 80; i++) {
        alt_up_char_buffer_draw(char_buf, ' ', i, line);
    }
}


void task3(void *pvParameters) {
    alt_up_pixel_buffer_dma_dev *pixel_buf;
    pixel_buf = alt_up_pixel_buffer_dma_open_dev(VIDEO_PIXEL_BUFFER_DMA_NAME);
    if(pixel_buf == NULL){
        printf("Cannot find pixel buffer device\n");
    }
    alt_up_pixel_buffer_dma_clear_screen(pixel_buf, 0);

    alt_up_char_buffer_dev *char_buf;
    char_buf = alt_up_char_buffer_open_dev("/dev/video_character_buffer_with_dma");
    if(char_buf == NULL){
        printf("can't find char buffer device\n");
    }

    // Blink LED for Task 3
    IOWR_ALTERA_AVALON_PIO_DATA(LED_TASK3_BASE, 0x1);
    vTaskDelay(pdMS_TO_TICKS(100));
    IOWR_ALTERA_AVALON_PIO_DATA(LED_TASK3_BASE, 0x0);
    vTaskDelay(pdMS_TO_TICKS(100));

    char freq_text[20];
    char roc_text[20];
    char load_status_text[MAX_LOADS][20];

    while(1) {
        // Read shared variables
        xSemaphoreTake(xMutex, portMAX_DELAY);
        float inst_freq_local = inst_freq;
        float roc_freq_local = roc_freq;
        int load_status_local[MAX_LOADS];
        for (int i = 0; i < MAX_LOADS; i++) {
            load_status_local[i] = load_status[i];
        }
        xSemaphoreGive(xMutex);

        // Clear lines before updating VGA display with frequency, rate of change, and load status information
		for (int i = 0; i < (MAX_LOADS + 2); i++) {
			custom_char_buffer_clear_line(char_buf, 30 + i);
		}

		// Update VGA display with frequency and rate of change information
		snprintf(freq_text, sizeof(freq_text), "Frequency: %.2f Hz", 16000 / (double)inst_freq_local);
		alt_up_char_buffer_string(char_buf, freq_text, 40, 30);
		snprintf(roc_text, sizeof(roc_text), "RoC: %.2f Hz/s", roc_freq_local);
		alt_up_char_buffer_string(char_buf, roc_text, 40, 31);

		// Update VGA display with load status information
		for (int i = 0; i < MAX_LOADS; i++) {
			snprintf(load_status_text[i], sizeof(load_status_text[i]), "Load %d: %s", i + 1, load_status_local[i] ? "ON" : "OFF");
			alt_up_char_buffer_string(char_buf, load_status_text[i], 40, 33 + i);
		}

		vTaskDelay(pdMS_TO_TICKS(1000));
	}
}





void ISR1(void *context, alt_u32 id) {
    // Handle user input (slide switches and push button)
    // ...

    // Update shared resources (load_status and relay_state)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update load_status based on the slide switches
    // Update relay_state based on the push button
    xSemaphoreGiveFromISR(xMutex, 0);
}

void ISR2(TimerHandle_t xTimer) {
    // Measure the time intervals and update timing measurements
    // ...

    // Update shared resources (timing_meas)
    xSemaphoreTakeFromISR(xMutex, 0);
    // Update timing_meas array
    xSemaphoreGiveFromISR(xMutex, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283