blob: de875cbaeaa7a8daabc6b7b22ef33a5e9259d349 [file] [log] [blame]
/********************************************************************************************************
* @file app_buzzer.c
*
* @brief This is the source file for b85m
*
* @author ROW GROUP
* @date 06,2020
*
* @par Copyright (c) 2020, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*******************************************************************************************************/
#include "tl_common.h"
#include "drivers.h"
#include "stack/ble/ble.h"
#include "../app_ui.h"
#include "../app_ota.h"
#include "app_buzzer.h"
#include "app_buzzer_song.h"
/**********************************************************************
* LOCAL MARCO
*/
#define BUZZER_GPIO GPIO_PB4
#define BUZZER_PWM_ID PWM4_ID
#define BUZZER_CLOCK CLOCK_SYS_CLOCK_HZ
#define BUZZER_DEBUG_LOG(...)
/**********************************************************************
* LOCAL TYPES
*/
typedef struct{
app_buzzer_symbol_t* song;
int size;
}app_buzzer_song_t;
typedef struct {
APP_BUZZER_STATUS_T status;
unsigned char sound_level;
unsigned char song_index;
unsigned char song_note_index;
unsigned short song_size;
unsigned short note_duration;
unsigned int note_timer_tick;
unsigned int song_start_tick;
}app_buzzer_ctrl_t;
enum{
BUZZER_DUTY_MAX = 100,
BUZZER_DUTY_50 = 50,
BUZZER_DUTY_30 = 30,
BUZZER_DUTY_15 = 15,
BUZZER_DUTY_5 = 5,
BUZZER_DUTY_MIN = 0,
};
/**********************************************************************
* GLOBAL VARIABLES
*/
/**********************************************************************
* LOCAL VARIABLES
*/
const app_buzzer_song_t app_song[] =
{
{(app_buzzer_symbol_t*)app_song_loop, sizeof(app_song_loop)/sizeof(app_buzzer_symbol_t)},
};
_attribute_data_retention_ static app_buzzer_ctrl_t s_app_buzzer_ctrl={0};
_attribute_data_retention_ static u32 s_buzzer_silence_tick = 0;
/**********************************************************************
* LOCAL FUNCTIONS
*/
void app_buzzer_pwm_init(void){
// pwm_set_clk(CLOCK_SYS_CLOCK_HZ, BUZZER_CLOCK);
app_ui_init_pwm_clock();
gpio_set_func(BUZZER_GPIO, AS_PWM4);
pwm_set_mode(BUZZER_PWM_ID, PWM_NORMAL_MODE);
}
/**********************************************************************
* GLOBAL FUNCTIONS
*/
void app_buzzer_buffer_init(void){
/* clear buffer data */
memset(&s_app_buzzer_ctrl, 0x00, sizeof(app_buzzer_ctrl_t) );
}
u8 app_buzzer_is_buzy(void){
return s_app_buzzer_ctrl.status;
}
void app_buzzer_play(APP_BUZZER_INDEX_T index, APP_BUZZER_STATUS_T status, u8 sound_level){
if(s_app_buzzer_ctrl.song_index == index && s_app_buzzer_ctrl.status == status){
/* Dynamically modify the volume of the song */
s_app_buzzer_ctrl.sound_level = min(sound_level, BUZZER_DUTY_MAX);
return;
}
/* Using a buzzer will cause the battery voltage to drop a lot. So stop OTA first */
if(ota_is_working){
app_ota_terminate(GOOGLE_OTA_USER_TERMINATE);
printf("play buzzer during OTA\n");
}
app_ota_ClearDelayCount();
device_led_setup(led_cfg[LED_BUZZER]);
/* Prevent index parameter errors */
s_app_buzzer_ctrl.song_index = min(index, APP_BUZZER_PLAY_INDEX_RINGTONE_0);
app_buzzer_clear_silence_tick();
app_buzzer_pwm_init();
s_app_buzzer_ctrl.status = min(status, APP_BUZZER_STATUS_PLAY_LOOP);
s_app_buzzer_ctrl.sound_level = min(sound_level, BUZZER_DUTY_MAX);
s_app_buzzer_ctrl.song_note_index = 0;
s_app_buzzer_ctrl.song_size = app_song[s_app_buzzer_ctrl.song_index].size;
printf("song index: %d song size: %d\n", s_app_buzzer_ctrl.song_index, s_app_buzzer_ctrl.song_size);
/* set 1st note */
u16 note = app_song[s_app_buzzer_ctrl.song_index].song[0].note;
u16 duration = app_song[s_app_buzzer_ctrl.song_index].song[0].duration;
s_app_buzzer_ctrl.song_start_tick = s_app_buzzer_ctrl.note_timer_tick = clock_time()|1;
s_app_buzzer_ctrl.note_duration = duration;
u16 counter = BUZZER_CLOCK/note;
pwm_set_cycle_and_duty(BUZZER_PWM_ID, counter, counter*s_app_buzzer_ctrl.sound_level/100);
printf("song_note_index: %d cycle: %d counter: %d duty: %d\n",s_app_buzzer_ctrl.song_note_index, note ,counter, s_app_buzzer_ctrl.sound_level);
pwm_start(BUZZER_PWM_ID);
bls_pm_setSuspendMask (SUSPEND_DISABLE);
}
void app_buzzer_stop(void){
device_led_off(APP_LED_RED);
pwm_stop(BUZZER_PWM_ID);
app_buzzer_buffer_init();
}
u32 app_buzzer_get_silence_tick(void){
return s_buzzer_silence_tick;
}
void app_buzzer_clear_silence_tick(void){
s_buzzer_silence_tick = 0;
}
u8 app_buzzer_set_and_get_pwm_duty_by_voltage(void){
enum{ MAX_BAT_VOL = 3200 };
extern u16 get_battery_voltage(void);
u16 my_bat_vol = get_battery_voltage();
my_bat_vol = min(my_bat_vol, MAX_BAT_VOL);
u8 my_buzzer_duty = BUZZER_DUTY_50;
switch (my_bat_vol)
{
case 2600 ... 3300: /* When the battery voltage is between 2.6V to 3.2V, keep the default PWM duty. */
break;
case 2500 ... 2599: /* When the battery voltage is between 2.5V to 2.59V, change PWM duty to 30%. */
my_buzzer_duty = BUZZER_DUTY_30;
break;
case 2350 ... 2499: /* When the battery voltage is between 2.35V to 2.49V, change PWM duty to 15%. */
my_buzzer_duty = BUZZER_DUTY_15;
break;
case 2250 ... 2349: /* When the battery voltage is between 2.25V to 2.24V, change PWM duty to 5%. */
my_buzzer_duty = BUZZER_DUTY_5;
break;
default:
my_buzzer_duty = BUZZER_DUTY_MIN;
break;
}
s_app_buzzer_ctrl.sound_level = min(my_buzzer_duty, BUZZER_DUTY_MAX);
return s_app_buzzer_ctrl.sound_level;
}
void app_buzzer_task(void){
if(!s_app_buzzer_ctrl.status) return;
if(clock_time_exceed(s_app_buzzer_ctrl.note_timer_tick,s_app_buzzer_ctrl.note_duration*1000)){
BUZZER_DEBUG_LOG("pwm_state: 0x%02X song level: %d index: %d",
reg_pwm_enable&BIT(BUZZER_PWM_ID),
s_app_buzzer_ctrl.sound_level,
s_app_buzzer_ctrl.song_note_index );
s_app_buzzer_ctrl.song_note_index++;
if(s_app_buzzer_ctrl.song_note_index >=s_app_buzzer_ctrl.song_size){
if(APP_BUZZER_STATUS_PLAY_LOOP == s_app_buzzer_ctrl.status){
/* If the buzzer is started by the find me command, it will loop infinitely */
s_app_buzzer_ctrl.song_note_index = 0;
}else{
app_buzzer_stop();
printf("play done !!!!!!!! \n");
return;
}
}
u16 note = app_song[s_app_buzzer_ctrl.song_index].song[s_app_buzzer_ctrl.song_note_index].note;
u16 duration = app_song[s_app_buzzer_ctrl.song_index].song[s_app_buzzer_ctrl.song_note_index].duration;
if(note){
u16 counter = BUZZER_CLOCK/note;
/* The value of s_app_buzzer_ctrl.sound_level will not exceed 100 when assigned. If this happens, set duty to the lowest value */
if(s_app_buzzer_ctrl.sound_level > 100){
s_app_buzzer_ctrl.sound_level = BUZZER_DUTY_MIN;
}
pwm_set_cycle_and_duty(BUZZER_PWM_ID, counter, counter*s_app_buzzer_ctrl.sound_level/100);
app_buzzer_clear_silence_tick();
}else{
/* A cmp_tick of 0 will cause the PWM to continuously output low level. cycle_tick only requires non-0. */
pwm_set_cycle_and_duty(BUZZER_PWM_ID, /* any non-zero value */32000, 0);
s_buzzer_silence_tick = clock_time()|1;
}
BUZZER_DEBUG_LOG("song_note_index: [%d] FREQ:[%d] duty:[%d] counter:[%d]", s_app_buzzer_ctrl.song_note_index, note, s_app_buzzer_ctrl.sound_level, counter);
s_app_buzzer_ctrl.note_timer_tick = clock_time()|1;
s_app_buzzer_ctrl.note_duration = duration;
}
}