Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ void sleep_ticks(uint32_t ticks)
;
}

/**
* @brief Sleep (i.e.: do nothing) for a number of seconds.
*
* @param[in] seconds Sleep duration, in seconds.
*/
void sleep_seconds(float seconds)
{
sleep_ticks((uint32_t)(seconds * SYSTICK_FREQUENCY_HZ));
}

/**
* @brief Start the stopwatch to measure elapsed time.
*
Expand Down
1 change: 1 addition & 0 deletions src/clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ void each(uint32_t period, void (*function)(void), uint32_t during);
uint32_t get_clock_ticks(void);
uint32_t read_cycle_counter(void);
void sleep_ticks(uint32_t ticks);
void sleep_seconds(float seconds);
void stopwatch_start(void);
float stopwatch_stop(void);
void sleep_us(uint32_t us);
Expand Down
30 changes: 30 additions & 0 deletions src/hmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,36 @@ void blink_collision(void)
led_right_off();
}

/**
* @brief Warn low battery using speaker sounds.
*/
void speaker_warn_low_battery(void)
{
speaker_play('C', 4, 0, 0.05);
sleep_ticks(50);
speaker_play('C', 3, 0, 0.05);
sleep_ticks(50);
}

/**
* @brief Notify about an error with a low pitch sustained sound.
*/
void speaker_play_error(void)
{
speaker_play('C', 3, 0, 2.);
}

/**
* @brief Play three fast, high tones to note a successful operation.
*/
void speaker_play_success(void)
{
for (int i = 0; i < 3; i++) {
speaker_play('C', 8, 0, 0.05);
sleep_ticks(50);
}
}

/**
* @brief Function to read button left.
*/
Expand Down
4 changes: 4 additions & 0 deletions src/hmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "clock.h"
#include "detection.h"
#include "speaker.h"
#include "speed.h"

void led_left_toggle(void);
Expand All @@ -18,6 +19,9 @@ void led_right_off(void);
void led_bluepill_off(void);
void repeat_blink(uint8_t count, uint16_t time);
void blink_collision(void);
void speaker_warn_low_battery(void);
void speaker_play_error(void);
void speaker_play_success(void);
bool button_left_read(void);
bool button_right_read(void);
bool button_left_read_consecutive(uint32_t count);
Expand Down
22 changes: 22 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "serial.h"
#include "setup.h"
#include "solve.h"
#include "speaker.h"
#include "speed.h"

static void competition(void);
Expand Down Expand Up @@ -46,6 +47,24 @@ static void user_configuration(bool run)
set_speed_mode(mode, run);
}

/**
* @brief Check battery voltage and warn if the voltage is getting too low.
*/
static void check_battery_voltage(void)
{
float voltage;

voltage = get_battery_voltage();
if (voltage < 3.6)
speaker_warn_low_battery();
Comment thread
cua-cua marked this conversation as resolved.
if (voltage < 3.5)
speaker_warn_low_battery();
if (voltage < 3.4)
speaker_warn_low_battery();
if (voltage < 3.3)
speaker_play_error();
}

/**
* @brief Includes the functions to be executed before robot starts to move.
*/
Expand All @@ -55,6 +74,7 @@ static void before_moving(void)
disable_walls_control();
repeat_blink(10, 100);
sleep_us(5000000);
check_battery_voltage();
led_left_on();
led_right_on();
wait_front_sensor_close_signal(0.12);
Expand All @@ -75,9 +95,11 @@ static void after_moving(void)
reset_motion();
blink_collision();
} else {
speaker_play_success();
repeat_blink(10, 100);
}
reset_motion();
check_battery_voltage();
}

/**
Expand Down
51 changes: 47 additions & 4 deletions src/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ void setup_spi_low_speed(void)
* @see Reference manual (RM0008) "TIMx functional description" and in
* particular "PWM mode" section.
*/
static void setup_pwm(void)
static void setup_motor_driver(void)
{
timer_set_mode(TIM3, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE,
TIM_CR1_DIR_UP);
Expand Down Expand Up @@ -252,6 +252,48 @@ static void setup_pwm(void)
timer_enable_counter(TIM3);
}

/**
* @brief Setup PWM for the speaker.
*
* TIM1 is used to generate the PWM signals for the speaker:
*
* - Configure channel 3 as output GPIO.
* - Edge-aligned, up-counting timer.
* - Prescale to increment timer counter at TIM1CLK_FREQUENCY_HZ.
* - Set output compare mode to PWM1 (output is active when the counter is
* less than the compare register contents and inactive otherwise.
* - Disable output compare output (speaker is off by default).
* - Enable outputs in the break subsystem.
*
* @see Reference manual (RM0008) "TIMx functional description" and in
* particular "PWM mode" section.
*/
void setup_speaker(void)
{
rcc_periph_reset_pulse(RST_TIM1);

gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_TIM1_CH3);

