Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment/interrupts and binary semaphores #2

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Binary file not shown.
24 changes: 24 additions & 0 deletions projects/lpc40xx_freertos/assignment_include.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @file assignment_include.h
* @author Tejas Pidkalwar
* @date 19th Sept 2020
* @brief This file maintains the macro defined to enable specific assignment implementation for
* execution, along with subparts of assignment enabling feature
*/
#ifndef _ASSIGNMENT_INCLUDE_
#define _ASSIGNMENT_INCLUDE_

/*
* This file defines macros corresponding each assignment.
* Enable only one assignment macro while compiling.
* This file also defines macros for sub parts corresponding to each assignment.
* Take care to enable only one part macro enabled while compiling.
*/

// Assignment 3
#define INTERRUPT_ASSIGNMENT
//#define PART0_IRQ_ASSGNMT
//#define PART1_IRQ_ASSGNMT
#define PART2_IRQ_ASSGNMT

#endif
8 changes: 8 additions & 0 deletions projects/lpc40xx_freertos/interrupt_vector_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include "function_types.h"
#include "lpc40xx.h"

#ifdef PART0_IRQ_ASSGNMT
extern void gpio_interrupt(void);
#endif

/**
* _estack symbol is actually a pointer to the start of the stack memory (provided by the linker script).
* Declaring as unsigned int to inform compiler that this symbol is constant and defined at link time.
Expand Down Expand Up @@ -93,7 +97,11 @@ __attribute__((section(".interrupt_vector_table"))) const function__void_f inter
lpc_peripheral__interrupt_dispatcher, // 51 UART 4
lpc_peripheral__interrupt_dispatcher, // 52 SSP 2
lpc_peripheral__interrupt_dispatcher, // 53 LCD
#ifdef PART0_IRQ_ASSGNMT
gpio_interrupt, // 54 GPIO Interrupt
#else
lpc_peripheral__interrupt_dispatcher, // 54 GPIO Interrupt
#endif
lpc_peripheral__interrupt_dispatcher, // 55 PWM 0
lpc_peripheral__interrupt_dispatcher, // 56 EEPROM
};
Expand Down
40 changes: 40 additions & 0 deletions projects/lpc40xx_freertos/l3_drivers/gpio_isr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @file gpio_isr.h
* @author Tejas Pidkalwar
* @date 20th Sept 2020
* @brief This file maintains the abstracted APIs to configure GPIO interrupts
*/

#pragma once

#include "lpc40xx.h"
#include <stdint.h>

typedef enum {
GPIO_INTR__FALLING_EDGE,
GPIO_INTR__RISING_EDGE,
} gpio_interrupt_e;

// Function pointer type (demonstrated later in the code sample)
typedef void (*function_pointer_t)(void);

/**
* Allow the user to attach GPIO0 interrupt callback
* @param pin GPIO pin to be configured for GPIO interrupt
* @param interrupt_type Type of interrupt configuration
* @param callback An ISR function to be called on occurance of this interrupt
*/
void gpio0__attach_interrupt(uint32_t pin, gpio_interrupt_e interrupt_type, function_pointer_t callback);

/**
* Allow the user to attach GPIO2 interrupt callback
* @param pin GPIO pin to be configured for GPIO interrupt
* @param interrupt_type Type of interrupt configuration
* @param callback An ISR function to be called on occurance of this interrupt
*/
void gpio2__attach_interrupt(uint32_t pin, gpio_interrupt_e interrupt_type, function_pointer_t callback);

/**
* Dispatcher for the GPIO interrupt to recognise interrupting GPIO and call corresponding ISR
*/
void gpio__interrupt_dispatcher(void);
130 changes: 130 additions & 0 deletions projects/lpc40xx_freertos/l3_drivers/sources/gpio_isr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/**
* @file gpio_isr.c
* @author Tejas Pidkalwar
* @date 20th Sept 2020
* @brief This file maintains the abstracted APIs to configure GPIO interrupts
*/

#include "gpio_isr.h"
#include "gpio.h"
#include "stdio.h"
/***************************GPIO 0********************************************/

/**
* Array of callback ISR functions for GPIO 0 falling edge interrupts
*/
static function_pointer_t gpio0_falling_edge_callbacks[32];

/**
* Array of callback ISR functions for GPIO 0 rising edge interrupts
*/
static function_pointer_t gpio0_rising_edge_callbacks[32];

