diff --git a/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h b/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h new file mode 100644 index 0000000..adb224a --- /dev/null +++ b/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h @@ -0,0 +1,60 @@ +/** + * @file gpio_lab.h + * @author Tejas Pidkalwar + * @date 11th Sept 2020 + * @brief This file contains the prototypes of register bit manipulating + * functions for GPIO0 and GPIO1 as a part of LED_TASK assignment. + */ +#pragma once + +#include +#include + +/** + * This struct is returned gpio__construct() + * All further APIs need instance of this struct to operate + */ +typedef struct { + uint8_t port_number : 3; + uint8_t pin_number : 5; +} gpio_lab_s; + +// NOTE: The IOCON is not part of this driver + +/** + * Alter the hardware registers to set the pin as input + * @param gpio GPIO structure of which base address we need + */ +void gpio_lab_set_as_input(gpio_lab_s gpio); + +/** + * Alter the hardware registers to set the pin as output + * @param gpio GPIO structure of which base address we need + */ +void gpio_lab_set_as_output(gpio_lab_s gpio); + +/** + * Alter the hardware registers to set the pin as high + * @param gpio GPIO structure of which base address we need + */ +void gpio_lab_set_high(gpio_lab_s gpio); + +/** + * Alter the hardware registers to set the pin as low + * @param gpio GPIO structure of which base address we need + */ +void gpio_lab_set_low(gpio_lab_s gpio); + +/** + * Alter the hardware registers to set the pin as low + * @param {uint8_t} pin_num => input the pin number want to access + * @param {bool} high - true => set pin high, false => set pin low + */ +void gpio_lab_set(gpio_lab_s gpio, bool high); + +/** + * Should return the state of the pin (input or output, doesn't matter) + * @param {uint8_t} pin_num => input the pin number want to access + * @return {bool} level of pin high => true, low => false + */ +bool gpio_lab_get_level(gpio_lab_s gpio); \ No newline at end of file diff --git a/projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c b/projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c new file mode 100644 index 0000000..6200b95 --- /dev/null +++ b/projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c @@ -0,0 +1,51 @@ +/** + * @file gpio_lab.c + * @author Tejas Pidkalwar + * @date 11th Sept 2020 + * @brief This file contains the implementations of register bit manipulating + * functions for GPIO0 and GPIO1 as a part of LED_TASK assignment. + */ + +#include "gpio_lab.h" + +#include "lpc40xx.h" + +/** + * array of pointer ro GPIO ports' base addresses + */ +static LPC_GPIO_TypeDef *gpio_lab_port_memory_map[] = {LPC_GPIO0, LPC_GPIO1, LPC_GPIO2, + LPC_GPIO3, LPC_GPIO4, LPC_GPIO5}; + +/** + * Retruns the pointer to an base address of an given port + * @param gpio GPIO structure of which base address we need + * @return (LPC_GPIO_TypeDef *) pointer to the base address of given port + */ +static LPC_GPIO_TypeDef *gpio_lab_get_struct(gpio_lab_s gpio) { + return (LPC_GPIO_TypeDef *)gpio_lab_port_memory_map[gpio.port_number]; +} + +/** + * Retruns the pin masked value for the given GPIO + * @param gpio GPIO structure of which base address we need + * @return pin masked value for the given GPIO + */ +static uint32_t gpio_lab_get_pin_mask(gpio_lab_s gpio) { return (1 << gpio.pin_number); } + +void gpio_lab_set_as_input(gpio_lab_s gpio) { gpio_lab_get_struct(gpio)->DIR &= ~gpio_lab_get_pin_mask(gpio); } + +void gpio_lab_set_as_output(gpio_lab_s gpio) { gpio_lab_get_struct(gpio)->DIR |= gpio_lab_get_pin_mask(gpio); } + +void gpio_lab_set_high(gpio_lab_s gpio) { gpio_lab_get_struct(gpio)->SET = gpio_lab_get_pin_mask(gpio); } + +void gpio_lab_set_low(gpio_lab_s gpio) { gpio_lab_get_struct(gpio)->CLR = gpio_lab_get_pin_mask(gpio); } + +void gpio_lab_set(gpio_lab_s gpio, bool high) { + // based on the high bit's input value manipulate GPIO PIN. + if (high) + gpio_lab_get_struct(gpio)->SET = gpio_lab_get_pin_mask(gpio); + else + gpio_lab_get_struct(gpio)->CLR = gpio_lab_get_pin_mask(gpio); +} + +bool gpio_lab_get_level(gpio_lab_s gpio) { return (gpio_lab_get_struct(gpio)->PIN & gpio_lab_get_pin_mask(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..988b2a5 100644 --- a/projects/lpc40xx_freertos/l5_application/main.c +++ b/projects/lpc40xx_freertos/l5_application/main.c @@ -1,22 +1,138 @@ #include #include "FreeRTOS.h" +#include "queue.h" +#include "semphr.h" #include "task.h" #include "board_io.h" #include "common_macros.h" #include "gpio.h" +#include "gpio_lab.h" #include "periodic_scheduler.h" #include "sj2_cli.h" +/** + * Local Macros + */ +#define INVALID_SWITCH 4 +#define MAX_LEDS 4 + +/** + * Local Functions + */ static void create_blinky_tasks(void); static void create_uart_task(void); static void blink_task(void *params); static void uart_task(void *params); +/** + * Local Variables + */ +static SemaphoreHandle_t switch_press_indication; +static volatile uint8_t led_index = 0; + +static void led_task(void *task_parameter) { + // Available LEDs served under this task + const gpio_lab_s led[] = {{1, 18}, {1, 24}, {1, 26}, {2, 3}}; + while (true) { + // Check every 1000ms whether semaphore is available. Other time FreeRTOS make this task sleep + if (xSemaphoreTake(switch_press_indication, 1000)) { + // Temperory variable to track remaining LEDs to be blinked + int temp = MAX_LEDS; + + // This loop will turn on all LEDs starting led_index + while (temp) { + printf("led on index =%d \n", led_index); + gpio_lab_set_high(led[led_index++ % 4]); + vTaskDelay(100); + temp--; + } + temp = MAX_LEDS; + + // This loop will turn off all LEDs starting led_index + while (temp) { + printf("led off index =%d \n", led_index); + gpio_lab_set_low(led[led_index++ % 4]); + vTaskDelay(100); + temp--; + } + } else { + puts("Timeout: No switch press indication for 1000ms"); + } + } +} + +static void switch_task(void *task_parameter) { + // Available switches served under this task + const gpio_lab_s switch_index[] = {{1, 19}, {1, 15}, {0, 30}, {0, 29}}; + // Initialize the switch to be toggle to invalid switch + uint8_t toggle_switch = INVALID_SWITCH; + + while (true) { + // Monitor pressed switch for successful toggle + switch (toggle_switch) { + case 3: + if (!gpio_lab_get_level(switch_index[3])) { + toggle_switch = INVALID_SWITCH; + led_index = 0; + // Release the semaphore when the switch is successfully toggled + if (!xSemaphoreGive(switch_press_indication)) + puts("Unable to release the semaphore"); + } + break; + case 2: + if (!gpio_lab_get_level(switch_index[2])) { + toggle_switch = INVALID_SWITCH; + led_index = 1; + // Release the semaphore when the switch is successfully toggled + if (!xSemaphoreGive(switch_press_indication)) + puts("Unable to release the semaphore"); + } + break; + case 1: + if (!gpio_lab_get_level(switch_index[1])) { + toggle_switch = INVALID_SWITCH; + led_index = 2; + // Release the semaphore when the switch is successfully toggled + if (!xSemaphoreGive(switch_press_indication)) + puts("Unable to release the semaphore"); + } + break; + case 0: + if (!gpio_lab_get_level(switch_index[0])) { + toggle_switch = INVALID_SWITCH; + led_index = 3; + // Release the semaphore when the switch is successfully toggled + if (!xSemaphoreGive(switch_press_indication)) + puts("Unable to release the semaphore"); + } + break; + default: + break; + } + + // Monitor the pressed switch + if (gpio_lab_get_level(switch_index[3])) + toggle_switch = 3; + else if (gpio_lab_get_level(switch_index[2])) + toggle_switch = 2; + else if (gpio_lab_get_level(switch_index[1])) + toggle_switch = 1; + else if (gpio_lab_get_level(switch_index[0])) + toggle_switch = 0; + // Task should always sleep otherwise they will use 100% CPU + // This task sleep also helps avoid spurious semaphore give during switch debeounce + vTaskDelay(100); + } +} + int main(void) { - create_blinky_tasks(); - create_uart_task(); + + switch_press_indication = xSemaphoreCreateBinary(); + + xTaskCreate(led_task, "led", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL); + xTaskCreate(switch_task, "switch", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL); puts("Starting RTOS"); vTaskStartScheduler(); // This function never returns unless RTOS scheduler runs out of memory and fails @@ -97,4 +213,4 @@ static void uart_task(void *params) { printf("This is a more efficient printf ... finished in"); printf(" %lu ticks\n\n", (xTaskGetTickCount() - ticks)); } -} +} \ No newline at end of file