diff --git a/doc/Assignment/Interrupt_assignment_observations.pdf b/doc/Assignment/Interrupt_assignment_observations.pdf new file mode 100644 index 0000000..ce5a6da Binary files /dev/null and b/doc/Assignment/Interrupt_assignment_observations.pdf differ diff --git a/projects/lpc40xx_freertos/assignment_include.h b/projects/lpc40xx_freertos/assignment_include.h new file mode 100644 index 0000000..9b20504 --- /dev/null +++ b/projects/lpc40xx_freertos/assignment_include.h @@ -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 \ No newline at end of file diff --git a/projects/lpc40xx_freertos/interrupt_vector_table.c b/projects/lpc40xx_freertos/interrupt_vector_table.c index a2f2e5a..87d252a 100644 --- a/projects/lpc40xx_freertos/interrupt_vector_table.c +++ b/projects/lpc40xx_freertos/interrupt_vector_table.c @@ -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. @@ -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 }; diff --git a/projects/lpc40xx_freertos/l3_drivers/gpio_isr.h b/projects/lpc40xx_freertos/l3_drivers/gpio_isr.h new file mode 100644 index 0000000..d475746 --- /dev/null +++ b/projects/lpc40xx_freertos/l3_drivers/gpio_isr.h @@ -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 + +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); \ No newline at end of file diff --git a/projects/lpc40xx_freertos/l3_drivers/sources/gpio_isr.c b/projects/lpc40xx_freertos/l3_drivers/sources/gpio_isr.c new file mode 100644 index 0000000..234b5a6 --- /dev/null +++ b/projects/lpc40xx_freertos/l3_drivers/sources/gpio_isr.c @@ -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); +} \ No newline at end of file diff --git a/projects/lpc40xx_freertos/l5_application/main.c b/projects/lpc40xx_freertos/l5_application/main.c index 3194d1d..63ad4cc 100644 --- a/projects/lpc40xx_freertos/l5_application/main.c +++ b/projects/lpc40xx_freertos/l5_application/main.c @@ -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 @@ -98,3 +209,5 @@ static void uart_task(void *params) { printf(" %lu ticks\n\n", (xTaskGetTickCount() - ticks)); } } + +#endif \ No newline at end of file diff --git a/projects/lpc40xx_freertos/lpc40xx.h b/projects/lpc40xx_freertos/lpc40xx.h index 2f138cb..9473013 100644 --- a/projects/lpc40xx_freertos/lpc40xx.h +++ b/projects/lpc40xx_freertos/lpc40xx.h @@ -27,6 +27,7 @@ #ifndef __LPC407x_8x_H__ #define __LPC407x_8x_H__ +#include "assignment_include.h" /* * ========================================================================== * ---------- Interrupt Number Definition -----------------------------------