【AI小智硬件程序(八)】

AI小智硬件程序(八)

构建开发板抽象层

我们已经完成了音频抽象的部分,现在开始实现板子抽象的部分。

一、创建板子抽象层

board.h

cpp 复制代码
#pragma once
#include <audio_hal.h>
void* create_board();
class Board
{
protected:
    Board(); 
private:
    // 禁用拷贝构造函数
    Board(const Board&) = delete; 
    // 禁用赋值操作
    Board& operator=(const Board&) = delete; 
public:
    virtual ~Board() = default;
    static Board& GetInstance() {
        static Board* instance = static_cast<Board*>(create_board());
        return *instance;
    }
    virtual AudioHAL* GetAudioHAL() = 0;
};
#define REGISTER_BOARD(BOARD_TYPE_CLASS_NAME) \ 
void* create_board() { \
    return new BOARD_TYPE_CLASS_NAME(); \
} 

board.c

cpp 复制代码
#include "board.h"
Board::Board()
{
}

本质上是在实现一个基于单例模式和工厂模式的开发板抽象层,为不同硬件的开发板提供统一的接口,同时保证整个程序中只有一个开发板实例。

bash 复制代码
static Board* instance = static_cast<Board*>(create_board());

这句是最关键的,定义了一个全局只初始化一次的Board基类指针instance,它的初始值是:调用「开发板工厂函数」create_board()创建一个具体的开发板子类对象(比如 ESP32 板子),再把这个子类对象的指针转成基类指针,存到instance里。

二、修改 CmakeList.txt

cpp 复制代码
"board/board.cpp"  


"board" 

三、创建开发板类型

ioelin_dev_board.h

cpp 复制代码
#pragma once
#include "board.h"
#include <audio_hal.h>

class IoelinDevBoard:public Board
{
private:
    /* data */
public:
    IoelinDevBoard();
    ~IoelinDevBoard();

    AudioHAL* GetAudioHAL() override;
};

ioelin_dev_board.cpp

cpp 复制代码
#include "ioelin_dev_board.h"


IoelinDevBoard::IoelinDevBoard()
{
}

IoelinDevBoard::~IoelinDevBoard()
{
}

AudioHAL* IoelinDevBoard::GetAudioHAL()
{
    return nullptr;
}

REGISTER_BOARD(IoelinDevBoard);

这两段代码,是针对「IoelinDevBoard」这款具体开发板的实现代码,也是我们之前聊的「开发板抽象层」的实际落地------ 简单说,就是为这款特定板子实现了抽象基类Board要求的接口,并且完成了注册,让整个程序能识别并使用这款板子。

四、创建 Kconfig.projbuild

Kconfig.projbuild是项目级的配置文件(常见于 ESP-IDF/Zephyr 等嵌入式框架),核心作用是通过menuconfig图形界面定义项目的可配置选项。

cpp 复制代码
menu "Board Configuration"
 
    
choice BOARD_TYPE
    prompt "Board Type"
    default BOARD_TYPE_IOELIN_DEV 
    config BOARD_TYPE_IOELIN_DEV
        bool "杯面_白ESP32-S3开发板"
endchoice

endmenu

五、修改 CmakeList.txt

cpp 复制代码
# 新增开发板需要再这里类似写一个配置BOARD_TYPE的宏为板子类型文件夹名称
if(CONFIG_BOARD_TYPE_IOELIN_DEV)
    set(BOARD_TYPE "ioelin-dev")     
