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
	 rmanach
						rmanach