add freertos and thread debug
This commit is contained in:
parent
9c0f6b0552
commit
03c65be18a
2
Makefile
2
Makefile
@ -42,7 +42,7 @@ format: .check-name
|
|||||||
|
|
||||||
run-debug: format
|
run-debug: format
|
||||||
@rm -f ${name}/${name}.debug
|
@rm -f ${name}/${name}.debug
|
||||||
@gcc -std=c99 -o2 ${name}/*.c -lm -o ${name}/${name}.debug && ./${name}/${name}.debug
|
@gcc -DDEBUG -std=c99 -o2 ${name}/*.c -lm -o ${name}/${name}.debug && ./${name}/${name}.debug
|
||||||
|
|
||||||
compile: format
|
compile: format
|
||||||
@rm -f ${name}/build/CMakeCache.txt
|
@rm -f ${name}/build/CMakeCache.txt
|
||||||
|
|||||||
@ -20,9 +20,38 @@ set_target_properties(picotool PROPERTIES
|
|||||||
# Initialise the Raspberry Pi Pico SDK
|
# Initialise the Raspberry Pi Pico SDK
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Include FreeRTOS directories
|
||||||
|
include_directories(
|
||||||
|
${FREERTOS_CONFIG_DIRECTORY}
|
||||||
|
${FREERTOS_SRC_DIRECTORY}/include
|
||||||
|
${FREERTOS_SRC_DIRECTORY}/portable/ThirdParty/GCC/RP2350_ARM_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/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. Default name is the project name, version 0.1
|
# Add executable. Default name is the project name, version 0.1
|
||||||
|
|
||||||
add_executable(buzzer main.c )
|
add_executable(buzzer main.c log.c gpio.c jobs.c ${FREERTOS_SOURCES} ${FREERTOS_PORT_FILES})
|
||||||
|
add_definitions(-DPICO)
|
||||||
|
|
||||||
pico_set_program_name(buzzer "buzzer")
|
pico_set_program_name(buzzer "buzzer")
|
||||||
pico_set_program_version(buzzer "0.1")
|
pico_set_program_version(buzzer "0.1")
|
||||||
@ -33,7 +62,7 @@ pico_enable_stdio_usb(buzzer 1)
|
|||||||
|
|
||||||
# Add the standard library to the build
|
# Add the standard library to the build
|
||||||
target_link_libraries(buzzer
|
target_link_libraries(buzzer
|
||||||
pico_stdlib hardware_pwm)
|
pico_stdlib hardware_pwm pico_multicore hardware_exception)
|
||||||
|
|
||||||
# Add the standard include files to the build
|
# Add the standard include files to the build
|
||||||
target_include_directories(buzzer PRIVATE
|
target_include_directories(buzzer PRIVATE
|
||||||
|
|||||||
BIN
buzzer/circuit.jpg
Executable file
BIN
buzzer/circuit.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
124
buzzer/gpio.c
Normal file
124
buzzer/gpio.c
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
//#define PICO
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
|
#include <pico/printf.h>
|
||||||
|
#include <pico/stdlib.h>
|
||||||
|
#include <hardware/pwm.h>
|
||||||
|
|
||||||
|
#define DEFAULT_WRAP_LEVEL 20
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define GPIO_OUT 1
|
||||||
|
#define GPIO_IN 0
|
||||||
|
|
||||||
|
static size_t GPIO_INPUT_MOCK_COUNTER = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
void _sleep_ms(size_t value) {
|
||||||
|
#ifdef PICO
|
||||||
|
sleep_ms(value);
|
||||||
|
#else
|
||||||
|
usleep(value * 1000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sleep_us(size_t value) {
|
||||||
|
#ifdef PICO
|
||||||
|
sleep_us(value);
|
||||||
|
#else
|
||||||
|
usleep(value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_set_level(gpio *g, uint16_t level) {
|
||||||
|
if (g->has_pwm && g->direction == GPIO_OUT) {
|
||||||
|
g->level = level;
|
||||||
|
g->state = level > 0;
|
||||||
|
#ifdef PICO
|
||||||
|
pwm_set_gpio_level(g->pin, level);
|
||||||
|
#else
|
||||||
|
debug("<GPIO.set_level (pin=%ld) (level=%d)>", g->pin, level);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_set_state(gpio *g, bool state) {
|
||||||
|
if (!g->has_pwm && g->direction == GPIO_OUT) {
|
||||||
|
#ifdef PICO
|
||||||
|
gpio_put(g->pin, state);
|
||||||
|
#else
|
||||||
|
// must be trace instead
|
||||||
|
// debug("<GPIO.set_state (pin=%ld) (level=%d)>", g->pin, state);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gpio_get_input(gpio* g) {
|
||||||
|
if (g->direction == GPIO_IN) {
|
||||||
|
#ifdef PICO
|
||||||
|
g->state = gpio_get(g->pin);
|
||||||
|
#else
|
||||||
|
int value = rand() % (10 + 1);
|
||||||
|
if (value == 0) {
|
||||||
|
g->state = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
g->state = GPIO_INPUT_MOCK_COUNTER++ % value == 0;
|
||||||
|
debug("gpio get input (state: %d)", g->state);
|
||||||
|
#endif
|
||||||
|
return g->state;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blink_failed(size_t pin, uint32_t delay_ms) {
|
||||||
|
#ifdef PICO
|
||||||
|
for (;;) {
|
||||||
|
gpio_put(pin, false);
|
||||||
|
_sleep_ms(delay_ms);
|
||||||
|
|
||||||
|
gpio_put(pin, true);
|
||||||
|
_sleep_ms(delay_ms);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for(;;) {
|
||||||
|
debug("fatal error occurred, please restart the application");
|
||||||
|
_sleep_ms(delay_ms);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void blink_passed(size_t pin, uint32_t delay_ms, char* msg) {
|
||||||
|
#ifdef PICO
|
||||||
|
gpio_put(pin, true);
|
||||||
|
_sleep_ms(delay_ms);
|
||||||
|
gpio_put(pin, false);
|
||||||
|
_sleep_ms(delay_ms);
|
||||||
|
#else
|
||||||
|
debug(msg);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_gpio(void) {
|
||||||
|
#ifdef PICO
|
||||||
|
stdio_init_all();
|
||||||
|
for (size_t i = 0; i < NB_GPIO; i++) {
|
||||||
|
gpio_init(GPIOS[i]->pin);
|
||||||
|
gpio_set_dir(GPIOS[i]->pin, GPIOS[i]->direction);
|
||||||
|
|
||||||
|
if (GPIOS[i]->has_pwm) {
|
||||||
|
uint slice_num = pwm_gpio_to_slice_num(GPIOS[i]->pin);
|
||||||
|
pwm_set_enabled(slice_num, true);
|
||||||
|
pwm_set_wrap(slice_num, DEFAULT_WRAP_LEVEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blink_passed(GPIOS[0]->pin, 200, "gpios init with success");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
62
buzzer/gpio.h
Normal file
62
buzzer/gpio.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//#define PICO
|
||||||
|
|
||||||
|
#ifndef GPIO_H
|
||||||
|
#define GPIO_H
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
|
#include <pico/printf.h>
|
||||||
|
#include <pico/stdlib.h>
|
||||||
|
#include <hardware/pwm.h>
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <semphr.h>
|
||||||
|
#include <task.h>
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define PICO_DEFAULT_LED_PIN 0
|
||||||
|
#define GPIO_OUT 1
|
||||||
|
#define GPIO_IN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NB_GPIO 3
|
||||||
|
|
||||||
|
typedef struct gpio gpio;
|
||||||
|
struct gpio {
|
||||||
|
size_t pin;
|
||||||
|
size_t direction;
|
||||||
|
bool has_pwm;
|
||||||
|
uint16_t level;
|
||||||
|
bool state;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gpio GPIO_DEFAULT_LED = (gpio) {
|
||||||
|
.pin = PICO_DEFAULT_LED_PIN, .direction = GPIO_OUT, .has_pwm = false, .level = 0, .state = false
|
||||||
|
};
|
||||||
|
|
||||||
|
static gpio GPIO_BUTTON = (gpio) {
|
||||||
|
.pin = 16, .direction = GPIO_IN, .has_pwm = false, .level = 0, .state = false
|
||||||
|
};
|
||||||
|
|
||||||
|
static gpio GPIO_BUZZER = (gpio) {
|
||||||
|
.pin = 15, .direction = GPIO_OUT, .has_pwm = false, .level = 0, .state = false
|
||||||
|
};
|
||||||
|
|
||||||
|
static gpio* GPIOS[NB_GPIO] = {&GPIO_DEFAULT_LED, &GPIO_BUTTON, &GPIO_BUZZER};
|
||||||
|
|
||||||
|
void gpio_set_level(gpio *g, uint16_t level);
|
||||||
|
void gpio_set_state(gpio *g, bool state);
|
||||||
|
bool gpio_get_input(gpio* g);
|
||||||
|
|
||||||
|
void init_gpio(void);
|
||||||
|
|
||||||
|
void blink_failed(size_t pin, uint32_t delay_ms);
|
||||||
|
void blink_passed(size_t pin, uint32_t delay_ms, char* msg);
|
||||||
|
|
||||||
|
void _sleep_ms(size_t value);
|
||||||
|
void _sleep_us(size_t value);
|
||||||
|
|
||||||
|
#endif
|
||||||
171
buzzer/jobs.c
Normal file
171
buzzer/jobs.c
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
//#define PICO
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
|
#include <pico/printf.h>
|
||||||
|
#include <pico/stdlib.h>
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "jobs.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#define BUTTON_BUFFETING_SLEEP_DURATION_MS 20
|
||||||
|
|
||||||
|
int init_app_state(AppState *s) {
|
||||||
|
s->action = STOP;
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
|
s->lock = xSemaphoreCreateMutex();
|
||||||
|
#else
|
||||||
|
if (pthread_mutex_init(&s->lock, NULL) != 0) {
|
||||||
|
printf("error: mutex init failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lock(AppState *s) {
|
||||||
|
#ifdef PICO
|
||||||
|
if (xSemaphoreTake(s->lock, (TickType_t)10) != pdTRUE) {
|
||||||
|
printf("unable to lock the FreeRTOS task\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return pthread_mutex_lock(&s->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int release(AppState *s) {
|
||||||
|
#ifdef PICO
|
||||||
|
xSemaphoreGive(s->lock);
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return pthread_mutex_unlock(&s->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int cancel_task(AppState *s) {
|
||||||
|
debug("stopping task...");
|
||||||
|
#ifdef PICO
|
||||||
|
if (s->task != NULL) {
|
||||||
|
vTaskDelete(*s->task);
|
||||||
|
free(s->task);
|
||||||
|
gpio_set_state(GPIOS[2], false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (s->task != NULL) {
|
||||||
|
if (pthread_cancel(*s->task) != 0) {
|
||||||
|
perror("error: unable to cancel the thread task\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_join(*s->task, NULL) != 0) {
|
||||||
|
perror("error: unable to wait for finished task\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(s->task);
|
||||||
|
s->task = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int launch_task(AppState *s, FnJob f) {
|
||||||
|
debug("starting task thread...");
|
||||||
|
#ifdef PICO
|
||||||
|
TaskHandle_t* task = malloc(sizeof(TaskHandle_t));
|
||||||
|
if (task == NULL) {
|
||||||
|
blink_failed(GPIOS[0]->pin, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseType_t res =
|
||||||
|
xTaskCreate(f, "task", configMINIMAL_STACK_SIZE,
|
||||||
|
NULL, configMAX_PRIORITIES - 1U, task);
|
||||||
|
|
||||||
|
if (res != pdPASS) {
|
||||||
|
printf("error: unable to launch run alarm task task, code error: %d\n",
|
||||||
|
res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s->task = task;
|
||||||
|
#else
|
||||||
|
pthread_t* task = malloc(sizeof(task));
|
||||||
|
if (task == NULL) {
|
||||||
|
perror("error: unable to allocate memory for task thread");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_create(task, NULL, f, s) != 0) {
|
||||||
|
perror("error: thread task creation failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->task = task;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_btn_state(void* args) {
|
||||||
|
TaskParam* params = (TaskParam*) args;
|
||||||
|
AppState *s = params->s;
|
||||||
|
bool has_proceed = false;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (!gpio_get_input(GPIOS[1])) {
|
||||||
|
#ifdef PICO
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(BUTTON_BUFFETING_SLEEP_DURATION_MS));
|
||||||
|
#else
|
||||||
|
_sleep_ms(BUTTON_BUFFETING_SLEEP_DURATION_MS);
|
||||||
|
#endif
|
||||||
|
if(!gpio_get_input(GPIOS[1]) && !has_proceed) {
|
||||||
|
if (lock(s) != 0) {
|
||||||
|
blink_failed(PICO_DEFAULT_LED_PIN, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->action == START) {
|
||||||
|
s->action = STOP;
|
||||||
|
cancel_task(s);
|
||||||
|
if (release(s) != 0) {
|
||||||
|
blink_failed(PICO_DEFAULT_LED_PIN, 200);
|
||||||
|
}
|
||||||
|
gpio_set_state(GPIOS[0], false);
|
||||||
|
has_proceed = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->action = START;
|
||||||
|
|
||||||
|
if (launch_task(s, params->f) != 0) {
|
||||||
|
blink_failed(PICO_DEFAULT_LED_PIN, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (release(s) != 0) {
|
||||||
|
blink_failed(PICO_DEFAULT_LED_PIN, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_set_state(GPIOS[0], true);
|
||||||
|
has_proceed = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
has_proceed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
|
void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) {
|
||||||
|
blink_failed(PICO_DEFAULT_LED_PIN, 200);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
47
buzzer/jobs.h
Normal file
47
buzzer/jobs.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//#define PICO
|
||||||
|
|
||||||
|
#ifndef JOBS_H
|
||||||
|
#define JOBS_H
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum ACTION Action;
|
||||||
|
enum ACTION {STOP, START};
|
||||||
|
|
||||||
|
typedef struct AppState AppState;
|
||||||
|
struct AppState {
|
||||||
|
Action action;
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
|
TaskHandle_t* task;
|
||||||
|
SemaphoreHandle_t lock;
|
||||||
|
#else
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
pthread_t* task;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*FnJob)(void* params);
|
||||||
|
|
||||||
|
typedef struct TaskParam TaskParam;
|
||||||
|
struct TaskParam {
|
||||||
|
AppState* s;
|
||||||
|
FnJob f;
|
||||||
|
};
|
||||||
|
|
||||||
|
int init_app_state(AppState *s);
|
||||||
|
|
||||||
|
void check_btn_state(void* args);
|
||||||
|
|
||||||
|
int lock(AppState *s);
|
||||||
|
int release(AppState *s);
|
||||||
|
int cancel_task(AppState *s);
|
||||||
|
int launch_task(AppState *s, FnJob f);
|
||||||
|
|
||||||
|
#endif
|
||||||
28
buzzer/log.c
Normal file
28
buzzer/log.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
void debug(const char *format, ...) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (format == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t now;
|
||||||
|
time(&now);
|
||||||
|
char time_str[26];
|
||||||
|
ctime_r(&now, time_str);
|
||||||
|
time_str[24] = '\0';
|
||||||
|
|
||||||
|
fprintf(stdout, "[DEBUG] [%s] ", time_str);
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vfprintf(stdout, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
6
buzzer/log.h
Normal file
6
buzzer/log.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef LOG_H
|
||||||
|
#define LOG_H
|
||||||
|
|
||||||
|
void debug(const char *format, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
144
buzzer/main.c
144
buzzer/main.c
@ -1,45 +1,129 @@
|
|||||||
|
//#define PICO
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
#include <pico/printf.h>
|
#include <pico/printf.h>
|
||||||
#include <pico/stdlib.h>
|
#include <pico/stdlib.h>
|
||||||
#include <hardware/pwm.h>
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define GPIO_BUTTON 16
|
#define PICO_DEFAULT_LED_PIN 0
|
||||||
#define GPIO_BUZZER 15
|
#define GPIO_OUT 1
|
||||||
#define NB_GPIO 2
|
#define GPIO_IN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct gpio gpio;
|
#include <math.h>
|
||||||
struct gpio {
|
|
||||||
size_t pin;
|
|
||||||
size_t direction;
|
|
||||||
};
|
|
||||||
|
|
||||||
static gpio GPIOS[2] = {
|
#include "log.h"
|
||||||
(gpio) {.pin = GPIO_BUZZER, .direction = GPIO_OUT},
|
#include "jobs.h"
|
||||||
(gpio) {
|
#include "gpio.h"
|
||||||
.pin = GPIO_BUTTON, .direction = GPIO_IN
|
|
||||||
|
#define ALARM_BASE_FREQ 2000 // auditive frequency human range: [20; 20000] hertz
|
||||||
|
#define ALARM_PERIOD_MS 500
|
||||||
|
#define PI 3.14
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Oscillator for passive buzzer hardware.
|
||||||
|
*
|
||||||
|
* It generates desired `freq_hz` for `duration_ms`.
|
||||||
|
*
|
||||||
|
* NOTE: `sleep_us` method does not impact FreeRTOS engine
|
||||||
|
* since, the scheduler started on two cores (RP2350). The behavior may differs
|
||||||
|
* on one core. Update the FreeRTOS tick freq and implement `pdUS_TO_TICKS` if needed.
|
||||||
|
*/
|
||||||
|
void gen_freq(gpio* g, size_t freq_hz, size_t duration_ms) {
|
||||||
|
if (!freq_hz) {
|
||||||
|
gpio_set_state(g, 0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
void init_gpio() {
|
float period = (1.0 / freq_hz) * 1000000; // signal period in micro seconds
|
||||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
size_t duty_period = period / 2; // working period = period / 2
|
||||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
size_t nb_period = duration_ms * 1000 / period; // number of period to play
|
||||||
|
|
||||||
for (size_t i = 0; i < NB_GPIO; i++) {
|
debug("freq_hz = (%ld), period_us = (%.2f), duty_period_us = (%ld), nb_period = (%ld)", freq_hz, period,
|
||||||
gpio_init(GPIOS[i].pin);
|
duty_period, nb_period);
|
||||||
gpio_set_dir(GPIOS[i].pin, GPIOS[i].direction);
|
|
||||||
|
for (size_t i = 0; i < nb_period; i++) {
|
||||||
|
gpio_set_state(g, true);
|
||||||
|
_sleep_us(duty_period);
|
||||||
|
gpio_set_state(g, false);
|
||||||
|
_sleep_us(duty_period);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void run_alarm(void *const params) {
|
||||||
|
for(;;) {
|
||||||
|
debug("running alarm...");
|
||||||
|
float sin_val;
|
||||||
|
int tone_val;
|
||||||
|
|
||||||
|
const size_t duration_ms = ALARM_PERIOD_MS / 36;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 360; i+=10) {
|
||||||
|
sin_val = sinf(i * (PI / 180));
|
||||||
|
tone_val = ALARM_BASE_FREQ + sin_val * (ALARM_BASE_FREQ / 10);
|
||||||
|
gen_freq(GPIOS[2], tone_val, duration_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the main FreeRTOS task */
|
||||||
|
void init_rtos_main(TaskParam *params) {
|
||||||
|
#ifdef PICO
|
||||||
|
BaseType_t res =
|
||||||
|
xTaskCreate(check_btn_state, "main", configMINIMAL_STACK_SIZE,
|
||||||
|
(void *const)params, configMAX_PRIORITIES - 1U, NULL);
|
||||||
|
|
||||||
|
if (res != pdPASS) {
|
||||||
|
blink_failed(GPIOS[0]->pin, 500);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A program to run alarm on button pushed.
|
||||||
|
*
|
||||||
|
* To activate the alarm, push the button. Same for desactivation.
|
||||||
|
* The alarm is launched in a separate task and controlled by
|
||||||
|
* the main task (which holds the push button logic).
|
||||||
|
*
|
||||||
|
* Hardware:
|
||||||
|
* - 1x Passive Buzzer
|
||||||
|
* - 1x Push button
|
||||||
|
* - 1 NPN transistor for signal amplification
|
||||||
|
* - 1x 1k ohm resistor (NPN collector)
|
||||||
|
* - 2x 10k ohm resistor
|
||||||
|
*
|
||||||
|
* You can run the application in "DEBUG" mode using:
|
||||||
|
* `make run-debug name=buzzer`
|
||||||
|
* The FreeRTOS engine is replaced by threads.
|
||||||
|
*/
|
||||||
int main() {
|
int main() {
|
||||||
stdio_init_all();
|
|
||||||
init_gpio();
|
init_gpio();
|
||||||
|
|
||||||
while (true) {
|
AppState as;
|
||||||
if (!gpio_get(GPIOS[1].pin)) {
|
init_app_state(&as);
|
||||||
gpio_put(PICO_DEFAULT_LED_PIN, true);
|
|
||||||
gpio_put(GPIOS[0].pin, true);
|
TaskParam params = (TaskParam) {
|
||||||
continue;
|
.s = &as,
|
||||||
}
|
.f = run_alarm,
|
||||||
gpio_put(GPIOS[0].pin, false);
|
};
|
||||||
gpio_put(PICO_DEFAULT_LED_PIN, false);
|
|
||||||
}
|
#ifdef PICO
|
||||||
|
init_rtos_main(¶ms);
|
||||||
|
#else
|
||||||
|
check_btn_state(¶ms);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PICO
|
||||||
|
vTaskStartScheduler();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
blink_failed(PICO_DEFAULT_LED_PIN, 200);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user