fix freertos kernel compatibility

This commit is contained in:
rmanach
2025-02-21 10:37:40 +01:00
parent 02e1de09ff
commit b27b45fb9a
6 changed files with 315 additions and 228 deletions
+9 -5
View File
@@ -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)
+186 -145
View File
@@ -1,92 +1,55 @@
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include <FreeRTOS.h>
#include <pico/printf.h>
#include <pico/stdlib.h>
#include <pico/time.h>
#include <semphr.h>
#include <task.h>
#include <queue.h>
#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);
}