diff --git a/buzzer/CMakeLists.txt b/buzzer/CMakeLists.txt
index 3194566..8415d68 100644
--- a/buzzer/CMakeLists.txt
+++ b/buzzer/CMakeLists.txt
@@ -62,7 +62,7 @@ pico_enable_stdio_usb(buzzer 1)
# Add the standard library to the build
target_link_libraries(buzzer
- pico_stdlib hardware_pwm pico_multicore hardware_exception)
+ pico_stdlib hardware_pwm pico_multicore hardware_exception hardware_adc)
# Add the standard include files to the build
target_include_directories(buzzer PRIVATE
diff --git a/buzzer/README.md b/buzzer/README.md
new file mode 100644
index 0000000..edfd6cf
--- /dev/null
+++ b/buzzer/README.md
@@ -0,0 +1,39 @@
+# buzzer
+
+
+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).
+
+You can run the application in "DEBUG" mode using:
+`make run-debug name=buzzer`
+The FreeRTOS engine is replaced by threads.
+
+## Hardware
+
+### Variant 1
+
+* 1x Passive Buzzer
+* 1x Push button
+* 1 NPN transistor for signal amplification
+* 1x 1k ohm resistor (NPN collector)
+* 2x 10k ohm resistor
+
+
+

+
+
+### Variant 2
+You can play with the frequency [1500; 2000] hz thanks to the potentiometer.
+
+* Variant 1
+* 1x Rotary potentiometer
+* 1x blue LED
+
+
+

