sound fine

This commit is contained in:
2024-10-03 02:37:05 +03:00
parent 0e845d9ebd
commit dd34d1bbb1
8 changed files with 326 additions and 158 deletions

View File

@ -9,7 +9,7 @@
#include "stm32f103xb.h"
#include "SimpleTimer.h"
static uint32_t bpm = 120; // Default BPM
uint32_t bpm = 120; // Default BPM
static uint32_t note_end_time_ch[4] = {0, 0, 0, 0}; // End times for each channel (1-4)
static Melody_t melodies[4]; // Array of melodies for each channel
@ -19,32 +19,34 @@ static Melody_t melodies[4]; // Array of melodies for each channel
// Initialize the sound system
void sound_init(void) {
// Enable timer clock
RCC->APB1ENR |= SOUND_TIMER_RCC;
// Dont need, conflict with uart
// Configure GPIO pins for timer output (assuming GPIOB pins for TIM4 CH3 and CH4)
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
// Configure only channels 3 and 4
// Channel 3
GPIOB->CRH &= ~(0xF << (3 * 4)); // Clear configuration for PB10 (TIM4_CH3)
GPIOB->CRH |= (0xB << (3 * 4)); // Set to alternate function push-pull
// Channel 4
GPIOB->CRH &= ~(0xF << (4 * 4)); // Clear configuration for PB11 (TIM4_CH4)
GPIOB->CRH |= (0xB << (4 * 4)); // Set to alternate function push-pull
// Initialize the timer for PWM output
SOUND_TIMER->PSC = 0;
SOUND_TIMER->ARR = 0xFFFF;
// Configure only channels 3 and 4 for PWM output
SOUND_TIMER->CCMR2 &= ~(TIM_CCMR2_OC3M | TIM_CCMR2_OC4M); // Clear channel 3 and 4 mode
SOUND_TIMER->CCMR2 |= (6 << TIM_CCMR2_OC3M_Pos); // Set channel 3 to PWM mode 1
SOUND_TIMER->CCER |= (TIM_CCER_CC3E | TIM_CCER_CC4E); // Enable output for channels 3 and 4
SOUND_TIMER->EGR = TIM_EGR_UG; // Update the timer
SOUND_TIMER->CR1 |= TIM_CR1_CEN; // Enable the timer
// // Enable timer clock
// RCC->APB1ENR |= SOUND_TIMER_RCC;
//
// // Configure GPIO pins for timer output (assuming GPIOB pins for TIM4 CH3 and CH4)
// RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
//
// // Configure only channels 3 and 4
// // Channel 3
// GPIOB->CRH &= ~(0xF << (3 * 4)); // Clear configuration for PB10 (TIM4_CH3)
// GPIOB->CRH |= (0xB << (3 * 4)); // Set to alternate function push-pull
//
// // Channel 4
// GPIOB->CRH &= ~(0xF << (4 * 4)); // Clear configuration for PB11 (TIM4_CH4)
// GPIOB->CRH |= (0xB << (4 * 4)); // Set to alternate function push-pull
//
// // Initialize the timer for PWM output
// SOUND_TIMER->PSC = 0;
// SOUND_TIMER->ARR = 0xFFFF;
//
// // Configure only channels 3 and 4 for PWM output
// SOUND_TIMER->CCMR2 &= ~(TIM_CCMR2_OC3M | TIM_CCMR2_OC4M); // Clear channel 3 and 4 mode
// SOUND_TIMER->CCMR2 |= (6 << TIM_CCMR2_OC3M_Pos); // Set channel 3 to PWM mode 1
// SOUND_TIMER->CCER |= (TIM_CCER_CC3E | TIM_CCER_CC4E); // Enable output for channels 3 and 4
//
// SOUND_TIMER->EGR = TIM_EGR_UG; // Update the timer
// SOUND_TIMER->CR1 |= TIM_CR1_CEN; // Enable the timer
}
@ -62,10 +64,17 @@ void sound_play_note(Note_t note, uint8_t channel) {
uint32_t *ccer = &SOUND_TIMER->CCER;
uint32_t enable_cc = TIM_CCER_CC1E << ((channel - 1) * 4);
uint32_t duration = (note.duration == T0) ? 0 : (60000 * 4 / (bpm * note.duration));
if (note.frequency == 0) {
*ccer &= ~enable_cc;
note_end_time_ch[channel - 1] = millis() + note.duration;
note_end_time_ch[channel - 1] = millis() + duration;
} else {
// Если текущая нота отличается от новой, отключите старую
if (*ccer & enable_cc) {
*ccer &= ~enable_cc; // Отключить старую ноту
}
uint32_t timer_clock = SystemCoreClock / 2;
uint32_t prescaler = (timer_clock / (note.frequency * 65536)) + 1;
uint32_t arr = (timer_clock / (prescaler * note.frequency)) - 1;
@ -82,22 +91,30 @@ void sound_play_note(Note_t note, uint8_t channel) {
SOUND_TIMER->EGR = TIM_EGR_UG;
SOUND_TIMER->CR1 |= TIM_CR1_CEN;
note_end_time_ch[channel - 1] = (note.duration == 0) ? 0 : millis() + note.duration;
note_end_time_ch[channel - 1] = (duration == 0) ? 0 : millis() + duration;
}
}
static void play_next_note(uint8_t channel);
// Play a melody on a specific channel with repeat count
void sound_play_melody(Note_t* melody, uint32_t size, uint8_t channel, uint32_t repeat_count) {
if (channel < 1 || channel > 4 || melody == NULL || size == 0) return;
uint8_t ch_idx = channel - 1;
// Если уже есть мелодия, которую нужно перебить
if (melodies[ch_idx].notes != NULL) {
// Остановите текущую мелодию
SOUND_TIMER->CCER &= ~(TIM_CCER_CC1E << (ch_idx * 4)); // Отключить выход
melodies[ch_idx].notes = NULL; // Удалить текущую мелодию
}
melodies[ch_idx].notes = melody;
melodies[ch_idx].size = size;
melodies[ch_idx].current_note = 0;
melodies[ch_idx].repeat_count = repeat_count;
melodies[ch_idx].repeat_left = repeat_count;
sound_play_note(melody[0], channel); // Play the first note
play_next_note(channel);
// sound_play_note(melody[0], channel); // Play the first note
}
// Function to play the next note in the melody for a specific channel
@ -135,8 +152,9 @@ void sound_tick(void) {
}
}
// Create a note
Note_t sound_create_note(MusicalNote_t note, NoteDuration_t duration, uint8_t duty_cycle) {
uint32_t note_duration = (duration == T0) ? 0 : (60000 * 4 / (bpm * duration));
return (Note_t){ .frequency = note, .duration = note_duration, .duty_cycle = duty_cycle };
return (Note_t){ .frequency = note, .duration = duration, .duty_cycle = duty_cycle };
}