Compare commits
3 Commits
feat/buzze
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eefa769bc8 | ||
|
|
a0a6586752 | ||
|
|
1084643b2b |
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@
|
||||
picotool
|
||||
sdk
|
||||
freertos*
|
||||
tinyusb
|
||||
|
||||
build
|
||||
toolchain
|
||||
|
||||
2
Makefile
2
Makefile
@ -42,7 +42,7 @@ format: .check-name
|
||||
|
||||
run-debug: format
|
||||
@rm -f ${name}/${name}.debug
|
||||
@gcc -DLOG_LEVEL=TRACE -std=c99 -o2 ${name}/*.c -lm -o ${name}/${name}.debug && ./${name}/${name}.debug
|
||||
@gcc -DLOG_LEVEL=DEBUG -std=c99 -o2 ${name}/*.c -lm -o ${name}/${name}.debug && ./${name}/${name}.debug
|
||||
|
||||
compile: format
|
||||
@rm -f ${name}/build/CMakeCache.txt
|
||||
|
||||
29
README.md
29
README.md
@ -90,3 +90,32 @@ Metadata Block 1
|
||||
image type: ARM Secure
|
||||
```
|
||||
|
||||
## Show program outputs via USB serial mode
|
||||
In order to show logs from your program running on the microcontroller, you have to integrate [TinyUSB](https://github.com/raspberrypi/tinyusb/tree/pico) in the Pico C SDK.
|
||||
|
||||
### Installation
|
||||
To do it, simply launch the following command:
|
||||
```bash
|
||||
./scripts/install_tiny_usb.bash <version>
|
||||
# for the 0.17.0 version
|
||||
./scripts/install_tiny_usb.bash 0.17.0
|
||||
```
|
||||
|
||||
It will download TinyUSB sources and create a symbolic link in the Pico C SDK for integration at compilation.
|
||||
|
||||
**NOTE**: If the SDK is located in specific directory, set the **INSTALL_PATH** variable pointing to the directory of the SDK before to launch the script.
|
||||
|
||||
### Display output on terminal
|
||||
Recompile and push your program on the microcontroller. Then to display the program outputs, you have to use `minicom`.
|
||||
|
||||
```bash
|
||||
sudo apt install minicom
|
||||
```
|
||||
|
||||
**NOTE**: if you have the habit to use another tool then, use it !
|
||||
|
||||
After the installation, the microcontroller plug into the USB port, you can launch the command to visualize the program outputs:
|
||||
|
||||
```bash
|
||||
sudo minicom -b 115200 -o -D /dev/ttyACM0
|
||||
```
|
||||
|
||||
@ -52,6 +52,7 @@ set(FREERTOS_PORT_FILES
|
||||
|
||||
add_executable(buzzer main.c log.c gpio.c jobs.c utils.c ${FREERTOS_SOURCES} ${FREERTOS_PORT_FILES})
|
||||
add_definitions(-DPICO)
|
||||
add_definitions(-DLOG_LEVEL=INFO)
|
||||
|
||||
pico_set_program_name(buzzer "buzzer")
|
||||
pico_set_program_version(buzzer "0.1")
|
||||
@ -62,7 +63,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
|
||||
|
||||
39
buzzer/README.md
Normal file
39
buzzer/README.md
Normal file
@ -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
|
||||
|
||||
<div align="center">
|
||||
<img src="circuit.jpg" style="transform:rotate(-90deg); margin:-100px;" width="300" />
|
||||
</div>
|
||||
|
||||
### Variant 2
|
||||
You can play with the frequency [1500; 2000] hz thanks to the potentiometer.
|
||||
|
||||
* Variant 1
|
||||
* 1x Rotary potentiometer
|
||||
* 1x blue LED
|
||||
|
||||
<div align="center">
|
||||
<img src="circuit_variant.jpg" style="transform:rotate(-90deg); margin:-90px;" width="300" />
|
||||
</div>
|
||||
|
||||
Enjoy ! 😉
|
||||
BIN
buzzer/circuit_variant.jpg
Normal file
BIN
buzzer/circuit_variant.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
@ -4,8 +4,7 @@
|
||||
#include <pico/printf.h>
|
||||
#include <pico/stdlib.h>
|
||||
#include <hardware/pwm.h>
|
||||
|
||||
#define DEFAULT_WRAP_LEVEL 20
|
||||
#include <hardware/adc.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -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("<GPIO.get_adc (input=0) (value=?)");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void gpio_set_level(gpio *g, uint16_t level) {
|
||||
if (g->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("<GPIO.set_level (pin=%ld) (level=%d)>", g->pin, level);
|
||||
trace("<GPIO.set_level (pin=%ld) (level=%d)>", g->pin, level);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -70,7 +84,7 @@ bool gpio_get_input(gpio* g) {
|
||||
}
|
||||
g->state = GPIO_INPUT_MOCK_COUNTER++ % value == 0;
|
||||
#endif
|
||||
trace("<GPIO.get_input (pin=%ld) (level=%d)>", g->pin, g->state);
|
||||
trace("<GPIO.get_input (pin=%ld) (state=%d)>", 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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
*
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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");
|
||||
|
||||
67
scripts/install_tiny_usb.bash
Executable file
67
scripts/install_tiny_usb.bash
Executable file
@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
###############################################
|
||||
#
|
||||
# Download and install Tiny USB.
|
||||
# src: https://github.com/hathach/tinyusb
|
||||
#
|
||||
# ex: ./install_tiny_usb.bash 0.17.0
|
||||
#
|
||||
###############################################
|
||||
|
||||
TINY_USB_VERSION=$1
|
||||
REGEX_VERSION="^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$"
|
||||
|
||||
if [[ -z ${INSTALL_PATH} ]]
|
||||
then
|
||||
INSTALL_PATH=${PWD}
|
||||
fi
|
||||
|
||||
usage() {
|
||||
echo "usage:"
|
||||
echo "./install_tiny_usb.bash <version> (ex: ./install_tiny_usb.bash 2.1.0)"
|
||||
}
|
||||
|
||||
if [[ ! "${TINY_USB_VERSION}" =~ ${REGEX_VERSION} ]]
|
||||
then
|
||||
echo "error: unable to parse the version: '${TINY_USB_VERSION}'"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d ${INSTALL_PATH}/tinyusb/${TINY_USB_VERSION} ]]
|
||||
then
|
||||
echo "installing Tiny USB ${TINY_USB_VERSION}"
|
||||
|
||||
tar_file="${TINY_USB_VERSION}.tar.gz"
|
||||
wget https://github.com/hathach/tinyusb/archive/refs/tags/${TINY_USB_VERSION}.tar.gz -P ${INSTALL_PATH}
|
||||
if [[ $? != 0 ]]
|
||||
then
|
||||
echo "error: unable to get tiny USB VERSION: ${TINY_USB_VERSION}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p ${INSTALL_PATH}/tinyusb
|
||||
tar xzvf ${INSTALL_PATH}/${tar_file} -C ${INSTALL_PATH}/tinyusb
|
||||
rm ${INSTALL_PATH}/${tar_file}
|
||||
|
||||
mv ${INSTALL_PATH}/tinyusb/tinyusb-${TINY_USB_VERSION} ${INSTALL_PATH}/tinyusb/${TINY_USB_VERSION}
|
||||
|
||||
echo "find Pico SDK to add TinyUSB support on compilation..."
|
||||
tiny_usb_dir=$(find ${INSTALL_PATH}/sdk -name tinyusb -type d | grep lib | head -1)
|
||||
if [[ ! -z ${tiny_usb_dir} ]]
|
||||
then
|
||||
cd ${tiny_usb_dir}/..
|
||||
lib_dir=${PWD}
|
||||
|
||||
rmdir ${tiny_usb_dir}
|
||||
ln -s ${INSTALL_PATH}/tinyusb/${TINY_USB_VERSION} tinyusb
|
||||
|
||||
echo "Tiny USB soft link added to Pico SDK: $(ls -lrt ${lib_dir}/tinyusb)"
|
||||
fi
|
||||
|
||||
echo "Tiny USB installed successfully: ${INSTALL_PATH}/tinyusb/${TINY_USB_VERSION}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Tiny USB already exists: ${INSTALL_PATH}/tinyusb/${TINY_USB_VERSION}"
|
||||
Loading…
x
Reference in New Issue
Block a user