Skip to content

Commit

Permalink
WIP: Vibrator music.
Browse files Browse the repository at this point in the history
  • Loading branch information
jakkra committed Oct 22, 2023
1 parent e757235 commit cc4ab0a
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 4 deletions.
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@
"nrf-connect.debugging.bindings": {
"${workspaceFolder}/app/build": "Launch build"
},
"files.associations": {
"stdbool.h": "c",
"typeinfo": "c"
},
}
1 change: 1 addition & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ target_sources(app PRIVATE src/zsw_cpu_freq.c)

target_sources(app PRIVATE src/drivers/zsw_display_control.c)
target_sources(app PRIVATE src/drivers/zsw_vibration_motor.c)
target_sources(app PRIVATE src/drivers/zsw_vib_sound.c)

target_sources(app PRIVATE src/managers/zsw_app_manager.c)
target_sources(app PRIVATE src/managers/zsw_notification_manager.c)
Expand Down
3 changes: 2 additions & 1 deletion app/boards/arm/zswatch_nrf5340/zswatch_nrf5340_common.dts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
pwms = <&pwm0 0 PWM_MSEC(5) 0>;
};
vibrator_pwm: pwm_led_1 {
pwms = <&pwm1 0 PWM_MSEC(20) 0>;
//pwms = <&pwm1 0 PWM_MSEC(20) 0>;
pwms = <&pwm1 0 PWM_HZ(880) PWM_POLARITY_NORMAL>;
};
};

Expand Down
1 change: 1 addition & 0 deletions app/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ CONFIG_FLASH_MAP_LABELS=y
#CONFIG_FILE_SYSTEM_LITTLEFS=y

CONFIG_SETTINGS=y
CONFIG_SETTINGS_RUNTIME=y
CONFIG_NVS=y
CONFIG_SETTINGS_NVS=y

Expand Down
247 changes: 247 additions & 0 deletions app/src/drivers/zsw_vib_sound.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
/*
* Copyright (c) 2022 Golioth, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app_work, LOG_LEVEL_DBG);

#include <drivers/zsw_vib_sound.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pwm.h>

#include <stdlib.h>


#define FUNKYTOWN_NOTES 13
#define MARIO_NOTES 37
#define GOLIOTH_NOTES 21

/* Sensor device structs */

static const struct gpio_dt_spec enable_gpio = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(vib_pwr), enable_gpios, {});
const struct pwm_dt_spec sBuzzer = PWM_DT_SPEC_GET_OR(DT_ALIAS(vibrator_pwm), {});

enum song_choice
{
beep,
funkytown,
mario,
golioth
};

enum song_choice song = 3;

struct note_duration
{
int note; // hz
int duration; // msec
};

struct note_duration funkytown_song[FUNKYTOWN_NOTES] = {
{.note = C5, .duration = quarter},
{.note = REST, .duration = eigth},
{.note = C5, .duration = quarter},
{.note = Bb4, .duration = quarter},
{.note = C5, .duration = quarter},
{.note = REST, .duration = quarter},
{.note = G4, .duration = quarter},
{.note = REST, .duration = quarter},
{.note = G4, .duration = quarter},
{.note = C5, .duration = quarter},
{.note = F5, .duration = quarter},
{.note = E5, .duration = quarter},
{.note = C5, .duration = quarter}};

struct note_duration mario_song[MARIO_NOTES] = {
{.note = E6, .duration = quarter},
{.note = REST, .duration = eigth},
{.note = E6, .duration = quarter},
{.note = REST, .duration = quarter},
{.note = E6, .duration = quarter},
{.note = REST, .duration = quarter},
{.note = C6, .duration = quarter},
{.note = E6, .duration = half},
{.note = G6, .duration = half},
{.note = REST, .duration = quarter},
{.note = G4, .duration = whole},
{.note = REST, .duration = whole},
// break in sound
{.note = C6, .duration = half},
{.note = REST, .duration = quarter},
{.note = G5, .duration = half},
{.note = REST, .duration = quarter},
{.note = E5, .duration = half},
{.note = REST, .duration = quarter},
{.note = A5, .duration = quarter},
{.note = REST, .duration = quarter},
{.note = B5, .duration = quarter},
{.note = REST, .duration = quarter},
{.note = Bb5, .duration = quarter},
{.note = A5, .duration = half},
{.note = G5, .duration = quarter},
{.note = E6, .duration = quarter},
{.note = G6, .duration = quarter},
{.note = A6, .duration = half},
{.note = F6, .duration = quarter},
{.note = G6, .duration = quarter},
{.note = REST, .duration = quarter},
{.note = E6, .duration = quarter},
{.note = REST, .duration = quarter},
{.note = C6, .duration = quarter},
{.note = D6, .duration = quarter},
{.note = B5, .duration = quarter}};