# elseif(CONFIG_BOARD_TYPE_XXX_XXX)
#     set(BOARD_TYPE "xxx-xxx")  
endif()
file(GLOB BOARD_TYPE_SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/board/${BOARD_TYPE}/*.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/board/${BOARD_TYPE}/*.c
)
list(APPEND SOURCES ${BOARD_TYPE_SOURCES})

通过 Kconfig.projbuild 定义 CONFIG_BOARD_TYPE_XXX 配置项,再结合 CMake 的 if-else 和 file(GLOB) 自动匹配文件,核心价值就是避免手动修改 CMakeLists.txt 里的文件列表------ 新增开发板时,只需要加 Kconfig 选项和对应的文件夹,不用改 CMake 代码,极大降低了维护成本。

总的结构

project/

├── board/

│ ├── ioelin-dev/ # Ioelin板子的代码

│ │ ├── ioelin_dev_board.h

│ │ └── ioelin_dev_board.cpp

│ └── esp32-dev/ # ESP32板子的代码

│ ├── esp32_dev_board.h

│ └── esp32_dev_board.cpp

├── CMakeLists.txt

└── Kconfig.projbuild

开发板抽象功能实现

1、管脚配置

cpp 复制代码
/* I2C port and GPIOs */
#define AUDIO_I2C_NUM            (I2C_NUM_0)
#define AUDIO_I2C_SDA_IO         GPIO_NUM_2
#define AUDIO_I2C_SCL_IO         GPIO_NUM_1

/* I2S port and GPIOs */
#define AUDIO_I2S_MCK_IO         GPIO_NUM_38
#define AUDIO_I2S_BCK_IO         GPIO_NUM_14
#define AUDIO_I2S_WS_IO          GPIO_NUM_13
#define AUDIO_I2S_DI_IO          GPIO_NUM_12
#define AUDIO_I2S_DO_IO          GPIO_NUM_45

/* 功放使能IO */
#define AUDIO_PA_EN_IO    GPIO_NUM_18 

/*** 音频输入输出采样率*/
#define AUDIO_OUT_SAMPLE_RATE     (16000)
#define AUDIO_IN_SAMPLE_RATE     (16000)
 
#define ES8311_I2C_ADDR     0x18
#define ES7210_I2C_ADDR     0x41

这里是在为ioelin_dev_board这款开发板,定义硬件相关的 "管脚、通信参数、芯片配置" 等宏常量,相当于把这款板子的硬件细节(比如 I2C 用哪个端口、音频芯片的 I2C 地址)统一集中在头文件里,方便后续代码直接引用。

2、初始化 i2c

cpp 复制代码
i2c_master_bus_handle_t init_i2c(i2c_port_t i2c_port,gpio_num_t i2c_sda_pin,gpio_num_t i2c_scl_pin);

定义一个通用的 I2C 初始化接口,规定 "初始化 I2C 需要传入 3 个参数"(I2C 端口号、SDA 引脚、SCL 引脚),返回初始化后的 I2C 总线句柄

cpp 复制代码
i2c_master_bus_handle_t Board::init_i2c(i2c_port_t i2c_port,gpio_num_t i2c_sda_pin,gpio_num_t i2c_scl_pin) {
    i2c_master_bus_handle_t i2c_bus;
    i2c_master_bus_config_t i2c_bus_cfg = {
        .i2c_port = i2c_port,
        .sda_io_num = i2c_sda_pin,
        .scl_io_num = i2c_scl_pin,
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .glitch_ignore_cnt = 7,
        .intr_priority = 0,
        .trans_queue_depth = 0,
        .flags = {
            .enable_internal_pullup = 1,
        },
    };
    ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus));
    return i2c_bus;
}

实现通用的 I2C 初始化逻辑 ------ 不管什么板子,只要传入正确的端口和引脚,就能用这段代码初始化出可用的 I2C 总线

cpp 复制代码
    i2c_master_bus_handle_t i2c0_bus;

为IoelinDevBoard专属的 I2C0 总线预留 "存储位置",后续初始化后的 I2C 句柄会存在这里,方便这款板子的其他函数(比如音频初始化)调用

cpp 复制代码
i2c0_bus = Board::init_i2c(AUDIO_I2C_NUM,AUDIO_I2C_SDA_IO,AUDIO_I2C_SCL_IO);

给通用的 I2C 初始化逻辑 "喂" 上IoelinDevBoard的专属硬件参数(这些宏就是你之前看到的AUDIO_I2C_NUM=I2C_NUM_0、AUDIO_I2C_SDA_IO=GPIO2等),初始化出这款板子的 I2C0 总线,并把句柄存到i2c0_bus里

3、初始化音频

cpp 复制代码
AudioHAL* audio_hal;
cpp 复制代码
audio_hal = new AudioEs8311Es7210(i2c0_bus,
                                    AUDIO_I2C_NUM,
                                    AUDIO_IN_SAMPLE_RATE,
                                    AUDIO_OUT_SAMPLE_RATE,
                                    AUDIO_I2S_MCK_IO,
                                    AUDIO_I2S_BCK_IO,
                                    AUDIO_I2S_WS_IO,
                                    AUDIO_I2S_DO_IO,
                                    AUDIO_I2S_DI_IO,
                                    AUDIO_PA_EN_IO,
                                    true,
                                    ES8311_I2C_ADDR,
                                    ES7210_I2C_ADDR,
                                    true);
cpp 复制代码
AudioHAL* IoelinDevBoard::GetAudioHAL()
{
    return audio_hal;
}
相关推荐
NAGNIP15 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab16 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab16 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP19 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年20 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼20 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS20 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区21 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈21 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
端平入洛1 天前
delete又未完全delete
c++