+
+
+Enjoy ! 😉
\ No newline at end of file
diff --git a/buzzer/circuit_variant.jpg b/buzzer/circuit_variant.jpg
new file mode 100644
index 0000000..1db738a
Binary files /dev/null and b/buzzer/circuit_variant.jpg differ
diff --git a/buzzer/gpio.c b/buzzer/gpio.c
index 74869ab..59f4cfe 100644
--- a/buzzer/gpio.c
+++ b/buzzer/gpio.c
@@ -4,8 +4,7 @@
#include
#include
#include
-
-#define DEFAULT_WRAP_LEVEL 20
+#include
#else
#include
#include
@@ -37,6 +36,21 @@ void _sleep_us(size_t value) {
#endif
}
+/**
+ * Returns a ratio of the ADC value input.
+ *
+ * The range of the ADC on Raspberry Pico 2 is 10 bits so the resolution is 1024 (2^10).
+ *
+ */
+double gpio_get_adc() {
+#ifdef PICO
+ return adc_read() / 1023.0 ; // 2^10 - 1
+#else
+ trace("has_pwm && g->direction == GPIO_OUT) {
g->level = level;
@@ -44,7 +58,7 @@ void gpio_set_level(gpio *g, uint16_t level) {
#ifdef PICO
pwm_set_gpio_level(g->pin, level);
#else
- debug("", g->pin, level);
+ trace("", g->pin, level);
#endif
}
}
@@ -70,7 +84,7 @@ bool gpio_get_input(gpio* g) {
}
g->state = GPIO_INPUT_MOCK_COUNTER++ % value == 0;
#endif
- trace("", g->pin, g->state);
+ trace("", g->pin, g->state);
return g->state;
}
return false;
@@ -91,12 +105,15 @@ void gpio_onoff(gpio* g, uint32_t delay_ms, size_t times) {
void init_gpio(void) {
#ifdef PICO
stdio_init_all();
+ adc_init();
+ adc_select_input(0); // pin: 26
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);
+ gpio_set_function(GPIOS[i]->pin, GPIO_FUNC_PWM);
pwm_set_enabled(slice_num, true);
pwm_set_wrap(slice_num, DEFAULT_WRAP_LEVEL);
}
diff --git a/buzzer/gpio.h b/buzzer/gpio.h
index 70119a3..20da477 100644
--- a/buzzer/gpio.h
+++ b/buzzer/gpio.h
@@ -22,7 +22,8 @@
#define GPIO_IN 0
#endif
-#define NB_GPIO 3
+#define NB_GPIO 5
+#define DEFAULT_WRAP_LEVEL 20
typedef struct gpio gpio;
struct gpio {
@@ -45,11 +46,20 @@ 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};
+static gpio GPIO_ADC = (gpio) {
+ .pin = 26, .direction = GPIO_IN, .has_pwm = false, .level = 0, .state = false
+};
+
+static gpio GPIO_LED = (gpio) {
+ .pin = 20, .direction = GPIO_OUT, .has_pwm = true, .level = 0, .state = false
+};
+
+static gpio* GPIOS[NB_GPIO] = {&GPIO_DEFAULT_LED, &GPIO_BUTTON, &GPIO_BUZZER, &GPIO_ADC, &GPIO_LED};
void gpio_set_level(gpio *g, uint16_t level);
void gpio_set_state(gpio *g, bool state);
bool gpio_get_input(gpio* g);
+double gpio_get_adc(void);
void gpio_onoff(gpio* g, uint32_t delay_ms, size_t times);
void init_gpio(void);
diff --git a/buzzer/jobs.c b/buzzer/jobs.c
index d128b0d..c84d283 100644
--- a/buzzer/jobs.c
+++ b/buzzer/jobs.c
@@ -29,6 +29,7 @@ int init_app_state(AppState *s) {
return -1;
}
#endif
+ s->freq_multiplicator = 0;
return 0;
}
@@ -60,6 +61,7 @@ int cancel_task(AppState *s) {
vTaskDelete(*s->task);
free(s->task);
gpio_set_state(GPIOS[2], false);
+ gpio_set_level(GPIOS[4],0);
return 0;
}
#else
@@ -76,6 +78,7 @@ int cancel_task(AppState *s) {
free(s->task);
s->task = NULL;
}
+ gpio_set_level(GPIOS[4],0);
return 0;
#endif
}
@@ -91,8 +94,8 @@ int launch_task(AppState *s, FnJob f) {
}
BaseType_t res =
- xTaskCreate(f, "task", configMINIMAL_STACK_SIZE,
- NULL, configMAX_PRIORITIES - 1U, task);
+ xTaskCreateAffinitySet(f, "task", configMINIMAL_STACK_SIZE,
+ s, configMAX_PRIORITIES - 1U, 1 << 1,task);
if (res != pdPASS) {
error("unable to launch run alarm task task, code error: %d",
@@ -117,6 +120,37 @@ int launch_task(AppState *s, FnJob f) {
return 0;
}
+/**
+ *
+ */
+void check_acd_value(void* args) {
+ AppState* s = (AppState*) args;
+ uint16_t current_freq_multiplicator = 0;
+
+ for (;;) {
+ double freq_mul = gpio_get_adc();
+ if (freq_mul != current_freq_multiplicator) {
+#ifdef PICO
+ gpio_set_level(GPIOS[4], current_freq_multiplicator * DEFAULT_WRAP_LEVEL);
+#endif
+
+ if (lock(s) != 0)
+ fatal(stop_app_fallback, "unable to lock app mutex");
+
+ s->freq_multiplicator = freq_mul;
+ current_freq_multiplicator = freq_mul;
+
+ if (release(s) != 0)
+ fatal(stop_app_fallback, "unable to release app mutex");
+
+ debug("freq multiplicator updated: %d\n", current_freq_multiplicator);
+ }
+#ifdef PICO
+ gpio_set_level(GPIOS[4], current_freq_multiplicator * DEFAULT_WRAP_LEVEL);
+#endif
+ }
+}
+
/**
* Main app loop.
*
diff --git a/buzzer/jobs.h b/buzzer/jobs.h
index 00082cd..8bc7c21 100644
--- a/buzzer/jobs.h
+++ b/buzzer/jobs.h
@@ -17,6 +17,7 @@ enum ACTION {STOP, START};
typedef struct AppState AppState;
struct AppState {
Action action;
+ double freq_multiplicator;
#ifdef PICO
TaskHandle_t* task;
@@ -38,6 +39,7 @@ struct TaskParam {
int init_app_state(AppState *s);
void check_btn_state(void* args);
+void check_acd_value(void* args);
int lock(AppState *s);
int release(AppState *s);
diff --git a/buzzer/main.c b/buzzer/main.c
index 64a676a..deaccb8 100644
--- a/buzzer/main.c
+++ b/buzzer/main.c
@@ -24,8 +24,8 @@
#include "gpio.h"
#include "utils.h"
-#define ALARM_BASE_FREQ 2000 // auditive frequency human range: [20; 20000] hertz
-#define ALARM_PERIOD_MS 500
+#define ALARM_BASE_FREQ 1500 // auditive frequency human range: [20; 20000] hertz
+#define ALARM_PERIOD_MS 200
#define PI 3.14
/**
@@ -35,7 +35,8 @@
*
* 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.
+ * on one core. Update the FreeRTOS tick freq and implement `pdUS_TO_TICKS` if needed or,
+ * run the alarm in dedicated core see: `xTaskCreateAffinitySet`.
*/
void gen_freq(gpio* g, size_t freq_hz, size_t duration_ms) {
if (!freq_hz) {
@@ -59,7 +60,22 @@ void gen_freq(gpio* g, size_t freq_hz, size_t duration_ms) {
}
void run_alarm(void *const params) {
+ AppState* as = (AppState* ) params;
+
for(;;) {
+ if (lock(as) != 0)
+ fatal(stop_app_fallback, "unable to lock the app state");
+
+ uint16_t freq = as->freq_multiplicator * 500 + ALARM_BASE_FREQ;
+
+ if (release(as) != 0)
+ fatal(stop_app_fallback, "unable to release the app state");
+
+
+#ifdef PICO
+ gpio_set_level(GPIOS[4], as->freq_multiplicator * DEFAULT_WRAP_LEVEL);
+#endif
+
debug("running alarm...");
float sin_val;
int tone_val;
@@ -68,18 +84,37 @@ void run_alarm(void *const params) {
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);
+ tone_val = freq + sin_val * (freq / 10);
gen_freq(GPIOS[2], tone_val, duration_ms);
}
}
}
+int init_check_adc_value(AppState* as) {
+#ifdef PICO
+ BaseType_t res =
+ xTaskCreateAffinitySet(check_acd_value, "check_adc_value", configMINIMAL_STACK_SIZE,
+ (void *const)as, configMAX_PRIORITIES - 1U, 1 << 0, NULL);
+
+ if (res != pdPASS)
+ return -1;
+
+ return 0;
+#else
+ pthread_t task;
+ if (pthread_create(&task, NULL, check_acd_value, as) != 0) {
+ return -1;
+ }
+ return 0;
+#endif
+}
+
// Initialize the main FreeRTOS task.
int 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);
+ xTaskCreateAffinitySet(check_btn_state, "main", configMINIMAL_STACK_SIZE,
+ (void *const)params, configMAX_PRIORITIES - 1U, 1 << 0, NULL);
if (res != pdPASS)
return -1;
@@ -105,9 +140,14 @@ int init_rtos_main(TaskParam *params) {
* You can run the application in "DEBUG" mode using:
* `make run-debug name=buzzer`
* The FreeRTOS engine is replaced by threads.
+ *
+ * A variant to play with the frequency can be done adding a
+ * potentiometer and set `check_adc` to true. See README.md for details.
+ *
*/
int main() {
init_gpio();
+ bool check_adc = false;
AppState as;
if (init_app_state(&as) != 0)
@@ -118,6 +158,11 @@ int main() {
.f = run_alarm,
};
+ // launch the check of the ADC value reveived by the potentiometer
+ if (check_adc)
+ if (init_check_adc_value(&as) != 0)
+ fatal(stop_app_fallback, "unable to launch check adc value task");
+
#ifdef PICO
if (init_rtos_main(¶ms) != 0)
fatal(stop_app_fallback, "unable to launch to FreeRTOS main task");