struct note_duration golioth_song[] = {
{.note = C6, .duration = quarter},
{.note = REST, .duration = 100},
{.note = G5, .duration = 100},
{.note = A5, .duration = 100},
{.note = Bb5, .duration = 100},
{.note = REST, .duration = 100},
{.note = Bb5, .duration = 100},
{.note = REST, .duration = quarter},
{.note = C5, .duration = half},
{.note = REST, .duration = half},
{.note = REST, .duration = quarter},
{.note = C6, .duration = quarter}
};

/* Thread plays song on buzzer */

K_SEM_DEFINE(buzzer_initialized_sem, 0, 1); /* Wait until buzzer is ready */

#define BUZZER_STACK 1024

static void play_song(enum song_choice song)
{
switch (song)
{
case 0:
LOG_DBG("beep");
pwm_set_dt(&sBuzzer, PWM_HZ(1000), PWM_HZ(1000) / 2);
gpio_pin_set_dt(&enable_gpio, 1);
k_msleep(100);
gpio_pin_set_dt(&enable_gpio, 0);
break;
case 1:
LOG_DBG("funkytown");
for (int i = 0; i < FUNKYTOWN_NOTES; i++)
{
if (funkytown_song[i].note < 10)
{
// Low frequency notes represent a 'pause'
gpio_pin_set_dt(&enable_gpio, 0);
pwm_set_pulse_dt(&sBuzzer, 0);
k_msleep(funkytown_song[i].duration);
gpio_pin_set_dt(&enable_gpio, 1);
}
else
{
pwm_set_dt(&sBuzzer, PWM_HZ(funkytown_song[i].note), PWM_HZ((funkytown_song[i].note)) / 2);
gpio_pin_set_dt(&enable_gpio, 1);
// LOG_DBG("note: %d, duration: %d", funkytown_song[i].note, funkytown_song[i].duration);
k_msleep(funkytown_song[i].duration);
gpio_pin_set_dt(&enable_gpio, 0);
}
}
break;

case 2:
LOG_DBG("mario");
for (int i = 0; i < MARIO_NOTES; i++)
{
if (mario_song[i].note < 10)
{
// Low frequency notes represent a 'pause'
gpio_pin_set_dt(&enable_gpio, 0);
pwm_set_pulse_dt(&sBuzzer, 0);
k_msleep(mario_song[i].duration);
gpio_pin_set_dt(&enable_gpio, 1);
}
else
{
pwm_set_dt(&sBuzzer, PWM_HZ(mario_song[i].note), PWM_HZ((mario_song[i].note)) / 2);
gpio_pin_set_dt(&enable_gpio, 1);
k_msleep(mario_song[i].duration);
gpio_pin_set_dt(&enable_gpio, 0);
}
}
break;
case 3:
LOG_DBG("golioth");
for (int i = 0; i < (sizeof(golioth_song)/sizeof(golioth_song[1])); i++)
{
if (golioth_song[i].note < 10)
{
// Low frequency notes represent a 'pause'
gpio_pin_set_dt(&enable_gpio, 0);
pwm_set_pulse_dt(&sBuzzer, 0);
k_msleep(golioth_song[i].duration);
gpio_pin_set_dt(&enable_gpio, 1);
}
else
{
pwm_set_dt(&sBuzzer, PWM_HZ(golioth_song[i].note), PWM_HZ((golioth_song[i].note)) / 2);
gpio_pin_set_dt(&enable_gpio, 1);
k_msleep(golioth_song[i].duration);
gpio_pin_set_dt(&enable_gpio, 0);
}
}
break;
default:
LOG_WRN("invalid switch state");
break;
}

// turn buzzer off (pulse duty to 0)
pwm_set_pulse_dt(&sBuzzer, 0);
gpio_pin_set_dt(&enable_gpio, 0);
}

