diff --git a/.gitignore b/.gitignore index bf13ba6..68e841e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ picotool sdk +freertos build toolchain \ No newline at end of file diff --git a/config/FreeRTOSConfig.h b/config/FreeRTOSConfig.h new file mode 100644 index 0000000..d856cab --- /dev/null +++ b/config/FreeRTOSConfig.h @@ -0,0 +1,104 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * 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 + +#define configSUPPORT_DYNAMIC_ALLOCATION 1 + +#define configENABLE_FPU 0 +#define configENABLE_TRUSTZONE 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* 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 ) + +#define configENABLE_MPU 0 + +/* 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 + +/* Cortex-M specific definitions. */ +#ifdef __NVIC_PRIO_BITS + /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ + #define configPRIO_BITS __NVIC_PRIO_BITS +#else + #define configPRIO_BITS 3 /* 7 priority levels */ +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" +function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x7 + +/* 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 + +/* 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( ;; ); } + +#endif /* FREERTOS_CONFIG_H */ \ No newline at end of file diff --git a/simple_led/CMakeLists.txt b/simple_led/CMakeLists.txt index 1b47dd3..aede7f3 100644 --- a/simple_led/CMakeLists.txt +++ b/simple_led/CMakeLists.txt @@ -5,35 +5,63 @@ cmake_minimum_required(VERSION 3.13) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(CMAKE_C_COMPILER "/home/romain/Downloads/pico-sdk/toolchain/riscv/bin/riscv32-unknown-elf-gcc") -# Pull in Raspberry Pi Pico SDK (must be before project) include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) project(simple_led C CXX ASM) -# Initialise the Raspberry Pi Pico SDK pico_sdk_init() -# Add executable. Default name is the project name, version 0.1 +set(FREERTOS_SRC_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../freertos/FreeRTOSv202411.00/FreeRTOS/Source) +set(FREERTOS_CONFIG_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../config) -add_executable(simple_led main.c ) +# add_library(FreeRTOS STATIC +# ${FREERTOS_SRC_DIRECTORY}/event_groups.c +# ${FREERTOS_SRC_DIRECTORY}/list.c +# ${FREERTOS_SRC_DIRECTORY}/queue.c +# ${FREERTOS_SRC_DIRECTORY}/stream_buffer.c +# ${FREERTOS_SRC_DIRECTORY}/tasks.c +# ${FREERTOS_SRC_DIRECTORY}/timers.c +# ${FREERTOS_SRC_DIRECTORY}/portable/MemMang/heap_3.c +# ${FREERTOS_SRC_DIRECTORY}/portable/GCC/ARM_CM33_NTZ/non_secure/port.c +# ${FREERTOS_SRC_DIRECTORY}/portable/GCC/ARM_CM33_NTZ/non_secure/portasm.c +# ) + +# Include FreeRTOS directories +include_directories( + ${FREERTOS_CONFIG_DIRECTORY} + ${FREERTOS_SRC_DIRECTORY}/include + ${FREERTOS_SRC_DIRECTORY}/portable/GCC/ARM_CM33_NTZ/non_secure +) + +set(FREERTOS_SOURCES + ${FREERTOS_SRC_DIRECTORY}/event_groups.c + ${FREERTOS_SRC_DIRECTORY}/list.c + ${FREERTOS_SRC_DIRECTORY}/queue.c + ${FREERTOS_SRC_DIRECTORY}/stream_buffer.c + ${FREERTOS_SRC_DIRECTORY}/tasks.c + ${FREERTOS_SRC_DIRECTORY}/timers.c + ${FREERTOS_SRC_DIRECTORY}/portable/MemMang/heap_3.c +) + +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 +) + +add_executable(simple_led main.c ${FREERTOS_SOURCES} ${FREERTOS_PORT_FILES}) pico_set_program_name(simple_led "simple_led") pico_set_program_version(simple_led "0.1") -# Modify the below lines to enable/disable output over UART/USB +target_link_libraries( + simple_led + pico_stdlib + # FreeRTOS +) + pico_enable_stdio_uart(simple_led 0) pico_enable_stdio_usb(simple_led 1) -# Add the standard library to the build -target_link_libraries(simple_led - pico_stdlib) - -# Add the standard include files to the build -target_include_directories(simple_led PRIVATE - ${CMAKE_CURRENT_LIST_DIR} -) - pico_add_extra_outputs(simple_led) diff --git a/simple_led/main.c b/simple_led/main.c index 1483b01..883c40e 100644 --- a/simple_led/main.c +++ b/simple_led/main.c @@ -1,52 +1,90 @@ -#include -#include "pico/stdlib.h" #include +#include +#include + +#include "pico/stdlib.h" +#include +#include +#include #ifndef LED_DELAY_MS - #define LED_DELAY_MS 250 + #define LED_DELAY_MS 500 #endif #define GPIO_15 15 #define GPIO_13 13 -void pico_led_init(void) { - #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); +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_led(void) { - pico_led_init(); - - while (true) { - gpio_put(GPIO_15, 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); - sleep_ms(LED_DELAY_MS); - - gpio_put(GPIO_15, true); gpio_put(PICO_DEFAULT_LED_PIN, false); - - sleep_ms(1000); + if (in_task) + vTaskDelay(pdMS_TO_TICKS(500)); + else + sleep_ms(500); } } -enum button_state {OFF, ON}; +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; +} typedef struct state state; struct state { int counter; int bs; bool can_incr; + + clock_t push_clock; + bool on_reset; + bool is_reset; }; static state global_state = (state) { .counter = 0, - .can_incr = true + .can_incr = true, + .on_reset = false, + .is_reset = false, }; void incr_counter(state *s) { @@ -70,28 +108,144 @@ bool can_push(state *s) { return true; } +void set_push_clock(state *s) { + if (s != NULL) { + if (s->push_clock) + return; + s->push_clock = clock(); + } +} -int main() -{ - gpio_init(GPIO_15); - gpio_set_dir(GPIO_15, GPIO_OUT); +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) + return true; + } + return false; +} - gpio_init(GPIO_13); - gpio_set_dir(GPIO_13, GPIO_IN); +void reset(state *s) { + s->push_clock = 0; + s->counter = 0; + s->is_reset = true; +} +void led_control() { while (1) { // return low level when the button is pressed if (!gpio_get(GPIO_13)) { - sleep_ms(20); // avoid "bounce" phenomenon (buffeting) + // sleep_ms(20); // avoid "bounce" phenomenon (buffeting) + vTaskDelay(20 / portTICK_PERIOD_MS); if (!gpio_get(GPIO_13)) { + if (global_state.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); + + reset(&global_state); + continue; + } + incr_counter(&global_state); if (can_push(&global_state)) gpio_put(GPIO_15, true); continue; } } + + if (global_state.is_reset) { + global_state.on_reset = false; + global_state.is_reset = false; + } + global_state.push_clock = 0; set_can_incr(&global_state, 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 + ); + + if (res != pdPASS) { + printf("error: unable to launch led control task, code error: %d\n", res); + } +} + +void init_gpio() { + #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); + + gpio_init(GPIO_13); + 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)); + } +} + +void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { + blink_failed(false); +} + +int main() +{ + stdio_init_all(); + init_gpio(); + + // TaskHandle_t health_task = run_health(); + // TaskHandle_t led_task = run_led_control(); + + 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); + + vTaskStartScheduler(); + + blink_failed(false); } \ No newline at end of file