/* Make sure to turn emitters off */
gpio_clear(GPIOA, GPIO8 | GPIO9);
gpio_clear(GPIOB, GPIO8 | GPIO9);

timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE,
TIM_CR1_DIR_UP);

timer_set_prescaler(
TIM1, (rcc_apb2_frequency / SPEAKER_BASE_FREQUENCY_HZ - 1));
timer_set_repetition_counter(TIM1, 0);
timer_enable_preload(TIM1);
timer_continuous_mode(TIM1);

timer_disable_oc_output(TIM1, TIM_OC3);
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);

timer_enable_break_main_output(TIM1);
}

/**
* @brief Configure timer to read a quadrature encoder.
*
Expand Down Expand Up @@ -428,9 +470,10 @@ static void setup_adc2(void)
*
* @see Reference manual (RM0008) "Advanced-control timers"
*/
static void setup_timer1(void)
void setup_emitters(void)
{
rcc_periph_reset_pulse(RST_TIM1);

timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE,
TIM_CR1_DIR_UP);
timer_set_clock_division(TIM1, 0x00);
Expand All @@ -452,9 +495,9 @@ void setup(void)
setup_adc2();
setup_usart();
setup_encoders();
setup_pwm();
setup_motor_driver();
setup_mpu();
setup_systick();
setup_timer1();
setup_emitters();
setup_adc1();
}
3 changes: 3 additions & 0 deletions src/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

/** System clock frequency is set in `setup_clock` */
#define SYSCLK_FREQUENCY_HZ 72000000
#define SPEAKER_BASE_FREQUENCY_HZ 1000000
#define SYSTICK_FREQUENCY_HZ 1000
#define DRIVER_PWM_PERIOD 1024

Expand Down Expand Up @@ -59,6 +60,8 @@
#define BATTERY_LOW_LIMIT_VOLTAGE 3.3

void setup(void);
void setup_emitters(void);
void setup_speaker(void);
void setup_spi_low_speed(void);
void setup_spi_high_speed(void);
void enable_systick_interruption(void);
Expand Down
81 changes: 81 additions & 0 deletions src/speaker.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "speaker.h"

/**
* Number of semitones above C, for each note in an octave.
*
* Notes are in order: {A, B, C, D, E, F, G}.
*/
uint8_t SEMITONES[8] = {9, 11, 0, 2, 4, 5, 7};

/**
* Base or reference note, used for the pitch.
*/
uint8_t BASE_NOTE = 9;
uint8_t BASE_OCTAVE = 4;
float BASE_FREQUENCY = 440.;

/**
* @brief Set the frequency for the speaker.
*
* Frequency is set modulating the PWM signal sent to the speaker.
*
* @param[in] hz Frequency, in Hertz.
*/
static void speaker_set_frequency(float hz)
{
uint16_t period;

period = (uint16_t)(SPEAKER_BASE_FREQUENCY_HZ / hz);
timer_set_period(TIM1, period);
timer_set_oc_value(TIM1, TIM_OC3, period / 2);
}

/**
* @brief Turn on the speaker to play the set frequency.
*/
static void speaker_on(void)
{
timer_enable_counter(TIM1);
timer_enable_oc_output(TIM1, TIM_OC3);
}

/**
* @brief Turn off the speaker.
*/
static void speaker_off(void)
{
timer_disable_counter(TIM1);
timer_disable_oc_output(TIM1, TIM_OC3);
}

/**
* @brief Play a note through the speaker.
*
* Even if this function uses the scientific notation, notes are played with
* the concert pitch (standard pitch). That means A above middle C is the
* reference note, played at 440 Hz.
*
* @param[in] note Which note to play, in scientific notation.
* @param[in] octave Which octave to play, in scientific notation.
* @param[in] accidental Number of semitones to sum to the note.
* @param[in] duration Duration of the note, in seconds.
*
* @note The speaker and emitters both share TIM1. While playing a note, the
* emitters will be completely disabled and enabled back only after finishing
* playing the note.
*/
Comment thread
cua-cua marked this conversation as resolved.
void speaker_play(char note, uint8_t octave, int8_t accidental, float duration)
{
int16_t sound;
float frequency;

sound = SEMITONES[note - 'A'] - BASE_NOTE + (octave - BASE_OCTAVE) * 12;
sound += accidental;
frequency = pow(2, sound / 12.) * BASE_FREQUENCY;
setup_speaker();
speaker_set_frequency(frequency);
speaker_on();
sleep_seconds(duration);
speaker_off();
setup_emitters();
}
12 changes: 12 additions & 0 deletions src/speaker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef __SPEAKER_H
#define __SPEAKER_H

#include <math.h>

#include <libopencm3/stm32/timer.h>

#include "setup.h"

void speaker_play(char note, uint8_t octave, int8_t accidental, float duration);

#endif /* __SPEAKER_H */