int app_buzzer_init()
{
int rc;

if (!device_is_ready(sBuzzer.dev))
{
return -ENODEV;
}
rc = gpio_pin_configure_dt(&enable_gpio, GPIO_OUTPUT_LOW);
if (rc != 0) {
printk("Failed init vibration motor enable pin\n");
}
if (!device_is_ready(enable_gpio.port)) {
LOG_WRN("Vibration motor enable/disable not supported");
return -ENODEV;
}
k_sem_give(&buzzer_initialized_sem);
return 0;
}

void play_beep_once(void)
{
song = beep;
play_song(song);
}

void play_funkytown_once(void)
{
song = funkytown;
play_song(song);
}

void play_mario_once(void)
{
song = mario;
play_song(song);
}

void play_golioth_once(void)
{
song = golioth;
play_song(song);
}
77 changes: 77 additions & 0 deletions app/src/drivers/zsw_vib_sound.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2022 Golioth, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __APP_WORK_H__
#define __APP_WORK_H__

void app_work_sensor_read(void);
int app_buzzer_init(void);
void play_funkytown_once(void);
void play_mario_once(void);
void play_beep_once(void);
void play_golioth_once(void);

/**
* Each Ostentus slide needs a unique key. You may add additional slides by
* inserting elements with the name of your choice to this enum.
*/
typedef enum {
UP_COUNTER,
DN_COUNTER
} slide_key;


#define BUZZER_MAX_FREQ 2500
#define BUZZER_MIN_FREQ 75

#define sixteenth 38
#define eigth 75
#define quarter 150
#define half 300
#define whole 600

#define C4 262
#define Db4 277
#define D4 294
#define Eb4 311
#define E4 330
#define F4 349
#define Gb4 370
#define G4 392
#define Ab4 415
#define A4 440
#define Bb4 466
#define B4 494
#define C5 523
#define Db5 554
#define D5 587
#define Eb5 622
#define E5 659
#define F5 698
#define Gb5 740
#define G5 784
#define Ab5 831
#define A5 880
#define Bb5 932
#define B5 988
#define C6 1046
#define Db6 1109
#define D6 1175
#define Eb6 1245
#define E6 1319
#define F6 1397
#define Gb6 1480
#define G6 1568
#define Ab6 1661
#define A6 1760
#define Bb6 1865
#define B6 1976

#define REST 1



#endif /* __APP_WORK_H__ */
4 changes: 2 additions & 2 deletions app/src/drivers/zsw_vibration_motor.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ static void pattern_timer_timeout(struct k_timer *timer_id);

K_TIMER_DEFINE(vibration_timer, pattern_timer_timeout, NULL);

static const struct pwm_dt_spec vib_motor = PWM_DT_SPEC_GET_OR(DT_ALIAS(vibrator_pwm), {});
static const struct gpio_dt_spec enable_gpio = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(vib_pwr), enable_gpios, {});
static const struct pwm_dt_spec vib_motor = PWM_DT_SPEC_GET_OR(DT_ALIAS(vibrator_pwmm), {});
static const struct gpio_dt_spec enable_gpio = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(vib_pwrr), enable_gpios, {});

static vib_motor_state_t press_pattern[] = {
{.enabled = true, .percent = 90, .delay = 40},
Expand Down
13 changes: 12 additions & 1 deletion app/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,20 @@ void run_wdt_work(struct k_work *item)
task_wdt_feed(kernal_wdt_id);
k_work_schedule(&wdt_work, K_MSEC(TASK_WDT_FEED_INTERVAL_MS));
}

#include <drivers/zsw_vib_sound.h>
int main(void)
{
app_buzzer_init();
while(true) {
play_beep_once();
k_msleep(1000);
play_funkytown_once();
k_msleep(1000);
play_mario_once();
k_msleep(1000);
play_golioth_once();
k_msleep(1000);
}
#ifdef CONFIG_SPI_FLASH_LOADER
if (bootmode_check(0xA)) {
LOG_WRN("SPI Flash Loader Boot Mode");
Expand Down

0 comments on commit cc4ab0a

Please sign in to comment.