void gpio0__attach_interrupt(uint32_t pin, gpio_interrupt_e interrupt_type, function_pointer_t callback) {
printf("Attaching callback function for interrupt on GPIO 0 PIN %ld\n", pin);
// Attaching the callback function for given pin as per the given interrupt type
if (interrupt_type == GPIO_INTR__FALLING_EDGE) {
gpio0_falling_edge_callbacks[pin] = callback;
LPC_GPIOINT->IO0IntEnF |= (1 << pin);
} else {
gpio0_rising_edge_callbacks[pin] = callback;
LPC_GPIOINT->IO0IntEnR |= (1 << pin);
}
}

/***************************GPIO 2********************************************/

/**
* Array of callback ISR functions for GPIO 2 falling edge interrupts
*/
static function_pointer_t gpio2_falling_edge_callbacks[32];

/**
* Array of callback ISR functions for GPIO 2 rising edge interrupts
*/
static function_pointer_t gpio2_rising_edge_callbacks[32];

void gpio2__attach_interrupt(uint32_t pin, gpio_interrupt_e interrupt_type, function_pointer_t callback) {
printf("Attaching callback function for interrupt on GPIO 2 PIN %ld\n", pin);
// Attaching the callback function for given pin as per the given interrupt type
if (interrupt_type == GPIO_INTR__FALLING_EDGE) {
gpio2_falling_edge_callbacks[pin] = callback;
LPC_GPIOINT->IO2IntEnF |= (1 << pin);
} else {
gpio2_rising_edge_callbacks[pin] = callback;
LPC_GPIOINT->IO2IntEnR |= (1 << pin);
}
}

/********************Common APIs**********************************************/

/**
* This function reads the status register to know which pin on GPIO0 has caused the interrupt
* @param interrupt_type The pointer to the type of interrupt
* @return pin return the pin that caused the interrupt
*/
static void update_interrupt_gpio_struct(gpio_interrupt_e *interrupt_type, gpio_s *gpio) {
uint32_t status;

// Read the GPIO interrupt registers to know interrupt causing GPIO specs
if (LPC_GPIOINT->IO0IntStatF) {
status = LPC_GPIOINT->IO0IntStatF;
*interrupt_type = GPIO_INTR__FALLING_EDGE;
gpio->port_number = 0;
} else if (LPC_GPIOINT->IO0IntStatR) {
status = LPC_GPIOINT->IO0IntStatR;
*interrupt_type = GPIO_INTR__RISING_EDGE;
gpio->port_number = 0;
} else if (LPC_GPIOINT->IO2IntStatF) {
status = LPC_GPIOINT->IO2IntStatF;
*interrupt_type = GPIO_INTR__FALLING_EDGE;
gpio->port_number = 1;
} else {
status = LPC_GPIOINT->IO2IntStatR;
*interrupt_type = GPIO_INTR__RISING_EDGE;
gpio->port_number = 1;
}

// get the pin number from the status register
int pin = 0;
while (status >>= 1)
pin++;
gpio->pin_number = pin;
}

/**
* Clear the interrupt on a given pin of port 0.
* @param pin pin number of which interrupt needs to be cleared
*/
static void gpio_clear_pin_interrupt(gpio_s gpio) {
if (gpio.port_number == 0)
LPC_GPIOINT->IO0IntClr |= (1 << gpio.pin_number);
else
LPC_GPIOINT->IO2IntClr |= (1 << gpio.pin_number);
}

void gpio__interrupt_dispatcher(void) {

gpio_interrupt_e interrupt_type;
gpio_s gpio;

// Check which pin generated the interrupt
update_interrupt_gpio_struct(&interrupt_type, &gpio);

function_pointer_t attached_user_handler;
if (gpio.port_number == 0) {
if (interrupt_type == GPIO_INTR__FALLING_EDGE)
attached_user_handler = gpio0_falling_edge_callbacks[gpio.pin_number];
else
attached_user_handler = gpio0_rising_edge_callbacks[gpio.pin_number];
} else {
if (interrupt_type == GPIO_INTR__FALLING_EDGE)
attached_user_handler = gpio0_falling_edge_callbacks[gpio.pin_number];
else
attached_user_handler = gpio0_rising_edge_callbacks[gpio.pin_number];
}
fprintf(stderr, "Dispatching to ISR fucntion corresponding to GPIO %d PIN %d\n", gpio.port_number, gpio.pin_number);
// Invoke the user registered callback, and then clear the interrupt
attached_user_handler();
gpio_clear_pin_interrupt(gpio);
}
115 changes: 114 additions & 1 deletion projects/lpc40xx_freertos/l5_application/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,132 @@
#include "periodic_scheduler.h"
#include "sj2_cli.h"

