From 66ee1392d95e02d2f36e04220184e56a5cdfcedd Mon Sep 17 00:00:00 2001 From: Tejas Pidkalwar Date: Sat, 12 Sep 2020 01:51:00 -0700 Subject: [PATCH 1/4] part0 and part1 of assignment is implemented and tested --- .../lpc40xx_freertos/l3_drivers/gpio_lab.h | 42 +++++++++++++++++++ .../l3_drivers/sources/gpio_lab.c | 29 +++++++++++++ .../lpc40xx_freertos/l5_application/main.c | 21 +++++++++- 3 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 projects/lpc40xx_freertos/l3_drivers/gpio_lab.h create mode 100644 projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c 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..a8bb759 --- /dev/null +++ b/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h @@ -0,0 +1,42 @@ +/** + * @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 + +// include this file at gpio_lab.c file +// #include "lpc40xx.h" + +// NOTE: The IOCON is not part of this driver + +// Alter the hardware registers to set the pin as input +void gpio0__set_as_input(uint8_t pin_num); + +// Alter the hardware registers to set the pin as output +void gpio0__set_as_output(uint8_t pin_num); + +// Alter the hardware registers to set the pin as high +void gpio0__set_high(uint8_t pin_num); + +// Alter the hardware registers to set the pin as low +void gpio0__set_low(uint8_t pin_num); + +/** + * 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 gpio0__set(uint8_t pin_num, 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 gpio0__get_level(uint8_t pin_num); \ 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..a2af188 --- /dev/null +++ b/projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c @@ -0,0 +1,29 @@ +/** + * @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" + +void gpio0__set_as_input(uint8_t pin_num) { LPC_GPIO0->DIR &= ~(1 << pin_num); } + +void gpio0__set_as_output(uint8_t pin_num) { LPC_GPIO0->DIR |= (1 << pin_num); } + +void gpio0__set_high(uint8_t pin_num) { LPC_GPIO0->SET = (1 << pin_num); } + +void gpio0__set_low(uint8_t pin_num) { LPC_GPIO0->CLR = (1 << pin_num); } + +void gpio0__set(uint8_t pin_num, bool high) { + // based on the high bit's input value manipulate GPIO PIN. + if (high) + LPC_GPIO0->SET = (1 << pin_num); + else + LPC_GPIO0->CLR = (1 << pin_num); +} + +bool gpio0__get_level(uint8_t pin_num) { return (LPC_GPIO0->PIN & (1 << pin_num)); } \ 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..c72b6f4 100644 --- a/projects/lpc40xx_freertos/l5_application/main.c +++ b/projects/lpc40xx_freertos/l5_application/main.c @@ -14,9 +14,26 @@ static void create_uart_task(void); static void blink_task(void *params); static void uart_task(void *params); +void led_port1_wire18_Task(void *pvParameters) { + const uint32_t led = (1 << 18); + // Set the IOCON mux fucntion select pins to 000 + LPC_IOCON->P1_18 &= ~(0x7); + + // Set the DIR register's bit corresponding to LED 0 + LPC_GPIO1->DIR |= led; + + while (true) { + // Turn on the LED0 + LPC_GPIO1->SET = led; + vTaskDelay(100); + LPC_GPIO1->CLR = led; + vTaskDelay(100); + } +} + int main(void) { - create_blinky_tasks(); - create_uart_task(); + + xTaskCreate(led_port1_wire18_Task, "led0", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL); puts("Starting RTOS"); vTaskStartScheduler(); // This function never returns unless RTOS scheduler runs out of memory and fails From ed1b5a82a29c8a185be1f3b6f394fdc078884dc3 Mon Sep 17 00:00:00 2001 From: Tejas Pidkalwar Date: Sat, 12 Sep 2020 02:53:22 -0700 Subject: [PATCH 2/4] part 3 of assignment is implemented. Two tasks created to blink 2 LEDs using same task function --- .../lpc40xx_freertos/l3_drivers/gpio_lab.h | 28 +++++++++++++++- .../l3_drivers/sources/gpio_lab.c | 19 ++++++++++- .../lpc40xx_freertos/l5_application/main.c | 33 ++++++++++++++----- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h b/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h index a8bb759..d59cf01 100644 --- a/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h +++ b/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h @@ -39,4 +39,30 @@ void gpio0__set(uint8_t pin_num, bool high); * @param {uint8_t} pin_num => input the pin number want to access * @return {bool} level of pin high => true, low => false */ -bool gpio0__get_level(uint8_t pin_num); \ No newline at end of file +bool gpio0__get_level(uint8_t pin_num); + +// Alter the hardware registers to set the pin as input +void gpio1__set_as_input(uint8_t pin_num); + +// Alter the hardware registers to set the pin as output +void gpio1__set_as_output(uint8_t pin_num); + +// Alter the hardware registers to set the pin as high +void gpio1__set_high(uint8_t pin_num); + +// Alter the hardware registers to set the pin as low +void gpio1__set_low(uint8_t pin_num); + +/** + * 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 gpio1__set(uint8_t pin_num, 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 gpio1__get_level(uint8_t pin_num); \ 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 index a2af188..43a853f 100644 --- a/projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c +++ b/projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c @@ -26,4 +26,21 @@ void gpio0__set(uint8_t pin_num, bool high) { LPC_GPIO0->CLR = (1 << pin_num); } -bool gpio0__get_level(uint8_t pin_num) { return (LPC_GPIO0->PIN & (1 << pin_num)); } \ No newline at end of file +bool gpio0__get_level(uint8_t pin_num) { return (LPC_GPIO0->PIN & (1 << pin_num)); } + +void gpio1__set_as_input(uint8_t pin_num) { LPC_GPIO1->DIR &= ~(1 << pin_num); } + +void gpio1__set_as_output(uint8_t pin_num) { LPC_GPIO1->DIR |= (1 << pin_num); } + +void gpio1__set_high(uint8_t pin_num) { LPC_GPIO1->SET = (1 << pin_num); } + +void gpio1__set_low(uint8_t pin_num) { LPC_GPIO1->CLR = (1 << pin_num); } + +void gpio1__set(uint8_t pin_num, bool high) { + if (high) + LPC_GPIO1->SET = (1 << pin_num); + else + LPC_GPIO1->CLR = (1 << pin_num); +} + +bool gpio1__get_level(uint8_t pin_num) { return (LPC_GPIO1->PIN & (1 << pin_num)); } \ 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 c72b6f4..d2ac762 100644 --- a/projects/lpc40xx_freertos/l5_application/main.c +++ b/projects/lpc40xx_freertos/l5_application/main.c @@ -6,6 +6,7 @@ #include "board_io.h" #include "common_macros.h" #include "gpio.h" +#include "gpio_lab.h" #include "periodic_scheduler.h" #include "sj2_cli.h" @@ -14,26 +15,40 @@ static void create_uart_task(void); static void blink_task(void *params); static void uart_task(void *params); -void led_port1_wire18_Task(void *pvParameters) { - const uint32_t led = (1 << 18); - // Set the IOCON mux fucntion select pins to 000 - LPC_IOCON->P1_18 &= ~(0x7); +typedef struct { + /* First get gpio0 driver to work only, and if you finish it + * you can do the extra credit to also make it work for other Ports + */ + // uint8_t port; + + uint8_t pin; +} port_pin_s; + +void led_task(void *task_parameter) { + // Type-cast the parameter that was passed from xTaskCreate() + const port_pin_s *led = (port_pin_s *)(task_parameter); - // Set the DIR register's bit corresponding to LED 0 - LPC_GPIO1->DIR |= led; + // Set the given pin as output + // gpio1__set_as_output(led->pin); while (true) { // Turn on the LED0 - LPC_GPIO1->SET = led; + gpio1__set_high(led->pin); vTaskDelay(100); - LPC_GPIO1->CLR = led; + + gpio1__set_low(led->pin); vTaskDelay(100); } } int main(void) { - xTaskCreate(led_port1_wire18_Task, "led0", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL); + // Select LED3 and LED2 connected to port1 pin 18 and 24 respectively + static port_pin_s led0 = {18}; + static port_pin_s led1 = {24}; + + xTaskCreate(led_task, "led0", 2048 / sizeof(void *), (void *)&led0, PRIORITY_LOW, NULL); + xTaskCreate(led_task, "led1", 2048 / sizeof(void *), (void *)&led1, PRIORITY_LOW, NULL); puts("Starting RTOS"); vTaskStartScheduler(); // This function never returns unless RTOS scheduler runs out of memory and fails From 05d3dc07015cc971374af181cc42e97b627323c7 Mon Sep 17 00:00:00 2001 From: Tejas Pidkalwar Date: Sat, 12 Sep 2020 16:00:04 -0700 Subject: [PATCH 3/4] Added Switch task, interfaced switch and led task using binary semaphore to get left to right led flashing on swtch3 press --- .../lpc40xx_freertos/l3_drivers/gpio_lab.h | 60 +++++++-------- .../l3_drivers/sources/gpio_lab.c | 49 +++++++------ .../lpc40xx_freertos/l5_application/main.c | 73 +++++++++++++------ 3 files changed, 104 insertions(+), 78 deletions(-) diff --git a/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h b/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h index d59cf01..adb224a 100644 --- a/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h +++ b/projects/lpc40xx_freertos/l3_drivers/gpio_lab.h @@ -10,59 +10,51 @@ #include #include -// include this file at gpio_lab.c file -// #include "lpc40xx.h" +/** + * 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 -void gpio0__set_as_input(uint8_t pin_num); - -// Alter the hardware registers to set the pin as output -void gpio0__set_as_output(uint8_t pin_num); - -// Alter the hardware registers to set the pin as high -void gpio0__set_high(uint8_t pin_num); - -// Alter the hardware registers to set the pin as low -void gpio0__set_low(uint8_t pin_num); - /** - * 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 + * Alter the hardware registers to set the pin as input + * @param gpio GPIO structure of which base address we need */ -void gpio0__set(uint8_t pin_num, bool high); +void gpio_lab_set_as_input(gpio_lab_s gpio); /** - * 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 + * Alter the hardware registers to set the pin as output + * @param gpio GPIO structure of which base address we need */ -bool gpio0__get_level(uint8_t pin_num); - -// Alter the hardware registers to set the pin as input -void gpio1__set_as_input(uint8_t pin_num); +void gpio_lab_set_as_output(gpio_lab_s gpio); -// Alter the hardware registers to set the pin as output -void gpio1__set_as_output(uint8_t pin_num); - -// Alter the hardware registers to set the pin as high -void gpio1__set_high(uint8_t pin_num); +/** + * 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 -void gpio1__set_low(uint8_t pin_num); +/** + * 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 gpio1__set(uint8_t pin_num, bool high); +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 gpio1__get_level(uint8_t pin_num); \ No newline at end of file +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 index 43a853f..6200b95 100644 --- a/projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c +++ b/projects/lpc40xx_freertos/l3_drivers/sources/gpio_lab.c @@ -10,37 +10,42 @@ #include "lpc40xx.h" -void gpio0__set_as_input(uint8_t pin_num) { LPC_GPIO0->DIR &= ~(1 << pin_num); } - -void gpio0__set_as_output(uint8_t pin_num) { LPC_GPIO0->DIR |= (1 << pin_num); } - -void gpio0__set_high(uint8_t pin_num) { LPC_GPIO0->SET = (1 << pin_num); } - -void gpio0__set_low(uint8_t pin_num) { LPC_GPIO0->CLR = (1 << pin_num); } +/** + * 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}; -void gpio0__set(uint8_t pin_num, bool high) { - // based on the high bit's input value manipulate GPIO PIN. - if (high) - LPC_GPIO0->SET = (1 << pin_num); - else - LPC_GPIO0->CLR = (1 << pin_num); +/** + * 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]; } -bool gpio0__get_level(uint8_t pin_num) { return (LPC_GPIO0->PIN & (1 << pin_num)); } +/** + * 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 gpio1__set_as_input(uint8_t pin_num) { LPC_GPIO1->DIR &= ~(1 << pin_num); } +void gpio_lab_set_as_input(gpio_lab_s gpio) { gpio_lab_get_struct(gpio)->DIR &= ~gpio_lab_get_pin_mask(gpio); } -void gpio1__set_as_output(uint8_t pin_num) { LPC_GPIO1->DIR |= (1 << pin_num); } +void gpio_lab_set_as_output(gpio_lab_s gpio) { gpio_lab_get_struct(gpio)->DIR |= gpio_lab_get_pin_mask(gpio); } -void gpio1__set_high(uint8_t pin_num) { LPC_GPIO1->SET = (1 << pin_num); } +void gpio_lab_set_high(gpio_lab_s gpio) { gpio_lab_get_struct(gpio)->SET = gpio_lab_get_pin_mask(gpio); } -void gpio1__set_low(uint8_t pin_num) { LPC_GPIO1->CLR = (1 << pin_num); } +void gpio_lab_set_low(gpio_lab_s gpio) { gpio_lab_get_struct(gpio)->CLR = gpio_lab_get_pin_mask(gpio); } -void gpio1__set(uint8_t pin_num, bool high) { +void gpio_lab_set(gpio_lab_s gpio, bool high) { + // based on the high bit's input value manipulate GPIO PIN. if (high) - LPC_GPIO1->SET = (1 << pin_num); + gpio_lab_get_struct(gpio)->SET = gpio_lab_get_pin_mask(gpio); else - LPC_GPIO1->CLR = (1 << pin_num); + gpio_lab_get_struct(gpio)->CLR = gpio_lab_get_pin_mask(gpio); } -bool gpio1__get_level(uint8_t pin_num) { return (LPC_GPIO1->PIN & (1 << pin_num)); } \ No newline at end of file +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 d2ac762..32d2f7d 100644 --- a/projects/lpc40xx_freertos/l5_application/main.c +++ b/projects/lpc40xx_freertos/l5_application/main.c @@ -1,6 +1,7 @@ #include #include "FreeRTOS.h" +#include "semphr.h" #include "task.h" #include "board_io.h" @@ -10,45 +11,73 @@ #include "periodic_scheduler.h" #include "sj2_cli.h" +/** + * 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); -typedef struct { - /* First get gpio0 driver to work only, and if you finish it - * you can do the extra credit to also make it work for other Ports - */ - // uint8_t port; - - uint8_t pin; -} port_pin_s; +/** + * Local Variables + */ +static SemaphoreHandle_t switch_press_indication; -void led_task(void *task_parameter) { +static void led_task(void *task_parameter) { // Type-cast the parameter that was passed from xTaskCreate() - const port_pin_s *led = (port_pin_s *)(task_parameter); - - // Set the given pin as output - // gpio1__set_as_output(led->pin); + const gpio_lab_s led = *((gpio_lab_s *)task_parameter); while (true) { - // Turn on the LED0 - gpio1__set_high(led->pin); - vTaskDelay(100); + // Check every 1000ms whether semaphore is available. Other time FreeRTOS make this task sleep + if (xSemaphoreTake(switch_press_indication, 1000)) { + // Turn on the LEDs + gpio_lab_set_high(led); + vTaskDelay(400); + // Turn off the LEDs + gpio_lab_set_low(led); + vTaskDelay(400); + } else { + puts("Timeout: No switch press indication for 1000ms"); + } + } +} - gpio1__set_low(led->pin); +static void switch_task(void *task_parameter) { + // Type-cast the paramter that was passed from xTaskCreate() + const gpio_lab_s switch3 = *((gpio_lab_s *)task_parameter); + + while (true) { + if (gpio_lab_get_level(switch3)) { + // Release the semaphore when the switch is pressed + if (!xSemaphoreGive(switch_press_indication)) + puts("Unable to release the semaphore"); + } + // 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) { + switch_press_indication = xSemaphoreCreateBinary(); + // Select LED3 and LED2 connected to port1 pin 18 and 24 respectively - static port_pin_s led0 = {18}; - static port_pin_s led1 = {24}; + static gpio_lab_s gpio_led3 = {1, 18}; + static gpio_lab_s gpio_led2 = {1, 24}; + static gpio_lab_s gpio_led1 = {1, 26}; + static gpio_lab_s gpio_led0 = {2, 3}; - xTaskCreate(led_task, "led0", 2048 / sizeof(void *), (void *)&led0, PRIORITY_LOW, NULL); - xTaskCreate(led_task, "led1", 2048 / sizeof(void *), (void *)&led1, PRIORITY_LOW, NULL); + xTaskCreate(led_task, "led3", 2048 / sizeof(void *), (void *)&gpio_led3, PRIORITY_CRITICAL, NULL); + xTaskCreate(led_task, "led2", 2048 / sizeof(void *), (void *)&gpio_led2, PRIORITY_HIGH, NULL); + xTaskCreate(led_task, "led1", 2048 / sizeof(void *), (void *)&gpio_led1, PRIORITY_MEDIUM, NULL); + xTaskCreate(led_task, "led0", 2048 / sizeof(void *), (void *)&gpio_led0, PRIORITY_LOW, NULL); + + // Select Switch3 connected to port0 pin 29 and 24 respectively + static gpio_lab_s gpio_switch3 = {0, 29}; + + xTaskCreate(switch_task, "switch3", 2048 / sizeof(void *), (void *)&gpio_switch3, PRIORITY_CRITICAL, NULL); puts("Starting RTOS"); vTaskStartScheduler(); // This function never returns unless RTOS scheduler runs out of memory and fails @@ -129,4 +158,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 From eba88c4fd7e0fec549ef484811a85efd43edb39e Mon Sep 17 00:00:00 2001 From: Tejas Pidkalwar Date: Mon, 14 Sep 2020 15:40:43 -0700 Subject: [PATCH 4/4] Added 4 switches support to flash all 4 LEDs, removed task parameter, added volatile global variable to mention the starting LED index to flash LEDs --- .../lpc40xx_freertos/l5_application/main.c | 115 +++++++++++++----- 1 file changed, 85 insertions(+), 30 deletions(-) diff --git a/projects/lpc40xx_freertos/l5_application/main.c b/projects/lpc40xx_freertos/l5_application/main.c index 32d2f7d..988b2a5 100644 --- a/projects/lpc40xx_freertos/l5_application/main.c +++ b/projects/lpc40xx_freertos/l5_application/main.c @@ -1,6 +1,7 @@ #include #include "FreeRTOS.h" +#include "queue.h" #include "semphr.h" #include "task.h" @@ -11,6 +12,12 @@ #include "periodic_scheduler.h" #include "sj2_cli.h" +/** + * Local Macros + */ +#define INVALID_SWITCH 4 +#define MAX_LEDS 4 + /** * Local Functions */ @@ -23,20 +30,33 @@ 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) { - // Type-cast the parameter that was passed from xTaskCreate() - const gpio_lab_s led = *((gpio_lab_s *)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)) { - // Turn on the LEDs - gpio_lab_set_high(led); - vTaskDelay(400); - // Turn off the LEDs - gpio_lab_set_low(led); - vTaskDelay(400); + // 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"); } @@ -44,15 +64,63 @@ static void led_task(void *task_parameter) { } static void switch_task(void *task_parameter) { - // Type-cast the paramter that was passed from xTaskCreate() - const gpio_lab_s switch3 = *((gpio_lab_s *)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) { - if (gpio_lab_get_level(switch3)) { - // Release the semaphore when the switch is pressed - if (!xSemaphoreGive(switch_press_indication)) - puts("Unable to release the semaphore"); + // 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); @@ -63,21 +131,8 @@ int main(void) { switch_press_indication = xSemaphoreCreateBinary(); - // Select LED3 and LED2 connected to port1 pin 18 and 24 respectively - static gpio_lab_s gpio_led3 = {1, 18}; - static gpio_lab_s gpio_led2 = {1, 24}; - static gpio_lab_s gpio_led1 = {1, 26}; - static gpio_lab_s gpio_led0 = {2, 3}; - - xTaskCreate(led_task, "led3", 2048 / sizeof(void *), (void *)&gpio_led3, PRIORITY_CRITICAL, NULL); - xTaskCreate(led_task, "led2", 2048 / sizeof(void *), (void *)&gpio_led2, PRIORITY_HIGH, NULL); - xTaskCreate(led_task, "led1", 2048 / sizeof(void *), (void *)&gpio_led1, PRIORITY_MEDIUM, NULL); - xTaskCreate(led_task, "led0", 2048 / sizeof(void *), (void *)&gpio_led0, PRIORITY_LOW, NULL); - - // Select Switch3 connected to port0 pin 29 and 24 respectively - static gpio_lab_s gpio_switch3 = {0, 29}; - - xTaskCreate(switch_task, "switch3", 2048 / sizeof(void *), (void *)&gpio_switch3, PRIORITY_CRITICAL, NULL); + 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