当前位置:网站首页>ESP32音频框架 ESP-ADF 添加按键外设流程代码跟踪
ESP32音频框架 ESP-ADF 添加按键外设流程代码跟踪
2022-07-02 09:38:00 【hwd00001】
这是一篇学习笔记,跟踪按键驱动代码,仅供自己查阅。
以例子《esp-adf\examples\player\pipeline_play_sdcard_music》的源码来分析。
1. 《play_sdcard_music_example.c》主函数app_main分析
下面直接贴出主函数中和按键相关的代码。
void app_main(void)
{
......
ESP_LOGI(TAG, "[1.0] Initialize peripherals management");
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);//------(1)
ESP_LOGI(TAG, "[1.1] Initialize and start peripherals");
audio_board_key_init(set); //------(2)
audio_board_sdcard_init(set, SD_MODE_1_LINE);
......
ESP_LOGI(TAG, "[ 3 ] Create and start input key service");
input_key_service_info_t input_key_info[] = INPUT_KEY_DEFAULT_INFO();//------(3)
input_key_service_cfg_t input_cfg = INPUT_KEY_SERVICE_DEFAULT_CONFIG();//------(4)
input_cfg.handle = set; //------(5)
periph_service_handle_t input_ser = input_key_service_create(&input_cfg);//------(6)
input_key_service_add_key(input_ser, input_key_info, INPUT_KEY_NUM);//------(7)
periph_service_set_callback(input_ser, input_key_service_cb,
(void *)board_handle);//------(8)
......
}
这里对每一行代码进行分析,跟踪。
1.1 esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);//------(1)
这个代码没有理解。函数的实现在《esp-adf\components\esp_peripherals\esp_peripherals.c》:
esp_periph_set_handle_t esp_periph_set_init(esp_periph_config_t *config)
{
esp_periph_set_t *periph_sets = NULL;
int _err_step = 1;
bool _success =
(
(periph_sets = audio_calloc(1, sizeof(esp_periph_set_t))) && _err_step ++ &&
(periph_sets->state_event_bits = xEventGroupCreate()) && _err_step ++ &&
(periph_sets->lock = mutex_create()) && _err_step ++
);
AUDIO_MEM_CHECK(TAG, _success, {
goto _periph_init_failed;
});
STAILQ_INIT(&periph_sets->periph_list);
//TODO: Should we uninstall gpio isr service??
//TODO: Because gpio need for sdcard and gpio, then install isr here
gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1);
periph_sets->run = false;
xEventGroupClearBits(periph_sets->state_event_bits, STARTED_BIT);
xEventGroupSetBits(periph_sets->state_event_bits, STOPPED_BIT);
periph_sets->task_stack = config->task_stack;
periph_sets->task_prio = config->task_prio;
periph_sets->task_core = config->task_core;
periph_sets->ext_stack = config->extern_stack;
audio_event_iface_cfg_t event_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
event_cfg.queue_set_size = 0;
event_cfg.context = periph_sets;
event_cfg.on_cmd = process_peripheral_event;
periph_sets->event_handle.iface = audio_event_iface_init(&event_cfg);
AUDIO_MEM_CHECK(TAG, periph_sets->event_handle.iface, goto _periph_init_failed);
audio_event_iface_set_cmd_waiting_timeout(periph_sets->event_handle.iface, DEFAULT_ESP_PERIPH_WAIT_TICK);
return periph_sets;
_periph_init_failed:
if (periph_sets) {
mutex_destroy(periph_sets->lock);
vEventGroupDelete(periph_sets->state_event_bits);
if (periph_sets->event_handle.iface) {
audio_event_iface_destroy(periph_sets->event_handle.iface);
}
audio_free(periph_sets);
periph_sets = NULL;
}
return NULL;
}
1.2 audio_board_key_init(set); //------(2)
根据自己的开发板选择对应的按键IO口,我用“ESP32_A1S_Audio_Kit_v2_2”的文件替换掉“lyrat_v4_3”的文件。这样在menuconfig 配置时,直接选择 Audio HAL == lyrat_v4_3。
看看本函数的实现代码:《D:\study\esp-adf\components\audio_board\lyrat_v4_3\board.c》
esp_err_t audio_board_key_init(esp_periph_set_handle_t set)
{
periph_button_cfg_t btn_cfg = {
.gpio_mask = ESP32_A1S_AUDIO_KEY1 |
ESP32_A1S_AUDIO_KEY2 |
ESP32_A1S_AUDIO_KEY3 |
ESP32_A1S_AUDIO_KEY4 |
ESP32_A1S_AUDIO_KEY5 |
ESP32_A1S_AUDIO_KEY6 , //REC BTN & MODE BTN
};
esp_periph_handle_t button_handle = periph_button_init(&btn_cfg);
AUDIO_NULL_CHECK(TAG, button_handle, return ESP_ERR_ADF_MEMORY_LACK);
esp_err_t ret = ESP_OK;
ret = esp_periph_start(set, button_handle);
if (ret != ESP_OK) {
return ret;
}
return ret;
}
1.3 input_key_service_info_t input_key_info[] =INPUT_KEY_DEFAULT_INFO()//------(3)
结合安可信的 ESP32-AUDIO-kit 底板按键部分原理图,可以更加清晰的理解。
通过电阻的选择,来决定使用电平值按键还是模拟值按键:
电平值按键:R55-R64 使用合适的电阻,R66-R70留空,需要6个IO口。
模拟值按键:R55-R64 留空,R66-R70 使用0R电阻,只需要1个IO口。
这个数据类型是一个结构体:
typedef struct {
esp_periph_id_t type; /*!< ID of peripherals,--总线类型,和按键相关的总线有3种:电平总线和模拟输入总线,触摸按键总线 */
int user_id; /*!< The key's user id -- 用户自定义功能ID */
int act_id; /*!< The key's action id -- 对应IO口 GPIO_NUM_x */
} input_key_service_info_t;
typedef enum {
PERIPH_ID_BUTTON = AUDIO_ELEMENT_TYPE_PERIPH + 1, //--电平总线
PERIPH_ID_TOUCH = AUDIO_ELEMENT_TYPE_PERIPH + 2, //--触摸总线
PERIPH_ID_SDCARD = AUDIO_ELEMENT_TYPE_PERIPH + 3,
PERIPH_ID_WIFI = AUDIO_ELEMENT_TYPE_PERIPH + 4,
PERIPH_ID_FLASH = AUDIO_ELEMENT_TYPE_PERIPH + 5,
PERIPH_ID_AUXIN = AUDIO_ELEMENT_TYPE_PERIPH + 6,
PERIPH_ID_ADC = AUDIO_ELEMENT_TYPE_PERIPH + 7, //--模拟输入总线
PERIPH_ID_CONSOLE = AUDIO_ELEMENT_TYPE_PERIPH + 8,
PERIPH_ID_BLUETOOTH = AUDIO_ELEMENT_TYPE_PERIPH + 9,
PERIPH_ID_LED = AUDIO_ELEMENT_TYPE_PERIPH + 10,
PERIPH_ID_SPIFFS = AUDIO_ELEMENT_TYPE_PERIPH + 11,
PERIPH_ID_ADC_BTN = AUDIO_ELEMENT_TYPE_PERIPH + 12,
PERIPH_ID_IS31FL3216 = AUDIO_ELEMENT_TYPE_PERIPH + 13,
PERIPH_ID_GPIO_ISR = AUDIO_ELEMENT_TYPE_PERIPH + 14,
PERIPH_ID_WS2812 = AUDIO_ELEMENT_TYPE_PERIPH + 15,
PERIPH_ID_AW2013 = AUDIO_ELEMENT_TYPE_PERIPH + 16,
PERIPH_ID_LCD = AUDIO_ELEMENT_TYPE_PERIPH + 17
} esp_periph_id_t;
给结构体数组input_key_info[]赋予初始值 INPUT_KEY_DEFAULT_INFO()
这是一个宏定义,具体如下:
...... //这里全部使用电平值按键
#define BUTTON_REC_ID GPIO_NUM_36 //KEY1
#define BUTTON_MODE_ID GPIO_NUM_19 //KEY3
#define BUTTON_SET_ID GPIO_NUM_5 //KEY2 -- old==GPIO_NUM_13
#define BUTTON_PLAY_ID GPIO_NUM_23 //KEY4
#define BUTTON_VOLUP_ID GPIO_NUM_18 //KEY5
#define BUTTON_VOLDOWN_ID GPIO_NUM_36 //KEY6 -- old==GPIO_NUM_5
......
#define INPUT_KEY_DEFAULT_INFO() {
\ {
\ .type = PERIPH_ID_BUTTON, \ .user_id = INPUT_KEY_USER_ID_REC, \ .act_id = BUTTON_REC_ID, \ }, \ {
\ .type = PERIPH_ID_BUTTON, \ .user_id = INPUT_KEY_USER_ID_MODE, \ .act_id = BUTTON_MODE_ID, \ }, \ {
\ .type = PERIPH_ID_BUTTON, \ .user_id = INPUT_KEY_USER_ID_SET, \ .act_id = BUTTON_SET_ID, \ }, \ {
\ .type = PERIPH_ID_BUTTON, \ .user_id = INPUT_KEY_USER_ID_PLAY, \ .act_id = BUTTON_PLAY_ID, \ }, \ {
\ .type = PERIPH_ID_BUTTON, \ .user_id = INPUT_KEY_USER_ID_VOLUP, \ .act_id = BUTTON_VOLUP_ID, \ }, \ {
\ .type = PERIPH_ID_BUTTON, \ .user_id = INPUT_KEY_USER_ID_VOLDOWN, \ .act_id = BUTTON_VOLDOWN_ID, \ } \ }
1.4 input_key_service_cfg_t input_cfg = INPUT_KEY_SERVICE_DEFAULT_CONFIG();//------(4)
input_cfg.handle = set; //------(5)
(4)(5)行共同对input_cfg 进行初始化。
set这个句柄我看不懂。
这个是按键服务配置结构体,看看里面包含了哪些内容:
// <esp-adf\components\esp_peripherals\esp_peripherals.c>
typedef struct esp_periph_sets {
EventGroupHandle_t state_event_bits;
xSemaphoreHandle lock;
int task_stack;
int task_prio;
int task_core;
audio_thread_t audio_thread;
bool ext_stack;
bool run;
esp_periph_event_t event_handle;
STAILQ_HEAD(esp_periph_list_item, esp_periph) periph_list;
} esp_periph_set_t;
// <esp-adf\components\esp_peripherals\include\esp_peripherals.h>
typedef struct esp_periph_sets *esp_periph_set_handle_t;
//<esp-adf\components\input_key_service\include\input_key_service.h>
typedef struct {
periph_service_config_t based_cfg; /*!< Peripheral service configuration */
esp_periph_set_handle_t handle; /*!< Peripheral set handle */
} input_key_service_cfg_t;
#define INPUT_KEY_SERVICE_DEFAULT_CONFIG() {
\ .based_cfg = {
\ .task_stack = INPUT_KEY_SERVICE_TASK_STACK_SIZE, \ .task_prio = INPUT_KEY_SERVICE_TASK_PRIORITY, \ .task_core = INPUT_KEY_SERVICE_TASK_ON_CORE, \ .extern_stack = false \ } \ }
1.5 periph_service_handle_t input_ser = input_key_service_create(&input_cfg);//------(6)
创建按键服务句柄,函数实现在《esp-adf\components\input_key_service\input_key_service.c》。
periph_service_handle_t input_key_service_create(input_key_service_cfg_t *input_key_config)
{
AUDIO_NULL_CHECK(TAG, input_key_config, return NULL);
periph_service_config_t *input_cfg = &input_key_config->based_cfg;
periph_service_config_t service_cfg = {
.task_stack = input_cfg->task_stack,
.task_prio = input_cfg->task_prio,
.task_core = input_cfg->task_core,
.extern_stack = input_cfg->extern_stack,
.task_func = input_key_service_task,
.service_start = input_key_service_start,
.service_stop = input_key_service_stop,
.service_destroy = input_key_service_destroy,
.service_ioctl = NULL,
.service_name = "input_key_service",
};
input_key_service_t *input_key_ser = NULL;
periph_service_handle_t input_key_handle = NULL;
input_key_ser = (input_key_service_t *)audio_calloc(1, sizeof(input_key_service_t));
AUDIO_NULL_CHECK(TAG, input_key_ser, goto _create_service_failed);
if (input_key_config->handle) {
input_key_ser->periph_set_handle = input_key_config->handle;
} else {
ESP_LOGE(TAG, "peripherals set handle is NULL");
free(input_key_ser);
return NULL;
}
input_key_ser->ser_state = PERIPH_SERVICE_STATE_UNKNOWN;
STAILQ_INIT(&input_key_ser->input_info_list);
service_cfg.user_data = (void *)input_key_ser;
input_key_handle = periph_service_create(&service_cfg);
AUDIO_NULL_CHECK(TAG, input_key_handle, goto _create_service_failed);
return input_key_handle;
_create_service_failed:
if (input_key_handle) {
audio_free(input_key_handle);
input_key_handle = NULL;
}
if (input_key_ser) {
audio_free(input_key_ser);
input_key_ser = NULL;
}
return NULL;
}
1.6 input_key_service_add_key(input_ser, input_key_info, INPUT_KEY_NUM);//------(7)
把包含6个按键信息的数组input_key_info添加到按键服务函数中。
《esp-adf\components\input_key_service\input_key_service.c》
esp_err_t input_key_service_add_key(periph_service_handle_t input_key_handle, input_key_service_info_t *input_key_info, int add_key_num)
{
AUDIO_NULL_CHECK(TAG, input_key_handle, return ESP_ERR_INVALID_ARG);
AUDIO_NULL_CHECK(TAG, input_key_info, return ESP_ERR_INVALID_ARG);
if (add_key_num <= 0) {
return ESP_FAIL;
}
input_key_service_t *input_key_ser = periph_service_get_data(input_key_handle);
AUDIO_NULL_CHECK(TAG, input_key_ser, return ESP_FAIL);
for (int i = 0; i < add_key_num; i++) {
input_key_node_t *input_key_node = (input_key_node_t *)audio_calloc(1, sizeof(input_key_node_t));
AUDIO_NULL_CHECK(TAG, input_key_node, return ESP_FAIL);
memcpy(&input_key_node->input_key_info, &input_key_info[i], sizeof(input_key_service_info_t));
STAILQ_INSERT_TAIL(&input_key_ser->input_info_list, input_key_node, entries);
}
return ESP_OK;
}
边栏推荐
- TIPC Service and Topology Tracking4
- Liftover for genome coordinate conversion
- Tick Data and Resampling
- Tdsql | difficult employment? Tencent cloud database micro authentication to help you
- TIPC protocol
- Attribute acquisition method and operation notes of C # multidimensional array
- VS2019代码中包含中文内容导致的编译错误和打印输出乱码问题
- The working day of the month is calculated from the 1st day of each month
- Resources读取2d纹理 转换为png格式
- Mongodb learning and sorting (condition operator, $type operator, limit() method, skip() method and sort() method)
猜你喜欢

