Skip to content
Closed
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
22 changes: 22 additions & 0 deletions src/hmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,28 @@ 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 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
3 changes: 3 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,8 @@ 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_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();
if (voltage < 3.5)
speaker_warn_low_battery();
if (voltage < 3.4)
speaker_warn_low_battery();
if (voltage < 3.3)
speaker_play('C', 3, 0, 2.);
}

/**
* @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
83 changes: 41 additions & 42 deletions src/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,9 @@ static void setup_clock(void)
*
* - Systick priority to 1 with SCB.
* - USART3 with priority 2 with NVIC.
* - TIM1_UP with priority 0.
*
* Interruptions enabled:
*
* - TIM1 Update interrupt.
* - USART3 interrupt.
*
* @note The priority levels are assigned on steps of 16 because the processor
Expand All @@ -77,11 +75,9 @@ static void setup_clock(void)
*/
static void setup_exceptions(void)
{
nvic_set_priority(NVIC_TIM1_UP_IRQ, 0);
nvic_set_priority(NVIC_SYSTICK_IRQ, PRIORITY_FACTOR * 1);
nvic_set_priority(NVIC_USART3_IRQ, PRIORITY_FACTOR * 2);

nvic_enable_irq(NVIC_TIM1_UP_IRQ);
nvic_enable_irq(NVIC_USART3_IRQ);
}

Expand Down Expand Up @@ -218,7 +214,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 +248,44 @@ 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.
*/
static void setup_speaker(void)
{
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_TIM1_CH3);

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_prescaler(TIM1,
(rcc_apb2_frequency / TIM1CLK_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 @@ -406,40 +440,6 @@ static void setup_adc2(void)
start_adc(ADC2);
}

/**
* @brief TIM1 setup.
*
* The TIM1 generates an update event interruption that invokes the
* function tim1_up_isr.
*
* - Set TIM1 default values.
* - Configure the base time (no clock division ratio, no aligned mode,
* direction up).
* - Set clock division, prescaler and period parameters to get an update
* event with a frequency of 16 KHz. 16 interruptions by ms, 4 sensors with
* 4 states.
*
* \f$frequency = \frac{timerclock}{(preescaler + 1)(period + 1)}\f$
*
* - Enable the TIM1.
* - Enable the interruption of type update event on the TIM1.
*
* @note The TIM1 is conected to the APB2 prescaler.
*
* @see Reference manual (RM0008) "Advanced-control timers"
*/
static void setup_timer1(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);
timer_set_prescaler(TIM1, (rcc_apb2_frequency / 160000 - 1));
timer_set_period(TIM1, 10 - 1);
timer_enable_counter(TIM1);
timer_enable_irq(TIM1, TIM_DIER_UIE);
}

/**
* @brief Execute all setup functions.
*/
Expand All @@ -452,9 +452,8 @@ void setup(void)
setup_adc2();
setup_usart();
setup_encoders();
setup_pwm();
setup_motor_driver();
setup_speaker();
setup_mpu();
setup_systick();
setup_timer1();
setup_adc1();
}
1 change: 1 addition & 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 TIM1CLK_FREQUENCY_HZ 1000000
#define SYSTICK_FREQUENCY_HZ 1000
#define DRIVER_PWM_PERIOD 1024

Expand Down
66 changes: 66 additions & 0 deletions src/speaker.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "speaker.h"

uint8_t BASE_NOTE = 9;
uint8_t BASE_OCTAVE = 4;
float BASE_FREQUENCY = 440.;
uint8_t POSITIONS[8] = {9, 11, 0, 2, 4, 5, 7};

/**
* @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)(TIM1CLK_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.
*/
void speaker_play(char note, uint8_t octave, int8_t accidental, float duration)
{
int16_t sound;
float frequency;

sound = POSITIONS[note - 'A'] - BASE_NOTE + (octave - BASE_OCTAVE) * 12;
sound += accidental;
frequency = pow(2, sound / 12.) * BASE_FREQUENCY;
speaker_set_frequency(frequency);
speaker_on();
sleep_ticks((uint32_t)(duration * 1000));
speaker_off();
}
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 */
Loading