From b27b45fb9a508f52f2c7da96a6dd9407af8e1a69 Mon Sep 17 00:00:00 2001 From: rmanach Date: Fri, 21 Feb 2025 10:37:40 +0100 Subject: [PATCH] fix freertos kernel compatibility --- .gitignore | 6 +- Makefile | 20 +- config/FreeRTOSConfig.h | 144 +++++++-------- scripts/install_freertos.bash | 28 +++ simple_led/CMakeLists.txt | 14 +- simple_led/main.c | 331 +++++++++++++++++++--------------- 6 files changed, 315 insertions(+), 228 deletions(-) create mode 100755 scripts/install_freertos.bash diff --git a/.gitignore b/.gitignore index 68e841e..9e45370 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,9 @@ picotool sdk -freertos +freertos* build -toolchain \ No newline at end of file +toolchain + +*.orig \ No newline at end of file diff --git a/Makefile b/Makefile index e5f192f..f20c37f 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ SDK_VERSION := 2.1.0 PICOTOOL := $(INSTALL_PATH)/picotool/$(SDK_VERSION)/build/picotool export PICO_SDK_PATH=$(INSTALL_PATH)/sdk/$(SDK_VERSION) - # if using a different platform or arch, set ot here + # if using a different platform or arch, set it here export PICO_PLATFORM=rp2350 # project name, need to be passed as make input (ex: make project name=test) @@ -13,6 +13,7 @@ name := "" install: @./scripts/install_sdk.bash $(SDK_VERSION) @./scripts/install_picotool.bash $(SDK_VERSION) + @./scripts/install_freertos.bash info: @$(PICOTOOL) info -a @@ -20,7 +21,22 @@ info: project: @./scripts/scaffold_project.bash $(name) $(SDK_VERSION) -compile: +.check-name: +ifeq ($(strip $(name)), "") + @echo "error: project name must be set, ex: name=" + @false +endif + +ifeq ($(shell test -d $(name) && echo "ok"),) + @echo "error: project $(name) does not exist" + @false +endif + +format: .check-name + @test -f "$(shell find /usr/bin/ -name astyle)" && astyle --style=java --indent=spaces=4 -K -xC120 $(name)/*.c + +compile: format + rm -f ${name}/build/CMakeCache.txt @(test -d ${name} && mkdir -p ${name}/build && cd ${name}/build && cmake .. && make -j$(nproc) && echo "project compile successfully") || echo "error: unable to compile project: $(name)" push: compile diff --git a/config/FreeRTOSConfig.h b/config/FreeRTOSConfig.h index d856cab..8db118c 100644 --- a/config/FreeRTOSConfig.h +++ b/config/FreeRTOSConfig.h @@ -13,92 +13,88 @@ * See http://www.freertos.org/a00110.html. *----------------------------------------------------------*/ -#define configUSE_PREEMPTION 1 -#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 -#define configUSE_IDLE_HOOK 0 -#define configUSE_TICK_HOOK 0 -#define configCPU_CLOCK_HZ ((unsigned long)150000000) // RP2350 default clock is 150 MHz -#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) -#define configMAX_PRIORITIES 5 -#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 ) -#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 16 * 1024 ) ) -#define configMAX_TASK_NAME_LEN ( 16 ) -#define configUSE_TRACE_FACILITIES 0 -#define configUSE_16_BIT_TICKS 0 -#define configIDLE_SHOULD_YIELD 1 -#define configUSE_MUTEXES 1 -#define configQUEUE_REGISTRY_SIZE 8 -#define configCHECK_FOR_STACK_OVERFLOW 2 -#define configUSE_RECURSIVE_MUTEXES 1 -#define configUSE_MALLOC_FAILED_HOOK 0 -#define configUSE_APPLICATION_TASK_TAG 0 -#define configUSE_COUNTING_SEMAPHORES 1 -#define configGENERATE_RUN_TIME_STATS 0 +// Scheduler Configuration +#define configUSE_PREEMPTION 1 // 1: Preemptive scheduler, 0: Cooperative scheduler +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 // Use optimized task selection if available +#define configUSE_IDLE_HOOK 0 // 1: Use Idle hook function +#define configUSE_TICK_HOOK 0 // 1: Use Tick hook function +#define configIDLE_SHOULD_YIELD 1 // 1: Idle task yields to same priority tasks -#define configSUPPORT_DYNAMIC_ALLOCATION 1 +// System Clock Configuration +#define configCPU_CLOCK_HZ ((unsigned long)150000000) // CPU frequency: 150 MHz for RP2350 +#define configTICK_RATE_HZ ((TickType_t)1000) // RTOS tick frequency (1000 Hz = 1ms tick) -#define configENABLE_FPU 0 -#define configENABLE_TRUSTZONE 0 +// Task Configuration +#define configMAX_PRIORITIES 5 // Maximum number of priority levels +#define configMINIMAL_STACK_SIZE ((unsigned short)256) // Minimum stack size in words +#define configMAX_TASK_NAME_LEN (16) // Maximum length of task names -/* Co-routine definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) +// Memory Configuration +#define configTOTAL_HEAP_SIZE ((size_t)(16 * 1024)) // Total RTOS heap size (16 KB) +#define configSUPPORT_DYNAMIC_ALLOCATION 1 // 1: Enable dynamic memory allocation -/* Software timer definitions. */ -#define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY ( 2 ) -#define configTIMER_QUEUE_LENGTH 10 -#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) +// Synchronization Primitives +#define configUSE_MUTEXES 1 // 1: Enable mutexes +#define configUSE_RECURSIVE_MUTEXES 1 // 1: Enable recursive mutexes +#define configUSE_COUNTING_SEMAPHORES 1 // 1: Enable counting semaphores +#define configQUEUE_REGISTRY_SIZE 8 // Number of queues/semaphores that can be registered -#define configENABLE_MPU 0 +// Debugging and Diagnostics +#define configUSE_TRACE_FACILITIES 0 // 1: Enable trace/debug facilities +#define configCHECK_FOR_STACK_OVERFLOW 2 // Stack overflow checking method (0=off, 1=method1, 2=method2) +#define configUSE_MALLOC_FAILED_HOOK 0 // 1: Use memory allocation failure hook +#define configUSE_APPLICATION_TASK_TAG 0 // 1: Enable task tagging +#define configGENERATE_RUN_TIME_STATS 0 // 1: Generate run-time statistics -/* Set the following definitions to 1 to include the API function, or zero -to exclude the API function. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskCleanUpResources 0 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_xTaskGetSchedulerState 1 -#define INCLUDE_xTaskGetCurrentTaskHandle 1 -#define INCLUDE_uxTaskGetStackHighWaterMark 0 -#define INCLUDE_xTaskGetIdleTaskHandle 0 -#define INCLUDE_eTaskGetState 0 -#define INCLUDE_xSemaphoreGetMutexHolder 0 -#define INCLUDE_xTimerPendFunctionCall 1 -#define INCLUDE_xQueueGetMutexHolder 0 -#define INCLUDE_xEventGroupSetBitFromISR 1 -#define INCLUDE_xTimerPendFunctionCall 1 +// Timer Configuration +#define configUSE_TIMERS 1 // 1: Enable software timers +#define configTIMER_TASK_PRIORITY (2) // Timer service task priority +#define configTIMER_QUEUE_LENGTH 10 // Timer command queue length +#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) // Timer task stack size -/* Cortex-M specific definitions. */ +// Co-routine Configuration +#define configUSE_CO_ROUTINES 0 // 1: Enable co-routines +#define configMAX_CO_ROUTINE_PRIORITIES (2) // Maximum co-routine priorities + +// Hardware Specific Configuration +#define configENABLE_FPU 1 // 1: Enable Floating Point Unit +#define configENABLE_TRUSTZONE 0 // 1: Enable TrustZone +#define configENABLE_MPU 0 // 1: Enable Memory Protection Unit (defined twice in original) +#define configRUN_FREERTOS_SECURE_ONLY 1 // 1: Run in secure mode only +#define configUSE_16_BIT_TICKS 0 // 0: Use 32-bit ticks, 1: Use 16-bit ticks + +// API Inclusion Configuration +#define INCLUDE_vTaskPrioritySet 1 // Include task priority set API +#define INCLUDE_uxTaskPriorityGet 1 // Include task priority get API +#define INCLUDE_vTaskDelete 1 // Include task delete API +#define INCLUDE_vTaskCleanUpResources 0 // Include task cleanup API +#define INCLUDE_vTaskSuspend 1 // Include task suspend API +#define INCLUDE_vTaskDelayUntil 1 // Include delay until API +#define INCLUDE_vTaskDelay 1 // Include delay API +#define INCLUDE_xTaskGetSchedulerState 1 // Include scheduler state API +#define INCLUDE_xTaskGetCurrentTaskHandle 1 // Include current task handle API +#define INCLUDE_uxTaskGetStackHighWaterMark 0 // Include stack high water mark API +#define INCLUDE_xTaskGetIdleTaskHandle 0 // Include idle task handle API +#define INCLUDE_eTaskGetState 0 // Include task state API +#define INCLUDE_xSemaphoreGetMutexHolder 0 // Include mutex holder API +#define INCLUDE_xTimerPendFunctionCall 1 // Include timer pend function call API (defined twice in original) +#define INCLUDE_xQueueGetMutexHolder 0 // Include queue mutex holder API +#define INCLUDE_xEventGroupSetBitFromISR 1 // Include event group set bit from ISR API + +// Cortex-M Interrupt Configuration #ifdef __NVIC_PRIO_BITS - /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ - #define configPRIO_BITS __NVIC_PRIO_BITS + #define configPRIO_BITS __NVIC_PRIO_BITS // Use CMSIS defined priority bits #else - #define configPRIO_BITS 3 /* 7 priority levels */ + #define configPRIO_BITS 3 // 7 priority levels (default) #endif -/* The lowest interrupt priority that can be used in a call to a "set priority" -function. */ -#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x7 +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x7 // Lowest interrupt priority +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 // Highest priority for FreeRTOS API calls -/* The highest interrupt priority that can be used by any interrupt service -routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL -INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER -PRIORITY THAN THIS! (higher priorities are lower numeric values. */ -#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 +#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) +#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) -/* Interrupt priorities used by the kernel port layer itself. These are generic -to all Cortex-M ports, and do not rely on any particular library functions. */ -#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) -/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! -See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ -#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) - -/* Normal assert() semantics without relying on the provision of an assert.h -header file. */ -#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } +// Assertion Definition +#define configASSERT(x) if((x) == 0) { taskDISABLE_INTERRUPTS(); for(;;); } // Basic assert implementation #endif /* FREERTOS_CONFIG_H */ \ No newline at end of file diff --git a/scripts/install_freertos.bash b/scripts/install_freertos.bash new file mode 100755 index 0000000..b4b14ae --- /dev/null +++ b/scripts/install_freertos.bash @@ -0,0 +1,28 @@ +#!/bin/bash + +###################################################### +# +# Install FreeRTOS Raspberry Pi Kernel. +# src: https://github.com/raspberrypi/FreeRTOS-Kernel +# +# ex: ./install_freertos.bash +# +###################################################### + +if [[ -z ${INSTALL_PATH} ]] +then + INSTALL_PATH=${PWD} +fi + +if [[ ! -d ${INSTALL_PATH}/freertos ]] +then + echo "installing freertos..." + git clone https://github.com/raspberrypi/FreeRTOS-Kernel ${INSTALL_PATH}/freertos + if [[ $? != 0 ]] + then + echo "error: unable to clone freertos" + exit 1 + fi +fi + +echo "freertos installation completed" diff --git a/simple_led/CMakeLists.txt b/simple_led/CMakeLists.txt index aede7f3..f50af74 100644 --- a/simple_led/CMakeLists.txt +++ b/simple_led/CMakeLists.txt @@ -12,9 +12,11 @@ project(simple_led C CXX ASM) pico_sdk_init() -set(FREERTOS_SRC_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../freertos/FreeRTOSv202411.00/FreeRTOS/Source) +set(FREERTOS_SRC_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../freertos) set(FREERTOS_CONFIG_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../config) +include(${FREERTOS_SRC_DIRECTORY}/portable/ThirdParty/GCC/RP2350_ARM_NTZ/FreeRTOS_Kernel_import.cmake) + # add_library(FreeRTOS STATIC # ${FREERTOS_SRC_DIRECTORY}/event_groups.c # ${FREERTOS_SRC_DIRECTORY}/list.c @@ -31,7 +33,7 @@ set(FREERTOS_CONFIG_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../config) include_directories( ${FREERTOS_CONFIG_DIRECTORY} ${FREERTOS_SRC_DIRECTORY}/include - ${FREERTOS_SRC_DIRECTORY}/portable/GCC/ARM_CM33_NTZ/non_secure + ${FREERTOS_SRC_DIRECTORY}/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure ) set(FREERTOS_SOURCES @@ -45,8 +47,9 @@ set(FREERTOS_SOURCES ) set(FREERTOS_PORT_FILES - ${FREERTOS_SRC_DIRECTORY}/portable/GCC/ARM_CM33_NTZ/non_secure/port.c - ${FREERTOS_SRC_DIRECTORY}/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c + ${FREERTOS_SRC_DIRECTORY}/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/port.c + ${FREERTOS_SRC_DIRECTORY}/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/portasm.c + ${FREERTOS_SRC_DIRECTORY}/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/mpu_wrappers_v2_asm.c ) add_executable(simple_led main.c ${FREERTOS_SOURCES} ${FREERTOS_PORT_FILES}) @@ -57,10 +60,11 @@ pico_set_program_version(simple_led "0.1") target_link_libraries( simple_led pico_stdlib + hardware_exception # FreeRTOS ) -pico_enable_stdio_uart(simple_led 0) +pico_enable_stdio_uart(simple_led 1) pico_enable_stdio_usb(simple_led 1) pico_add_extra_outputs(simple_led) diff --git a/simple_led/main.c b/simple_led/main.c index 883c40e..33eec00 100644 --- a/simple_led/main.c +++ b/simple_led/main.c @@ -1,92 +1,55 @@ -#include -#include -#include - -#include "pico/stdlib.h" #include +#include +#include +#include +#include #include -#include - -#ifndef LED_DELAY_MS - #define LED_DELAY_MS 500 -#endif #define GPIO_15 15 #define GPIO_13 13 -void blink_success(bool in_task) { - gpio_put(PICO_DEFAULT_LED_PIN, true); - if (in_task) - vTaskDelay(pdMS_TO_TICKS(500)); - else - sleep_ms(500); - gpio_put(PICO_DEFAULT_LED_PIN, false); -} - -void blink_failed(bool in_task) { - for (;;) { - gpio_put(PICO_DEFAULT_LED_PIN, true); - if (in_task) - vTaskDelay(pdMS_TO_TICKS(500)); - else - sleep_ms(500); - - gpio_put(PICO_DEFAULT_LED_PIN, false); - if (in_task) - vTaskDelay(pdMS_TO_TICKS(500)); - else - sleep_ms(500); - } -} - -void blink_default_led(void) { - #ifdef PICO_DEFAULT_LED_PIN - while (true) { - gpio_put(PICO_DEFAULT_LED_PIN, true); - // sleep_ms(LED_DELAY_MS); - vTaskDelay(LED_DELAY_MS / portTICK_PERIOD_MS); - gpio_put(PICO_DEFAULT_LED_PIN, false); - // sleep_ms(1000); - vTaskDelay(LED_DELAY_MS / portTICK_PERIOD_MS); - } - #endif -} - -void run_health() { - BaseType_t res = xTaskCreate( - blink_default_led, - "healthcheck", - configMINIMAL_STACK_SIZE, - NULL, - configMAX_PRIORITIES - 1U, - NULL - ); - - if (res != pdPASS) { - printf("error: unable to launch healthcheck task, code error: %d\n", res); - } - - return; -} +enum status { STOP, RUNNING, FAILED, UNKNOWN }; +/** + * Handle the application state. + */ typedef struct state state; struct state { + SemaphoreHandle_t lock; + int counter; - int bs; bool can_incr; - clock_t push_clock; + absolute_time_t push_clock; bool on_reset; bool is_reset; + + int status; }; -static state global_state = (state) { +/** + * Parameters available to be passed in task function. + */ +typedef struct params params; +struct params { + uint gpio; + uint32_t delays_ms; + bool in_task; + state *s; +}; + +static state global_state = { .counter = 0, .can_incr = true, .on_reset = false, .is_reset = false, + .status = RUNNING, }; +void init_state(state *s) { + s->lock = xSemaphoreCreateMutex(); +} + void incr_counter(state *s) { if (s != NULL) { if (s->can_incr) { @@ -112,15 +75,37 @@ void set_push_clock(state *s) { if (s != NULL) { if (s->push_clock) return; - s->push_clock = clock(); + s->push_clock = get_absolute_time(); + } +} + +void set_status(state *s, int status) { + if (s != NULL) { + if (xSemaphoreTake(s->lock, (TickType_t)10) == pdTRUE) { + s->status = status; + xSemaphoreGive(s->lock); + return; + } + blink_failed(PICO_DEFAULT_LED_PIN, 200, false); + } +} + +int get_status(state *s) { + if (s != NULL) { + if (xSemaphoreTake(s->lock, (TickType_t)10) == pdTRUE) { + int res = s->status; + xSemaphoreGive(s->lock); + return res; + } + blink_failed(PICO_DEFAULT_LED_PIN, 200, false); } } bool is_resetting(state *s) { if (s != NULL) { - clock_t c = clock(); - double exec_time = (double)(c - s->push_clock) / CLOCKS_PER_SEC; - if (exec_time >= 2) + absolute_time_t end = get_absolute_time(); + uint64_t elapsed_ms = absolute_time_diff_us(s->push_clock, end) / 1000; + if (elapsed_ms >= 2000) return true; } return false; @@ -132,76 +117,133 @@ void reset(state *s) { s->is_reset = true; } -void led_control() { - while (1) { +void blink_success(uint gpio, uint32_t delay_ms, bool in_task) { + gpio_put(gpio, true); + if (in_task) + vTaskDelay(pdMS_TO_TICKS(delay_ms)); + else + sleep_ms(delay_ms); + gpio_put(gpio, false); +} + +void blink_failed(uint gpio, uint32_t delay_ms, bool in_task) { + for (;;) { + gpio_put(gpio, false); + if (in_task) + vTaskDelay(pdMS_TO_TICKS(delay_ms)); + else + sleep_ms(delay_ms); + + gpio_put(gpio, true); + if (in_task) + vTaskDelay(pdMS_TO_TICKS(delay_ms)); + else + sleep_ms(delay_ms); + } +} + +void healtchheck(void *const vParameters) { + params *p = (params *const)vParameters; + for (;;) { + if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING || + get_status(p->s) != RUNNING) + gpio_put(p->gpio, false); + else + gpio_put(p->gpio, true); + vTaskDelay(pdMS_TO_TICKS(p->delays_ms)); + } +} + +void run_health(state *s) { + static params p = { + .delays_ms = 50, + .gpio = PICO_DEFAULT_LED_PIN, + .in_task = true, + }; + p.s = s; + + TaskHandle_t t; + BaseType_t res = + xTaskCreate(healtchheck, "healthcheck", configMINIMAL_STACK_SIZE, + (void *const)&p, configMAX_PRIORITIES - 1U, &t); + + if (res != pdPASS) { + stdio_printf("error: unable to launch healthcheck task, code error: %d\n", + res); + blink_failed(PICO_DEFAULT_LED_PIN, 200, false); + } + + return; +} + +void led_control(void *const vParameters) { + params *p = (params *const)vParameters; + + for (;;) { // return low level when the button is pressed if (!gpio_get(GPIO_13)) { - // sleep_ms(20); // avoid "bounce" phenomenon (buffeting) - vTaskDelay(20 / portTICK_PERIOD_MS); + vTaskDelay(pdMS_TO_TICKS(20)); // avoid "bounce" phenomenon (buffeting) if (!gpio_get(GPIO_13)) { - if (global_state.is_reset) + if (p->s->is_reset) continue; - set_push_clock(&global_state); - if (is_resetting(&global_state)) { - gpio_put(GPIO_15, true); - // sleep_ms(500); - vTaskDelay(500 / portTICK_PERIOD_MS); - gpio_put(GPIO_15, false); - // sleep_ms(500); - vTaskDelay(500 / portTICK_PERIOD_MS); - gpio_put(GPIO_15, true); - // sleep_ms(500); - vTaskDelay(500 / portTICK_PERIOD_MS); - gpio_put(GPIO_15, false); - // sleep_ms(500); - vTaskDelay(500 / portTICK_PERIOD_MS); - gpio_put(GPIO_15, true); - // sleep_ms(500); - vTaskDelay(500 / portTICK_PERIOD_MS); - gpio_put(GPIO_15, false); + set_push_clock(p->s); + if (is_resetting(p->s)) { + set_status(p->s, STOP); + reset(p->s); + for (int i = 0; i < 3; i++) { + gpio_put(GPIO_15, true); + vTaskDelay(pdMS_TO_TICKS(200)); - reset(&global_state); + gpio_put(GPIO_15, false); + vTaskDelay(pdMS_TO_TICKS(200)); + } continue; } - incr_counter(&global_state); - if (can_push(&global_state)) + incr_counter(p->s); + if (can_push(p->s)) gpio_put(GPIO_15, true); + else + set_status(p->s, STOP); continue; } } - if (global_state.is_reset) { - global_state.on_reset = false; - global_state.is_reset = false; + if (p->s->is_reset) { + set_status(p->s, RUNNING); + p->s->on_reset = false; + p->s->is_reset = false; } - global_state.push_clock = 0; - set_can_incr(&global_state, true); + p->s->push_clock = 0; + set_can_incr(p->s, true); gpio_put(GPIO_15, false); } } -void run_led_control() { - BaseType_t res = xTaskCreate( - led_control, - "led_controller", - configMINIMAL_STACK_SIZE, - NULL, - configMAX_PRIORITIES - 1U, - NULL - ); +void run_led_control(state *s) { + static params p; + p.s = s; + + BaseType_t res = + xTaskCreate(led_control, "led_controller", configMINIMAL_STACK_SIZE, + (void *const)&p, configMAX_PRIORITIES - 1U, NULL); if (res != pdPASS) { - printf("error: unable to launch led control task, code error: %d\n", res); + stdio_printf("error: unable to launch led control task, code error: %d\n", + res); + blink_failed(PICO_DEFAULT_LED_PIN, 200, false); } } +/** + * Initialize needed GPIO. + */ void init_gpio() { - #ifdef PICO_DEFAULT_LED_PIN - gpio_init(PICO_DEFAULT_LED_PIN); - gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - #endif +#ifdef PICO_DEFAULT_LED_PIN + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); +#endif gpio_init(GPIO_15); gpio_set_dir(GPIO_15, GPIO_OUT); @@ -210,42 +252,41 @@ void init_gpio() { gpio_set_dir(GPIO_13, GPIO_IN); } -void check_scheduler_init(void *pvParameters) { - for (;;) { - BaseType_t state = xTaskGetSchedulerState(); - if (state == taskSCHEDULER_RUNNING) - blink_success(true); - blink_success(true); - // vTaskDelay(pdMS_TO_TICKS(500)); - } -} - +/** + * Callback when unable to initialize task (not enough stask memory). + * Increase `uxStackDepth` arg when creating task if needed. + */ void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { - blink_failed(false); + blink_failed(PICO_DEFAULT_LED_PIN, 100, true); } -int main() -{ +/** + * A simple application to play with leds with FreeRTOS. + * Yes, FreeRTOS is overkill for this kind of application + * but it's cool to see how easyly it can be integrated and + * easy to use for concurrent tasks. + * + * Hardware: + * - a push button switch + * - a red led + * - 2 10k ohm resistors + * - 1 200 ohm resistor + * + * When the Pico is on, the default led is on (acts as a healthcheck). + * You can then push the button and see the red led lights on. + * After 10 pushed, the red light lights off and the default led too. + * To reset the application, holds the button ~2 secs, the red light will + * blink two time and the application will be started again. + * + */ +int main() { stdio_init_all(); init_gpio(); - // TaskHandle_t health_task = run_health(); - // TaskHandle_t led_task = run_led_control(); + init_state(&global_state); - BaseType_t res = xTaskCreate( - check_scheduler_init, - "check_init", - 256, - NULL, - configMAX_PRIORITIES - 1, - NULL - ); - if (res != pdPASS) - blink_failed(false); - else - blink_success(false); + run_health(&global_state); + run_led_control(&global_state); vTaskStartScheduler(); - - blink_failed(false); } \ No newline at end of file