TIPC addressing 2

Summary of data export methods in powerbi

揭露数据不一致的利器 —— 实时核对系统

Wechat applet uses Baidu API to achieve plant recognition

QT learning diary 7 - qmainwindow

ImportError: cannot import name ‘Digraph‘ from ‘graphviz‘

MySQL linked list data storage query sorting problem

从攻击面视角,看信创零信任方案实践

MySQL比较运算符IN问题求解

JS——每次调用从数组里面随机取一个数,且不能与上一次为同一个
随机推荐
enumrate的start属性的坑
How does the whole network display IP ownership?
bedtools使用教程
What is the relationship between digital transformation of manufacturing industry and lean production
可昇級合約的原理-DelegateCall
Regular and common formulas
Xiao Sha's pain (double pointer
VS2019代码中包含中文内容导致的编译错误和打印输出乱码问题
八大排序汇总
ROS lacks xacro package
Astparser parsing class files with enum enumeration methods
Liftover for genome coordinate conversion
Is the Ren domain name valuable? Is it worth investing? What is the application scope of Ren domain name?
ren域名有价值吗?值不值得投资?ren域名的应用范围有哪些?
Implementation of six singleton modes
LVM operation
Always report errors when connecting to MySQL database
Never forget, there will be echoes | hanging mirror sincerely invites you to participate in the opensca user award research
数字化转型挂帅复产复工,线上线下全融合重建商业逻辑
揭露数据不一致的利器 —— 实时核对系统