#ifdef INTERRUPT_ASSIGNMENT

#include "delay.h"
#include "gpio_isr.h"
#include "lpc_peripherals.h"
#include "semphr.h"

#endif

#ifdef INTERRUPT_ASSIGNMENT

void gpio_interrupt(void);
static void sleep_on_sem_task(void *p);

static SemaphoreHandle_t waitOnSemaphore;

#else

static void create_blinky_tasks(void);
static void create_uart_task(void);
static void blink_task(void *params);
static void uart_task(void *params);

#endif

int main(void) {

#ifdef INTERRUPT_ASSIGNMENT

#ifdef PART0_IRQ_ASSGNMT
// Set GPIO 0 Pin 30 as a input
LPC_GPIO0->DIR &= ~(1 << 30);
LPC_GPIOINT->IO0IntEnR |= (1 << 30);

// lpc_peripheral__enable_interrupt(LPC_PERIPHERAL__GPIO, gpio_interrupt, "gpio0");

NVIC_EnableIRQ(GPIO_IRQn);

static gpio_s led2;

led2 = board_io__get_led2();
while (1) {
delay__ms(100);
gpio__toggle(led2);
}
#endif

#if (defined(PART1_IRQ_ASSGNMT) || defined(PART2_IRQ_ASSGNMT))
waitOnSemaphore = xSemaphoreCreateBinary();

// Initializing GPIO to switch 2 to configure for interrupt
static gpio_s switch2;
switch2 = board_io__get_sw2();

// Set GPIO 0 Pin 30 as a input
gpio__set_as_input(switch2);

NVIC_EnableIRQ(GPIO_IRQn);
xTaskCreate(sleep_on_sem_task, "waitOnSem", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL);
#endif

#ifdef PART1_IRQ_ASSGNMT

LPC_GPIOINT->IO0IntEnR |= (1 << 30);
lpc_peripheral__enable_interrupt(LPC_PERIPHERAL__GPIO, gpio_interrupt, "gpio0");

#endif

#ifdef PART2_IRQ_ASSGNMT

gpio0__attach_interrupt(switch2.pin_number, GPIO_INTR__FALLING_EDGE, gpio_interrupt);

lpc_peripheral__enable_interrupt(LPC_PERIPHERAL__GPIO, gpio__interrupt_dispatcher, "gpio_isr");

#endif

#else
create_blinky_tasks();
create_uart_task();

#endif
puts("Starting RTOS");
vTaskStartScheduler(); // This function never returns unless RTOS scheduler runs out of memory and fails

return 0;
}

#ifdef INTERRUPT_ASSIGNMENT

void gpio_interrupt(void) {
// Clear interrupt
LPC_GPIOINT->IO0IntClr |= (1 << 30);

#ifdef PART0_IRQ_ASSGNMT
fprintf(stderr, "Switch is pressed, Enterring ISR to blink LED3\n");
static gpio_s led3;
led3 = board_io__get_led3();
int count = 4;
while (count--) {
delay__ms(100);
gpio__toggle(led3);
}
#endif
#if (defined(PART1_IRQ_ASSGNMT) || defined(PART2_IRQ_ASSGNMT))
fprintf(stderr, "Switch is pressed, Will enter Semaphore Task\n");
if (!xSemaphoreGiveFromISR(waitOnSemaphore, NULL))
fprintf(stderr, "Unable to Release Semaphore");
#endif
}

static void sleep_on_sem_task(void *p) {
while (1) {
if (xSemaphoreTake(waitOnSemaphore, portMAX_DELAY)) {
fprintf(stderr, "ISR gave me semaphore to enter this task\n");
static gpio_s led3;
led3 = board_io__get_led3();
int count = 4;
while (count--) {
delay__ms(100);
gpio__toggle(led3);
}
}
}
}

#else

static void create_blinky_tasks(void) {
/**
* Use '#if (1)' if you wish to observe how two tasks can blink LEDs
Expand Down Expand Up @@ -98,3 +209,5 @@ static void uart_task(void *params) {
printf(" %lu ticks\n\n", (xTaskGetTickCount() - ticks));
}
}

#endif
1 change: 1 addition & 0 deletions projects/lpc40xx_freertos/lpc40xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#ifndef __LPC407x_8x_H__
#define __LPC407x_8x_H__

#include "assignment_include.h"
/*
* ==========================================================================
* ---------- Interrupt Number Definition -----------------------------------
Expand Down